vojo/src/app/features/bots/catalog.ts
2026-05-01 20:21:55 +03:00

53 lines
1.6 KiB
TypeScript

import { useMemo } from 'react';
import { useClientConfig } from '../../hooks/useClientConfig';
import type { BotConfig, ClientConfig } from '../../hooks/useClientConfig';
export type BotPreset = {
/** Stable URL slug — `/bots/<id>`. Never reuse across bots. */
id: string;
/** Bot user mxid. The DM with this user IS the bot's control room. */
mxid: string;
name: string;
};
const BOT_ID_RE = /^[A-Za-z0-9_-]+$/;
const MXID_RE = /^@[^:\s]+:[^\s]+$/;
const isValidBotPreset = (preset: BotConfig | undefined): preset is BotPreset =>
typeof preset?.id === 'string' &&
BOT_ID_RE.test(preset.id) &&
typeof preset.mxid === 'string' &&
MXID_RE.test(preset.mxid) &&
typeof preset.name === 'string' &&
preset.name.trim().length > 0;
export const getBotPresets = (clientConfig: ClientConfig): BotPreset[] => {
const seenIds = new Set<string>();
const seenMxids = new Set<string>();
const bots: BotPreset[] = [];
const configuredBots = Array.isArray(clientConfig.bots) ? clientConfig.bots : [];
configuredBots.forEach((preset) => {
if (!isValidBotPreset(preset)) return;
if (seenIds.has(preset.id) || seenMxids.has(preset.mxid)) return;
seenIds.add(preset.id);
seenMxids.add(preset.mxid);
bots.push({
id: preset.id,
mxid: preset.mxid,
name: preset.name.trim(),
});
});
return bots;
};
export const useBotPresets = (): BotPreset[] => {
const clientConfig = useClientConfig();
return useMemo(() => getBotPresets(clientConfig), [clientConfig]);
};
export const findBotPresetById = (
presets: readonly BotPreset[],
id: string
): BotPreset | undefined => presets.find((preset) => preset.id === id);