{"version":3,"file":"narration.cjs","names":["Type","Check"],"sources":["../../src/schemas/narration.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis';\nimport { type Static, Type } from 'typebox';\nimport { Check } from 'typebox/value';\n\n/** Voice-owned Cordis service for caller-authored narration requests. */\nexport const DOOM_NARRATION_SERVICE = 'doom/narration';\n/** Stable provider identity used when consumers pair narration with the mode catalog. */\nexport const DOOM_VOICE_SOURCE = '@agimon-ai/doompi-voice';\n/** Stable mode identity for autonomous narration. */\nexport const DOOM_VOICE_AUTO_MODE_ID = 'voice-auto';\nexport const MAX_NARRATION_TEXT_CHARACTERS = 4_096;\n\nexport const NarrationRequestSchema = Type.Object(\n  {\n    text: Type.String({ minLength: 1, maxLength: MAX_NARRATION_TEXT_CHARACTERS }),\n  },\n  { additionalProperties: false },\n);\n\nexport type NarrationRequest = Static<typeof NarrationRequestSchema>;\n\n/** Generic outbound speech seam. The provider owns delivery and lifecycle. */\nexport interface DoomNarrationService {\n  readonly generation: string;\n  request(request: NarrationRequest): void | Promise<void>;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n  interface Context {\n    'doom/narration': DoomNarrationService;\n  }\n}\n\nfunction replaceControlCharacters(text: string): string {\n  return Array.from(text, (character) => {\n    const codePoint = character.codePointAt(0);\n    return codePoint !== undefined && (codePoint < 0x20 || codePoint === 0x7f) ? ' ' : character;\n  }).join('');\n}\n\n/** Normalize caller-owned speech while preserving Unicode-safe truncation. */\nexport function normalizeNarrationText(text: string): string | undefined {\n  const normalized = replaceControlCharacters(text).replace(/\\s+/gu, ' ').trim();\n  if (!normalized) return undefined;\n\n  let truncated = '';\n  for (const character of normalized) {\n    if (truncated.length + character.length > MAX_NARRATION_TEXT_CHARACTERS) break;\n    truncated += character;\n  }\n  return truncated;\n}\n\n/** Builds the validated request value consumers pass to the injected service. */\nexport function createNarrationRequest(text: string): NarrationRequest | undefined {\n  const normalized = normalizeNarrationText(text);\n  return normalized === undefined ? undefined : Object.freeze({ text: normalized });\n}\n\nexport function isNarrationRequest(value: unknown): value is NarrationRequest {\n  return Check(NarrationRequestSchema, value);\n}\n\nexport function readDoomNarrationService(context: Context): DoomNarrationService | undefined {\n  return context.get(DOOM_NARRATION_SERVICE) as DoomNarrationService | undefined;\n}\n\nexport function requireDoomNarrationService(context: Context): DoomNarrationService {\n  const service = readDoomNarrationService(context);\n  if (!service) throw new Error('Doom narration is unavailable. Load @agimon-ai/doompi-voice.');\n  return service;\n}\n"],"mappings":"oDAKA,MAAa,EAAyB,iBAKzB,EAAgC,KAEhC,EAAyBA,EAAAA,KAAK,OACzC,CACE,KAAMA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAG,UAAW,CAA8B,CAAC,CAC9E,EACA,CAAE,qBAAsB,EAAM,CAChC,EAgBA,SAAS,EAAyB,EAAsB,CACtD,OAAO,MAAM,KAAK,EAAO,GAAc,CACrC,IAAM,EAAY,EAAU,YAAY,CAAC,EACzC,OAAO,IAAc,IAAA,KAAc,EAAY,IAAQ,IAAc,KAAQ,IAAM,CACrF,CAAC,CAAC,CAAC,KAAK,EAAE,CACZ,CAGA,SAAgB,EAAuB,EAAkC,CACvE,IAAM,EAAa,EAAyB,CAAI,CAAC,CAAC,QAAQ,QAAS,GAAG,CAAC,CAAC,KAAK,EAC7E,GAAI,CAAC,EAAY,OAEjB,IAAI,EAAY,GAChB,IAAK,IAAM,KAAa,EAAY,CAClC,GAAI,EAAU,OAAS,EAAU,OAAA,KAAwC,MACzE,GAAa,CACf,CACA,OAAO,CACT,CAGA,SAAgB,EAAuB,EAA4C,CACjF,IAAM,EAAa,EAAuB,CAAI,EAC9C,OAAO,IAAe,IAAA,GAAY,IAAA,GAAY,OAAO,OAAO,CAAE,KAAM,CAAW,CAAC,CAClF,CAEA,SAAgB,EAAmB,EAA2C,CAC5E,OAAA,EAAOC,EAAAA,MAAAA,CAAM,EAAwB,CAAK,CAC5C,CAEA,SAAgB,EAAyB,EAAoD,CAC3F,OAAO,EAAQ,IAAI,CAAsB,CAC3C,CAEA,SAAgB,EAA4B,EAAwC,CAClF,IAAM,EAAU,EAAyB,CAAO,EAChD,GAAI,CAAC,EAAS,MAAU,MAAM,8DAA8D,EAC5F,OAAO,CACT"}