Чаты: реестры и интеграция
Функциональность чатов и голосовых звонков поставляется расширением @rynt/chats-calls. Оно регистрирует экран «Чаты» в core.page / core.nav и два собственных реестра, которые другие пакеты могут пополнять без изменения исходников чатов.
npm-пакет типов: @rynt/extension-chats-calls (entry ./types).
Архитектура
| Роль | Пакет | Что делает |
|---|---|---|
| Хост чатов | @rynt/chats-calls | UI, WebSocket, звонки (LiveKit), встроенные типы сообщений |
| Потребитель | ваше расширение | Новый payload.type, кнопка ввода, отправка через expose |
| Лаунчер | клиент | Резолв зависимостей, маркетплейс, ExtensionRegistrySlotButton |
Реестры @rynt/chats-calls
registryId | Паттерн | Ключ | Значение |
|---|---|---|---|
@rynt/chats-calls.message-types | A | payload.type | { body: Component } — тело сообщения в ленте |
@rynt/chats-calls.input-toolbar | B | произвольный id кнопки | { component: Component } — кнопка над полем ввода |
Константы и типы (рекомендуется импортировать из npm):
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 рендерит все записи:
const inputToolbarRows = computed(() => {
void extensionRegistriesRevision.value;
return getExtensionRegistry<ChatInputToolbarRegistration>(
CHATS_INPUT_TOOLBAR_REGISTRY_ID,
).entries();
});Prop компонента кнопки: { conversationId: string }.
Слоты core.*, которые использует @rynt/chats-calls
registryId | Ключ | Назначение |
|---|---|---|
core.page | chats.main | Экран чатов |
core.nav | chats.main | Пункт меню с бейджем непрочитанных |
core.shell | chats.bootstrap | Инициализация WS / моделей |
core.shell | chats.globalCall | Глобальный UI звонка |
core.sidebar | chats.activeCall | Полоса активного звонка |
core.sidebar | chats.support | Ссылка поддержки в footer |
core.userStrip | chats.openPrivateChat | «Написать» из списка друзей |
Также: registerLauncherEntity('chat_message', Message.vue) — entity-компонент сообщения в общих списках.
Expose: отправка сообщений
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:
{
"dependencies": {
"@rynt/extension-chats-calls": "^0.0.4",
"@rynt/chats-calls": ">=0.0.1"
}
}setup:
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:
{
"declaresRegistries": [
{ "id": "@rynt/chats-calls.message-types", "title": "Типы сообщений чата" },
{ "id": "@rynt/chats-calls.input-toolbar", "title": "Панель ввода чата" }
]
}Потребитель — extensionDependencies + extendsRegistries:
{
"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:
- Если ключ есть в
@rynt/chats-calls.message-types— рендерbody. - Иначе — текст «Не поддерживаемый тип» +
ExtensionRegistrySlotButton(установка расширения из маркетплейса по пареregistryId+registryKey).
Утилиты из @rynt/sdk/extension:
hasRegistryEntry(registryId, key)resolveRegistrySlot(registryId, key)→{ status: 'present' | 'missing', row? }
Подробнее: Расширяемые реестры.
Типизация для зависимого расширения
- Зависимость
@rynt/extension-chats-callsвpackage.json. - В
env.d.ts:
import '@rynt/extension-chats-calls/types';- Augmentation реестра (если нужны свои типы строки):
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 при отправке сообщений.
См. также
- Расширяемые реестры (общая теория)
- Контракт манифеста: чаты
- Навигация и оболочка —
core.page,core.shell,core.userStrip