Skip to content

Чаты: реестры и интеграция

Функциональность чатов и голосовых звонков поставляется расширением @rynt/chats-calls. Оно регистрирует экран «Чаты» в core.page / core.nav и два собственных реестра, которые другие пакеты могут пополнять без изменения исходников чатов.

npm-пакет типов: @rynt/extension-chats-calls (entry ./types).

Архитектура

РольПакетЧто делает
Хост чатов@rynt/chats-callsUI, WebSocket, звонки (LiveKit), встроенные типы сообщений
Потребительваше расширениеНовый payload.type, кнопка ввода, отправка через expose
ЛаунчерклиентРезолв зависимостей, маркетплейс, ExtensionRegistrySlotButton

Реестры @rynt/chats-calls

registryIdПаттернКлючЗначение
@rynt/chats-calls.message-typesApayload.type{ body: Component } — тело сообщения в ленте
@rynt/chats-calls.input-toolbarBпроизвольный id кнопки{ component: Component } — кнопка над полем ввода

Константы и типы (рекомендуется импортировать из npm):

ts
import {
  CHATS_MESSAGE_TYPES_REGISTRY_ID,
  CHATS_INPUT_TOOLBAR_REGISTRY_ID,
  type ChatMessageTypeRegistration,
  type ChatInputToolbarRegistration,
  type ChatMessageBodyProps,
  type ChatsCallsExtensionExpose,
} from '@rynt/extension-chats-calls/types';

Встроенные типы сообщений

Регистрируются в registerBuiltinChatMessageBodies() при старте @rynt/chats-calls:

Ключ (payload.type)Назначение
textОбычный текст, вложения, превью ссылок
invite_serverПриглашение на сервер
buildПубликация сборки
local_buildЛокальная сборка
request_join_localЗапрос присоединиться к локальной сборке

Props тела сообщения (ChatMessageBodyProps)

Компонент из реестра message-types получает как минимум:

  • payload, attachments, messageId, isOwnMessage, conversationId, textPreview
  • колбэки для встроенных сценариев: joinServer, launchBuild, installAndLaunchLocal, shareLocalBuild, …
  • openImageViewer, embed-хелперы для YouTube / MyInstants

Стороннему типу достаточно подмножества полей, релевантных вашему payload.

Панель ввода (input-toolbar)

ChatMessagesSection рендерит все записи:

ts
const inputToolbarRows = computed(() => {
  void extensionRegistriesRevision.value;
  return getExtensionRegistry<ChatInputToolbarRegistration>(
    CHATS_INPUT_TOOLBAR_REGISTRY_ID,
  ).entries();
});

Prop компонента кнопки: { conversationId: string }.

Слоты core.*, которые использует @rynt/chats-calls

registryIdКлючНазначение
core.pagechats.mainЭкран чатов
core.navchats.mainПункт меню с бейджем непрочитанных
core.shellchats.bootstrapИнициализация WS / моделей
core.shellchats.globalCallГлобальный UI звонка
core.sidebarchats.activeCallПолоса активного звонка
core.sidebarchats.supportСсылка поддержки в footer
core.userStripchats.openPrivateChat«Написать» из списка друзей

Также: registerLauncherEntity('chat_message', Message.vue) — entity-компонент сообщения в общих списках.

Expose: отправка сообщений

ts
import { useExtensionExpose } from '@rynt/sdk/extension';

const chats = useExtensionExpose('@rynt/chats-calls');

await chats.value?.sendMessageToConversation(
  conversationId,
  { type: 'demo_ping', foo: 'bar' },
  'Превью в списке диалогов',
  /* attachments? */,
);
  • payload — произвольный объект; поле type должно совпадать с ключом в реестре message-types.
  • textPreview — строка для списка чатов и уведомлений.

Типизация: augmentation ExtensionExposeMap в @rynt/extension-chats-calls/types + import '@rynt/extension-chats-calls/types' в env.d.ts потребителя.

Пример потребителя: @rynt/chats-message-sample

Минимальный пакет в монорепозитории: регистрирует тип demo_ping и кнопку в тулбаре.

package.json:

json
{
  "dependencies": {
    "@rynt/extension-chats-calls": "^0.0.4",
    "@rynt/chats-calls": ">=0.0.1"
  }
}

setup:

ts
import { markRaw } from 'vue';
import { defineRyntExtension, getExtensionRegistry } from '@rynt/sdk/extension';
import DemoPingMessageBody from './DemoPingMessageBody.vue';
import PingToolbarButton from './PingToolbarButton.vue';

export default defineRyntExtension(() => {
  getExtensionRegistry('@rynt/chats-calls.message-types').register(
    'demo_ping',
    { body: markRaw(DemoPingMessageBody) },
    80,
  );

  getExtensionRegistry('@rynt/chats-calls.input-toolbar').register(
    'demo_ping',
    { component: markRaw(PingToolbarButton) },
    10,
  );
});

Манифест

Автор реестров (@rynt/chats-calls) — в declaresRegistries:

json
{
  "declaresRegistries": [
    { "id": "@rynt/chats-calls.message-types", "title": "Типы сообщений чата" },
    { "id": "@rynt/chats-calls.input-toolbar", "title": "Панель ввода чата" }
  ]
}

ПотребительextensionDependencies + extendsRegistries:

json
{
  "extensionDependencies": {
    "@rynt/chats-calls": "^0.0.4"
  },
  "extendsRegistries": [
    { "registryId": "@rynt/chats-calls.message-types", "keys": ["demo_ping"] },
    { "registryId": "@rynt/chats-calls.input-toolbar", "keys": ["demo_ping"] }
  ]
}

Рендер сообщения и fallback

Message.vue выбирает компонент по payload.type:

  1. Если ключ есть в @rynt/chats-calls.message-types — рендер body.
  2. Иначе — текст «Не поддерживаемый тип» + ExtensionRegistrySlotButton (установка расширения из маркетплейса по паре registryId + registryKey).

Утилиты из @rynt/sdk/extension:

  • hasRegistryEntry(registryId, key)
  • resolveRegistrySlot(registryId, key){ status: 'present' | 'missing', row? }

Подробнее: Расширяемые реестры.

Типизация для зависимого расширения

  1. Зависимость @rynt/extension-chats-calls в package.json.
  2. В env.d.ts:
ts
import '@rynt/extension-chats-calls/types';
  1. Augmentation реестра (если нужны свои типы строки):
ts
declare module '@rynt/sdk/extension-registry-payload-map' {
  interface ExtensionRegistryPayloadMap {
    '@rynt/chats-calls.message-types': ChatMessageTypeRegistration;
  }
}

См. также Типизация контрактов.

Звонки

Голосовые звонки (LiveKit) — часть @rynt/chats-calls, не отдельный реестр для сторонних расширений. UI: GlobalCallView, CallView, модель useCallsModel. Для интеграции с чатами достаточно зависимости на @rynt/chats-calls и expose при отправке сообщений.

См. также

Справочник реестров