import { isSemaEvent, isSemaEventLabel, isSemaIntent, isSemaIntentBinding } from './event' import type { SemaActionEvent, SemaIntentBinding } from './types' export class SemaInvariantError extends Error { constructor(message: string) { super(message) this.name = 'SemaInvariantError' } } export function validateSemaIntentBinding(binding: SemaIntentBinding, ctx = 'sema.intent'): void { if (!isSemaIntentBinding(binding)) { throw new SemaInvariantError(`${ctx} is not a valid SemaIntentBinding`) } const supported = binding.supported ?? [] if (supported.length === 0) return for (const intent of supported) { if (!isSemaIntent(intent)) { throw new SemaInvariantError(`${ctx}: intent "${String(intent)}" is not a valid SemaIntent`) } } if (!supported.includes(binding.default)) { throw new SemaInvariantError( `${ctx}: default intent "${binding.default}" must be included in supported intents` ) } } export function validateSemaEvent(event: SemaActionEvent, ctx = 'sema.event'): void { if (isSemaEventLabel(event)) return if (!isSemaEvent(event)) { throw new SemaInvariantError(`${ctx} is not a valid canonical semantic event`) } if (!('intent' in event) || typeof event.intent === 'string') return validateSemaIntentBinding(event.intent, `${ctx}.intent`) }