Files
glchat/web/src/lib/systemMessage.ts
T

59 lines
2.7 KiB
TypeScript
Raw Normal View History

/**
* Системные сообщения (AGENT.md §7.6).
*
* Сервер пишет их с `type: "system"`, а `content` — JSON-строка о событии:
* `{"event":"member_join","user_id":"123"}`, `{"event":"member_kick",…}` или
* `{"event":"channel_created","name":"общий","type":"text"}`. Разбор живёт
* отдельно от компонентов: лента рисует человекочитаемую строку, а
* справочник авторов по нему же добирает идентификаторы участников.
*
* Неизвестное событие и невалидный JSON возвращают `null` — вызывающий код
* показывает исходный текст сообщения как есть, ничего не теряя.
*/
/** Событие системного сообщения. */
export type SystemMessageEvent =
| { kind: 'member_join'; userId: string }
| { kind: 'member_leave'; userId: string }
| { kind: 'member_kick'; userId: string }
| { kind: 'channel_created'; name: string; channelType: string };
function asRecord(value: unknown): Record<string, unknown> | null {
return typeof value === 'object' && value !== null ? (value as Record<string, unknown>) : null;
}
/** Разбор `content` системного сообщения. */
export function parseSystemMessage(content: string): SystemMessageEvent | null {
let payload: unknown;
try {
payload = JSON.parse(content) as unknown;
} catch {
// Не JSON — показываем текст как есть.
return null;
}
const record = asRecord(payload);
const event = record?.['event'];
const userId = record?.['user_id'];
if (event === 'member_join' || event === 'member_leave' || event === 'member_kick') {
return typeof userId === 'string' && userId !== '' ? { kind: event, userId } : null;
}
if (event === 'channel_created') {
const name = record?.['name'];
if (typeof name !== 'string' || name === '') {
return null;
}
const type = record?.['type'];
return { kind: 'channel_created', name, channelType: typeof type === 'string' ? type : 'text' };
}
return null;
}
/**
* Идентификатор пользователя из системного сообщения. Нужен ленте: имя
* автора события резолвится тем же справочником, что и авторы сообщений.
*/
export function systemMessageUserId(content: string): string | null {
const event = parseSystemMessage(content);
return event !== null && event.kind !== 'channel_created' ? event.userId : null;
}