import type { AppserviceConfig } from './types.js'; export interface RegistrationOptions { /** Unique appservice id in Synapse. Default: "mosaic-as". */ id?: string; /** URL where Synapse reaches the appservice, e.g. http://mosaic-as:8008 */ url: string; /** Alias namespace regex prefix. Default: "#mosaic-". */ aliasPrefix?: string; } const escapeRegex = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); /** * Build the Synapse appservice registration document (mosaic-as.yaml). * Deployment (infrastructure repo) serializes this to YAML and mounts it via * app_service_config_files. */ export function buildRegistration(cfg: AppserviceConfig, options: RegistrationOptions) { const prefix = cfg.userPrefix ?? 'agent-'; return { id: options.id ?? 'mosaic-as', url: options.url, as_token: cfg.asToken, hs_token: cfg.hsToken, sender_localpart: cfg.senderLocalpart ?? 'mosaic-as', rate_limited: false, namespaces: { users: [ { regex: `@${escapeRegex(prefix)}.*:${escapeRegex(cfg.domain)}`, exclusive: true, }, ], aliases: [ { regex: `${escapeRegex(options.aliasPrefix ?? '#mosaic-')}.*:${escapeRegex(cfg.domain)}`, exclusive: false, }, ], rooms: [], }, }; } const assertYamlSafe = (field: string, value: string): string => { // Tokens/urls/ids are single-line opaque strings; control characters would // let a crafted value terminate the scalar and inject YAML keys. if (/[\r\n\x00-\x08\x0b-\x1f]/.test(value)) { throw new Error(`registration field ${field} contains control characters`); } return value.replace(/'/g, "''"); }; /** Minimal YAML serialization for the flat registration document. */ export function registrationToYaml(registration: ReturnType): string { const ns = registration.namespaces; const nsBlock = (entries: Array<{ regex: string; exclusive: boolean }>): string => entries.length === 0 ? ' []' : '\n' + entries.map((e) => ` - regex: '${e.regex}'\n exclusive: ${e.exclusive}`).join('\n'); return [ `id: '${assertYamlSafe('id', registration.id)}'`, `url: '${assertYamlSafe('url', registration.url)}'`, `as_token: '${assertYamlSafe('as_token', registration.as_token)}'`, `hs_token: '${assertYamlSafe('hs_token', registration.hs_token)}'`, `sender_localpart: '${assertYamlSafe('sender_localpart', registration.sender_localpart)}'`, `rate_limited: ${registration.rate_limited}`, 'namespaces:', ` users:${nsBlock(ns.users)}`, ` aliases:${nsBlock(ns.aliases)}`, ` rooms:${nsBlock(ns.rooms)}`, '', ].join('\n'); }