@sinch/functions-runtime 0.3.8 โ†’ 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../runtime-shared/src/ai/connect-agent.ts","../../runtime-shared/src/builders/svaml.ts","../../runtime-shared/src/builders/menu.ts","../../runtime-shared/src/config/universal.ts","../../runtime-shared/src/host/middleware.ts","../../runtime-shared/src/host/app.ts","../../runtime-shared/src/sinch/index.ts","../../runtime-shared/src/ai/elevenlabs/state.ts","../../runtime-shared/src/utils/templateRender.ts","../../runtime-shared/src/utils/versionExtractor.ts","../../runtime-shared/src/utils/defaultEndpointHandler.ts","../../runtime-shared/src/utils/functionLoader.ts","../../runtime-shared/src/types/api.ts","../src/cache/local.ts","../src/tunnel/index.ts","../src/tunnel/webhook-config.ts","../src/secrets/index.ts"],"sourcesContent":["/**\n * Connect Agent Action for SVAML Builders\n *\n * Provides the ability to connect voice calls to AI agents via SIP.\n */\n\n/**\n * Supported AI agent providers\n */\nexport enum AgentProvider {\n ElevenLabs = 'elevenlabs',\n}\n\n/**\n * Options for connecting to an AI agent\n */\nexport interface ConnectAgentOptions {\n /** Optional caller ID to display */\n cli?: string;\n /** Maximum call duration in seconds */\n maxDuration?: number;\n /** Suppress subsequent callbacks */\n suppressCallbacks?: boolean;\n /** Custom headers to send to the agent */\n customHeaders?: Record<string, string>;\n /** Call ID for tracking */\n callId?: string;\n /** Caller ID for personalization */\n callerId?: string;\n}\n\n/**\n * Helper class for building SIP URIs for agent connections\n */\nexport class AgentSipHelper {\n /**\n * Build a SIP URI for connecting to an ElevenLabs agent\n */\n static buildElevenLabsSipUri(agentId: string, options?: ConnectAgentOptions): string {\n // ElevenLabs SIP format: sip:agentId@sip.elevenlabs.io\n const baseUri = `sip:${agentId}@sip.elevenlabs.io`;\n\n // Add custom headers as SIP URI parameters if provided\n if (options?.customHeaders && Object.keys(options.customHeaders).length > 0) {\n const headers = Object.entries(options.customHeaders)\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&');\n return `${baseUri};${headers}`;\n }\n\n return baseUri;\n }\n\n /**\n * Build a SIP URI for the given provider and agent\n */\n static buildSipUri(\n provider: AgentProvider,\n agentId: string,\n options?: ConnectAgentOptions\n ): string {\n switch (provider) {\n case AgentProvider.ElevenLabs:\n return this.buildElevenLabsSipUri(agentId, options);\n default:\n throw new Error(`Unsupported agent provider: ${provider}`);\n }\n }\n}\n\n/**\n * Connect agent action type for SVAML\n */\nexport interface ConnectAgentAction {\n name: 'connectSip';\n destination: {\n endpoint: string;\n };\n cli?: string;\n maxDuration?: number;\n suppressCallbacks?: boolean;\n}\n\n/**\n * Create a connectSip action for SVAML\n * This is used internally by the SVAML builders\n */\nexport function createConnectAgentAction(\n provider: AgentProvider,\n agentId: string,\n options?: ConnectAgentOptions\n): ConnectAgentAction {\n const sipUri = AgentSipHelper.buildSipUri(provider, agentId, options);\n\n const action: ConnectAgentAction = {\n name: 'connectSip',\n destination: {\n endpoint: sipUri,\n },\n };\n\n if (options?.cli) {\n action.cli = options.cli;\n }\n\n if (options?.maxDuration !== undefined) {\n action.maxDuration = options.maxDuration;\n }\n\n if (options?.suppressCallbacks !== undefined) {\n action.suppressCallbacks = options.suppressCallbacks;\n }\n\n return action;\n}\n\nexport default {\n AgentProvider,\n AgentSipHelper,\n createConnectAgentAction,\n};\n","/**\n * SVAML Builder Classes\n *\n * Provides a fluent API for building SVAML responses.\n * These builders construct SVAML JSON directly without requiring the Sinch SDK.\n *\n * @example\n * ```typescript\n * const response = new IceSvamlBuilder()\n * .say('Welcome to our service!')\n * .connectPstn('+15551234567')\n * .build();\n * ```\n */\n\nimport type {\n SvamletResponse,\n SvamletInstruction,\n SvamletAction,\n SayInstruction,\n PlayInstruction,\n PlayFilesInstruction,\n StartRecordingInstruction,\n StopRecordingInstruction,\n SetCookieInstruction,\n AnswerInstruction,\n SendDtmfInstruction,\n Menu,\n} from '../types/svaml.js';\nimport type { MenuStructure } from './menu.js';\nimport {\n AgentProvider,\n createConnectAgentAction,\n type ConnectAgentOptions,\n} from '../ai/connect-agent.js';\n\n// ============================================\n// Recording Options\n// ============================================\n\nexport interface RecordingOptions {\n /** URL to send the recording to */\n destinationUrl?: string;\n /** Credentials for the destination */\n credentials?: string;\n /** Recording format */\n format?: 'mp3' | 'wav';\n /** Enable notification events */\n notificationEvents?: boolean;\n /** Enable transcription */\n transcriptionEnabled?: boolean;\n /** Transcription locale */\n transcriptionLocale?: string;\n}\n\n// ============================================\n// Connect Options\n// ============================================\n\nexport interface ConnectPstnOptions {\n /** CLI (Caller ID) to display */\n cli?: string;\n /** Maximum duration in seconds */\n maxDuration?: number;\n /** Timeout in seconds */\n timeout?: number;\n /** Enable ACE callback */\n enableAce?: boolean;\n /** Enable DICE callback */\n enableDice?: boolean;\n /** Enable PIE callback */\n enablePie?: boolean;\n /** DTMF to send on connect */\n dtmf?: string;\n /** Custom data to pass to callbacks */\n custom?: string;\n /** Dial tone indications */\n indications?: 'se' | 'us' | 'no' | 'fi' | 'uk' | 'de' | 'fr';\n /** Enable AMD (Answering Machine Detection) */\n amd?: { enabled: boolean };\n}\n\nexport interface ConnectSipOptions {\n /** CLI (Caller ID) to display */\n cli?: string;\n /** Custom SIP headers */\n headers?: Record<string, string>;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\nexport interface ConnectMxpOptions {\n /** CLI (Caller ID) to display */\n cli?: string;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\nexport interface ConnectConfOptions {\n /** Music on hold */\n moh?: 'ring' | 'music';\n /** Enable DICE callback */\n enableDice?: boolean;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\nexport interface ParkOptions {\n /** Maximum park duration in seconds */\n maxDuration?: number;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\nexport interface RunMenuOptions {\n /** Allow user to interrupt prompts */\n barge?: boolean;\n /** Enable DICE callback */\n enableDice?: boolean;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\n// ============================================\n// Base Builder\n// ============================================\n\n/**\n * Base class for SVAML builders with common instruction methods\n */\nabstract class BaseSvamlBuilder<T extends BaseSvamlBuilder<T>> {\n protected instructions: SvamletInstruction[] = [];\n protected action: SvamletAction | null = null;\n\n /**\n * Add a text-to-speech instruction\n *\n * @param text - Text to speak\n * @param locale - Voice locale (e.g., 'en-US')\n */\n say(text: string, locale = 'en-US'): T {\n const instruction: SayInstruction = { name: 'say', text, locale };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Play an audio file\n *\n * @param url - URL of the audio file to play\n */\n play(url: string): T {\n const instruction: PlayInstruction = { name: 'play', url };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Play multiple audio files\n *\n * @param urls - Array of audio file URLs\n * @param locale - Locale for any TTS prompts\n */\n playFiles(urls: string[], locale = 'en-US'): T {\n const instruction: PlayFilesInstruction = { name: 'playFiles', ids: urls, locale };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Start recording the call\n *\n * @param options - Recording options\n */\n startRecording(options?: RecordingOptions): T {\n const instruction: StartRecordingInstruction = {\n name: 'startRecording',\n options,\n };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Stop recording the call\n */\n stopRecording(): T {\n const instruction: StopRecordingInstruction = { name: 'stopRecording' };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Set a cookie (persists data across callbacks)\n *\n * @param key - Cookie key\n * @param value - Cookie value\n */\n setCookie(key: string, value: string): T {\n const instruction: SetCookieInstruction = { name: 'setCookie', key, value };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Send DTMF tones\n *\n * @param digits - DTMF digits to send\n */\n sendDtmf(digits: string): T {\n const instruction: SendDtmfInstruction = { name: 'sendDtmf', value: digits };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Hang up the call\n */\n hangup(): T {\n this.action = { name: 'hangup' };\n return this as unknown as T;\n }\n\n /**\n * Continue to next callback\n */\n continue(): T {\n this.action = { name: 'continue' };\n return this as unknown as T;\n }\n\n /**\n * Build the final SVAML response\n *\n * @throws Error if no action has been set\n */\n build(): SvamletResponse {\n if (!this.action) {\n throw new Error(\n 'SVAML response requires an action. Call hangup(), continue(), connectPstn(), etc.'\n );\n }\n\n return {\n instructions: this.instructions.length > 0 ? this.instructions : undefined,\n action: this.action,\n };\n }\n}\n\n// ============================================\n// ICE Builder\n// ============================================\n\n/**\n * ICE (Incoming Call Event) SVAML Builder\n *\n * Use this to build responses for incoming call events.\n *\n * @example\n * ```typescript\n * export async function ice(context, event) {\n * return new IceSvamlBuilder()\n * .say('Welcome! Connecting you now.')\n * .connectPstn('+15551234567')\n * .build();\n * }\n * ```\n */\nexport class IceSvamlBuilder extends BaseSvamlBuilder<IceSvamlBuilder> {\n /**\n * Answer the call explicitly\n */\n answer(): this {\n const instruction: AnswerInstruction = { name: 'answer' };\n this.instructions.push(instruction);\n return this;\n }\n\n /**\n * Connect to a PSTN phone number\n *\n * @param number - E.164 formatted phone number (e.g., '+15551234567')\n * @param options - Connection options\n */\n connectPstn(number: string, options?: ConnectPstnOptions): this {\n this.action = {\n name: 'connectPstn',\n number,\n ...options,\n };\n return this;\n }\n\n /**\n * Connect to a SIP endpoint\n *\n * @param destination - SIP URI\n * @param options - Connection options\n */\n connectSip(destination: string, options?: ConnectSipOptions): this {\n this.action = {\n name: 'connectSip',\n destination,\n ...options,\n };\n return this;\n }\n\n /**\n * Connect to an MXP (Sinch SDK) user\n *\n * @param destination - MXP user identifier\n * @param options - Connection options\n */\n connectMxp(destination: string, options?: ConnectMxpOptions): this {\n this.action = {\n name: 'connectMxp',\n destination,\n ...options,\n };\n return this;\n }\n\n /**\n * Join a conference\n *\n * @param conferenceId - Conference ID to join\n * @param options - Conference options\n */\n connectConf(conferenceId: string, options?: ConnectConfOptions): this {\n this.action = {\n name: 'connectConf',\n conferenceId,\n ...options,\n };\n return this;\n }\n\n /**\n * Run an IVR menu\n *\n * @param menus - Array of menu definitions or MenuStructure from createMenu().build()\n * @param options - Menu options\n */\n runMenu(menus: Menu[] | MenuStructure, options?: RunMenuOptions): this {\n const menuArray = Array.isArray(menus) ? menus : menus.menus;\n const barge = Array.isArray(menus) ? options?.barge : menus.barge;\n this.action = {\n name: 'runMenu',\n menus: menuArray,\n barge,\n ...options,\n };\n return this;\n }\n\n /**\n * Park the call (put on hold)\n *\n * @param holdPrompt - Prompt to play while on hold\n * @param options - Park options\n */\n park(holdPrompt?: string, options?: ParkOptions): this {\n this.action = {\n name: 'park',\n holdPrompt,\n ...options,\n };\n return this;\n }\n\n /**\n * Connect to an AI voice agent\n *\n * @param provider - The AI agent provider (e.g., AgentProvider.ElevenLabs)\n * @param agentId - The agent ID to connect to\n * @param options - Connection options\n *\n * @example\n * ```typescript\n * return new IceSvamlBuilder()\n * .say('Connecting you to our AI assistant.')\n * .connectAgent(AgentProvider.ElevenLabs, 'agent_123')\n * .build();\n * ```\n */\n connectAgent(provider: AgentProvider, agentId: string, options?: ConnectAgentOptions): this {\n this.action = createConnectAgentAction(provider, agentId, options);\n return this;\n }\n}\n\n// ============================================\n// ACE Builder\n// ============================================\n\n/**\n * ACE (Answered Call Event) SVAML Builder\n *\n * Use this to build responses for answered call events (outbound calls).\n *\n * @example\n * ```typescript\n * export async function ace(context, event) {\n * if (event.amd?.status === 'machine') {\n * return new AceSvamlBuilder().hangup().build();\n * }\n * return new AceSvamlBuilder()\n * .say('Hello! This is a call from Acme Corp.')\n * .continue()\n * .build();\n * }\n * ```\n */\nexport class AceSvamlBuilder extends BaseSvamlBuilder<AceSvamlBuilder> {\n // ACE has limited actions - only hangup() and continue() from base\n}\n\n// ============================================\n// PIE Builder\n// ============================================\n\n/**\n * PIE (Prompt Input Event) SVAML Builder\n *\n * Use this to build responses for user input events (DTMF/voice).\n *\n * @example\n * ```typescript\n * export async function pie(context, event) {\n * const selection = event.menuResult?.value;\n *\n * if (selection === '1') {\n * return new PieSvamlBuilder()\n * .say('Connecting you to sales.')\n * .connectPstn('+15551234567')\n * .build();\n * }\n *\n * return new PieSvamlBuilder()\n * .say('Goodbye!')\n * .hangup()\n * .build();\n * }\n * ```\n */\nexport class PieSvamlBuilder extends BaseSvamlBuilder<PieSvamlBuilder> {\n /**\n * Connect to a PSTN phone number\n *\n * @param number - E.164 formatted phone number\n * @param options - Connection options\n */\n connectPstn(number: string, options?: ConnectPstnOptions): this {\n this.action = {\n name: 'connectPstn',\n number,\n ...options,\n };\n return this;\n }\n\n /**\n * Run an IVR menu\n *\n * @param menus - Array of menu definitions or MenuStructure from createMenu().build()\n * @param options - Menu options\n */\n runMenu(menus: Menu[] | MenuStructure, options?: RunMenuOptions): this {\n const menuArray = Array.isArray(menus) ? menus : menus.menus;\n const barge = Array.isArray(menus) ? options?.barge : menus.barge;\n this.action = {\n name: 'runMenu',\n menus: menuArray,\n barge,\n ...options,\n };\n return this;\n }\n\n /**\n * Park the call (put on hold)\n *\n * @param holdPrompt - Prompt to play while on hold\n * @param options - Park options\n */\n park(holdPrompt?: string, options?: ParkOptions): this {\n this.action = {\n name: 'park',\n holdPrompt,\n ...options,\n };\n return this;\n }\n\n /**\n * Connect to an AI voice agent\n *\n * @param provider - The AI agent provider (e.g., AgentProvider.ElevenLabs)\n * @param agentId - The agent ID to connect to\n * @param options - Connection options\n *\n * @example\n * ```typescript\n * // Transfer to AI agent based on menu selection\n * if (event.menuResult?.value === 'ai') {\n * return new PieSvamlBuilder()\n * .say('Connecting you to our AI assistant.')\n * .connectAgent(AgentProvider.ElevenLabs, 'agent_123')\n * .build();\n * }\n * ```\n */\n connectAgent(provider: AgentProvider, agentId: string, options?: ConnectAgentOptions): this {\n this.action = createConnectAgentAction(provider, agentId, options);\n return this;\n }\n}\n\n// ============================================\n// Factory Functions\n// ============================================\n\n/**\n * Create a new ICE SVAML builder\n */\nexport function createIceBuilder(): IceSvamlBuilder {\n return new IceSvamlBuilder();\n}\n\n/**\n * Create a new ACE SVAML builder\n */\nexport function createAceBuilder(): AceSvamlBuilder {\n return new AceSvamlBuilder();\n}\n\n/**\n * Create a new PIE SVAML builder\n */\nexport function createPieBuilder(): PieSvamlBuilder {\n return new PieSvamlBuilder();\n}\n","/**\n * Menu Builder Classes\n *\n * Provides a fluent API for building voice IVR menus with validation.\n * Ensures menus are built correctly for both local development and production.\n *\n * Requirements:\n * - All menu structures MUST start with 'main' menu as id\n * - Actions can be: 'return', 'return(value)', or 'menu(menuid)'\n *\n * @example\n * ```typescript\n * const menu = new MenuBuilder()\n * .prompt('Press 1 for sales, 2 for support')\n * .option('1', 'return(sales)')\n * .option('2', 'return(support)')\n * .build();\n * ```\n */\n\nimport type { Menu, MenuOption } from '../types/svaml.js';\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * Valid DTMF keys for menu options\n */\nexport type DtmfKey = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '*' | '#';\n\n/**\n * Menu action types\n * - 'return' - Return to PIE callback with DTMF value\n * - 'return(value)' - Return to PIE callback with custom value\n * - 'menu(menuId)' - Navigate to submenu\n */\nexport type MenuAction = 'return' | `return(${string})` | `menu(${string})`;\n\n/**\n * Complete menu structure for runMenu action\n */\nexport interface MenuStructure {\n /** Enable barge-in (interrupt prompts with input) */\n barge: boolean;\n /** Array of menu definitions */\n menus: Menu[];\n}\n\n/**\n * Language option for language selection menu template\n */\nexport interface LanguageOption {\n /** DTMF key to press */\n dtmf: DtmfKey;\n /** Display name of the language */\n name: string;\n /** Locale code to return (e.g., 'en-US') */\n value: string;\n}\n\n/**\n * Simple menu option for quick menu creation\n */\nexport interface SimpleMenuOption {\n /** DTMF key */\n dtmf: string;\n /** Menu action */\n action: string;\n}\n\n// ============================================\n// Constants\n// ============================================\n\nconst VALID_DTMF_KEYS: readonly string[] = [\n '0',\n '1',\n '2',\n '3',\n '4',\n '5',\n '6',\n '7',\n '8',\n '9',\n '*',\n '#',\n];\n\n// ============================================\n// MenuBuilder Class\n// ============================================\n\n/**\n * Menu builder for creating voice IVR menus with validation\n *\n * @example\n * ```typescript\n * // Simple menu\n * const menu = new MenuBuilder()\n * .prompt('Press 1 for sales, 2 for support')\n * .option('1', 'return(sales)')\n * .option('2', 'return(support)')\n * .build();\n *\n * // Multi-level menu with submenus\n * const menu = new MenuBuilder()\n * .prompt('Press 1 for English, 2 for Spanish')\n * .option('1', 'menu(english)')\n * .option('2', 'menu(spanish)')\n * .addSubmenu('english')\n * .prompt('Press 1 for sales, 2 for support')\n * .option('1', 'return(en-sales)')\n * .option('2', 'return(en-support)')\n * .build();\n * ```\n */\nexport class MenuBuilder {\n private menuStructure: MenuStructure;\n private currentMenu: Menu;\n\n /**\n * Create a new MenuBuilder\n *\n * @param id - Menu ID (must be 'main' for root menu)\n * @throws Error if id is not 'main' for root menu\n */\n constructor(id = 'main') {\n if (id !== 'main') {\n throw new Error(\"Menu structure must start with 'main' menu as id\");\n }\n\n this.menuStructure = {\n barge: true,\n menus: [],\n };\n\n this.currentMenu = {\n id,\n mainPrompt: '',\n options: [],\n repeats: 2,\n maxDigits: 1,\n timeoutMills: 8000,\n };\n }\n\n /**\n * Set the main prompt for the menu\n *\n * @param text - The prompt text (will be wrapped in TTS tags)\n * @param locale - Voice locale (default: 'en-US')\n */\n prompt(text: string, locale = 'en-US'): this {\n this.currentMenu.mainPrompt = `#tts[${text}]`;\n this.currentMenu.locale = locale;\n return this;\n }\n\n /**\n * Set the repeat prompt (played when user doesn't respond)\n *\n * @param text - The repeat prompt text\n */\n repeatPrompt(text: string): this {\n this.currentMenu.repeatPrompt = `#tts[${text}]`;\n return this;\n }\n\n /**\n * Add a menu option\n *\n * @param dtmf - The DTMF key (0-9, *, #)\n * @param action - Action: 'return', 'return(value)', or 'menu(menuid)'\n * @throws Error if DTMF key or action is invalid\n */\n option(dtmf: string, action: string = 'return'): this {\n if (!this.isValidDtmf(dtmf)) {\n throw new Error(`Invalid DTMF key: ${dtmf}. Must be 0-9, *, or #`);\n }\n\n if (!this.isValidAction(action)) {\n throw new Error(\n `Invalid action: ${action}. Must be 'return', 'return(value)', or 'menu(menuid)'`\n );\n }\n\n const menuOption: MenuOption = {\n dtmf: dtmf.toString(),\n action,\n };\n this.currentMenu.options.push(menuOption);\n return this;\n }\n\n /**\n * Set maximum number of digits to collect\n *\n * @param digits - Maximum digits (1-20)\n * @throws Error if digits is out of range\n */\n maxDigits(digits: number): this {\n if (digits < 1 || digits > 20) {\n throw new Error('maxDigits must be between 1 and 20');\n }\n this.currentMenu.maxDigits = digits;\n return this;\n }\n\n /**\n * Set timeout in milliseconds\n *\n * @param ms - Timeout in milliseconds (1000-30000)\n * @throws Error if timeout is out of range\n */\n timeout(ms: number): this {\n if (ms < 1000 || ms > 30000) {\n throw new Error('Timeout must be between 1000ms and 30000ms');\n }\n this.currentMenu.timeoutMills = ms;\n return this;\n }\n\n /**\n * Set number of times to repeat the menu\n *\n * @param count - Number of repeats (0-5)\n * @throws Error if count is out of range\n */\n repeats(count: number): this {\n if (count < 0 || count > 5) {\n throw new Error('Repeats must be between 0 and 5');\n }\n this.currentMenu.repeats = count;\n return this;\n }\n\n /**\n * Enable/disable barge-in (allow interrupting prompts with input)\n *\n * @param enabled - Whether to allow barge-in (default: true)\n */\n barge(enabled = true): this {\n this.menuStructure.barge = enabled;\n return this;\n }\n\n /**\n * Add the current menu and start a new submenu\n *\n * @param id - Menu ID for the submenu\n * @throws Error if submenu ID is invalid\n */\n addSubmenu(id: string): this {\n if (!id || typeof id !== 'string') {\n throw new Error('Submenu ID must be a non-empty string');\n }\n\n // Add current menu to structure\n this.menuStructure.menus.push({ ...this.currentMenu });\n\n // Start new submenu\n this.currentMenu = {\n id,\n mainPrompt: '',\n options: [],\n repeats: 2,\n maxDigits: 1,\n timeoutMills: 8000,\n };\n\n return this;\n }\n\n /**\n * Build and return the complete menu structure\n *\n * @throws Error if menu structure is invalid\n */\n build(): MenuStructure {\n // Add the current menu if it has options\n if (this.currentMenu.options.length > 0) {\n this.menuStructure.menus.push({ ...this.currentMenu });\n }\n\n // Validate that we have at least the main menu\n if (this.menuStructure.menus.length === 0) {\n throw new Error('Menu must have at least one menu with options');\n }\n\n // Validate that first menu is 'main'\n if (this.menuStructure.menus[0].id !== 'main') {\n throw new Error(\"First menu must have id 'main'\");\n }\n\n return this.menuStructure;\n }\n\n /**\n * Get just the menus array (for use with runMenu action)\n */\n buildMenus(): Menu[] {\n return this.build().menus;\n }\n\n /**\n * Validate DTMF key format\n */\n private isValidDtmf(dtmf: string): boolean {\n return VALID_DTMF_KEYS.includes(dtmf.toString());\n }\n\n /**\n * Validate action format\n */\n private isValidAction(action: string): boolean {\n if (action === 'return') return true;\n if (action.startsWith('return(') && action.endsWith(')')) return true;\n if (action.startsWith('menu(') && action.endsWith(')')) return true;\n return false;\n }\n}\n\n// ============================================\n// Factory Functions\n// ============================================\n\n/**\n * Create a new MenuBuilder\n *\n * @param id - Menu ID (defaults to 'main')\n */\nexport function createMenu(id = 'main'): MenuBuilder {\n return new MenuBuilder(id);\n}\n\n/**\n * Create a simple menu quickly\n *\n * @param prompt - Main prompt text\n * @param options - Array of menu options\n */\nexport function createSimpleMenu(prompt: string, options: SimpleMenuOption[] = []): MenuStructure {\n const builder = createMenu().prompt(prompt);\n\n for (const { dtmf, action } of options) {\n builder.option(dtmf, action);\n }\n\n return builder.build();\n}\n\n// ============================================\n// Menu Templates\n// ============================================\n\n/**\n * Pre-built menu templates for common use cases\n */\nexport const MenuTemplates = {\n /**\n * Standard business menu (Sales, Support, Operator)\n *\n * @param companyName - Company name for greeting\n */\n business(companyName = 'Our Company'): MenuStructure {\n return createMenu()\n .prompt(\n `Thank you for calling ${companyName}! Press 1 for sales, 2 for support, or 0 for an operator.`\n )\n .repeatPrompt('Press 1 for sales, 2 for support, or 0 for operator.')\n .option('1', 'return(sales)')\n .option('2', 'return(support)')\n .option('0', 'return(operator)')\n .build();\n },\n\n /**\n * Yes/No confirmation menu\n *\n * @param question - Question to ask\n */\n yesNo(question = 'Please make your selection'): MenuStructure {\n return createMenu()\n .prompt(`${question} Press 1 for Yes, or 2 for No.`)\n .repeatPrompt('Press 1 for Yes, or 2 for No.')\n .option('1', 'return(yes)')\n .option('2', 'return(no)')\n .build();\n },\n\n /**\n * Language selection menu\n *\n * @param languages - Language options\n */\n language(\n languages: LanguageOption[] = [\n { dtmf: '1', name: 'English', value: 'en-US' },\n { dtmf: '2', name: 'Spanish', value: 'es-ES' },\n ]\n ): MenuStructure {\n const promptText =\n languages.map((lang) => `Press ${lang.dtmf} for ${lang.name}`).join(', ') + '.';\n\n const builder = createMenu().prompt(promptText).repeatPrompt(promptText);\n\n for (const lang of languages) {\n builder.option(lang.dtmf, `return(${lang.value})`);\n }\n\n return builder.build();\n },\n\n /**\n * After hours menu\n *\n * @param companyName - Company name\n * @param businessHours - Business hours text\n */\n afterHours(\n companyName = 'Our Company',\n businessHours = '9 AM to 5 PM, Monday through Friday'\n ): MenuStructure {\n return createMenu()\n .prompt(\n `Thank you for calling ${companyName}. Our office hours are ${businessHours}. Press 1 to leave a voicemail, 2 for our website, or 9 for emergency support.`\n )\n .repeatPrompt('Press 1 for voicemail, 2 for website, or 9 for emergency support.')\n .option('1', 'return(voicemail)')\n .option('2', 'return(website)')\n .option('9', 'return(emergency)')\n .timeout(10000)\n .build();\n },\n\n /**\n * Recording consent menu\n */\n recordingConsent(): MenuStructure {\n return createMenu()\n .prompt(\n 'For quality and training purposes, this call may be recorded. Press 1 to continue with recording, or press 2 to opt out.'\n )\n .repeatPrompt('Press 1 to allow recording, or press 2 to opt out.')\n .option('1', 'return(consent)')\n .option('2', 'return(no_consent)')\n .timeout(10000)\n .build();\n },\n\n /**\n * Numeric input menu (for collecting multi-digit input like account numbers)\n *\n * @param prompt - Instructions for user\n * @param digits - Number of digits to collect (default: 4)\n */\n numericInput(prompt: string, digits = 4): MenuStructure {\n return createMenu()\n .prompt(`${prompt} Then press pound.`)\n .repeatPrompt(`Please enter your ${digits} digit number, then press pound.`)\n .maxDigits(digits)\n .option('#', 'return')\n .timeout(15000)\n .build();\n },\n} as const;\n","/**\n * Universal Configuration Utility for Sinch Functions\n *\n * Provides a consistent API for accessing configuration across local development\n * and production environments. Works directly with process.env after secrets\n * have been loaded.\n *\n * @example\n * ```typescript\n * const config = createConfig(context);\n * const apiKey = config.getSecret('PROJECT_ID_API_SECRET');\n * const companyName = config.getVariable('COMPANY_NAME', 'Default Company');\n * ```\n */\n\nimport type { FunctionContext } from '../types/context.js';\nimport type { IFunctionCache } from '../cache/types.js';\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * Application credentials structure\n */\nexport interface ApplicationCredentials {\n applicationKey: string;\n applicationSecret: string;\n}\n\n/**\n * Configuration summary for debugging\n */\nexport interface ConfigSummary {\n environment: 'production' | 'development';\n variables: Record<string, string | undefined>;\n secrets: Record<string, string>;\n hasApplicationCredentials: boolean;\n}\n\n// ============================================\n// UniversalConfig Class\n// ============================================\n\n/**\n * Universal configuration utility class\n *\n * Provides a consistent interface for accessing environment variables,\n * secrets, and configuration across local and production environments.\n */\nexport class UniversalConfig {\n private context: FunctionContext;\n private env: Record<string, string | undefined>;\n\n /**\n * Create a new UniversalConfig instance\n *\n * @param context - Function execution context\n */\n constructor(context: FunctionContext) {\n this.context = context;\n this.env = context.env || (process.env as Record<string, string | undefined>);\n }\n\n /**\n * Get a secret value (e.g., API keys, passwords, tokens)\n *\n * @param name - Secret name (e.g., 'PROJECT_ID_API_SECRET')\n * @param defaultValue - Optional default value if secret not found\n */\n getSecret(name: string, defaultValue: string | null = null): string | null {\n return this.env[name] ?? defaultValue;\n }\n\n /**\n * Get an environment variable (non-secret configuration)\n *\n * @param name - Variable name (e.g., 'COMPANY_NAME', 'API_URL')\n * @param defaultValue - Optional default value\n */\n getVariable(name: string, defaultValue: string | null = null): string | null {\n return this.env[name] ?? defaultValue;\n }\n\n /**\n * Check if a secret exists (has a value)\n *\n * @param name - Secret name\n */\n hasSecret(name: string): boolean {\n return !!this.env[name];\n }\n\n /**\n * Check if a variable exists (has a value)\n *\n * @param name - Variable name\n */\n hasVariable(name: string): boolean {\n return !!this.env[name];\n }\n\n /**\n * Get required secret (throws error if not found)\n *\n * @param name - Secret name\n * @throws Error if secret is not found\n */\n requireSecret(name: string): string {\n const value = this.getSecret(name);\n if (!value) {\n throw new Error(`Required secret '${name}' not found in environment`);\n }\n return value;\n }\n\n /**\n * Get required variable (throws error if not found)\n *\n * @param name - Variable name\n * @throws Error if variable is not found\n */\n requireVariable(name: string): string {\n const value = this.getVariable(name);\n if (!value) {\n throw new Error(`Required variable '${name}' not found in environment`);\n }\n return value;\n }\n\n /**\n * Get Sinch application credentials\n */\n getApplicationCredentials(): ApplicationCredentials | null {\n const key = this.env.VOICE_APPLICATION_KEY;\n const secret = this.env.VOICE_APPLICATION_SECRET;\n\n if (key && secret) {\n return { applicationKey: key, applicationSecret: secret };\n }\n return null;\n }\n\n /**\n * Check if running in development mode\n */\n isDevelopment(): boolean {\n return this.env.NODE_ENV !== 'production';\n }\n\n /**\n * Check if running in production mode\n */\n isProduction(): boolean {\n return this.env.NODE_ENV === 'production';\n }\n\n /**\n * Get cache client instance\n */\n getCache(): IFunctionCache | undefined {\n return this.context.cache;\n }\n\n /**\n * Get comprehensive configuration summary (useful for debugging)\n * Excludes actual secret values for security\n */\n getConfigSummary(): ConfigSummary {\n const secretKeys = [\n 'PROJECT_ID_API_SECRET',\n 'VOICE_APPLICATION_SECRET',\n 'DATABASE_PASSWORD',\n 'API_KEY',\n ];\n\n const summary: ConfigSummary = {\n environment: this.isProduction() ? 'production' : 'development',\n variables: {},\n secrets: {},\n hasApplicationCredentials: !!this.getApplicationCredentials(),\n };\n\n for (const [key, value] of Object.entries(this.env)) {\n if (secretKeys.some((secretKey) => key.includes(secretKey))) {\n summary.secrets[key] = value ? '[REDACTED]' : '[NOT SET]';\n } else if (['NODE_ENV', 'PORT', 'SINCH_REGION'].includes(key)) {\n summary.variables[key] = value;\n }\n }\n\n return summary;\n }\n}\n\n// ============================================\n// Factory Functions\n// ============================================\n\n/**\n * Create a universal config instance for a function execution context\n *\n * @param context - Function execution context\n */\nexport function createConfig(context: FunctionContext): UniversalConfig {\n return new UniversalConfig(context);\n}\n\n// Alias for backwards compatibility\nexport const createUniversalConfig = createConfig;\n","/**\n * Express Middleware for Sinch Functions\n *\n * Provides JSON parsing with automatic camelCase transformation\n * and other middleware utilities.\n */\n\nimport type { Request, Response, NextFunction, Express } from 'express';\nimport { createRequire } from 'module';\nconst requireCjs = createRequire(import.meta.url);\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * Options for camelCase key transformation\n */\nexport interface CamelCaseOptions {\n /** Transform nested objects */\n deep?: boolean;\n /** Paths to skip transformation */\n stopPaths?: string[];\n /** Keys to exclude from transformation */\n exclude?: (string | RegExp)[];\n}\n\n/**\n * Options for JSON parsing middleware\n */\nexport interface JsonParsingOptions {\n /** Maximum body size (default: '10mb') */\n limit?: string;\n /** Accept JSON5 features (default: true) */\n allowJson5?: boolean;\n /** CamelCase transformation options */\n camelCase?: CamelCaseOptions;\n}\n\n/**\n * Extended Express Request with rawBody for signature validation\n */\nexport interface SinchRequest extends Request {\n rawBody?: string;\n _keysTransformed?: boolean;\n}\n\n// ============================================\n// Default Options\n// ============================================\n\nconst defaultOptions: Required<JsonParsingOptions> = {\n limit: '10mb',\n allowJson5: true,\n camelCase: {\n deep: true,\n stopPaths: ['custom', 'applicationkey'],\n exclude: [],\n },\n};\n\n// ============================================\n// Key Transformation\n// ============================================\n\n/**\n * Special case mappings for known Sinch fields without separators\n */\nconst SPECIAL_CASES: Record<string, string> = {\n callid: 'callId',\n applicationkey: 'applicationKey',\n callbackurl: 'callbackUrl',\n clinumber: 'cliNumber',\n menuResult: 'menuResult',\n userid: 'userId',\n username: 'userName',\n callleg: 'callLeg',\n conferenceid: 'conferenceId',\n participantid: 'participantId',\n};\n\n/**\n * Convert string to camelCase\n *\n * Handles:\n * - snake_case: call_id -> callId\n * - kebab-case: call-id -> callId\n * - lowercase concatenated: callid -> callId\n */\nexport function toCamelCase(str: string): string {\n if (!str) return str;\n\n // Already has separators - use standard conversion\n if (str.includes('_') || str.includes('-')) {\n return str.replace(/[-_]([a-z])/g, (_, char: string) => char.toUpperCase());\n }\n\n // Check if already camelCase\n if (/[a-z][A-Z]/.test(str)) {\n return str;\n }\n\n // All lowercase - check special cases\n const lower = str.toLowerCase();\n if (SPECIAL_CASES[lower]) {\n return SPECIAL_CASES[lower];\n }\n\n return str;\n}\n\n/**\n * Deep transform object keys to camelCase\n */\nexport function transformKeys<T>(obj: T, options: CamelCaseOptions = {}): T {\n const { stopPaths = [], exclude = [], deep = true } = options;\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return (deep ? obj.map((item) => transformKeys(item, options)) : obj) as T;\n }\n\n if (typeof obj !== 'object') {\n return obj;\n }\n\n const result: Record<string, unknown> = {};\n\n // Prototype pollution protection - skip dangerous keys\n const DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype'];\n\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n // Skip keys that could cause prototype pollution\n if (DANGEROUS_KEYS.includes(key)) {\n continue;\n }\n\n let newKey = key;\n let shouldTransformValue = deep;\n\n // Check exclusions\n const isExcluded = exclude.some((pattern) => {\n if (pattern instanceof RegExp) {\n return pattern.test(key);\n }\n return pattern === key;\n });\n\n if (!isExcluded) {\n newKey = toCamelCase(key);\n }\n\n // Also skip if transformed key is dangerous\n if (DANGEROUS_KEYS.includes(newKey)) {\n continue;\n }\n\n // Check if we should stop transforming nested values\n if (stopPaths.includes(newKey)) {\n shouldTransformValue = false;\n }\n\n result[newKey] = shouldTransformValue ? transformKeys(value, options) : value;\n }\n\n return result as T;\n}\n\n// ============================================\n// JSON Parsing\n// ============================================\n\n/**\n * Parse JSON with fallback to basic JSON5 support\n */\nexport function parseJson(text: string, allowJson5 = true): unknown {\n if (!text || typeof text !== 'string') {\n return {};\n }\n\n const trimmed = text.trim();\n if (!trimmed) {\n return {};\n }\n\n // First try strict JSON\n try {\n return JSON.parse(trimmed);\n } catch (e) {\n if (!allowJson5) {\n throw new Error(`Invalid JSON: ${(e as Error).message}`);\n }\n\n // Basic JSON5 cleanup\n try {\n const cleaned = trimmed\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Remove /* */ comments\n .replace(/\\/\\/.*$/gm, '') // Remove // comments\n .replace(/,(\\s*[}\\]])/g, '$1'); // Remove trailing commas\n\n return JSON.parse(cleaned);\n } catch (e2) {\n throw new Error(`Invalid JSON/JSON5: ${(e as Error).message}`);\n }\n }\n}\n\n/**\n * Create Express middleware for lenient JSON parsing with camelCase transformation\n */\nexport function createLenientJsonParser(\n options: JsonParsingOptions = {}\n): (req: SinchRequest, res: Response, next: NextFunction) => void {\n const opts = { ...defaultOptions, ...options };\n\n return function lenientJsonParser(req: SinchRequest, res: Response, next: NextFunction): void {\n // Skip if body is already parsed\n if (req.body && typeof req.body === 'object' && !Buffer.isBuffer(req.body)) {\n if (!req._keysTransformed) {\n req.body = transformKeys(req.body, opts.camelCase);\n req._keysTransformed = true;\n }\n return next();\n }\n\n // Get raw body\n let raw = '';\n if (typeof req.body === 'string') {\n raw = req.body;\n req.rawBody = raw;\n } else if (Buffer.isBuffer(req.body)) {\n raw = req.body.toString('utf8');\n req.rawBody = raw;\n } else {\n req.body = {};\n return next();\n }\n\n try {\n let parsed = parseJson(raw, opts.allowJson5);\n // Skip camelCase transformation for webhook endpoints.\n // Webhook payloads (e.g. Conversation API) use snake_case field names\n // and controllers/extensions expect them preserved.\n // Voice callbacks hit \"/\" with event type in body โ€” they still get transformed.\n const isWebhookPath = req.path.startsWith('/webhook');\n if (!isWebhookPath) {\n parsed = transformKeys(parsed, opts.camelCase);\n }\n req._keysTransformed = true;\n req.body = parsed;\n next();\n } catch (error) {\n res.status(400).json({\n error: 'Invalid JSON in request body',\n message: (error as Error).message,\n hint: opts.allowJson5\n ? 'This endpoint accepts JSON and JSON5 (comments and trailing commas allowed)'\n : 'This endpoint requires strict JSON format',\n });\n }\n };\n}\n\n/**\n * Setup Express app with JSON parsing middleware\n */\nexport function setupJsonParsing(app: Express, options: JsonParsingOptions = {}): Express {\n // Dynamic import of express to avoid requiring it at module load time\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const express = requireCjs('express') as typeof import('express');\n\n // Use text parser to get raw body first\n app.use(\n express.text({\n type: ['application/json', 'application/*+json', 'text/json'],\n limit: options.limit || '10mb',\n })\n );\n\n // Apply lenient parser with camelCase transformation\n app.use(createLenientJsonParser(options));\n\n return app;\n}\n","/**\n * Express Application Factory for Sinch Functions\n *\n * Creates and configures Express apps for handling Sinch voice callbacks\n * and custom API endpoints. This is the core of the runtime.\n */\n\nimport type { Express, Request, Response } from 'express';\nimport type { FunctionContext, FunctionConfig } from '../types/context.js';\nimport type { IFunctionCache } from '../cache/types.js';\nimport type { FunctionRequest } from '../types/api.js';\nimport type { SvamletResponse } from '../types/svaml.js';\nimport type { SinchFunction } from '../types/handlers.js';\nimport type {\n IceCallbackData,\n AceCallbackData,\n PieCallbackData,\n DiceCallbackData,\n NotifyCallbackData,\n} from '../types/voice.js';\nimport { setupJsonParsing, type SinchRequest, type JsonParsingOptions } from './middleware.js';\nimport { createRequire } from 'module';\nimport { pathToFileURL } from 'url';\nimport * as nodePath from 'path';\nimport * as nodeFs from 'fs';\n\n// Create a CommonJS-compatible require for loading dependencies\nconst requireCjs = createRequire(import.meta.url);\n\n/**\n * Landing page HTML embedded as a string constant.\n * This avoids file system reads and works correctly when bundled.\n */\nconst LANDING_PAGE_HTML = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Sinch Function</title>\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.ico\">\n <link href=\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&display=swap\" rel=\"stylesheet\">\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: \"DM Sans\", Arial, sans-serif; min-height: 100vh; overflow: hidden; background: #ffffff; }\n #gradient-canvas { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 0; }\n .content { position: relative; z-index: 10; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 2rem; mix-blend-mode: difference; }\n .icon-wrapper { width: 120px; height: 120px; margin-bottom: 2rem; animation: float 6s ease-in-out infinite; }\n @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }\n .icon-wrapper svg { width: 100%; height: 100%; fill: white; }\n .title { font-size: clamp(32px, 6vw, 56px); font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; color: white; text-align: center; max-width: 600px; margin-bottom: 1.5rem; }\n .status { display: inline-flex; align-items: center; gap: 0.75rem; font-size: 18px; font-weight: 500; color: white; opacity: 0.9; }\n .status-dot { width: 10px; height: 10px; background: white; border-radius: 50%; position: relative; }\n .status-dot::before { content: ''; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid white; animation: ripple 2s ease-out infinite; }\n @keyframes ripple { 0% { transform: scale(1); opacity: 0.6; } 100% { transform: scale(2); opacity: 0; } }\n footer { position: fixed; bottom: 0; left: 0; right: 0; padding: 1.5rem 2rem; text-align: center; z-index: 10; mix-blend-mode: difference; }\n .footer-content { display: flex; align-items: center; justify-content: center; gap: 0.5rem; font-size: 13px; color: white; opacity: 0.7; }\n .footer-content svg { height: 16px; width: auto; fill: white; }\n @media (prefers-reduced-motion: reduce) { .icon-wrapper { animation: none; } .status-dot::before { animation: none; display: none; } }\n </style>\n</head>\n<body>\n <canvas id=\"gradient-canvas\"></canvas>\n <div class=\"content\">\n <div class=\"icon-wrapper\">\n <svg viewBox=\"0 0 1024 1024\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M0 0 C20.93144435 -0.58142901 39.09496106 1.50604372 55.875 15.5625 C66.82790249 26.17665293 72.53226475 40.66646351 74.60546875 55.56640625 C74.87588186 58.00035983 74.87588186 58.00035983 76 60 C76.96454894 67.72509952 77.18355452 75.52548686 77.39453125 83.30078125 C77.46339082 85.43557289 77.53307981 87.57033791 77.60351562 89.70507812 C77.70976411 92.99051459 77.81152568 96.27576582 77.89868164 99.56176758 C78.52393733 129.23731142 78.52393733 129.23731142 88 157 C88.35578125 157.67804688 88.7115625 158.35609375 89.078125 159.0546875 C94.76089061 168.37922543 104.94901494 170.48725373 115 173 C115 182.57 115 192.14 115 202 C112.69 202.37125 110.38 202.7425 108 203.125 C99.905737 204.67003153 95.0680161 206.8924082 90.109375 213.53125 C83.71376381 223.52775152 81.23188184 234.44421869 79.9609375 246.09765625 C79.87667007 246.86579147 79.79240265 247.6339267 79.70558167 248.42533875 C78.67925596 258.36255872 78.32712705 268.3341428 77.9375 278.3125 C76.56010435 312.28921394 76.56010435 312.28921394 74.25 321.5 C74.0744458 322.21430176 73.8988916 322.92860352 73.71801758 323.66455078 C69.36621237 340.7251508 62.22279512 355.52722574 46.7734375 364.97265625 C31.08266768 373.31391199 17.46036093 374.45648002 0 374 C0 362.78 0 351.56 0 340 C4.95 339.67 9.9 339.34 15 339 C21.41425661 337.54221441 27.40557289 335.94604143 32 331 C41.96653782 315.14896379 41.37732492 296.30175799 42 278.25 C44.29042973 212.3198731 44.29042973 212.3198731 64.91015625 190 C66.29780265 187.98880883 66.29780265 187.98880883 65.37890625 185.48046875 C64.05564488 183.10009772 62.69232678 181.32846483 60.875 179.3125 C43.91950219 157.82609672 43.67363702 127.5168667 42.25390625 101.43359375 C42.19595886 100.36962875 42.13801147 99.30566376 42.07830811 98.2094574 C41.84407978 93.84466467 41.61402719 89.47975805 41.39819336 85.11401367 C40.99015593 64.27717646 40.99015593 64.27717646 32.98828125 45.5234375 C32 44 32 44 32 42 C31.42121094 41.71253906 30.84242188 41.42507813 30.24609375 41.12890625 C28.83602338 40.42019262 27.43139326 39.70043581 26.03515625 38.96484375 C25.38417969 38.62582031 24.73320313 38.28679687 24.0625 37.9375 C23.41410156 37.59589844 22.76570312 37.25429688 22.09765625 36.90234375 C15.27203813 33.966184 7.11372705 34.47424847 0 34 C0 22.78 0 11.56 0 0 Z\" transform=\"translate(654,325)\"/>\n <path d=\"M0 0 C3.444375 0.04125 6.88875 0.0825 10.4375 0.125 C10.4375 11.345 10.4375 22.565 10.4375 34.125 C7.83875 34.2075 5.24 34.29 2.5625 34.375 C-7.18272292 34.85729903 -15.63749007 36.71684985 -22.5625 44.125 C-31.49595906 57.5251886 -31.12984766 74.21365918 -31.625 89.6875 C-34.18432686 164.24320576 -34.18432686 164.24320576 -54.375 183.4765625 C-55.74969183 185.03433577 -55.74969183 185.03433577 -55.515625 186.95703125 C-54.17099734 190.0155081 -52.28807488 192.49561568 -50.3125 195.1875 C-32.54496946 220.15391355 -32.63824135 251.51444506 -31.51293945 280.92919922 C-31.08045868 292.11365858 -30.51897291 303.08447592 -28.5625 314.125 C-28.43262695 314.88192139 -28.30275391 315.63884277 -28.16894531 316.41870117 C-26.61388783 323.91215705 -23.50529382 330.13896804 -17.1875 334.5625 C-8.59143743 340.04835084 0.27828442 339.49004903 10.4375 340.125 C10.4375 351.345 10.4375 362.565 10.4375 374.125 C-11.03507606 374.69006779 -28.20349315 372.92712593 -45.375 358.5625 C-68.63112564 336.25560398 -67.21470802 299.23895394 -68.0625 269.5625 C-68.59361144 237.84268541 -68.59361144 237.84268541 -82.5625 210.125 C-89.22872268 204.50037462 -95.95018781 203.27807805 -104.5625 201.125 C-104.5625 191.885 -104.5625 182.645 -104.5625 173.125 C-102.0875 172.444375 -99.6125 171.76375 -97.0625 171.0625 C-88.61410179 168.53529591 -83.39407037 165.21504609 -78.3125 157.875 C-77.69451944 156.64176126 -77.11369297 155.38950152 -76.5625 154.125 C-76.05783203 152.97451172 -76.05783203 152.97451172 -75.54296875 151.80078125 C-70.10324087 138.17090127 -68.58488302 123.17691663 -68.1328125 108.6171875 C-68.0590342 106.55597377 -67.98479985 104.49477633 -67.91015625 102.43359375 C-67.79799647 99.2401961 -67.68897443 96.04681123 -67.58837891 92.85302734 C-67.22538737 81.52946225 -66.65494051 70.32073083 -65.13671875 59.0859375 C-64.95793686 57.75983963 -64.95793686 57.75983963 -64.77554321 56.4069519 C-62.24372342 39.06207822 -55.12155189 23.04594995 -40.9609375 12.1171875 C-28.07509054 3.53900119 -15.33988115 -0.26186367 0 0 Z\" transform=\"translate(359.5625,324.875)\"/>\n <path d=\"M0 0 C9.89334431 8.68950817 14.30034619 23.01452361 15.24373245 35.79419899 C15.49099471 41.77148785 15.42334062 47.74978768 15.37109375 53.73046875 C15.36548489 55.63859724 15.36122091 57.54673011 15.35823059 59.4548645 C15.34688325 64.42950786 15.31750548 69.40388024 15.28411865 74.37841797 C15.25319735 79.47359555 15.23967854 84.56881775 15.22460938 89.6640625 C15.19262409 99.62643911 15.13994121 109.58854505 15.078125 119.55078125 C3.528125 119.55078125 -8.021875 119.55078125 -19.921875 119.55078125 C-19.97085938 114.4203125 -20.01984375 109.28984375 -20.0703125 104.00390625 C-20.10574492 100.73175245 -20.14173112 97.45962313 -20.1796875 94.1875 C-20.23973228 89.00671097 -20.29785091 83.82595572 -20.34375 78.64501953 C-20.38093086 74.46275871 -20.42737419 70.28068941 -20.47993851 66.09859467 C-20.49830992 64.51204578 -20.51347972 62.92545612 -20.52521896 61.3388443 C-20.22141003 42.05064114 -20.22141003 42.05064114 -28.921875 25.55078125 C-33.2097739 21.98892101 -37.29807009 19.87523153 -42.921875 19.55078125 C-43.79714844 19.48890625 -44.67242188 19.42703125 -45.57421875 19.36328125 C-54.66067243 18.98906437 -62.9621186 20.4280254 -69.859375 26.73828125 C-76.14726535 33.73487866 -78.0525657 41.92333342 -78.12719727 51.07324219 C-78.13709686 51.82485123 -78.14699646 52.57646027 -78.15719604 53.35084534 C-78.18871966 55.82891721 -78.21353223 58.30700823 -78.23828125 60.78515625 C-78.25885867 62.50580334 -78.27985536 64.22644545 -78.30125427 65.94708252 C-78.35639351 70.47125217 -78.40583867 74.99546682 -78.45410156 79.51971436 C-78.51321858 84.95049451 -78.57940167 90.38119259 -78.64440155 95.81190491 C-78.74230855 104.0581468 -78.83123469 112.30444185 -78.921875 120.55078125 C-90.801875 120.55078125 -102.681875 120.55078125 -114.921875 120.55078125 C-114.921875 77.65078125 -114.921875 34.75078125 -114.921875 -9.44921875 C-103.701875 -9.44921875 -92.481875 -9.44921875 -80.921875 -9.44921875 C-79.96000569 -5.60174152 -79.61528473 -2.14754023 -79.359375 1.80078125 C-79.27558594 3.0640625 -79.19179688 4.32734375 -79.10546875 5.62890625 C-79.04488281 6.593125 -78.98429688 7.55734375 -78.921875 8.55078125 C-78.48875 7.72578125 -78.055625 6.90078125 -77.609375 6.05078125 C-71.50314599 -3.01214812 -59.57220635 -8.76116827 -49.16015625 -11.05859375 C-31.06340614 -13.24155516 -14.8555768 -11.20207112 0 0 Z\" transform=\"translate(613.921875,481.44921875)\"/>\n <path d=\"M0 0 C1.53906801 1.53906801 1.16955456 2.91263628 1.1875 5.0625 C1.1451715 9.92322255 0.65815533 14.68227908 0.0625 19.5 C-0.02427002 20.20648682 -0.11104004 20.91297363 -0.20043945 21.64086914 C-0.86920125 26.7384025 -0.86920125 26.7384025 -2 29 C-2.96808594 28.84144531 -3.93617188 28.68289063 -4.93359375 28.51953125 C-9.31081865 27.89956204 -13.64601408 27.74275212 -18.0625 27.6875 C-18.83916016 27.65849609 -19.61582031 27.62949219 -20.41601562 27.59960938 C-25.75566236 27.54083257 -28.83098013 28.36372264 -33 32 C-37.31404494 38.3211768 -37.31404494 38.3211768 -37 53 C-25.78 53 -14.56 53 -3 53 C-3 62.57 -3 72.14 -3 82 C-14.55 82 -26.1 82 -38 82 C-38 115 -38 148 -38 182 C-49.55 182 -61.1 182 -73 182 C-73 149 -73 116 -73 82 C-79.93 82 -86.86 82 -94 82 C-94 72.43 -94 62.86 -94 53 C-87.07 53 -80.14 53 -73 53 C-73.04125 50.6075 -73.0825 48.215 -73.125 45.75 C-73.17827085 31.60875021 -70.96095372 19.48048613 -61.0078125 8.81640625 C-54.5981324 3.0177657 -47.30019677 0.02408307 -39 -2 C-38.37625488 -2.17200928 -37.75250977 -2.34401855 -37.10986328 -2.52124023 C-25.33848182 -5.19234404 -11.53065338 -2.96722147 0 0 Z\" transform=\"translate(486,419)\"/>\n </svg>\n </div>\n <h1 class=\"title\">Your function is ready for traffic</h1>\n <div class=\"status\"><span class=\"status-dot\"></span>Running</div>\n </div>\n <footer>\n <div class=\"footer-content\">\n Powered by\n <svg viewBox=\"0 0 93 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M92.298 25.271a17.167 17.167 0 0 1-.814 5.312c-1.51 4.734-5.27 8.678-10.06 10.549-5.64 2.202-12.252 1.416-18.624-2.21l-4.649-2.67a16.424 16.424 0 0 1-3.563 3.064l-14.817 8.679-.027.015v-7.501l.027-.014 22.29-13.057a16.017 16.017 0 0 1-.713 3.206l4.656 2.65c5.95 3.386 10.388 2.85 13.065 1.806 2.991-1.167 5.323-3.59 6.245-6.483.692-2.15.679-4.467-.04-6.609-.955-2.88-3.319-5.275-6.324-6.41-2.688-1.014-7.132-1.494-13.04 1.962L29.7 38.747l-.043.028c-4.017 2.35-8.14 3.556-12.065 3.58a18.162 18.162 0 0 1-6.53-1.145C6.247 39.396 2.44 35.498.874 30.783A17.116 17.116 0 0 1 .81 20.166c1.51-4.733 5.272-8.676 10.063-10.548 5.64-2.202 12.252-1.416 18.623 2.212l4.649 2.67a16.377 16.377 0 0 1 3.563-3.067l.281-.163 1.726-1.011-7.37-4.197A3.238 3.238 0 0 1 35.551.437l10.591 6.06L56.52.457a3.238 3.238 0 0 1 3.27 5.588l-29.528 17.05c.132-1.017.36-2.019.683-2.992l-4.656-2.65c-5.946-3.383-10.384-2.847-13.061-1.803-2.991 1.167-5.325 3.59-6.247 6.481a10.623 10.623 0 0 0 .039 6.608c.956 2.882 3.321 5.277 6.324 6.41 2.689 1.012 7.136 1.495 13.042-1.966l36.256-21.208c4.017-2.349 8.14-3.555 12.067-3.579a18.112 18.112 0 0 1 6.53 1.145c4.812 1.813 8.62 5.712 10.187 10.426a17.23 17.23 0 0 1 .872 5.304Z\"/>\n </svg>\n </div>\n </footer>\n <script type=\"importmap\">{\"imports\":{\"three\":\"https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js\"}}</script>\n <script type=\"module\">\n import * as THREE from 'three';\n const COLORS={yellow:new THREE.Color(0xFFBE3C),green:new THREE.Color(0x059688),blue:new THREE.Color(0x3AA7EA),red:new THREE.Color(0xEF5858)};\n const vertexShader=\\`varying vec2 vUv;void main(){vUv=uv;gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);}\\`;\n const fragmentShader=\\`uniform float uTime;uniform vec2 uResolution;uniform vec3 uColor1;uniform vec3 uColor2;uniform vec3 uColor3;uniform vec3 uColor4;varying vec2 vUv;vec3 mod289(vec3 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 mod289(vec4 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 permute(vec4 x){return mod289(((x*34.0)+1.0)*x);}vec4 taylorInvSqrt(vec4 r){return 1.79284291400159-0.85373472095314*r;}float snoise(vec3 v){const vec2 C=vec2(1.0/6.0,1.0/3.0);const vec4 D=vec4(0.0,0.5,1.0,2.0);vec3 i=floor(v+dot(v,C.yyy));vec3 x0=v-i+dot(i,C.xxx);vec3 g=step(x0.yzx,x0.xyz);vec3 l=1.0-g;vec3 i1=min(g.xyz,l.zxy);vec3 i2=max(g.xyz,l.zxy);vec3 x1=x0-i1+C.xxx;vec3 x2=x0-i2+C.yyy;vec3 x3=x0-D.yyy;i=mod289(i);vec4 p=permute(permute(permute(i.z+vec4(0.0,i1.z,i2.z,1.0))+i.y+vec4(0.0,i1.y,i2.y,1.0))+i.x+vec4(0.0,i1.x,i2.x,1.0));float n_=0.142857142857;vec3 ns=n_*D.wyz-D.xzx;vec4 j=p-49.0*floor(p*ns.z*ns.z);vec4 x_=floor(j*ns.z);vec4 y_=floor(j-7.0*x_);vec4 x=x_*ns.x+ns.yyyy;vec4 y=y_*ns.x+ns.yyyy;vec4 h=1.0-abs(x)-abs(y);vec4 b0=vec4(x.xy,y.xy);vec4 b1=vec4(x.zw,y.zw);vec4 s0=floor(b0)*2.0+1.0;vec4 s1=floor(b1)*2.0+1.0;vec4 sh=-step(h,vec4(0.0));vec4 a0=b0.xzyw+s0.xzyw*sh.xxyy;vec4 a1=b1.xzyw+s1.xzyw*sh.zzww;vec3 p0=vec3(a0.xy,h.x);vec3 p1=vec3(a0.zw,h.y);vec3 p2=vec3(a1.xy,h.z);vec3 p3=vec3(a1.zw,h.w);vec4 norm=taylorInvSqrt(vec4(dot(p0,p0),dot(p1,p1),dot(p2,p2),dot(p3,p3)));p0*=norm.x;p1*=norm.y;p2*=norm.z;p3*=norm.w;vec4 m=max(0.6-vec4(dot(x0,x0),dot(x1,x1),dot(x2,x2),dot(x3,x3)),0.0);m=m*m;return 42.0*dot(m*m,vec4(dot(p0,x0),dot(p1,x1),dot(p2,x2),dot(p3,x3)));}float metaball(vec2 p,vec2 center,float radius){float d=length(p-center);return radius/(d*d+0.0001);}void main(){vec2 uv=vUv;vec2 aspect=vec2(uResolution.x/uResolution.y,1.0);vec2 p=(uv-0.5)*aspect;float time=uTime*0.15;vec2 blob1=vec2(0.6*sin(time*0.7+snoise(vec3(time*0.2,0.0,0.0))),0.5*cos(time*0.5+snoise(vec3(0.0,time*0.2,0.0))));vec2 blob2=vec2(0.55*cos(time*0.6+1.5+snoise(vec3(time*0.15,1.0,0.0))),0.6*sin(time*0.8+2.0+snoise(vec3(1.0,time*0.15,0.0))));vec2 blob3=vec2(0.7*sin(time*0.5+3.0+snoise(vec3(time*0.1,2.0,0.0))),0.5*cos(time*0.7+1.0+snoise(vec3(2.0,time*0.1,0.0))));vec2 blob4=vec2(0.55*cos(time*0.8+4.5+snoise(vec3(time*0.12,3.0,0.0))),0.65*sin(time*0.6+0.5+snoise(vec3(3.0,time*0.12,0.0))));float size1=0.16+0.04*sin(time*1.2);float size2=0.14+0.03*cos(time*1.5);float size3=0.18+0.05*sin(time*0.9);float size4=0.12+0.04*cos(time*1.1);float m1=metaball(p,blob1,size1);float m2=metaball(p,blob2,size2);float m3=metaball(p,blob3,size3);float m4=metaball(p,blob4,size4);float field=m1+m2+m3+m4;float noise=snoise(vec3(p*3.0,time*0.3))*0.15;field+=noise;vec3 color=vec3(0.0);float total=m1+m2+m3+m4+0.0001;color+=uColor1*(m1/total);color+=uColor2*(m2/total);color+=uColor3*(m3/total);color+=uColor4*(m4/total);float gradientNoise=snoise(vec3(uv*2.0,time*0.1));color+=gradientNoise*0.05;float threshold=0.8;float edge=smoothstep(threshold-0.3,threshold+0.5,field);vec3 bg1=mix(uColor1,uColor3,uv.y)*0.6+0.4;vec3 bg2=mix(uColor2,uColor4,uv.x)*0.6+0.4;vec3 background=mix(bg1,bg2,0.5+0.5*sin(time*0.2));vec3 finalColor=mix(background,color,edge);float vignette=1.0-length(uv-0.5)*0.5;finalColor*=vignette;finalColor=pow(finalColor,vec3(0.95));gl_FragColor=vec4(finalColor,1.0);}\\`;\n class GradientAnimation{constructor(){this.canvas=document.getElementById('gradient-canvas');this.scene=new THREE.Scene();this.camera=new THREE.OrthographicCamera(-1,1,1,-1,0,1);this.renderer=new THREE.WebGLRenderer({canvas:this.canvas,antialias:true,alpha:false});this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2));this.renderer.setSize(window.innerWidth,window.innerHeight);this.uniforms={uTime:{value:0},uResolution:{value:new THREE.Vector2(window.innerWidth,window.innerHeight)},uColor1:{value:COLORS.yellow},uColor2:{value:COLORS.green},uColor3:{value:COLORS.blue},uColor4:{value:COLORS.red}};const geometry=new THREE.PlaneGeometry(2,2);const material=new THREE.ShaderMaterial({vertexShader,fragmentShader,uniforms:this.uniforms});this.mesh=new THREE.Mesh(geometry,material);this.scene.add(this.mesh);window.addEventListener('resize',this.onResize.bind(this));this.animate();}onResize(){this.renderer.setSize(window.innerWidth,window.innerHeight);this.uniforms.uResolution.value.set(window.innerWidth,window.innerHeight);}animate(){this.uniforms.uTime.value+=0.016;this.renderer.render(this.scene,this.camera);requestAnimationFrame(this.animate.bind(this));}}\n new GradientAnimation();\n </script>\n</body>\n</html>`;\n\n/**\n * Get the landing page HTML content\n * Exported so production runtime can also use it\n */\nexport function getLandingPageHtml(): string {\n return LANDING_PAGE_HTML;\n}\n\n/**\n * Favicon SVG - the {fn} icon used in the landing page\n */\nconst FAVICON_SVG = `<svg viewBox=\"0 0 1024 1024\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"1024\" height=\"1024\" fill=\"#3AA7EA\"/>\n <path fill=\"white\" d=\"M0 0 C20.93144435 -0.58142901 39.09496106 1.50604372 55.875 15.5625 C66.82790249 26.17665293 72.53226475 40.66646351 74.60546875 55.56640625 C74.87588186 58.00035983 74.87588186 58.00035983 76 60 C76.96454894 67.72509952 77.18355452 75.52548686 77.39453125 83.30078125 C77.46339082 85.43557289 77.53307981 87.57033791 77.60351562 89.70507812 C77.70976411 92.99051459 77.81152568 96.27576582 77.89868164 99.56176758 C78.52393733 129.23731142 78.52393733 129.23731142 88 157 C88.35578125 157.67804688 88.7115625 158.35609375 89.078125 159.0546875 C94.76089061 168.37922543 104.94901494 170.48725373 115 173 C115 182.57 115 192.14 115 202 C112.69 202.37125 110.38 202.7425 108 203.125 C99.905737 204.67003153 95.0680161 206.8924082 90.109375 213.53125 C83.71376381 223.52775152 81.23188184 234.44421869 79.9609375 246.09765625 C79.87667007 246.86579147 79.79240265 247.6339267 79.70558167 248.42533875 C78.67925596 258.36255872 78.32712705 268.3341428 77.9375 278.3125 C76.56010435 312.28921394 76.56010435 312.28921394 74.25 321.5 C74.0744458 322.21430176 73.8988916 322.92860352 73.71801758 323.66455078 C69.36621237 340.7251508 62.22279512 355.52722574 46.7734375 364.97265625 C31.08266768 373.31391199 17.46036093 374.45648002 0 374 C0 362.78 0 351.56 0 340 C4.95 339.67 9.9 339.34 15 339 C21.41425661 337.54221441 27.40557289 335.94604143 32 331 C41.96653782 315.14896379 41.37732492 296.30175799 42 278.25 C44.29042973 212.3198731 44.29042973 212.3198731 64.91015625 190 C66.29780265 187.98880883 66.29780265 187.98880883 65.37890625 185.48046875 C64.05564488 183.10009772 62.69232678 181.32846483 60.875 179.3125 C43.91950219 157.82609672 43.67363702 127.5168667 42.25390625 101.43359375 C42.19595886 100.36962875 42.13801147 99.30566376 42.07830811 98.2094574 C41.84407978 93.84466467 41.61402719 89.47975805 41.39819336 85.11401367 C40.99015593 64.27717646 40.99015593 64.27717646 32.98828125 45.5234375 C32 44 32 44 32 42 C31.42121094 41.71253906 30.84242188 41.42507813 30.24609375 41.12890625 C28.83602338 40.42019262 27.43139326 39.70043581 26.03515625 38.96484375 C25.38417969 38.62582031 24.73320313 38.28679687 24.0625 37.9375 C23.41410156 37.59589844 22.76570312 37.25429688 22.09765625 36.90234375 C15.27203813 33.966184 7.11372705 34.47424847 0 34 C0 22.78 0 11.56 0 0 Z\" transform=\"translate(654,325)\"/>\n <path fill=\"white\" d=\"M0 0 C3.444375 0.04125 6.88875 0.0825 10.4375 0.125 C10.4375 11.345 10.4375 22.565 10.4375 34.125 C7.83875 34.2075 5.24 34.29 2.5625 34.375 C-7.18272292 34.85729903 -15.63749007 36.71684985 -22.5625 44.125 C-31.49595906 57.5251886 -31.12984766 74.21365918 -31.625 89.6875 C-34.18432686 164.24320576 -34.18432686 164.24320576 -54.375 183.4765625 C-55.74969183 185.03433577 -55.74969183 185.03433577 -55.515625 186.95703125 C-54.17099734 190.0155081 -52.28807488 192.49561568 -50.3125 195.1875 C-32.54496946 220.15391355 -32.63824135 251.51444506 -31.51293945 280.92919922 C-31.08045868 292.11365858 -30.51897291 303.08447592 -28.5625 314.125 C-28.43262695 314.88192139 -28.30275391 315.63884277 -28.16894531 316.41870117 C-26.61388783 323.91215705 -23.50529382 330.13896804 -17.1875 334.5625 C-8.59143743 340.04835084 0.27828442 339.49004903 10.4375 340.125 C10.4375 351.345 10.4375 362.565 10.4375 374.125 C-11.03507606 374.69006779 -28.20349315 372.92712593 -45.375 358.5625 C-68.63112564 336.25560398 -67.21470802 299.23895394 -68.0625 269.5625 C-68.59361144 237.84268541 -68.59361144 237.84268541 -82.5625 210.125 C-89.22872268 204.50037462 -95.95018781 203.27807805 -104.5625 201.125 C-104.5625 191.885 -104.5625 182.645 -104.5625 173.125 C-102.0875 172.444375 -99.6125 171.76375 -97.0625 171.0625 C-88.61410179 168.53529591 -83.39407037 165.21504609 -78.3125 157.875 C-77.69451944 156.64176126 -77.11369297 155.38950152 -76.5625 154.125 C-76.05783203 152.97451172 -76.05783203 152.97451172 -75.54296875 151.80078125 C-70.10324087 138.17090127 -68.58488302 123.17691663 -68.1328125 108.6171875 C-68.0590342 106.55597377 -67.98479985 104.49477633 -67.91015625 102.43359375 C-67.79799647 99.2401961 -67.68897443 96.04681123 -67.58837891 92.85302734 C-67.22538737 81.52946225 -66.65494051 70.32073083 -65.13671875 59.0859375 C-64.95793686 57.75983963 -64.95793686 57.75983963 -64.77554321 56.4069519 C-62.24372342 39.06207822 -55.12155189 23.04594995 -40.9609375 12.1171875 C-28.07509054 3.53900119 -15.33988115 -0.26186367 0 0 Z\" transform=\"translate(359.5625,324.875)\"/>\n <path fill=\"white\" d=\"M0 0 C9.89334431 8.68950817 14.30034619 23.01452361 15.24373245 35.79419899 C15.49099471 41.77148785 15.42334062 47.74978768 15.37109375 53.73046875 C15.36548489 55.63859724 15.36122091 57.54673011 15.35823059 59.4548645 C15.34688325 64.42950786 15.31750548 69.40388024 15.28411865 74.37841797 C15.25319735 79.47359555 15.23967854 84.56881775 15.22460938 89.6640625 C15.19262409 99.62643911 15.13994121 109.58854505 15.078125 119.55078125 C3.528125 119.55078125 -8.021875 119.55078125 -19.921875 119.55078125 C-19.97085938 114.4203125 -20.01984375 109.28984375 -20.0703125 104.00390625 C-20.10574492 100.73175245 -20.14173112 97.45962313 -20.1796875 94.1875 C-20.23973228 89.00671097 -20.29785091 83.82595572 -20.34375 78.64501953 C-20.38093086 74.46275871 -20.42737419 70.28068941 -20.47993851 66.09859467 C-20.49830992 64.51204578 -20.51347972 62.92545612 -20.52521896 61.3388443 C-20.22141003 42.05064114 -20.22141003 42.05064114 -28.921875 25.55078125 C-33.2097739 21.98892101 -37.29807009 19.87523153 -42.921875 19.55078125 C-43.79714844 19.48890625 -44.67242188 19.42703125 -45.57421875 19.36328125 C-54.66067243 18.98906437 -62.9621186 20.4280254 -69.859375 26.73828125 C-76.14726535 33.73487866 -78.0525657 41.92333342 -78.12719727 51.07324219 C-78.13709686 51.82485123 -78.14699646 52.57646027 -78.15719604 53.35084534 C-78.18871966 55.82891721 -78.21353223 58.30700823 -78.23828125 60.78515625 C-78.25885867 62.50580334 -78.27985536 64.22644545 -78.30125427 65.94708252 C-78.35639351 70.47125217 -78.40583867 74.99546682 -78.45410156 79.51971436 C-78.51321858 84.95049451 -78.57940167 90.38119259 -78.64440155 95.81190491 C-78.74230855 104.0581468 -78.83123469 112.30444185 -78.921875 120.55078125 C-90.801875 120.55078125 -102.681875 120.55078125 -114.921875 120.55078125 C-114.921875 77.65078125 -114.921875 34.75078125 -114.921875 -9.44921875 C-103.701875 -9.44921875 -92.481875 -9.44921875 -80.921875 -9.44921875 C-79.96000569 -5.60174152 -79.61528473 -2.14754023 -79.359375 1.80078125 C-79.27558594 3.0640625 -79.19179688 4.32734375 -79.10546875 5.62890625 C-79.04488281 6.593125 -78.98429688 7.55734375 -78.921875 8.55078125 C-78.48875 7.72578125 -78.055625 6.90078125 -77.609375 6.05078125 C-71.50314599 -3.01214812 -59.57220635 -8.76116827 -49.16015625 -11.05859375 C-31.06340614 -13.24155516 -14.8555768 -11.20207112 0 0 Z\" transform=\"translate(613.921875,481.44921875)\"/>\n <path fill=\"white\" d=\"M0 0 C1.53906801 1.53906801 1.16955456 2.91263628 1.1875 5.0625 C1.1451715 9.92322255 0.65815533 14.68227908 0.0625 19.5 C-0.02427002 20.20648682 -0.11104004 20.91297363 -0.20043945 21.64086914 C-0.86920125 26.7384025 -0.86920125 26.7384025 -2 29 C-2.96808594 28.84144531 -3.93617188 28.68289063 -4.93359375 28.51953125 C-9.31081865 27.89956204 -13.64601408 27.74275212 -18.0625 27.6875 C-18.83916016 27.65849609 -19.61582031 27.62949219 -20.41601562 27.59960938 C-25.75566236 27.54083257 -28.83098013 28.36372264 -33 32 C-37.31404494 38.3211768 -37.31404494 38.3211768 -37 53 C-25.78 53 -14.56 53 -3 53 C-3 62.57 -3 72.14 -3 82 C-14.55 82 -26.1 82 -38 82 C-38 115 -38 148 -38 182 C-49.55 182 -61.1 182 -73 182 C-73 149 -73 116 -73 82 C-79.93 82 -86.86 82 -94 82 C-94 72.43 -94 62.86 -94 53 C-87.07 53 -80.14 53 -73 53 C-73.04125 50.6075 -73.0825 48.215 -73.125 45.75 C-73.17827085 31.60875021 -70.96095372 19.48048613 -61.0078125 8.81640625 C-54.5981324 3.0177657 -47.30019677 0.02408307 -39 -2 C-38.37625488 -2.17200928 -37.75250977 -2.34401855 -37.10986328 -2.52124023 C-25.33848182 -5.19234404 -11.53065338 -2.96722147 0 0 Z\" transform=\"translate(486,419)\"/>\n</svg>`;\n\n/**\n * Get the favicon SVG content\n * Exported so production runtime can also use it\n */\nexport function getFaviconSvg(): string {\n return FAVICON_SVG;\n}\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * Options for creating the Express app\n */\nexport interface AppOptions {\n /** JSON parsing options */\n jsonParsingOptions?: JsonParsingOptions;\n /** Enable landing page for browser requests at root (default: true) */\n landingPageEnabled?: boolean;\n /** Directory to serve static files from (optional) */\n staticDir?: string;\n}\n\n/**\n * Options for setting up the request handler\n */\nexport interface RequestHandlerOptions {\n /** Function to load user code module (can be sync or async for ESM) */\n loadUserFunction?: () => SinchFunction | Promise<SinchFunction>;\n /** Function to build context for each request */\n buildContext?: (req: Request) => FunctionContext;\n /** Logger function */\n logger?: (...args: unknown[]) => void;\n /** Enable landing page for browser requests at root (default: true) */\n landingPageEnabled?: boolean;\n /** Called when request starts */\n onRequestStart?: (data: { functionName: string; req: Request }) => void;\n /** Called when request ends */\n onRequestEnd?: (data: {\n functionName: string;\n req: Request;\n response?: FormattedResponse;\n error?: Error;\n duration: number;\n statusCode: number;\n }) => void;\n}\n\n/**\n * Formatted response structure\n */\nexport interface FormattedResponse {\n statusCode: number;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\n// ============================================\n// Constants\n// ============================================\n\n/** Voice callback function names */\nexport const VOICE_CALLBACKS = ['ice', 'ace', 'pie', 'dice', 'notify'] as const;\n\n/** Notification-only events (don't require SVAML response) */\nexport const NOTIFICATION_EVENTS = ['dice', 'notify'] as const;\n\nexport type VoiceCallback = (typeof VOICE_CALLBACKS)[number];\nexport type NotificationEvent = (typeof NOTIFICATION_EVENTS)[number];\n\n// ============================================\n// Helper Functions\n// ============================================\n\n/**\n * Check if a function name is a voice callback\n */\nexport function isVoiceCallback(functionName: string): functionName is VoiceCallback {\n return VOICE_CALLBACKS.includes(functionName as VoiceCallback);\n}\n\n/**\n * Check if a function is a notification-only event\n */\nexport function isNotificationEvent(functionName: string): functionName is NotificationEvent {\n return NOTIFICATION_EVENTS.includes(functionName as NotificationEvent);\n}\n\n/**\n * Extract function name from request path or body\n */\nexport function extractFunctionName(path: string, body?: { event?: string }): string {\n // Check if body contains an event type (voice callbacks)\n if (body?.event && isVoiceCallback(body.event)) {\n return body.event;\n }\n\n // Strip query string (req.originalUrl includes it, req.path does not)\n const pathname = path.split('?')[0];\n\n // Parse path for function name\n const segments = pathname.split('/').filter((s) => s && s !== '*');\n\n // Single segment paths map directly to function names\n if (segments.length === 1 && isVoiceCallback(segments[0])) {\n return segments[0];\n }\n\n // /webhook/conversation โ†’ conversationWebhook export\n // /webhook/<service> โ†’ <service>Webhook export\n if (segments.length >= 2 && segments[0] === 'webhook') {\n return `${segments[1]}Webhook`;\n }\n\n // /webhook alone โ†’ webhook export (backwards compat)\n if (segments.length === 1 && segments[0] === 'webhook') {\n return 'webhook';\n }\n\n // Default to last segment or 'default'\n return segments[segments.length - 1] || 'default';\n}\n\n/**\n * Generate unique request ID\n */\nexport function generateRequestId(): string {\n return `req_${Date.now()}_${Math.random().toString(36).substring(7)}`;\n}\n\n/**\n * Find the function file - checks dist/function.js first (TypeScript projects),\n * then falls back to function.js (JavaScript projects)\n */\nfunction findFunctionPath(): string {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fs = requireCjs('fs') as typeof import('fs');\n const distPath = nodePath.join(process.cwd(), 'dist', 'function.js');\n const rootPath = nodePath.join(process.cwd(), 'function.js');\n\n if (fs.existsSync(distPath)) {\n return distPath;\n }\n return rootPath;\n}\n\n// ============================================\n// Response Formatting\n// ============================================\n\n/**\n * Format SVAML response for voice callbacks\n */\nexport function formatSvamlResponse(result: unknown, functionName: string): FormattedResponse {\n if (!result || typeof result !== 'object') {\n throw new Error(`Voice callback ${functionName} must return a valid SVAML object`);\n }\n\n const svaml = result as SvamletResponse;\n\n if (!svaml.action && !svaml.instructions) {\n throw new Error(\n `Voice callback ${functionName} must return SVAML with an action or instructions`\n );\n }\n\n // Ensure instructions array exists\n if (!svaml.instructions) {\n svaml.instructions = [];\n }\n\n return {\n statusCode: 200,\n headers: { 'Content-Type': 'application/json' },\n body: svaml,\n };\n}\n\n/**\n * Format custom endpoint response\n */\nexport function formatCustomResponse(result: unknown): FormattedResponse {\n if (!result || typeof result !== 'object') {\n return {\n statusCode: 200,\n headers: { 'Content-Type': 'application/json' },\n body: result,\n };\n }\n\n const response = result as {\n statusCode?: number;\n headers?: Record<string, string>;\n body?: unknown;\n };\n\n if (!response.statusCode) {\n return {\n statusCode: 200,\n headers: { 'Content-Type': 'application/json' },\n body: result,\n };\n }\n\n return {\n statusCode: response.statusCode,\n headers: response.headers,\n body: response.body,\n };\n}\n\n// ============================================\n// Request Validation\n// ============================================\n\n/**\n * Validate voice callback request\n */\nexport function validateVoiceRequest(body: unknown): {\n valid: boolean;\n error?: string;\n expectedEvents?: string[];\n} {\n if (!body || typeof body !== 'object') {\n return {\n valid: false,\n error: 'Missing request body',\n expectedEvents: [...VOICE_CALLBACKS],\n };\n }\n\n const data = body as { event?: string; callId?: string };\n\n if (!data.event) {\n return {\n valid: false,\n error: 'Missing event type in request body',\n expectedEvents: [...VOICE_CALLBACKS],\n };\n }\n\n if (!data.callId) {\n return {\n valid: false,\n error: 'Missing callId in request body',\n };\n }\n\n return { valid: true };\n}\n\n// ============================================\n// Context Building\n// ============================================\n\n/**\n * No-op cache implementation used by buildBaseContext\n * Real cache implementations are provided by the runtime packages.\n */\nconst noOpCache: IFunctionCache = {\n set: async () => {},\n get: async () => null,\n has: async () => false,\n delete: async () => false,\n extend: async () => false,\n keys: async () => [],\n getMany: async () => ({}),\n};\n\n/**\n * Build base context object for function execution\n *\n * Note: Call-specific data like callId is available on the callback event data,\n * not on the context object.\n */\nexport function buildBaseContext(\n req: Request,\n config: Partial<FunctionConfig> = {}\n): FunctionContext {\n return {\n requestId: (req.headers['x-request-id'] as string) || generateRequestId(),\n timestamp: new Date().toISOString(),\n env: process.env as Record<string, string>,\n config: {\n projectId: config.projectId || 'unknown',\n functionName: config.functionName || 'unknown',\n environment: config.environment || 'development',\n variables: config.variables,\n },\n cache: noOpCache,\n assets: (filename: string) => {\n const filePath = nodePath.join(process.cwd(), 'assets', filename);\n return nodeFs.promises.readFile(filePath, 'utf-8');\n },\n };\n}\n\n// ============================================\n// Request Handlers\n// ============================================\n\n/**\n * Handle voice callback execution\n */\nexport async function handleVoiceCallback(\n functionName: string,\n userFunction: SinchFunction,\n context: FunctionContext,\n callbackData: unknown,\n logger?: (...args: unknown[]) => void\n): Promise<FormattedResponse> {\n const handler = userFunction[functionName as keyof SinchFunction];\n\n if (!handler || typeof handler !== 'function') {\n throw new Error(`Function '${functionName}' not found in function.js`);\n }\n\n // Execute the function with proper typing based on event type\n let result: unknown;\n switch (functionName) {\n case 'ice':\n result = await (handler as SinchFunction['ice'])?.(context, callbackData as IceCallbackData);\n break;\n case 'ace':\n result = await (handler as SinchFunction['ace'])?.(context, callbackData as AceCallbackData);\n break;\n case 'pie':\n result = await (handler as SinchFunction['pie'])?.(context, callbackData as PieCallbackData);\n break;\n case 'dice':\n result = await (handler as SinchFunction['dice'])?.(\n context,\n callbackData as DiceCallbackData\n );\n break;\n case 'notify':\n result = await (handler as SinchFunction['notify'])?.(\n context,\n callbackData as NotifyCallbackData\n );\n break;\n default:\n throw new Error(`Unknown voice callback: ${functionName}`);\n }\n\n if (logger) {\n logger('Function result:', result);\n }\n\n // DICE and NOTIFY are notification-only events\n if (isNotificationEvent(functionName)) {\n if (logger) {\n logger(`${functionName.toUpperCase()} callback completed`);\n }\n return {\n statusCode: 200,\n headers: { 'Content-Type': 'application/json' },\n body: {},\n };\n }\n\n return formatSvamlResponse(result, functionName);\n}\n\n/**\n * Handle custom endpoint execution\n */\nexport async function handleCustomEndpoint(\n functionName: string,\n userFunction: SinchFunction,\n context: FunctionContext,\n request: FunctionRequest,\n logger?: (...args: unknown[]) => void\n): Promise<FormattedResponse> {\n // For custom endpoints, check for handler in user function.\n // For root path: 'default' is the canonical name but 'home' is the TS-friendly alias\n let handler = userFunction[functionName as keyof SinchFunction] as\n | ((ctx: FunctionContext, req: FunctionRequest) => Promise<unknown>)\n | undefined;\n\n if ((!handler || typeof handler !== 'function') && functionName === 'default') {\n handler = userFunction['home' as keyof SinchFunction] as typeof handler;\n }\n\n if (!handler || typeof handler !== 'function') {\n throw new Error(`Function '${functionName}' not found in function.js`);\n }\n\n const result = await handler(context, request);\n\n if (logger) {\n logger('Function result:', result);\n }\n\n return formatCustomResponse(result);\n}\n\n// ============================================\n// Express App Factory\n// ============================================\n\n/**\n * Create and configure Express app with standard middleware\n */\nexport function createApp(options: AppOptions = {}): Express {\n // Dynamic import to avoid requiring express at module load\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const express = requireCjs('express') as typeof import('express');\n\n const app = express();\n\n // Optional static file serving (before any other routes)\n // Auto-detect ./public if no explicit staticDir provided\n const staticDir =\n options.staticDir ?? (nodeFs.existsSync('./public') ? './public' : undefined);\n if (staticDir) {\n app.use(\n express.static(staticDir, {\n index: false, // Don't serve index.html for /, we handle that below\n dotfiles: 'ignore',\n })\n );\n }\n\n // Default JSON parsing options\n const jsonOptions = options.jsonParsingOptions || {\n limit: '10mb',\n allowJson5: true,\n camelCase: {\n deep: true,\n stopPaths: ['custom'],\n exclude: [],\n },\n };\n\n // Setup JSON parsing with camelCase transformation\n setupJsonParsing(app, jsonOptions);\n\n // URL encoding for form data\n app.use(express.urlencoded({ extended: true, limit: '10mb' }));\n\n return app;\n}\n\n/**\n * Setup the main request handler\n */\nexport function setupRequestHandler(app: Express, options: RequestHandlerOptions = {}): void {\n const {\n loadUserFunction = async () => {\n // Use dynamic import to support both ESM and CJS user functions\n // Convert to file URL for Windows compatibility\n const functionPath = findFunctionPath();\n const functionUrl = pathToFileURL(functionPath).href;\n const module = await import(functionUrl);\n return (module.default || module) as SinchFunction;\n },\n buildContext = buildBaseContext,\n logger = console.log,\n landingPageEnabled = true,\n onRequestStart = () => {},\n onRequestEnd = () => {},\n } = options;\n\n // Main request handler (Express v5 syntax - {*splat} matches root path too)\n app.use('/{*splat}', async (req: SinchRequest, res: Response) => {\n const startTime = Date.now();\n\n // Favicon: serve the {fn} icon as SVG (GET and HEAD)\n // MUST be checked BEFORE landing page - browsers send Accept: text/html for favicon too!\n // Note: With Express v5's /{*splat}, req.path may be \"/\" - use req.originalUrl instead\n if ((req.method === 'GET' || req.method === 'HEAD') && req.originalUrl === '/favicon.ico') {\n const svg = getFaviconSvg();\n res.type('image/svg+xml').send(svg);\n return;\n }\n\n // Landing page: serve HTML for browser requests to root path\n // This takes precedence over user's default handler for browser requests\n // Note: use req.originalUrl not req.path โ€” inside /{*splat}, req.path is always \"/\"\n if (req.method === 'GET' && req.originalUrl === '/' && landingPageEnabled) {\n const acceptHeader = req.headers.accept || '';\n if (acceptHeader.includes('text/html')) {\n const html = getLandingPageHtml();\n res.type('html').send(html);\n return;\n }\n }\n\n // Auto-serve public/index.html at GET / when landing page is disabled\n if (req.method === 'GET' && req.originalUrl === '/' && !landingPageEnabled) {\n const indexPath = nodePath.join(process.cwd(), 'public', 'index.html');\n if (nodeFs.existsSync(indexPath)) {\n res.type('html').sendFile(indexPath);\n return;\n }\n }\n\n try {\n const functionName = extractFunctionName(req.originalUrl, req.body as { event?: string });\n\n logger(`[${new Date().toISOString()}] ${req.method} ${req.path} -> ${functionName}`);\n\n onRequestStart({ functionName, req });\n\n // Build context for function\n const context = buildContext(req);\n\n // Load user function (supports both sync and async loaders)\n const userFunction = await Promise.resolve(loadUserFunction());\n\n let response: FormattedResponse;\n\n if (isVoiceCallback(functionName)) {\n // Validate voice request\n const validation = validateVoiceRequest(req.body);\n if (!validation.valid) {\n res.status(400).json({\n error: validation.error,\n ...(validation.expectedEvents && { expectedEvents: validation.expectedEvents }),\n });\n return;\n }\n\n // Handle voice callback\n response = await handleVoiceCallback(functionName, userFunction, context, req.body, logger);\n } else {\n // Handle custom endpoint\n const request: FunctionRequest = {\n method: req.method as FunctionRequest['method'],\n path: req.path,\n query: req.query as Record<string, string>,\n headers: req.headers as Record<string, string>,\n body: req.body,\n params: req.params as Record<string, string>,\n };\n\n response = await handleCustomEndpoint(functionName, userFunction, context, request, logger);\n }\n\n // Send response\n res.status(response.statusCode);\n\n if (response.headers) {\n for (const [key, value] of Object.entries(response.headers)) {\n res.setHeader(key, value);\n }\n }\n\n const contentType = response.headers?.['Content-Type'];\n const isJsonContent = contentType?.includes('application/json');\n const isHtmlContent = contentType?.includes('text/html');\n\n if (response.body === undefined) {\n res.end();\n } else if (isJsonContent) {\n res.json(response.body);\n } else if (isHtmlContent) {\n res.send(String(response.body));\n } else {\n res.send(response.body);\n }\n\n const duration = Date.now() - startTime;\n logger(`[${new Date().toISOString()}] Response sent: ${response.statusCode} (${duration}ms)`);\n\n onRequestEnd({\n functionName,\n req,\n response,\n duration,\n statusCode: response.statusCode,\n });\n } catch (error) {\n const duration = Date.now() - startTime;\n\n logger('Function execution error:', {\n error: (error as Error).message,\n stack: (error as Error).stack,\n function: extractFunctionName(req.originalUrl, req.body as { event?: string }),\n });\n\n res.status(500).json({\n error: 'Internal server error',\n message: (error as Error).message,\n ...(process.env.NODE_ENV === 'development' && { stack: (error as Error).stack }),\n });\n\n onRequestEnd({\n functionName: extractFunctionName(req.originalUrl, req.body as { event?: string }),\n req,\n error: error as Error,\n duration,\n statusCode: 500,\n });\n }\n });\n}\n","/**\n * Sinch SDK Client Factory for Sinch Functions\n *\n * Provides pre-initialized Sinch SDK clients based on available configuration.\n * Only initializes products that have required environment variables.\n *\n * Usage in functions:\n * - context.voice - Available when VOICE_APPLICATION_KEY is set\n * - context.conversation - Available when CONVERSATION_APP_ID is set\n * - context.sms - Available when SMS_SERVICE_PLAN_ID is set\n * - context.numbers - Available when ENABLE_NUMBERS_API is set\n */\n\nimport { SinchClient, validateAuthenticationHeader } from '@sinch/sdk-core';\nimport type { VoiceService } from '@sinch/voice';\nimport type { ConversationService } from '@sinch/conversation';\nimport type { SmsService } from '@sinch/sms';\nimport type { NumbersService } from '@sinch/numbers';\n\nexport interface SinchClients {\n voice?: VoiceService;\n conversation?: ConversationService;\n sms?: SmsService;\n numbers?: NumbersService;\n validateWebhookSignature?: (requestData: WebhookRequestData) => boolean;\n}\n\nexport interface WebhookRequestData {\n method: string;\n path: string;\n headers: Record<string, string>;\n body: string;\n}\n\n/**\n * Create Sinch product clients based on available configuration\n * Only initializes products that have required environment variables\n */\nfunction createSinchClients(): SinchClients {\n const clients: SinchClients = {};\n\n // Base credentials check - using new naming convention\n // PROJECT_ID_API_KEY and PROJECT_ID_API_SECRET belong to PROJECT_ID\n const hasCredentials =\n process.env.PROJECT_ID && process.env.PROJECT_ID_API_KEY && process.env.PROJECT_ID_API_SECRET;\n\n if (!hasCredentials) {\n // No Sinch credentials available, return empty object\n // This allows functions to work without Sinch integration\n return clients;\n }\n\n try {\n // Initialize base Sinch client with credentials\n const sinchClient = new SinchClient({\n projectId: process.env.PROJECT_ID!,\n keyId: process.env.PROJECT_ID_API_KEY!,\n keySecret: process.env.PROJECT_ID_API_SECRET!,\n });\n\n // Conversation API - only if app ID is configured\n if (process.env.CONVERSATION_APP_ID) {\n clients.conversation = sinchClient.conversation;\n console.log('[SINCH] Conversation API initialized');\n }\n\n // Voice API - only if voice application is configured\n if (process.env.VOICE_APPLICATION_KEY && process.env.VOICE_APPLICATION_SECRET) {\n // Initialize voice client with application credentials for webhook validation\n const voiceClient = new SinchClient({\n projectId: process.env.PROJECT_ID!,\n keyId: process.env.PROJECT_ID_API_KEY!,\n keySecret: process.env.PROJECT_ID_API_SECRET!,\n applicationKey: process.env.VOICE_APPLICATION_KEY,\n applicationSecret: process.env.VOICE_APPLICATION_SECRET,\n });\n\n clients.voice = voiceClient.voice;\n console.log('[SINCH] Voice API initialized with application credentials');\n }\n\n // SMS API - only if service plan is configured\n if (process.env.SMS_SERVICE_PLAN_ID) {\n clients.sms = sinchClient.sms;\n console.log('[SINCH] SMS API initialized');\n }\n\n // Numbers API - only if explicitly enabled\n if (process.env.ENABLE_NUMBERS_API === 'true') {\n clients.numbers = sinchClient.numbers;\n console.log('[SINCH] Numbers API initialized');\n }\n } catch (error: any) {\n console.error('[SINCH] Failed to initialize Sinch clients:', error.message);\n return {};\n }\n\n // Add the webhook validation function for Voice callbacks\n if (process.env.VOICE_APPLICATION_KEY && process.env.VOICE_APPLICATION_SECRET) {\n clients.validateWebhookSignature = (requestData: WebhookRequestData): boolean => {\n console.log('[SINCH] Validating Voice webhook signature');\n\n try {\n const result = validateAuthenticationHeader(\n process.env.VOICE_APPLICATION_KEY!,\n process.env.VOICE_APPLICATION_SECRET!,\n requestData.headers,\n requestData.body,\n requestData.path,\n requestData.method\n );\n\n console.log('[SINCH] Validation result:', result ? 'VALID' : 'INVALID');\n return result;\n } catch (error: any) {\n console.error('[SINCH] Validation error:', error.message);\n return false;\n }\n };\n }\n\n return clients;\n}\n\n// Lazy initialization with caching\nlet cachedClients: SinchClients | null = null;\n\n/**\n * Get or create Sinch clients (with caching)\n */\nexport function getSinchClients(): SinchClients {\n if (!cachedClients) {\n cachedClients = createSinchClients();\n }\n return cachedClients;\n}\n\n/**\n * Reset cached clients (useful for testing)\n */\nexport function resetSinchClients(): void {\n cachedClients = null;\n}\n\nexport default { getSinchClients, resetSinchClients };\n","/**\n * ElevenLabs State Management for Sinch Functions\n *\n * Singleton to store auto-configuration results for subsequent calls.\n */\n\n/**\n * State for ElevenLabs configuration\n */\nexport interface ElevenLabsStateData {\n /** Phone number ID from Sinch */\n phoneNumberId?: string;\n /** The phone number (E.164 format) */\n phoneNumber?: string;\n /** The ElevenLabs agent ID */\n agentId?: string;\n /** SIP address for the agent */\n sipAddress?: string;\n /** Whether auto-configuration has been completed */\n isConfigured: boolean;\n /** Timestamp of last configuration */\n configuredAt?: Date;\n}\n\n/**\n * Singleton class to manage ElevenLabs state across the runtime\n */\nclass ElevenLabsStateManager {\n private state: ElevenLabsStateData = {\n isConfigured: false,\n };\n\n /**\n * Get the current state\n */\n getState(): Readonly<ElevenLabsStateData> {\n return { ...this.state };\n }\n\n /**\n * Check if ElevenLabs is configured\n */\n isConfigured(): boolean {\n return this.state.isConfigured;\n }\n\n /**\n * Update state with auto-configuration results\n */\n setConfigured(data: Omit<ElevenLabsStateData, 'isConfigured' | 'configuredAt'>): void {\n this.state = {\n ...data,\n isConfigured: true,\n configuredAt: new Date(),\n };\n }\n\n /**\n * Clear the configuration state\n */\n clear(): void {\n this.state = {\n isConfigured: false,\n };\n }\n\n /**\n * Get the phone number ID for making calls\n */\n getPhoneNumberId(): string | undefined {\n return this.state.phoneNumberId;\n }\n\n /**\n * Get the SIP address for connecting to the agent\n */\n getSipAddress(): string | undefined {\n return this.state.sipAddress;\n }\n\n /**\n * Get the configured agent ID\n */\n getAgentId(): string | undefined {\n return this.state.agentId;\n }\n}\n\n/**\n * Singleton instance of ElevenLabs state\n */\nexport const ElevenLabsState = new ElevenLabsStateManager();\n\nexport default ElevenLabsState;\n","/**\n * Simple template renderer for HTML files\n * Replaces {{variableName}} placeholders with actual values\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nexport class TemplateRender {\n /**\n * Load and render an HTML template with variables\n * @param templatePath - Path to the HTML template file\n * @param variables - Object containing variables to replace in template\n * @returns Rendered HTML string\n */\n static render(templatePath: string, variables: Record<string, any> = {}): string {\n try {\n // Read the template file\n const template = fs.readFileSync(templatePath, 'utf8');\n\n // Replace all {{variableName}} placeholders with actual values\n let rendered = template;\n for (const [key, value] of Object.entries(variables)) {\n const placeholder = `{{${key}}}`;\n const regex = new RegExp(placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g');\n rendered = rendered.replace(regex, String(value));\n }\n\n return rendered;\n } catch (error: any) {\n console.error('Error rendering template:', error);\n throw new Error(`Failed to render template: ${templatePath}`);\n }\n }\n\n /**\n * Get the absolute path to a template file relative to the current directory\n * @param templateName - Name of the template file (e.g., 'index.html')\n * @param baseDir - Base directory to search from (defaults to cwd)\n * @returns Absolute path to the template file\n */\n static getTemplatePath(templateName: string, baseDir?: string): string {\n const searchDir = baseDir || process.cwd();\n // Look in utils/pages directory (matching original structure)\n const pagesPath = path.join(searchDir, 'utils', 'pages', templateName);\n if (fs.existsSync(pagesPath)) {\n return pagesPath;\n }\n // Also try direct pages directory\n const directPath = path.join(searchDir, 'pages', templateName);\n if (fs.existsSync(directPath)) {\n return directPath;\n }\n // Fallback to the original path pattern\n return path.join(searchDir, 'utils', 'pages', templateName);\n }\n}\n\nexport default TemplateRender;\n","/**\n * Version extractor utility for reading template versions from README.md files\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nexport class VersionExtractor {\n /**\n * Extract version from README.md file in the template directory\n * Looks for \"Template Version: X.X.X\" pattern in the last few lines\n * @param templateDir - Path to the template directory containing README.md\n * @returns Version string or default fallback\n */\n static getTemplateVersion(templateDir: string = process.cwd()): string {\n try {\n const readmePath = path.join(templateDir, 'README.md');\n\n if (!fs.existsSync(readmePath)) {\n console.warn('README.md not found, using default version');\n return 'v1.0.0';\n }\n\n const readmeContent = fs.readFileSync(readmePath, 'utf8');\n const lines = readmeContent.split('\\n');\n\n // Look for version pattern in the last few lines\n const versionPattern = /Template Version:\\s*([\\d.]+)/i;\n\n for (let i = lines.length - 1; i >= Math.max(0, lines.length - 10); i--) {\n const match = lines[i].match(versionPattern);\n if (match) {\n return `v${match[1]}`;\n }\n }\n\n console.warn('Version pattern not found in README.md, using default');\n return 'v1.0.0';\n } catch (error: any) {\n console.error('Error reading template version:', error.message);\n return 'v1.0.0';\n }\n }\n}\n\nexport default VersionExtractor;\n","/**\n * Shared default endpoint handler with content negotiation\n * Supports both HTML (for browsers) and JSON (for API clients) responses\n */\n\nimport { TemplateRender } from './templateRender.js';\nimport type { FunctionContext } from '../types/context.js';\n\nexport interface DefaultEndpointOptions {\n serviceName?: string;\n companyName?: string;\n templateVersion?: string;\n availableEndpoints?: Record<string, string>;\n}\n\nexport interface HttpRequest {\n method: string;\n path: string;\n query?: Record<string, any>;\n headers?: Record<string, string>;\n body?: any;\n params?: Record<string, string>;\n}\n\nexport interface HttpResponse {\n statusCode: number;\n headers: Record<string, string>;\n body: any;\n}\n\nexport class DefaultEndpointHandler {\n /**\n * Handle the default endpoint with content negotiation\n * @param context - Function context with config and cache\n * @param request - HTTP request object with method, path, query, headers, body, params\n * @param options - Configuration options for the response\n * @returns HTTP response object with statusCode, headers, and body\n */\n static async handle(\n context: FunctionContext,\n request: HttpRequest,\n options: DefaultEndpointOptions = {}\n ): Promise<HttpResponse> {\n const {\n serviceName = 'Sinch Function',\n companyName = 'Your Company',\n templateVersion = 'v1.0.0',\n availableEndpoints = {},\n } = options;\n\n console.info('Default endpoint called');\n console.info(`Request: ${request.method} ${request.path}`);\n\n // Check Accept header for content negotiation\n const acceptHeader = request.headers?.accept || request.headers?.Accept || '';\n const wantsHtml =\n acceptHeader.includes('text/html') ||\n (!acceptHeader.includes('application/json') &&\n !acceptHeader.includes('application/*') &&\n !acceptHeader.includes('*/*'));\n\n // If HTML is requested, return the HTML template\n if (wantsHtml) {\n try {\n const templatePath = TemplateRender.getTemplatePath('index.html');\n const html = TemplateRender.render(templatePath, {\n companyName: serviceName,\n requestId: context.requestId,\n method: request.method,\n path: request.path,\n timestamp: new Date().toISOString(),\n templateVersion: templateVersion,\n runtime: 'Node.js',\n });\n\n return {\n statusCode: 200,\n headers: {\n 'Content-Type': 'text/html; charset=utf-8',\n },\n body: html,\n };\n } catch (error) {\n // Fall through to JSON response if template not found\n console.warn('HTML template not found, returning JSON');\n }\n }\n\n // Return JSON response for API clients\n return {\n statusCode: 200,\n headers: {\n 'Content-Type': 'application/json',\n },\n body: {\n message: `Welcome to ${serviceName}`,\n timestamp: new Date().toISOString(),\n requestId: context.requestId,\n method: request.method,\n path: request.path,\n availableEndpoints,\n usage: {\n html: 'Set Accept: text/html header or visit in browser',\n json: 'Set Accept: application/json header or use API client',\n },\n },\n };\n }\n}\n\nexport default DefaultEndpointHandler;\n","/**\n * Function loader utilities - shared between dev and prod runtimes\n */\n\nimport path from 'path';\n\n/**\n * Get the path to the compiled function file.\n * TypeScript projects compile to dist/function.js\n */\nexport function findFunctionPath(): string {\n return path.join(process.cwd(), 'dist', 'function.js');\n}\n","/**\n * HTTP request/response types for custom API endpoints\n */\n\n/**\n * HTTP methods supported by function endpoints\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\n/**\n * HTTP request for custom endpoints\n *\n * Abstraction over Express request for user-friendly API handling.\n */\nexport interface FunctionRequest {\n /** HTTP method */\n method: HttpMethod;\n /** Request path */\n path: string;\n /** Query parameters */\n query?: Record<string, string | string[]>;\n /** Request headers (lowercase keys) */\n headers?: Record<string, string>;\n /** Request body (parsed JSON) */\n body?: unknown;\n /** Route parameters (e.g., /users/:id) */\n params?: Record<string, string>;\n}\n\n/**\n * HTTP response for custom endpoints\n *\n * Return this from custom API handlers to control the response.\n */\nexport interface FunctionResponse {\n /** HTTP status code (default: 200) */\n statusCode: number;\n /** Response headers */\n headers?: Record<string, string>;\n /** Response body (will be JSON serialized) */\n body?: unknown;\n}\n\n/**\n * Create a success response\n */\nexport function ok<T>(body: T, headers?: Record<string, string>): FunctionResponse {\n return { statusCode: 200, body, headers };\n}\n\n/**\n * Create a created response (201)\n */\nexport function created<T>(body: T, headers?: Record<string, string>): FunctionResponse {\n return { statusCode: 201, body, headers };\n}\n\n/**\n * Create a no content response (204)\n */\nexport function noContent(): FunctionResponse {\n return { statusCode: 204 };\n}\n\n/**\n * Create a bad request response (400)\n */\nexport function badRequest(message: string): FunctionResponse {\n return { statusCode: 400, body: { error: message } };\n}\n\n/**\n * Create a not found response (404)\n */\nexport function notFound(message = 'Not found'): FunctionResponse {\n return { statusCode: 404, body: { error: message } };\n}\n\n/**\n * Create an internal error response (500)\n */\nexport function internalError(message = 'Internal server error'): FunctionResponse {\n return { statusCode: 500, body: { error: message } };\n}\n\n/**\n * Create a response with custom status code\n */\nexport function createResponse<T>(\n statusCode: number,\n body?: T,\n headers?: Record<string, string>\n): FunctionResponse {\n return { statusCode, body, headers };\n}\n\n/**\n * Create a JSON response\n */\nexport function createJsonResponse<T>(body: T, statusCode = 200): FunctionResponse {\n return {\n statusCode,\n headers: { 'Content-Type': 'application/json' },\n body,\n };\n}\n\n/**\n * Create an error response\n */\nexport function createErrorResponse(message: string, statusCode = 400): FunctionResponse {\n return {\n statusCode,\n headers: { 'Content-Type': 'application/json' },\n body: { error: message },\n };\n}\n","/**\n * Local cache implementation for development\n *\n * Uses in-memory Map with TTL support to simulate production cache behavior.\n * In production, the package is swapped to @sinch/functions-runtime-prod\n * which provides DaprCache instead.\n */\n\nimport type { IFunctionCache } from '@sinch/functions-runtime-shared';\n\ninterface CacheEntry<T> {\n value: T;\n expiresAt: number;\n}\n\n// Global cache store - persists across hot reloads in development\nconst globalCache = new Map<string, CacheEntry<unknown>>();\n\n/**\n * Local cache client for development\n *\n * Implements IFunctionCache using an in-memory Map with TTL support.\n * Data is lost when the process restarts.\n */\nexport class LocalCache implements IFunctionCache {\n private cache: Map<string, CacheEntry<unknown>>;\n\n constructor() {\n this.cache = globalCache;\n }\n\n async set<T = unknown>(key: string, value: T, ttlSeconds = 3600): Promise<void> {\n this.cache.set(key, {\n value,\n expiresAt: Date.now() + ttlSeconds * 1000,\n });\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const item = this.cache.get(key);\n if (!item || Date.now() > item.expiresAt) {\n this.cache.delete(key);\n return null;\n }\n return item.value as T;\n }\n\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== null;\n }\n\n async delete(key: string): Promise<boolean> {\n return this.cache.delete(key);\n }\n\n async extend(key: string, additionalSeconds: number): Promise<boolean> {\n const item = this.cache.get(key);\n if (!item || Date.now() > item.expiresAt) {\n return false;\n }\n item.expiresAt += additionalSeconds * 1000;\n return true;\n }\n\n async keys(pattern = '*'): Promise<string[]> {\n const allKeys = Array.from(this.cache.keys());\n\n // Clean up expired keys while we're at it\n const now = Date.now();\n for (const key of allKeys) {\n const item = this.cache.get(key);\n if (item && now > item.expiresAt) {\n this.cache.delete(key);\n }\n }\n\n const validKeys = Array.from(this.cache.keys());\n\n if (pattern === '*') {\n return validKeys;\n }\n\n // Simple wildcard pattern matching\n const regex = new RegExp('^' + pattern.replace(/\\*/g, '.*') + '$');\n return validKeys.filter((key) => regex.test(key));\n }\n\n async getMany<T = unknown>(keys: string[]): Promise<Record<string, T | null>> {\n const results: Record<string, T | null> = {};\n for (const key of keys) {\n results[key] = await this.get<T>(key);\n }\n return results;\n }\n\n /**\n * Clear all entries from the cache\n * (Utility method for testing)\n */\n async clear(): Promise<void> {\n this.cache.clear();\n }\n\n /**\n * Get the number of entries in the cache\n * (Utility method for debugging)\n */\n get size(): number {\n return this.cache.size;\n }\n}\n\n/**\n * Factory function to create a cache client\n *\n * @param _projectId - Project ID (unused in local development)\n * @param _functionName - Function name (unused in local development)\n */\nexport function createCacheClient(_projectId?: string, _functionName?: string): IFunctionCache {\n return new LocalCache();\n}\n","/**\n * Tunnel Client for Sinch Functions\n *\n * Connects to the Sinch tunnel gateway via WebSocket to receive\n * incoming voice and conversation callbacks during local development.\n *\n * Features:\n * - Voice webhook auto-configuration\n * - Conversation webhook auto-configuration with cleanup\n * - ElevenLabs auto-configuration (when enabled)\n * - Stale webhook cleanup on connect\n * - Webhook cleanup on disconnect\n */\n\nimport WebSocket from 'ws';\nimport axios from 'axios';\nimport {\n WebhookConfig,\n configureConversationWebhooks,\n cleanupConversationWebhook,\n configureElevenLabs,\n} from './webhook-config.js';\n\n// Default tunnel gateway URL (production) - internal override via TUNNEL_GATEWAY_URL\nconst TUNNEL_GATEWAY_DEFAULT = 'https://tunnel.fn.sinch.com';\n\ninterface TunnelMessage {\n type: 'welcome' | 'request' | 'ping' | 'pong' | 'response';\n id?: string;\n tunnelId?: string;\n publicUrl?: string;\n method?: string;\n path?: string;\n query?: string;\n headers?: Record<string, string>;\n body?: string;\n statusCode?: number;\n}\n\nexport class TunnelClient {\n private ws: WebSocket | null = null;\n private tunnelUrl: string | null = null;\n private tunnelId: string | null = null;\n private isConnected = false;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 10;\n private reconnectDelay = 5000;\n private heartbeatInterval: NodeJS.Timeout | null = null;\n private localPort: number;\n private webhookConfig: WebhookConfig = {};\n private welcomeResolver: ((value: boolean) => void) | null = null;\n\n constructor(localPort = 3000) {\n this.localPort = localPort;\n }\n\n private getTunnelGatewayUrl(): string {\n // Check for explicit TUNNEL_GATEWAY_URL (undocumented, for internal testing only)\n const explicitUrl = process.env.TUNNEL_GATEWAY_URL;\n if (explicitUrl) {\n return explicitUrl;\n }\n\n // Always use production gateway\n return TUNNEL_GATEWAY_DEFAULT;\n }\n\n private generateTunnelId(): string {\n // Generate a ULID (Universally Unique Lexicographically Sortable Identifier)\n // Format: 26 characters using Crockford's Base32\n const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';\n\n // Timestamp component (10 chars) - milliseconds since Unix epoch\n const timestamp = Date.now();\n let timestampPart = '';\n let t = timestamp;\n for (let i = 0; i < 10; i++) {\n timestampPart = ENCODING[t % 32] + timestampPart;\n t = Math.floor(t / 32);\n }\n\n // Random component (16 chars)\n const randomBytes = new Uint8Array(10);\n crypto.getRandomValues(randomBytes);\n let randomPart = '';\n for (let i = 0; i < 10; i++) {\n // Use each byte to generate approximately 1.6 chars (8 bits -> ~1.6 base32 chars)\n // We'll use a simpler approach: take 5 bits at a time\n const byte = randomBytes[i];\n randomPart += ENCODING[byte >> 3]; // Upper 5 bits\n if (randomPart.length < 16) {\n randomPart += ENCODING[((byte & 0x07) << 2) | (i + 1 < 10 ? randomBytes[i + 1] >> 6 : 0)];\n }\n }\n // Trim to exactly 16 characters\n randomPart = randomPart.substring(0, 16);\n\n return timestampPart + randomPart;\n }\n\n async connect(): Promise<void> {\n // Check if tunnel is enabled\n if (process.env.SINCH_TUNNEL !== 'true') {\n console.log('Tunnel is disabled (set SINCH_TUNNEL=true to enable)');\n return;\n }\n\n // Get tunnel gateway URL (no auth required for new gateway)\n const gatewayUrl = this.getTunnelGatewayUrl();\n\n // Generate tunnel ID for this connection\n this.tunnelId = this.generateTunnelId();\n\n // Build WebSocket URL: wss://tunnel.fn-dev.sinch.com/ws?tunnel={tunnelId}\n const gatewayUri = new URL(gatewayUrl);\n const wsUrl = new URL(gatewayUrl);\n wsUrl.protocol = gatewayUri.protocol === 'https:' ? 'wss:' : 'ws:';\n wsUrl.pathname = '/ws';\n wsUrl.searchParams.set('tunnel', this.tunnelId);\n const tunnelEndpoint = wsUrl.toString();\n\n console.log(`Connecting to tunnel gateway at ${tunnelEndpoint}...`);\n\n try {\n // No auth header needed for new gateway\n this.ws = new WebSocket(tunnelEndpoint);\n\n // Create promise to wait for welcome message\n const welcomePromise = new Promise<boolean>((resolve, reject) => {\n this.welcomeResolver = resolve;\n // Timeout after 10 seconds\n setTimeout(() => reject(new Error('Timed out waiting for welcome message')), 10000);\n });\n\n this.ws.on('open', () => {\n this.isConnected = true;\n this.reconnectAttempts = 0;\n console.log('WebSocket connected, waiting for welcome message...');\n });\n\n this.ws.on('message', async (data: WebSocket.Data) => {\n try {\n const message: TunnelMessage = JSON.parse(data.toString());\n await this.handleMessage(message);\n } catch (error) {\n console.error('Error processing tunnel message:', error);\n }\n });\n\n this.ws.on('close', async () => {\n this.isConnected = false;\n console.log('Tunnel connection closed');\n this.stopHeartbeat();\n this.scheduleReconnect();\n });\n\n this.ws.on('error', (error: Error) => {\n console.error('Tunnel connection error:', error.message);\n });\n\n // Wait for welcome message\n await welcomePromise;\n\n if (!this.tunnelUrl) {\n throw new Error('Did not receive tunnel URL from gateway');\n }\n\n console.log('Tunnel connected successfully!');\n\n // Start heartbeat\n this.startHeartbeat();\n\n // Configure all webhooks\n await this.configureWebhooks();\n } catch (error: any) {\n console.error('Failed to establish tunnel connection:', error.message);\n this.scheduleReconnect();\n }\n }\n\n private async handleMessage(message: TunnelMessage): Promise<void> {\n switch (message.type) {\n case 'welcome':\n this.handleWelcomeMessage(message);\n break;\n case 'request':\n await this.handleRequest(message);\n break;\n case 'ping':\n this.sendPong();\n break;\n }\n }\n\n private handleWelcomeMessage(message: TunnelMessage): void {\n // Extract tunnelId and publicUrl from welcome message\n // { \"type\": \"welcome\", \"tunnelId\": \"01HQXK5M3N...\", \"publicUrl\": \"https://tunnel.fn-dev.sinch.com/ingress/01HQXK5M3N...\" }\n this.tunnelId = message.tunnelId || null;\n this.tunnelUrl = message.publicUrl || null;\n\n console.log(`Received welcome: tunnelId=${this.tunnelId}`);\n\n // Signal that welcome was received\n if (this.welcomeResolver) {\n this.welcomeResolver(true);\n this.welcomeResolver = null;\n }\n }\n\n private async handleRequest(message: TunnelMessage): Promise<void> {\n console.log(`Forwarding ${message.method} request to ${message.path}`);\n\n try {\n // Forward to local Express server\n const localUrl = `http://localhost:${this.localPort}${message.path}${message.query || ''}`;\n\n const axiosConfig: any = {\n method: message.method,\n url: localUrl,\n headers: {},\n };\n\n // Copy ALL headers\n if (message.headers) {\n axiosConfig.headers = { ...message.headers };\n }\n\n // Add body if present\n if (message.body) {\n axiosConfig.data = message.body;\n }\n\n const response = await axios(axiosConfig);\n\n // Collect headers - axios uses lowercase, normalize to proper case for common ones\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(response.headers)) {\n if (value) {\n // Normalize common headers to proper case\n const normalizedKey =\n key.toLowerCase() === 'content-type'\n ? 'Content-Type'\n : key.toLowerCase() === 'content-length'\n ? 'Content-Length'\n : key;\n headers[normalizedKey] = String(value);\n }\n }\n\n // Ensure Content-Type is set for JSON responses\n if (!headers['Content-Type'] && response.data) {\n headers['Content-Type'] = 'application/json';\n }\n\n const body =\n typeof response.data === 'string' ? response.data : JSON.stringify(response.data);\n\n // Send response back through tunnel\n const responseMessage: TunnelMessage = {\n type: 'response',\n id: message.id,\n statusCode: response.status,\n headers,\n body,\n };\n\n this.ws?.send(JSON.stringify(responseMessage));\n } catch (error: any) {\n console.error('Error forwarding request:', error.message);\n\n // Send error response\n const errorResponse: TunnelMessage = {\n type: 'response',\n id: message.id,\n statusCode: error.response?.status || 502,\n headers: { 'Content-Type': 'text/plain' },\n body: 'Error forwarding request to local server',\n };\n\n this.ws?.send(JSON.stringify(errorResponse));\n }\n }\n\n private sendPong(): void {\n const pongMessage: TunnelMessage = { type: 'pong' };\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(pongMessage));\n }\n }\n\n private startHeartbeat(): void {\n this.heartbeatInterval = setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n const pingMessage: TunnelMessage = { type: 'ping' };\n this.ws.send(JSON.stringify(pingMessage));\n }\n }, 30000);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n }\n\n /**\n * Configure all webhooks (Voice, Conversation, ElevenLabs)\n */\n private async configureWebhooks(): Promise<void> {\n // New format: AUTO_CONFIGURE=true + SINCH_SERVICES=voice,conversation\n // Old format: AUTO_CONFIGURE_VOICE, AUTO_CONFIGURE_CONVERSATION (backwards compat)\n const hasNewFormat = 'AUTO_CONFIGURE' in process.env;\n const autoEnabled = process.env.AUTO_CONFIGURE === 'true';\n const sinchServices = (process.env.SINCH_SERVICES ?? '').split(',').map((s) => s.trim());\n\n const autoConfigVoice = hasNewFormat\n ? autoEnabled && sinchServices.includes('voice')\n : process.env.AUTO_CONFIGURE_VOICE !== 'false' && !!process.env.VOICE_APPLICATION_KEY;\n\n const autoConfigConversation = hasNewFormat\n ? autoEnabled && sinchServices.includes('conversation')\n : process.env.AUTO_CONFIGURE_CONVERSATION !== 'false' && !!process.env.CONVERSATION_APP_ID;\n\n // Configure Voice webhooks\n if (autoConfigVoice && process.env.VOICE_APPLICATION_KEY) {\n await this.configureVoiceWebhooks();\n }\n\n // Configure Conversation webhooks\n if (autoConfigConversation && process.env.CONVERSATION_APP_ID) {\n await configureConversationWebhooks(this.tunnelUrl!, this.webhookConfig);\n }\n\n // Configure ElevenLabs (if enabled)\n if (process.env.ELEVENLABS_AUTO_CONFIGURE === 'true') {\n await configureElevenLabs();\n }\n }\n\n /**\n * Cleanup webhooks on disconnect\n */\n private async cleanupWebhooks(): Promise<void> {\n await cleanupConversationWebhook(this.webhookConfig);\n }\n\n private async configureVoiceWebhooks(): Promise<void> {\n try {\n const appKey = process.env.VOICE_APPLICATION_KEY;\n const appSecret = process.env.VOICE_APPLICATION_SECRET;\n\n if (!appKey || !appSecret) {\n console.log('๐Ÿ’ก Voice API not configured - skipping phone number display');\n return;\n }\n\n // Update webhook URLs to tunnel URL\n try {\n const updateUrl = `https://callingapi.sinch.com/v1/configuration/callbacks/applications/${appKey}/`;\n const auth = Buffer.from(`${appKey}:${appSecret}`).toString('base64');\n\n await axios.post(\n updateUrl,\n {\n url: {\n primary: this.tunnelUrl,\n fallback: null,\n },\n },\n {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n }\n );\n\n console.log('โœ… Updated voice webhook URL');\n } catch (error: any) {\n console.log('โš ๏ธ Could not update webhook URL:', error.message);\n }\n\n // List numbers using Voice API\n try {\n const listUrl = `https://callingapi.sinch.com/v1/configuration/numbers/`;\n const auth = Buffer.from(`${appKey}:${appSecret}`).toString('base64');\n\n const response = await axios.get(listUrl, {\n headers: {\n Authorization: `Basic ${auth}`,\n },\n });\n\n const numbers = response.data?.numbers || [];\n const appNumbers = numbers.filter((n: any) => n.applicationkey === appKey);\n\n if (appNumbers.length > 0) {\n console.log('๐Ÿ“ฑ Test Phone Numbers:');\n appNumbers.forEach((num: any) => {\n console.log(` โ˜Ž๏ธ ${num.number}`);\n });\n console.log('๐Ÿ’ก Call any of these numbers to test your voice function!');\n } else {\n console.log('โš ๏ธ No phone numbers assigned to this application yet');\n console.log('๐Ÿ’ก Add numbers at https://dashboard.sinch.com/voice/apps');\n }\n } catch (error: any) {\n console.log('๐Ÿ’ก Could not fetch phone numbers:', error.message);\n }\n } catch (error) {\n console.log('๐Ÿ’ก Could not fetch phone numbers (Voice API may not be configured)');\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n console.error('Max reconnection attempts reached. Giving up.');\n return;\n }\n\n this.reconnectAttempts++;\n const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1), 30000);\n\n console.log(`Attempting to reconnect in ${delay / 1000} seconds...`);\n setTimeout(() => this.connect(), delay);\n }\n\n async disconnect(): Promise<void> {\n this.stopHeartbeat();\n await this.cleanupWebhooks();\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n this.isConnected = false;\n }\n\n getTunnelUrl(): string | null {\n return this.tunnelUrl;\n }\n\n getIsConnected(): boolean {\n return this.isConnected;\n }\n}\n\n// Export singleton factory\nlet tunnelInstance: TunnelClient | null = null;\n\nexport function getTunnelClient(localPort = 3000): TunnelClient {\n if (!tunnelInstance) {\n tunnelInstance = new TunnelClient(localPort);\n }\n return tunnelInstance;\n}\n\nexport default TunnelClient;\n","/**\n * Webhook Configuration Helpers for Tunnel Client\n *\n * Additional webhook configuration for Conversation API and ElevenLabs.\n * Used by TunnelClient to auto-configure webhooks on connect.\n */\n\nimport { SinchClient } from '@sinch/sdk-core';\n\nexport interface WebhookConfig {\n conversationWebhookId?: string;\n voiceConfigured?: boolean;\n}\n\n/**\n * Configure Conversation API webhooks to point to tunnel URL\n * Cleans up stale tunnel webhooks and creates a fresh one\n */\nexport async function configureConversationWebhooks(\n tunnelUrl: string,\n config: WebhookConfig\n): Promise<void> {\n try {\n const conversationAppId = process.env.CONVERSATION_APP_ID;\n const projectId = process.env.PROJECT_ID;\n const keyId = process.env.PROJECT_ID_API_KEY;\n const keySecret = process.env.PROJECT_ID_API_SECRET;\n\n if (!conversationAppId || !projectId || !keyId || !keySecret) {\n console.log('๐Ÿ’ก Conversation API not fully configured - skipping webhook setup');\n return;\n }\n\n const webhookUrl = `${tunnelUrl}/webhook/conversation`;\n console.log(`๐Ÿ’ฌ Conversation webhook URL: ${webhookUrl}`);\n\n // Create Sinch client for Conversation API\n const sinchClient = new SinchClient({\n projectId,\n keyId,\n keySecret,\n });\n\n // List existing webhooks\n const webhooksResult = await sinchClient.conversation.webhooks.list({\n app_id: conversationAppId,\n });\n const existingWebhooks = webhooksResult.webhooks || [];\n\n // Clean up stale tunnel webhooks (matching /api/ingress/ pattern)\n const tunnelWebhooks = existingWebhooks.filter((w: any) => w.target?.includes('/api/ingress/'));\n\n for (const staleWebhook of tunnelWebhooks) {\n try {\n await sinchClient.conversation.webhooks.delete({ webhook_id: staleWebhook.id! });\n console.log(`๐Ÿงน Cleaned up stale tunnel webhook: ${staleWebhook.id}`);\n } catch (err: any) {\n // Ignore errors deleting stale webhooks\n }\n }\n\n // Create fresh webhook\n const createResult = await sinchClient.conversation.webhooks.create({\n webhookCreateRequestBody: {\n app_id: conversationAppId,\n target: webhookUrl,\n target_type: 'HTTP',\n triggers: ['MESSAGE_INBOUND'],\n },\n });\n\n config.conversationWebhookId = createResult.id;\n console.log(`โœ… Created Conversation webhook: ${webhookUrl}`);\n console.log('๐Ÿ’ฌ Send a message to your Conversation app to test!');\n } catch (error: any) {\n console.log('โš ๏ธ Could not configure Conversation webhooks:', error.message);\n }\n}\n\n/**\n * Delete the Conversation webhook created for this tunnel session\n */\nexport async function cleanupConversationWebhook(config: WebhookConfig): Promise<void> {\n if (!config.conversationWebhookId) return;\n\n try {\n const conversationAppId = process.env.CONVERSATION_APP_ID;\n const projectId = process.env.PROJECT_ID;\n const keyId = process.env.PROJECT_ID_API_KEY;\n const keySecret = process.env.PROJECT_ID_API_SECRET;\n\n if (!conversationAppId || !projectId || !keyId || !keySecret) return;\n\n const sinchClient = new SinchClient({\n projectId,\n keyId,\n keySecret,\n });\n\n await sinchClient.conversation.webhooks.delete({ webhook_id: config.conversationWebhookId });\n\n console.log('๐Ÿงน Cleaned up tunnel webhook');\n config.conversationWebhookId = undefined;\n } catch (error: any) {\n // Ignore errors - webhook may already be deleted\n }\n}\n\n/**\n * Configure ElevenLabs auto-configuration (if enabled)\n */\nexport async function configureElevenLabs(): Promise<void> {\n try {\n const agentId = process.env.ELEVENLABS_AGENT_ID;\n const apiKey = process.env.ELEVENLABS_API_KEY;\n\n if (!agentId || !apiKey) {\n console.log('๐Ÿ’ก ElevenLabs not fully configured - skipping auto-configuration');\n return;\n }\n\n // Import ElevenLabs client dynamically to avoid circular dependencies\n // const { ElevenLabsClient } = await import('@sinch/functions-runtime-shared');\n\n // ElevenLabsClient is imported but full auto-config not yet implemented\n void apiKey; // Prevent unused variable warning\n\n // ElevenLabs auto-configuration placeholder\n console.log('๐Ÿค– ElevenLabs auto-configuration enabled');\n console.log(` Agent ID: ${agentId}`);\n } catch (error: any) {\n console.log('โš ๏ธ Could not configure ElevenLabs:', error.message);\n }\n}\n","/**\n * Secrets Loader for Local Development\n *\n * Loads secrets from OS keychain (Windows Credential Manager, macOS Keychain, Linux Secret Service)\n * using the same storage pattern as the Sinch CLI. This enables F5 debugging in VS Code\n * without needing to run 'sinch functions dev'.\n *\n * Security: Only loads secrets that are declared in .env file (empty values)\n * In production, secrets are injected by the platform, so this is development-only.\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport os from 'os';\n\nexport class SecretsLoader {\n // Same service name as CLI uses\n private SERVICE_NAME = 'sinch-functions-cli';\n private username = os.userInfo().username;\n\n /**\n * Load secrets from OS keychain for variables declared in .env\n * Only loads secrets that have empty values in .env (security best practice)\n */\n async loadFromKeychain(): Promise<boolean> {\n // Only load in development mode\n if (process.env.NODE_ENV === 'production') {\n return false;\n }\n\n try {\n // Try to load keytar if available (optional dependency)\n let keytar: any;\n try {\n keytar = await import('keytar');\n } catch (error: any) {\n if (error.code === 'MODULE_NOT_FOUND' || error.code === 'ERR_MODULE_NOT_FOUND') {\n // Keytar not installed - this is OK, it's optional\n console.debug('[Secrets] Keytar not available - secrets not loaded');\n return false;\n } else {\n console.error('[Secrets] Error loading keytar:', error.message);\n }\n return false;\n }\n\n // Read .env file to find which secrets to load\n const envPath = path.join(process.cwd(), '.env');\n if (!fs.existsSync(envPath)) {\n console.debug('[Secrets] No .env file found, skipping keychain load');\n return false;\n }\n\n // Parse .env file to find empty variables that might be secrets\n const envContent = fs.readFileSync(envPath, 'utf8');\n // Handle both Windows (CRLF) and Unix (LF) line endings\n const envLines = envContent.replace(/\\r\\n/g, '\\n').split('\\n');\n const secretsToLoad: string[] = [];\n\n envLines.forEach((line) => {\n // Remove any trailing carriage returns and trim\n const trimmedLine = line.replace(/\\r$/, '').trim();\n if (trimmedLine && !trimmedLine.startsWith('#')) {\n const equalIndex = trimmedLine.indexOf('=');\n if (equalIndex !== -1) {\n const envKey = trimmedLine.substring(0, equalIndex).trim();\n const envValue = trimmedLine.substring(equalIndex + 1).trim();\n\n // If value is empty, this might be a secret to load from keychain\n if (envKey && envValue === '' && !process.env[envKey]) {\n secretsToLoad.push(envKey);\n }\n }\n }\n });\n\n if (secretsToLoad.length === 0) {\n console.debug('[Secrets] No empty variables found in .env');\n return false;\n }\n\n let secretsLoaded = 0;\n\n // Handle special Sinch secrets with their specific keychain patterns\n if (secretsToLoad.includes('PROJECT_ID_API_SECRET')) {\n const apiSecret = await keytar.getPassword(this.SERVICE_NAME, `${this.username}-keySecret`);\n if (apiSecret) {\n process.env.PROJECT_ID_API_SECRET = apiSecret;\n console.log('โœ… Loaded PROJECT_ID_API_SECRET from secure storage');\n secretsLoaded++;\n }\n }\n\n if (secretsToLoad.includes('VOICE_APPLICATION_SECRET')) {\n // Get application key from environment or sinch.json\n const applicationKey =\n process.env.VOICE_APPLICATION_KEY || this.getApplicationKeyFromConfig();\n if (applicationKey) {\n const appSecret = await keytar.getPassword(this.SERVICE_NAME, applicationKey);\n if (appSecret) {\n process.env.VOICE_APPLICATION_SECRET = appSecret;\n console.log('โœ… Loaded VOICE_APPLICATION_SECRET from secure storage');\n secretsLoaded++;\n }\n }\n }\n\n // Handle custom secrets added via 'sinch functions secrets add'\n const functionName = this.getFunctionNameFromConfig();\n for (const secretName of secretsToLoad) {\n // Skip the special Sinch secrets we already handled\n if (secretName === 'PROJECT_ID_API_SECRET' || secretName === 'VOICE_APPLICATION_SECRET') {\n continue;\n }\n\n // Try to load custom secret using function-specific key\n if (functionName) {\n const value = await keytar.getPassword(\n this.SERVICE_NAME,\n `${functionName}-${secretName}`\n );\n if (value) {\n process.env[secretName] = value;\n console.log(`โœ… Loaded ${secretName} from secure storage`);\n secretsLoaded++;\n }\n }\n }\n\n if (secretsLoaded === 0) {\n console.log('โ„น๏ธ No secrets found in secure storage for declared variables');\n console.log('๐Ÿ’ก To configure Sinch auth: sinch auth login');\n console.log('๐Ÿ’ก To add custom secrets: sinch functions secrets add <KEY> <VALUE>');\n }\n\n return secretsLoaded > 0;\n } catch (error: any) {\n // Other unexpected error - log but don't fail\n console.error('[Secrets] Unexpected error:', error.message);\n console.log('๐Ÿ’ก To manage secrets manually, use: sinch functions secrets');\n return false;\n }\n }\n\n /**\n * Helper to get application key from sinch.json\n */\n private getApplicationKeyFromConfig(): string | null {\n try {\n const sinchJsonPath = path.join(process.cwd(), 'sinch.json');\n if (fs.existsSync(sinchJsonPath)) {\n const sinchConfig = JSON.parse(fs.readFileSync(sinchJsonPath, 'utf8'));\n return sinchConfig.voiceAppId || sinchConfig.applicationKey || null;\n }\n } catch (error: any) {\n console.debug('[Secrets] Could not read sinch.json:', error.message);\n }\n return null;\n }\n\n /**\n * Helper to get function name from sinch.json\n */\n private getFunctionNameFromConfig(): string | null {\n try {\n const sinchJsonPath = path.join(process.cwd(), 'sinch.json');\n if (fs.existsSync(sinchJsonPath)) {\n const sinchConfig = JSON.parse(fs.readFileSync(sinchJsonPath, 'utf8'));\n return sinchConfig.name || null;\n }\n } catch (error: any) {\n console.debug('[Secrets] Could not read sinch.json:', error.message);\n }\n return null;\n }\n\n /**\n * Load custom secrets added via 'sinch functions secrets' command\n */\n async loadCustomSecrets(secretNames: string[] = []): Promise<Record<string, string>> {\n const secrets: Record<string, string> = {};\n\n try {\n const keytar = await import('keytar');\n const functionName = this.getFunctionNameFromConfig();\n\n if (!functionName) {\n console.debug('[Secrets] Could not determine function name for custom secrets');\n return secrets;\n }\n\n for (const secretName of secretNames) {\n // Custom secrets are stored with function-specific pattern\n const value = await keytar.getPassword(this.SERVICE_NAME, `${functionName}-${secretName}`);\n if (value) {\n secrets[secretName] = value;\n process.env[secretName] = value; // Also inject into process.env\n }\n }\n } catch (error: any) {\n console.debug('[Secrets] Could not load custom secrets:', error.message);\n }\n\n return secrets;\n }\n\n /**\n * Check if keytar is available\n */\n async isAvailable(): Promise<boolean> {\n try {\n await import('keytar');\n return true;\n } catch {\n return false;\n }\n }\n}\n\n// Export singleton instance\nexport const secretsLoader = new SecretsLoader();\n\nexport default secretsLoader;\n"],"mappings":"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","names":["AgentProvider","createRequire","requireCjs","path","fs","fs","path","path","SinchClient","fs","path"]}
1
+ {"version":3,"sources":["../../runtime-shared/src/ai/connect-agent.ts","../../runtime-shared/src/builders/svaml.ts","../../runtime-shared/src/builders/menu.ts","../../runtime-shared/src/config/universal.ts","../../runtime-shared/src/host/middleware.ts","../../runtime-shared/src/host/app.ts","../../runtime-shared/src/sinch/index.ts","../../runtime-shared/src/ai/elevenlabs/state.ts","../../runtime-shared/src/ai/elevenlabs/client.ts","../../runtime-shared/src/ai/elevenlabs/controller.ts","../../runtime-shared/src/ai/elevenlabs/autoconfigurator.ts","../../runtime-shared/src/conversation/message-builder.ts","../../runtime-shared/src/conversation/message-helpers.ts","../../runtime-shared/src/conversation/controller.ts","../../runtime-shared/src/conversation/extensions.ts","../../runtime-shared/src/voice/helpers.ts","../../runtime-shared/src/utils/templateRender.ts","../../runtime-shared/src/utils/versionExtractor.ts","../../runtime-shared/src/utils/functionLoader.ts","../../runtime-shared/src/types/api.ts","../src/cache/local.ts","../src/tunnel/index.ts","../src/tunnel/webhook-config.ts","../src/secrets/index.ts"],"sourcesContent":["/**\n * Connect Agent Action for SVAML Builders\n *\n * Provides the ability to connect voice calls to AI agents via SIP.\n */\n\n/**\n * Supported AI agent providers\n */\nexport enum AgentProvider {\n ElevenLabs = 'elevenlabs',\n}\n\n/**\n * Options for connecting to an AI agent\n */\nexport interface ConnectAgentOptions {\n /** Optional caller ID to display */\n cli?: string;\n /** Maximum call duration in seconds */\n maxDuration?: number;\n /** Suppress subsequent callbacks */\n suppressCallbacks?: boolean;\n /** Custom headers to send to the agent */\n customHeaders?: Record<string, string>;\n /** Call ID for tracking */\n callId?: string;\n /** Caller ID for personalization */\n callerId?: string;\n}\n\n/**\n * Helper class for building SIP URIs for agent connections\n */\nexport class AgentSipHelper {\n /**\n * Build a SIP URI for connecting to an ElevenLabs agent\n */\n static buildElevenLabsSipUri(agentId: string, options?: ConnectAgentOptions): string {\n // ElevenLabs SIP format: sip:agentId@sip.elevenlabs.io\n const baseUri = `sip:${agentId}@sip.elevenlabs.io`;\n\n // Add custom headers as SIP URI parameters if provided\n if (options?.customHeaders && Object.keys(options.customHeaders).length > 0) {\n const headers = Object.entries(options.customHeaders)\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)\n .join('&');\n return `${baseUri};${headers}`;\n }\n\n return baseUri;\n }\n\n /**\n * Build a SIP URI for the given provider and agent\n */\n static buildSipUri(\n provider: AgentProvider,\n agentId: string,\n options?: ConnectAgentOptions\n ): string {\n switch (provider) {\n case AgentProvider.ElevenLabs:\n return this.buildElevenLabsSipUri(agentId, options);\n default:\n throw new Error(`Unsupported agent provider: ${provider}`);\n }\n }\n}\n\n/**\n * Connect agent action type for SVAML\n */\nexport interface ConnectAgentAction {\n name: 'connectSip';\n destination: {\n endpoint: string;\n };\n cli?: string;\n maxDuration?: number;\n suppressCallbacks?: boolean;\n}\n\n/**\n * Create a connectSip action for SVAML\n * This is used internally by the SVAML builders\n */\nexport function createConnectAgentAction(\n provider: AgentProvider,\n agentId: string,\n options?: ConnectAgentOptions\n): ConnectAgentAction {\n const sipUri = AgentSipHelper.buildSipUri(provider, agentId, options);\n\n const action: ConnectAgentAction = {\n name: 'connectSip',\n destination: {\n endpoint: sipUri,\n },\n };\n\n if (options?.cli) {\n action.cli = options.cli;\n }\n\n if (options?.maxDuration !== undefined) {\n action.maxDuration = options.maxDuration;\n }\n\n if (options?.suppressCallbacks !== undefined) {\n action.suppressCallbacks = options.suppressCallbacks;\n }\n\n return action;\n}\n\nexport default {\n AgentProvider,\n AgentSipHelper,\n createConnectAgentAction,\n};\n","/**\n * SVAML Builder Classes\n *\n * Provides a fluent API for building SVAML responses.\n * These builders construct SVAML JSON directly without requiring the Sinch SDK.\n *\n * @example\n * ```typescript\n * const response = new IceSvamlBuilder()\n * .say('Welcome to our service!')\n * .connectPstn('+15551234567')\n * .build();\n * ```\n */\n\nimport type {\n SvamletResponse,\n SvamletInstruction,\n SvamletAction,\n SayInstruction,\n PlayInstruction,\n PlayFilesInstruction,\n StartRecordingInstruction,\n StopRecordingInstruction,\n SetCookieInstruction,\n AnswerInstruction,\n SendDtmfInstruction,\n Menu,\n} from '../types/svaml.js';\nimport type { MenuStructure } from './menu.js';\nimport {\n AgentProvider,\n createConnectAgentAction,\n type ConnectAgentOptions,\n} from '../ai/connect-agent.js';\n\n// ============================================\n// Recording Options\n// ============================================\n\nexport interface RecordingOptions {\n /** URL to send the recording to */\n destinationUrl?: string;\n /** Credentials for the destination */\n credentials?: string;\n /** Recording format */\n format?: 'mp3' | 'wav';\n /** Enable notification events */\n notificationEvents?: boolean;\n /** Enable transcription */\n transcriptionEnabled?: boolean;\n /** Transcription locale */\n transcriptionLocale?: string;\n}\n\n// ============================================\n// Connect Options\n// ============================================\n\nexport interface ConnectPstnOptions {\n /** CLI (Caller ID) to display */\n cli?: string;\n /** Maximum duration in seconds */\n maxDuration?: number;\n /** Timeout in seconds */\n timeout?: number;\n /** Enable ACE callback */\n enableAce?: boolean;\n /** Enable DICE callback */\n enableDice?: boolean;\n /** Enable PIE callback */\n enablePie?: boolean;\n /** DTMF to send on connect */\n dtmf?: string;\n /** Custom data to pass to callbacks */\n custom?: string;\n /** Dial tone indications */\n indications?: 'se' | 'us' | 'no' | 'fi' | 'uk' | 'de' | 'fr';\n /** Enable AMD (Answering Machine Detection) */\n amd?: { enabled: boolean };\n}\n\nexport interface ConnectSipOptions {\n /** CLI (Caller ID) to display */\n cli?: string;\n /** Custom SIP headers */\n headers?: Record<string, string>;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\nexport interface ConnectMxpOptions {\n /** CLI (Caller ID) to display */\n cli?: string;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\nexport interface ConnectConfOptions {\n /** Music on hold */\n moh?: 'ring' | 'music';\n /** Enable DICE callback */\n enableDice?: boolean;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\nexport interface ParkOptions {\n /** Maximum park duration in seconds */\n maxDuration?: number;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\nexport interface RunMenuOptions {\n /** Allow user to interrupt prompts */\n barge?: boolean;\n /** Enable DICE callback */\n enableDice?: boolean;\n /** Custom data to pass to callbacks */\n custom?: string;\n}\n\n// ============================================\n// Base Builder\n// ============================================\n\n/**\n * Base class for SVAML builders with common instruction methods\n */\nabstract class BaseSvamlBuilder<T extends BaseSvamlBuilder<T>> {\n protected instructions: SvamletInstruction[] = [];\n protected action: SvamletAction | null = null;\n\n /**\n * Add a text-to-speech instruction\n *\n * @param text - Text to speak\n * @param locale - Voice locale (e.g., 'en-US')\n */\n say(text: string, locale = 'en-US'): T {\n const instruction: SayInstruction = { name: 'say', text, locale };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Play an audio file\n *\n * @param url - URL of the audio file to play\n */\n play(url: string): T {\n const instruction: PlayInstruction = { name: 'play', url };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Play multiple audio files\n *\n * @param urls - Array of audio file URLs\n * @param locale - Locale for any TTS prompts\n */\n playFiles(urls: string[], locale = 'en-US'): T {\n const instruction: PlayFilesInstruction = { name: 'playFiles', ids: urls, locale };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Start recording the call\n *\n * @param options - Recording options\n */\n startRecording(options?: RecordingOptions): T {\n const instruction: StartRecordingInstruction = {\n name: 'startRecording',\n options,\n };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Stop recording the call\n */\n stopRecording(): T {\n const instruction: StopRecordingInstruction = { name: 'stopRecording' };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Set a cookie (persists data across callbacks)\n *\n * @param key - Cookie key\n * @param value - Cookie value\n */\n setCookie(key: string, value: string): T {\n const instruction: SetCookieInstruction = { name: 'setCookie', key, value };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Send DTMF tones\n *\n * @param digits - DTMF digits to send\n */\n sendDtmf(digits: string): T {\n const instruction: SendDtmfInstruction = { name: 'sendDtmf', value: digits };\n this.instructions.push(instruction);\n return this as unknown as T;\n }\n\n /**\n * Hang up the call\n */\n hangup(): T {\n this.action = { name: 'hangup' };\n return this as unknown as T;\n }\n\n /**\n * Continue to next callback\n */\n continue(): T {\n this.action = { name: 'continue' };\n return this as unknown as T;\n }\n\n /**\n * Build the final SVAML response\n *\n * @throws Error if no action has been set\n */\n build(): SvamletResponse {\n if (!this.action) {\n throw new Error(\n 'SVAML response requires an action. Call hangup(), continue(), connectPstn(), etc.'\n );\n }\n\n return {\n instructions: this.instructions.length > 0 ? this.instructions : undefined,\n action: this.action,\n };\n }\n}\n\n// ============================================\n// ICE Builder\n// ============================================\n\n/**\n * ICE (Incoming Call Event) SVAML Builder\n *\n * Use this to build responses for incoming call events.\n *\n * @example\n * ```typescript\n * export async function ice(context, event) {\n * return new IceSvamlBuilder()\n * .say('Welcome! Connecting you now.')\n * .connectPstn('+15551234567')\n * .build();\n * }\n * ```\n */\nexport class IceSvamlBuilder extends BaseSvamlBuilder<IceSvamlBuilder> {\n /**\n * Answer the call explicitly\n */\n answer(): this {\n const instruction: AnswerInstruction = { name: 'answer' };\n this.instructions.push(instruction);\n return this;\n }\n\n /**\n * Connect to a PSTN phone number\n *\n * @param number - E.164 formatted phone number (e.g., '+15551234567')\n * @param options - Connection options\n *\n * @example\n * ```typescript\n * // Simple connect\n * new IceSvamlBuilder().connectPstn('+15551234567').build();\n *\n * // With options: caller ID, timeout, and AMD\n * new IceSvamlBuilder()\n * .connectPstn('+15551234567', {\n * cli: '+15559876543',\n * timeout: 30,\n * amd: { enabled: true },\n * })\n * .build();\n * ```\n */\n connectPstn(number: string, options?: ConnectPstnOptions): this {\n this.action = {\n name: 'connectPstn',\n number,\n ...options,\n };\n return this;\n }\n\n /**\n * Connect to a SIP endpoint\n *\n * @param destination - SIP URI\n * @param options - Connection options\n */\n connectSip(destination: string, options?: ConnectSipOptions): this {\n this.action = {\n name: 'connectSip',\n destination,\n ...options,\n };\n return this;\n }\n\n /**\n * Connect to an MXP (Sinch SDK) user\n *\n * @param destination - MXP user identifier\n * @param options - Connection options\n */\n connectMxp(destination: string, options?: ConnectMxpOptions): this {\n this.action = {\n name: 'connectMxp',\n destination,\n ...options,\n };\n return this;\n }\n\n /**\n * Join a conference\n *\n * @param conferenceId - Conference ID to join\n * @param options - Conference options\n */\n connectConf(conferenceId: string, options?: ConnectConfOptions): this {\n this.action = {\n name: 'connectConf',\n conferenceId,\n ...options,\n };\n return this;\n }\n\n /**\n * Run an IVR menu\n *\n * @param menus - Array of menu definitions or MenuStructure from createMenu().build()\n * @param options - Menu options\n *\n * @example\n * ```typescript\n * // Using MenuTemplates\n * new IceSvamlBuilder()\n * .runMenu(MenuTemplates.business('Acme Corp'))\n * .build();\n *\n * // Using createMenu builder\n * const menu = createMenu()\n * .prompt('Press 1 for sales, 2 for support.')\n * .option('1', 'return(sales)')\n * .option('2', 'return(support)')\n * .build();\n * new IceSvamlBuilder().runMenu(menu).build();\n * ```\n */\n runMenu(menus: Menu[] | MenuStructure, options?: RunMenuOptions): this {\n const menuArray = Array.isArray(menus) ? menus : menus.menus;\n const barge = Array.isArray(menus) ? options?.barge : menus.barge;\n this.action = {\n name: 'runMenu',\n menus: menuArray,\n barge,\n ...options,\n };\n return this;\n }\n\n /**\n * Park the call (put on hold)\n *\n * @param holdPrompt - Prompt to play while on hold\n * @param options - Park options\n *\n * @example\n * ```typescript\n * // Park with hold music prompt\n * new IceSvamlBuilder()\n * .park('Please hold while we connect you.', { maxDuration: 120 })\n * .build();\n * ```\n */\n park(holdPrompt?: string, options?: ParkOptions): this {\n this.action = {\n name: 'park',\n holdPrompt,\n ...options,\n };\n return this;\n }\n\n /**\n * Connect to an AI voice agent\n *\n * @param provider - The AI agent provider (e.g., AgentProvider.ElevenLabs)\n * @param agentId - The agent ID to connect to\n * @param options - Connection options\n *\n * @example\n * ```typescript\n * return new IceSvamlBuilder()\n * .say('Connecting you to our AI assistant.')\n * .connectAgent(AgentProvider.ElevenLabs, 'agent_123')\n * .build();\n * ```\n */\n connectAgent(provider: AgentProvider, agentId: string, options?: ConnectAgentOptions): this {\n this.action = createConnectAgentAction(provider, agentId, options);\n return this;\n }\n}\n\n// ============================================\n// ACE Builder\n// ============================================\n\n/**\n * ACE (Answered Call Event) SVAML Builder\n *\n * Use this to build responses for answered call events (outbound calls).\n *\n * @example\n * ```typescript\n * export async function ace(context, event) {\n * if (event.amd?.status === 'machine') {\n * return new AceSvamlBuilder().hangup().build();\n * }\n * return new AceSvamlBuilder()\n * .say('Hello! This is a call from Acme Corp.')\n * .continue()\n * .build();\n * }\n * ```\n */\nexport class AceSvamlBuilder extends BaseSvamlBuilder<AceSvamlBuilder> {\n // ACE has limited actions - only hangup() and continue() from base\n}\n\n// ============================================\n// PIE Builder\n// ============================================\n\n/**\n * PIE (Prompt Input Event) SVAML Builder\n *\n * Use this to build responses for user input events (DTMF/voice).\n *\n * @example\n * ```typescript\n * export async function pie(context, event) {\n * const selection = event.menuResult?.value;\n *\n * if (selection === '1') {\n * return new PieSvamlBuilder()\n * .say('Connecting you to sales.')\n * .connectPstn('+15551234567')\n * .build();\n * }\n *\n * return new PieSvamlBuilder()\n * .say('Goodbye!')\n * .hangup()\n * .build();\n * }\n * ```\n */\nexport class PieSvamlBuilder extends BaseSvamlBuilder<PieSvamlBuilder> {\n /**\n * Connect to a PSTN phone number\n *\n * @param number - E.164 formatted phone number\n * @param options - Connection options\n */\n connectPstn(number: string, options?: ConnectPstnOptions): this {\n this.action = {\n name: 'connectPstn',\n number,\n ...options,\n };\n return this;\n }\n\n /**\n * Run an IVR menu\n *\n * @param menus - Array of menu definitions or MenuStructure from createMenu().build()\n * @param options - Menu options\n */\n runMenu(menus: Menu[] | MenuStructure, options?: RunMenuOptions): this {\n const menuArray = Array.isArray(menus) ? menus : menus.menus;\n const barge = Array.isArray(menus) ? options?.barge : menus.barge;\n this.action = {\n name: 'runMenu',\n menus: menuArray,\n barge,\n ...options,\n };\n return this;\n }\n\n /**\n * Park the call (put on hold)\n *\n * @param holdPrompt - Prompt to play while on hold\n * @param options - Park options\n */\n park(holdPrompt?: string, options?: ParkOptions): this {\n this.action = {\n name: 'park',\n holdPrompt,\n ...options,\n };\n return this;\n }\n\n /**\n * Connect to an AI voice agent\n *\n * @param provider - The AI agent provider (e.g., AgentProvider.ElevenLabs)\n * @param agentId - The agent ID to connect to\n * @param options - Connection options\n *\n * @example\n * ```typescript\n * // Transfer to AI agent based on menu selection\n * if (event.menuResult?.value === 'ai') {\n * return new PieSvamlBuilder()\n * .say('Connecting you to our AI assistant.')\n * .connectAgent(AgentProvider.ElevenLabs, 'agent_123')\n * .build();\n * }\n * ```\n */\n connectAgent(provider: AgentProvider, agentId: string, options?: ConnectAgentOptions): this {\n this.action = createConnectAgentAction(provider, agentId, options);\n return this;\n }\n}\n\n// ============================================\n// Factory Functions\n// ============================================\n\n/**\n * Create a new ICE SVAML builder\n */\nexport function createIceBuilder(): IceSvamlBuilder {\n return new IceSvamlBuilder();\n}\n\n/**\n * Create a new ACE SVAML builder\n */\nexport function createAceBuilder(): AceSvamlBuilder {\n return new AceSvamlBuilder();\n}\n\n/**\n * Create a new PIE SVAML builder\n */\nexport function createPieBuilder(): PieSvamlBuilder {\n return new PieSvamlBuilder();\n}\n","/**\n * Menu Builder Classes\n *\n * Provides a fluent API for building voice IVR menus with validation.\n * Ensures menus are built correctly for both local development and production.\n *\n * Requirements:\n * - All menu structures MUST start with 'main' menu as id\n * - Actions can be: 'return', 'return(value)', or 'menu(menuid)'\n *\n * @example\n * ```typescript\n * const menu = new MenuBuilder()\n * .prompt('Press 1 for sales, 2 for support')\n * .option('1', 'return(sales)')\n * .option('2', 'return(support)')\n * .build();\n * ```\n */\n\nimport type { Menu, MenuOption } from '../types/svaml.js';\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * Valid DTMF keys for menu options\n */\nexport type DtmfKey = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '*' | '#';\n\n/**\n * Menu action types\n * - 'return' - Return to PIE callback with DTMF value\n * - 'return(value)' - Return to PIE callback with custom value\n * - 'menu(menuId)' - Navigate to submenu\n */\nexport type MenuAction = 'return' | `return(${string})` | `menu(${string})`;\n\n/**\n * Complete menu structure for runMenu action\n */\nexport interface MenuStructure {\n /** Enable barge-in (interrupt prompts with input) */\n barge: boolean;\n /** Array of menu definitions */\n menus: Menu[];\n}\n\n/**\n * Language option for language selection menu template\n */\nexport interface LanguageOption {\n /** DTMF key to press */\n dtmf: DtmfKey;\n /** Display name of the language */\n name: string;\n /** Locale code to return (e.g., 'en-US') */\n value: string;\n}\n\n/**\n * Simple menu option for quick menu creation\n */\nexport interface SimpleMenuOption {\n /** DTMF key */\n dtmf: string;\n /** Menu action */\n action: string;\n}\n\n// ============================================\n// Constants\n// ============================================\n\nconst VALID_DTMF_KEYS: readonly string[] = [\n '0',\n '1',\n '2',\n '3',\n '4',\n '5',\n '6',\n '7',\n '8',\n '9',\n '*',\n '#',\n];\n\n// ============================================\n// MenuBuilder Class\n// ============================================\n\n/**\n * Menu builder for creating voice IVR menus with validation\n *\n * @example\n * ```typescript\n * // Simple menu\n * const menu = new MenuBuilder()\n * .prompt('Press 1 for sales, 2 for support')\n * .option('1', 'return(sales)')\n * .option('2', 'return(support)')\n * .build();\n *\n * // Multi-level menu with submenus\n * const menu = new MenuBuilder()\n * .prompt('Press 1 for English, 2 for Spanish')\n * .option('1', 'menu(english)')\n * .option('2', 'menu(spanish)')\n * .addSubmenu('english')\n * .prompt('Press 1 for sales, 2 for support')\n * .option('1', 'return(en-sales)')\n * .option('2', 'return(en-support)')\n * .build();\n * ```\n */\nexport class MenuBuilder {\n private menuStructure: MenuStructure;\n private currentMenu: Menu;\n\n /**\n * Create a new MenuBuilder\n *\n * @param id - Menu ID (must be 'main' for root menu)\n * @throws Error if id is not 'main' for root menu\n */\n constructor(id = 'main') {\n if (id !== 'main') {\n throw new Error(\"Menu structure must start with 'main' menu as id\");\n }\n\n this.menuStructure = {\n barge: true,\n menus: [],\n };\n\n this.currentMenu = {\n id,\n mainPrompt: '',\n options: [],\n repeats: 2,\n maxDigits: 1,\n timeoutMills: 8000,\n };\n }\n\n /**\n * Set the main prompt for the menu\n *\n * @param text - The prompt text (will be wrapped in TTS tags)\n * @param locale - Voice locale (default: 'en-US')\n */\n prompt(text: string, locale = 'en-US'): this {\n this.currentMenu.mainPrompt = `#tts[${text}]`;\n this.currentMenu.locale = locale;\n return this;\n }\n\n /**\n * Set the repeat prompt (played when user doesn't respond)\n *\n * @param text - The repeat prompt text\n */\n repeatPrompt(text: string): this {\n this.currentMenu.repeatPrompt = `#tts[${text}]`;\n return this;\n }\n\n /**\n * Add a menu option\n *\n * @param dtmf - The DTMF key (0-9, *, #)\n * @param action - Action: 'return', 'return(value)', or 'menu(menuid)'\n * @throws Error if DTMF key or action is invalid\n */\n option(dtmf: string, action: string = 'return'): this {\n if (!this.isValidDtmf(dtmf)) {\n throw new Error(`Invalid DTMF key: ${dtmf}. Must be 0-9, *, or #`);\n }\n\n if (!this.isValidAction(action)) {\n throw new Error(\n `Invalid action: ${action}. Must be 'return', 'return(value)', or 'menu(menuid)'`\n );\n }\n\n const menuOption: MenuOption = {\n dtmf: dtmf.toString(),\n action,\n };\n this.currentMenu.options.push(menuOption);\n return this;\n }\n\n /**\n * Set maximum number of digits to collect\n *\n * @param digits - Maximum digits (1-20)\n * @throws Error if digits is out of range\n */\n maxDigits(digits: number): this {\n if (digits < 1 || digits > 20) {\n throw new Error('maxDigits must be between 1 and 20');\n }\n this.currentMenu.maxDigits = digits;\n return this;\n }\n\n /**\n * Set timeout in milliseconds\n *\n * @param ms - Timeout in milliseconds (1000-30000)\n * @throws Error if timeout is out of range\n */\n timeout(ms: number): this {\n if (ms < 1000 || ms > 30000) {\n throw new Error('Timeout must be between 1000ms and 30000ms');\n }\n this.currentMenu.timeoutMills = ms;\n return this;\n }\n\n /**\n * Set number of times to repeat the menu\n *\n * @param count - Number of repeats (0-5)\n * @throws Error if count is out of range\n */\n repeats(count: number): this {\n if (count < 0 || count > 5) {\n throw new Error('Repeats must be between 0 and 5');\n }\n this.currentMenu.repeats = count;\n return this;\n }\n\n /**\n * Enable/disable barge-in (allow interrupting prompts with input)\n *\n * @param enabled - Whether to allow barge-in (default: true)\n */\n barge(enabled = true): this {\n this.menuStructure.barge = enabled;\n return this;\n }\n\n /**\n * Add the current menu and start a new submenu\n *\n * @param id - Menu ID for the submenu\n * @throws Error if submenu ID is invalid\n */\n addSubmenu(id: string): this {\n if (!id || typeof id !== 'string') {\n throw new Error('Submenu ID must be a non-empty string');\n }\n\n // Add current menu to structure\n this.menuStructure.menus.push({ ...this.currentMenu });\n\n // Start new submenu\n this.currentMenu = {\n id,\n mainPrompt: '',\n options: [],\n repeats: 2,\n maxDigits: 1,\n timeoutMills: 8000,\n };\n\n return this;\n }\n\n /**\n * Build and return the complete menu structure\n *\n * @throws Error if menu structure is invalid\n */\n build(): MenuStructure {\n // Add the current menu if it has options\n if (this.currentMenu.options.length > 0) {\n this.menuStructure.menus.push({ ...this.currentMenu });\n }\n\n // Validate that we have at least the main menu\n if (this.menuStructure.menus.length === 0) {\n throw new Error('Menu must have at least one menu with options');\n }\n\n // Validate that first menu is 'main'\n if (this.menuStructure.menus[0].id !== 'main') {\n throw new Error(\"First menu must have id 'main'\");\n }\n\n return this.menuStructure;\n }\n\n /**\n * Get just the menus array (for use with runMenu action)\n */\n buildMenus(): Menu[] {\n return this.build().menus;\n }\n\n /**\n * Validate DTMF key format\n */\n private isValidDtmf(dtmf: string): boolean {\n return VALID_DTMF_KEYS.includes(dtmf.toString());\n }\n\n /**\n * Validate action format\n */\n private isValidAction(action: string): boolean {\n if (action === 'return') return true;\n if (action.startsWith('return(') && action.endsWith(')')) return true;\n if (action.startsWith('menu(') && action.endsWith(')')) return true;\n return false;\n }\n}\n\n// ============================================\n// Factory Functions\n// ============================================\n\n/**\n * Create a new MenuBuilder\n *\n * @param id - Menu ID (defaults to 'main')\n */\nexport function createMenu(id = 'main'): MenuBuilder {\n return new MenuBuilder(id);\n}\n\n/**\n * Create a simple menu quickly\n *\n * @param prompt - Main prompt text\n * @param options - Array of menu options\n */\nexport function createSimpleMenu(prompt: string, options: SimpleMenuOption[] = []): MenuStructure {\n const builder = createMenu().prompt(prompt);\n\n for (const { dtmf, action } of options) {\n builder.option(dtmf, action);\n }\n\n return builder.build();\n}\n\n// ============================================\n// Menu Templates\n// ============================================\n\n/**\n * Pre-built menu templates for common use cases\n */\nexport const MenuTemplates = {\n /**\n * Standard business menu (Sales, Support, Operator)\n *\n * @param companyName - Company name for greeting\n */\n business(companyName = 'Our Company'): MenuStructure {\n return createMenu()\n .prompt(\n `Thank you for calling ${companyName}! Press 1 for sales, 2 for support, or 0 for an operator.`\n )\n .repeatPrompt('Press 1 for sales, 2 for support, or 0 for operator.')\n .option('1', 'return(sales)')\n .option('2', 'return(support)')\n .option('0', 'return(operator)')\n .build();\n },\n\n /**\n * Yes/No confirmation menu\n *\n * @param question - Question to ask\n */\n yesNo(question = 'Please make your selection'): MenuStructure {\n return createMenu()\n .prompt(`${question} Press 1 for Yes, or 2 for No.`)\n .repeatPrompt('Press 1 for Yes, or 2 for No.')\n .option('1', 'return(yes)')\n .option('2', 'return(no)')\n .build();\n },\n\n /**\n * Language selection menu\n *\n * @param languages - Language options\n */\n language(\n languages: LanguageOption[] = [\n { dtmf: '1', name: 'English', value: 'en-US' },\n { dtmf: '2', name: 'Spanish', value: 'es-ES' },\n ]\n ): MenuStructure {\n const promptText =\n languages.map((lang) => `Press ${lang.dtmf} for ${lang.name}`).join(', ') + '.';\n\n const builder = createMenu().prompt(promptText).repeatPrompt(promptText);\n\n for (const lang of languages) {\n builder.option(lang.dtmf, `return(${lang.value})`);\n }\n\n return builder.build();\n },\n\n /**\n * After hours menu\n *\n * @param companyName - Company name\n * @param businessHours - Business hours text\n */\n afterHours(\n companyName = 'Our Company',\n businessHours = '9 AM to 5 PM, Monday through Friday'\n ): MenuStructure {\n return createMenu()\n .prompt(\n `Thank you for calling ${companyName}. Our office hours are ${businessHours}. Press 1 to leave a voicemail, 2 for our website, or 9 for emergency support.`\n )\n .repeatPrompt('Press 1 for voicemail, 2 for website, or 9 for emergency support.')\n .option('1', 'return(voicemail)')\n .option('2', 'return(website)')\n .option('9', 'return(emergency)')\n .timeout(10000)\n .build();\n },\n\n /**\n * Recording consent menu\n */\n recordingConsent(): MenuStructure {\n return createMenu()\n .prompt(\n 'For quality and training purposes, this call may be recorded. Press 1 to continue with recording, or press 2 to opt out.'\n )\n .repeatPrompt('Press 1 to allow recording, or press 2 to opt out.')\n .option('1', 'return(consent)')\n .option('2', 'return(no_consent)')\n .timeout(10000)\n .build();\n },\n\n /**\n * Numeric input menu (for collecting multi-digit input like account numbers)\n *\n * @param prompt - Instructions for user\n * @param digits - Number of digits to collect (default: 4)\n */\n numericInput(prompt: string, digits = 4): MenuStructure {\n return createMenu()\n .prompt(`${prompt} Then press pound.`)\n .repeatPrompt(`Please enter your ${digits} digit number, then press pound.`)\n .maxDigits(digits)\n .option('#', 'return')\n .timeout(15000)\n .build();\n },\n} as const;\n","/**\n * Universal Configuration Utility for Sinch Functions\n *\n * Provides a consistent API for accessing configuration across local development\n * and production environments. Works directly with process.env after secrets\n * have been loaded.\n *\n * @example\n * ```typescript\n * const config = createConfig(context);\n * const apiKey = config.getSecret('PROJECT_ID_API_SECRET');\n * const companyName = config.getVariable('COMPANY_NAME', 'Default Company');\n * ```\n */\n\nimport type { FunctionContext } from '../types/context.js';\nimport type { IFunctionCache } from '../cache/types.js';\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * Application credentials structure\n */\nexport interface ApplicationCredentials {\n applicationKey: string;\n applicationSecret: string;\n}\n\n/**\n * Configuration summary for debugging\n */\nexport interface ConfigSummary {\n environment: 'production' | 'development';\n variables: Record<string, string | undefined>;\n secrets: Record<string, string>;\n hasApplicationCredentials: boolean;\n}\n\n// ============================================\n// UniversalConfig Class\n// ============================================\n\n/**\n * Universal configuration utility class\n *\n * Provides a consistent interface for accessing environment variables,\n * secrets, and configuration across local and production environments.\n */\nexport class UniversalConfig {\n private context: FunctionContext;\n private env: Record<string, string | undefined>;\n\n /**\n * Create a new UniversalConfig instance\n *\n * @param context - Function execution context\n */\n constructor(context: FunctionContext) {\n this.context = context;\n this.env = context.env || (process.env as Record<string, string | undefined>);\n }\n\n /**\n * Get a secret value (e.g., API keys, passwords, tokens)\n *\n * @param name - Secret name (e.g., 'PROJECT_ID_API_SECRET')\n * @param defaultValue - Optional default value if secret not found\n */\n getSecret(name: string, defaultValue: string | null = null): string | null {\n return this.env[name] ?? defaultValue;\n }\n\n /**\n * Get an environment variable (non-secret configuration)\n *\n * @param name - Variable name (e.g., 'COMPANY_NAME', 'API_URL')\n * @param defaultValue - Optional default value\n */\n getVariable(name: string, defaultValue: string | null = null): string | null {\n return this.env[name] ?? defaultValue;\n }\n\n /**\n * Check if a secret exists (has a value)\n *\n * @param name - Secret name\n */\n hasSecret(name: string): boolean {\n return !!this.env[name];\n }\n\n /**\n * Check if a variable exists (has a value)\n *\n * @param name - Variable name\n */\n hasVariable(name: string): boolean {\n return !!this.env[name];\n }\n\n /**\n * Get required secret (throws error if not found)\n *\n * @param name - Secret name\n * @throws Error if secret is not found\n */\n requireSecret(name: string): string {\n const value = this.getSecret(name);\n if (!value) {\n throw new Error(`Required secret '${name}' not found in environment`);\n }\n return value;\n }\n\n /**\n * Get required variable (throws error if not found)\n *\n * @param name - Variable name\n * @throws Error if variable is not found\n */\n requireVariable(name: string): string {\n const value = this.getVariable(name);\n if (!value) {\n throw new Error(`Required variable '${name}' not found in environment`);\n }\n return value;\n }\n\n /**\n * Get Sinch application credentials\n */\n getApplicationCredentials(): ApplicationCredentials | null {\n const key = this.env.VOICE_APPLICATION_KEY;\n const secret = this.env.VOICE_APPLICATION_SECRET;\n\n if (key && secret) {\n return { applicationKey: key, applicationSecret: secret };\n }\n return null;\n }\n\n /**\n * Check if running in development mode\n */\n isDevelopment(): boolean {\n return this.env.NODE_ENV !== 'production';\n }\n\n /**\n * Check if running in production mode\n */\n isProduction(): boolean {\n return this.env.NODE_ENV === 'production';\n }\n\n /**\n * Get cache client instance\n */\n getCache(): IFunctionCache | undefined {\n return this.context.cache;\n }\n\n /**\n * Get comprehensive configuration summary (useful for debugging)\n * Excludes actual secret values for security\n */\n getConfigSummary(): ConfigSummary {\n const secretKeys = [\n 'PROJECT_ID_API_SECRET',\n 'VOICE_APPLICATION_SECRET',\n 'DATABASE_PASSWORD',\n 'API_KEY',\n ];\n\n const summary: ConfigSummary = {\n environment: this.isProduction() ? 'production' : 'development',\n variables: {},\n secrets: {},\n hasApplicationCredentials: !!this.getApplicationCredentials(),\n };\n\n for (const [key, value] of Object.entries(this.env)) {\n if (secretKeys.some((secretKey) => key.includes(secretKey))) {\n summary.secrets[key] = value ? '[REDACTED]' : '[NOT SET]';\n } else if (['NODE_ENV', 'PORT', 'SINCH_REGION'].includes(key)) {\n summary.variables[key] = value;\n }\n }\n\n return summary;\n }\n}\n\n// ============================================\n// Factory Functions\n// ============================================\n\n/**\n * Create a universal config instance for a function execution context\n *\n * @param context - Function execution context\n */\nexport function createConfig(context: FunctionContext): UniversalConfig {\n return new UniversalConfig(context);\n}\n\n// Alias for backwards compatibility\nexport const createUniversalConfig = createConfig;\n","/**\n * Express Middleware for Sinch Functions\n *\n * Provides JSON parsing with automatic camelCase transformation\n * and other middleware utilities.\n */\n\nimport type { Request, Response, NextFunction, Express } from 'express';\nimport { createRequire } from 'module';\nconst requireCjs = createRequire(import.meta.url);\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * Options for camelCase key transformation\n * @internal\n */\nexport interface CamelCaseOptions {\n /** Transform nested objects */\n deep?: boolean;\n /** Paths to skip transformation */\n stopPaths?: string[];\n /** Keys to exclude from transformation */\n exclude?: (string | RegExp)[];\n}\n\n/**\n * Options for JSON parsing middleware\n * @internal\n */\nexport interface JsonParsingOptions {\n /** Maximum body size (default: '10mb') */\n limit?: string;\n /** Accept JSON5 features (default: true) */\n allowJson5?: boolean;\n /** CamelCase transformation options */\n camelCase?: CamelCaseOptions;\n}\n\n/**\n * Extended Express Request with rawBody for signature validation\n * @internal\n */\nexport interface SinchRequest extends Request {\n rawBody?: string;\n _keysTransformed?: boolean;\n}\n\n// ============================================\n// Default Options\n// ============================================\n\nconst defaultOptions: Required<JsonParsingOptions> = {\n limit: '10mb',\n allowJson5: true,\n camelCase: {\n deep: true,\n stopPaths: ['custom', 'applicationkey'],\n exclude: [],\n },\n};\n\n// ============================================\n// Key Transformation\n// ============================================\n\n/**\n * Special case mappings for known Sinch fields without separators\n */\nconst SPECIAL_CASES: Record<string, string> = {\n callid: 'callId',\n applicationkey: 'applicationKey',\n callbackurl: 'callbackUrl',\n clinumber: 'cliNumber',\n menuResult: 'menuResult',\n userid: 'userId',\n username: 'userName',\n callleg: 'callLeg',\n conferenceid: 'conferenceId',\n participantid: 'participantId',\n};\n\n/**\n * Convert string to camelCase\n *\n * Handles:\n * - snake_case: call_id -> callId\n * - kebab-case: call-id -> callId\n * - lowercase concatenated: callid -> callId\n * @internal\n */\nexport function toCamelCase(str: string): string {\n if (!str) return str;\n\n // Already has separators - use standard conversion\n if (str.includes('_') || str.includes('-')) {\n return str.replace(/[-_]([a-z])/g, (_, char: string) => char.toUpperCase());\n }\n\n // Check if already camelCase\n if (/[a-z][A-Z]/.test(str)) {\n return str;\n }\n\n // All lowercase - check special cases\n const lower = str.toLowerCase();\n if (SPECIAL_CASES[lower]) {\n return SPECIAL_CASES[lower];\n }\n\n return str;\n}\n\n/**\n * Deep transform object keys to camelCase\n * @internal\n */\nexport function transformKeys<T>(obj: T, options: CamelCaseOptions = {}): T {\n const { stopPaths = [], exclude = [], deep = true } = options;\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return (deep ? obj.map((item) => transformKeys(item, options)) : obj) as T;\n }\n\n if (typeof obj !== 'object') {\n return obj;\n }\n\n const result: Record<string, unknown> = {};\n\n // Prototype pollution protection - skip dangerous keys\n const DANGEROUS_KEYS = ['__proto__', 'constructor', 'prototype'];\n\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n // Skip keys that could cause prototype pollution\n if (DANGEROUS_KEYS.includes(key)) {\n continue;\n }\n\n let newKey = key;\n let shouldTransformValue = deep;\n\n // Check exclusions\n const isExcluded = exclude.some((pattern) => {\n if (pattern instanceof RegExp) {\n return pattern.test(key);\n }\n return pattern === key;\n });\n\n if (!isExcluded) {\n newKey = toCamelCase(key);\n }\n\n // Also skip if transformed key is dangerous\n if (DANGEROUS_KEYS.includes(newKey)) {\n continue;\n }\n\n // Check if we should stop transforming nested values\n if (stopPaths.includes(newKey)) {\n shouldTransformValue = false;\n }\n\n result[newKey] = shouldTransformValue ? transformKeys(value, options) : value;\n }\n\n return result as T;\n}\n\n// ============================================\n// JSON Parsing\n// ============================================\n\n/**\n * Parse JSON with fallback to basic JSON5 support\n * @internal\n */\nexport function parseJson(text: string, allowJson5 = true): unknown {\n if (!text || typeof text !== 'string') {\n return {};\n }\n\n const trimmed = text.trim();\n if (!trimmed) {\n return {};\n }\n\n // First try strict JSON\n try {\n return JSON.parse(trimmed);\n } catch (e) {\n if (!allowJson5) {\n throw new Error(`Invalid JSON: ${(e as Error).message}`);\n }\n\n // Basic JSON5 cleanup\n try {\n const cleaned = trimmed\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '') // Remove /* */ comments\n .replace(/\\/\\/.*$/gm, '') // Remove // comments\n .replace(/,(\\s*[}\\]])/g, '$1'); // Remove trailing commas\n\n return JSON.parse(cleaned);\n } catch (e2) {\n throw new Error(`Invalid JSON/JSON5: ${(e as Error).message}`);\n }\n }\n}\n\n/**\n * Create Express middleware for lenient JSON parsing with camelCase transformation\n * @internal\n */\nexport function createLenientJsonParser(\n options: JsonParsingOptions = {}\n): (req: SinchRequest, res: Response, next: NextFunction) => void {\n const opts = { ...defaultOptions, ...options };\n\n return function lenientJsonParser(req: SinchRequest, res: Response, next: NextFunction): void {\n // Skip if body is already parsed\n if (req.body && typeof req.body === 'object' && !Buffer.isBuffer(req.body)) {\n if (!req._keysTransformed) {\n req.body = transformKeys(req.body, opts.camelCase);\n req._keysTransformed = true;\n }\n return next();\n }\n\n // Get raw body\n let raw = '';\n if (typeof req.body === 'string') {\n raw = req.body;\n req.rawBody = raw;\n } else if (Buffer.isBuffer(req.body)) {\n raw = req.body.toString('utf8');\n req.rawBody = raw;\n } else {\n req.body = {};\n return next();\n }\n\n try {\n let parsed = parseJson(raw, opts.allowJson5);\n // Skip camelCase transformation for webhook endpoints.\n // Webhook payloads (e.g. Conversation API) use snake_case field names\n // and controllers/extensions expect them preserved.\n // Voice callbacks hit \"/\" with event type in body โ€” they still get transformed.\n const isWebhookPath = req.path.startsWith('/webhook');\n if (!isWebhookPath) {\n parsed = transformKeys(parsed, opts.camelCase);\n }\n req._keysTransformed = true;\n req.body = parsed;\n next();\n } catch (error) {\n res.status(400).json({\n error: 'Invalid JSON in request body',\n message: (error as Error).message,\n hint: opts.allowJson5\n ? 'This endpoint accepts JSON and JSON5 (comments and trailing commas allowed)'\n : 'This endpoint requires strict JSON format',\n });\n }\n };\n}\n\n/**\n * Setup Express app with JSON parsing middleware\n * @internal\n */\nexport function setupJsonParsing(app: Express, options: JsonParsingOptions = {}): Express {\n // Dynamic import of express to avoid requiring it at module load time\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const express = requireCjs('express') as typeof import('express');\n\n // Use text parser to get raw body first\n app.use(\n express.text({\n type: ['application/json', 'application/*+json', 'text/json'],\n limit: options.limit || '10mb',\n })\n );\n\n // Apply lenient parser with camelCase transformation\n app.use(createLenientJsonParser(options));\n\n return app;\n}\n","/**\n * Express Application Factory for Sinch Functions\n *\n * Creates and configures Express apps for handling Sinch voice callbacks\n * and custom API endpoints. This is the core of the runtime.\n */\n\nimport type { Express, Request, Response } from 'express';\nimport type { FunctionContext, FunctionConfig } from '../types/context.js';\nimport type { IFunctionCache } from '../cache/types.js';\nimport type { FunctionRequest } from '../types/api.js';\nimport type { SvamletResponse } from '../types/svaml.js';\nimport type { SinchFunction } from '../types/handlers.js';\nimport type {\n IceCallbackData,\n AceCallbackData,\n PieCallbackData,\n DiceCallbackData,\n NotifyCallbackData,\n} from '../types/voice.js';\nimport { setupJsonParsing, type SinchRequest, type JsonParsingOptions } from './middleware.js';\nimport { createRequire } from 'module';\nimport { pathToFileURL } from 'url';\nimport * as nodePath from 'path';\nimport * as nodeFs from 'fs';\n\n// Create a CommonJS-compatible require for loading dependencies\nconst requireCjs = createRequire(import.meta.url);\n\n/**\n * Landing page HTML embedded as a string constant.\n * This avoids file system reads and works correctly when bundled.\n */\nconst LANDING_PAGE_HTML = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Sinch Function</title>\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.ico\">\n <link href=\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&display=swap\" rel=\"stylesheet\">\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: \"DM Sans\", Arial, sans-serif; min-height: 100vh; overflow: hidden; background: #ffffff; }\n #gradient-canvas { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 0; }\n .content { position: relative; z-index: 10; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 2rem; mix-blend-mode: difference; }\n .icon-wrapper { width: 120px; height: 120px; margin-bottom: 2rem; animation: float 6s ease-in-out infinite; }\n @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }\n .icon-wrapper svg { width: 100%; height: 100%; fill: white; }\n .title { font-size: clamp(32px, 6vw, 56px); font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; color: white; text-align: center; max-width: 600px; margin-bottom: 1.5rem; }\n .status { display: inline-flex; align-items: center; gap: 0.75rem; font-size: 18px; font-weight: 500; color: white; opacity: 0.9; }\n .status-dot { width: 10px; height: 10px; background: white; border-radius: 50%; position: relative; }\n .status-dot::before { content: ''; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid white; animation: ripple 2s ease-out infinite; }\n @keyframes ripple { 0% { transform: scale(1); opacity: 0.6; } 100% { transform: scale(2); opacity: 0; } }\n footer { position: fixed; bottom: 0; left: 0; right: 0; padding: 1.5rem 2rem; text-align: center; z-index: 10; mix-blend-mode: difference; }\n .footer-content { display: flex; align-items: center; justify-content: center; gap: 0.5rem; font-size: 13px; color: white; opacity: 0.7; }\n .footer-content svg { height: 16px; width: auto; fill: white; }\n @media (prefers-reduced-motion: reduce) { .icon-wrapper { animation: none; } .status-dot::before { animation: none; display: none; } }\n </style>\n</head>\n<body>\n <canvas id=\"gradient-canvas\"></canvas>\n <div class=\"content\">\n <div class=\"icon-wrapper\">\n <svg viewBox=\"0 0 1024 1024\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M0 0 C20.93144435 -0.58142901 39.09496106 1.50604372 55.875 15.5625 C66.82790249 26.17665293 72.53226475 40.66646351 74.60546875 55.56640625 C74.87588186 58.00035983 74.87588186 58.00035983 76 60 C76.96454894 67.72509952 77.18355452 75.52548686 77.39453125 83.30078125 C77.46339082 85.43557289 77.53307981 87.57033791 77.60351562 89.70507812 C77.70976411 92.99051459 77.81152568 96.27576582 77.89868164 99.56176758 C78.52393733 129.23731142 78.52393733 129.23731142 88 157 C88.35578125 157.67804688 88.7115625 158.35609375 89.078125 159.0546875 C94.76089061 168.37922543 104.94901494 170.48725373 115 173 C115 182.57 115 192.14 115 202 C112.69 202.37125 110.38 202.7425 108 203.125 C99.905737 204.67003153 95.0680161 206.8924082 90.109375 213.53125 C83.71376381 223.52775152 81.23188184 234.44421869 79.9609375 246.09765625 C79.87667007 246.86579147 79.79240265 247.6339267 79.70558167 248.42533875 C78.67925596 258.36255872 78.32712705 268.3341428 77.9375 278.3125 C76.56010435 312.28921394 76.56010435 312.28921394 74.25 321.5 C74.0744458 322.21430176 73.8988916 322.92860352 73.71801758 323.66455078 C69.36621237 340.7251508 62.22279512 355.52722574 46.7734375 364.97265625 C31.08266768 373.31391199 17.46036093 374.45648002 0 374 C0 362.78 0 351.56 0 340 C4.95 339.67 9.9 339.34 15 339 C21.41425661 337.54221441 27.40557289 335.94604143 32 331 C41.96653782 315.14896379 41.37732492 296.30175799 42 278.25 C44.29042973 212.3198731 44.29042973 212.3198731 64.91015625 190 C66.29780265 187.98880883 66.29780265 187.98880883 65.37890625 185.48046875 C64.05564488 183.10009772 62.69232678 181.32846483 60.875 179.3125 C43.91950219 157.82609672 43.67363702 127.5168667 42.25390625 101.43359375 C42.19595886 100.36962875 42.13801147 99.30566376 42.07830811 98.2094574 C41.84407978 93.84466467 41.61402719 89.47975805 41.39819336 85.11401367 C40.99015593 64.27717646 40.99015593 64.27717646 32.98828125 45.5234375 C32 44 32 44 32 42 C31.42121094 41.71253906 30.84242188 41.42507813 30.24609375 41.12890625 C28.83602338 40.42019262 27.43139326 39.70043581 26.03515625 38.96484375 C25.38417969 38.62582031 24.73320313 38.28679687 24.0625 37.9375 C23.41410156 37.59589844 22.76570312 37.25429688 22.09765625 36.90234375 C15.27203813 33.966184 7.11372705 34.47424847 0 34 C0 22.78 0 11.56 0 0 Z\" transform=\"translate(654,325)\"/>\n <path d=\"M0 0 C3.444375 0.04125 6.88875 0.0825 10.4375 0.125 C10.4375 11.345 10.4375 22.565 10.4375 34.125 C7.83875 34.2075 5.24 34.29 2.5625 34.375 C-7.18272292 34.85729903 -15.63749007 36.71684985 -22.5625 44.125 C-31.49595906 57.5251886 -31.12984766 74.21365918 -31.625 89.6875 C-34.18432686 164.24320576 -34.18432686 164.24320576 -54.375 183.4765625 C-55.74969183 185.03433577 -55.74969183 185.03433577 -55.515625 186.95703125 C-54.17099734 190.0155081 -52.28807488 192.49561568 -50.3125 195.1875 C-32.54496946 220.15391355 -32.63824135 251.51444506 -31.51293945 280.92919922 C-31.08045868 292.11365858 -30.51897291 303.08447592 -28.5625 314.125 C-28.43262695 314.88192139 -28.30275391 315.63884277 -28.16894531 316.41870117 C-26.61388783 323.91215705 -23.50529382 330.13896804 -17.1875 334.5625 C-8.59143743 340.04835084 0.27828442 339.49004903 10.4375 340.125 C10.4375 351.345 10.4375 362.565 10.4375 374.125 C-11.03507606 374.69006779 -28.20349315 372.92712593 -45.375 358.5625 C-68.63112564 336.25560398 -67.21470802 299.23895394 -68.0625 269.5625 C-68.59361144 237.84268541 -68.59361144 237.84268541 -82.5625 210.125 C-89.22872268 204.50037462 -95.95018781 203.27807805 -104.5625 201.125 C-104.5625 191.885 -104.5625 182.645 -104.5625 173.125 C-102.0875 172.444375 -99.6125 171.76375 -97.0625 171.0625 C-88.61410179 168.53529591 -83.39407037 165.21504609 -78.3125 157.875 C-77.69451944 156.64176126 -77.11369297 155.38950152 -76.5625 154.125 C-76.05783203 152.97451172 -76.05783203 152.97451172 -75.54296875 151.80078125 C-70.10324087 138.17090127 -68.58488302 123.17691663 -68.1328125 108.6171875 C-68.0590342 106.55597377 -67.98479985 104.49477633 -67.91015625 102.43359375 C-67.79799647 99.2401961 -67.68897443 96.04681123 -67.58837891 92.85302734 C-67.22538737 81.52946225 -66.65494051 70.32073083 -65.13671875 59.0859375 C-64.95793686 57.75983963 -64.95793686 57.75983963 -64.77554321 56.4069519 C-62.24372342 39.06207822 -55.12155189 23.04594995 -40.9609375 12.1171875 C-28.07509054 3.53900119 -15.33988115 -0.26186367 0 0 Z\" transform=\"translate(359.5625,324.875)\"/>\n <path d=\"M0 0 C9.89334431 8.68950817 14.30034619 23.01452361 15.24373245 35.79419899 C15.49099471 41.77148785 15.42334062 47.74978768 15.37109375 53.73046875 C15.36548489 55.63859724 15.36122091 57.54673011 15.35823059 59.4548645 C15.34688325 64.42950786 15.31750548 69.40388024 15.28411865 74.37841797 C15.25319735 79.47359555 15.23967854 84.56881775 15.22460938 89.6640625 C15.19262409 99.62643911 15.13994121 109.58854505 15.078125 119.55078125 C3.528125 119.55078125 -8.021875 119.55078125 -19.921875 119.55078125 C-19.97085938 114.4203125 -20.01984375 109.28984375 -20.0703125 104.00390625 C-20.10574492 100.73175245 -20.14173112 97.45962313 -20.1796875 94.1875 C-20.23973228 89.00671097 -20.29785091 83.82595572 -20.34375 78.64501953 C-20.38093086 74.46275871 -20.42737419 70.28068941 -20.47993851 66.09859467 C-20.49830992 64.51204578 -20.51347972 62.92545612 -20.52521896 61.3388443 C-20.22141003 42.05064114 -20.22141003 42.05064114 -28.921875 25.55078125 C-33.2097739 21.98892101 -37.29807009 19.87523153 -42.921875 19.55078125 C-43.79714844 19.48890625 -44.67242188 19.42703125 -45.57421875 19.36328125 C-54.66067243 18.98906437 -62.9621186 20.4280254 -69.859375 26.73828125 C-76.14726535 33.73487866 -78.0525657 41.92333342 -78.12719727 51.07324219 C-78.13709686 51.82485123 -78.14699646 52.57646027 -78.15719604 53.35084534 C-78.18871966 55.82891721 -78.21353223 58.30700823 -78.23828125 60.78515625 C-78.25885867 62.50580334 -78.27985536 64.22644545 -78.30125427 65.94708252 C-78.35639351 70.47125217 -78.40583867 74.99546682 -78.45410156 79.51971436 C-78.51321858 84.95049451 -78.57940167 90.38119259 -78.64440155 95.81190491 C-78.74230855 104.0581468 -78.83123469 112.30444185 -78.921875 120.55078125 C-90.801875 120.55078125 -102.681875 120.55078125 -114.921875 120.55078125 C-114.921875 77.65078125 -114.921875 34.75078125 -114.921875 -9.44921875 C-103.701875 -9.44921875 -92.481875 -9.44921875 -80.921875 -9.44921875 C-79.96000569 -5.60174152 -79.61528473 -2.14754023 -79.359375 1.80078125 C-79.27558594 3.0640625 -79.19179688 4.32734375 -79.10546875 5.62890625 C-79.04488281 6.593125 -78.98429688 7.55734375 -78.921875 8.55078125 C-78.48875 7.72578125 -78.055625 6.90078125 -77.609375 6.05078125 C-71.50314599 -3.01214812 -59.57220635 -8.76116827 -49.16015625 -11.05859375 C-31.06340614 -13.24155516 -14.8555768 -11.20207112 0 0 Z\" transform=\"translate(613.921875,481.44921875)\"/>\n <path d=\"M0 0 C1.53906801 1.53906801 1.16955456 2.91263628 1.1875 5.0625 C1.1451715 9.92322255 0.65815533 14.68227908 0.0625 19.5 C-0.02427002 20.20648682 -0.11104004 20.91297363 -0.20043945 21.64086914 C-0.86920125 26.7384025 -0.86920125 26.7384025 -2 29 C-2.96808594 28.84144531 -3.93617188 28.68289063 -4.93359375 28.51953125 C-9.31081865 27.89956204 -13.64601408 27.74275212 -18.0625 27.6875 C-18.83916016 27.65849609 -19.61582031 27.62949219 -20.41601562 27.59960938 C-25.75566236 27.54083257 -28.83098013 28.36372264 -33 32 C-37.31404494 38.3211768 -37.31404494 38.3211768 -37 53 C-25.78 53 -14.56 53 -3 53 C-3 62.57 -3 72.14 -3 82 C-14.55 82 -26.1 82 -38 82 C-38 115 -38 148 -38 182 C-49.55 182 -61.1 182 -73 182 C-73 149 -73 116 -73 82 C-79.93 82 -86.86 82 -94 82 C-94 72.43 -94 62.86 -94 53 C-87.07 53 -80.14 53 -73 53 C-73.04125 50.6075 -73.0825 48.215 -73.125 45.75 C-73.17827085 31.60875021 -70.96095372 19.48048613 -61.0078125 8.81640625 C-54.5981324 3.0177657 -47.30019677 0.02408307 -39 -2 C-38.37625488 -2.17200928 -37.75250977 -2.34401855 -37.10986328 -2.52124023 C-25.33848182 -5.19234404 -11.53065338 -2.96722147 0 0 Z\" transform=\"translate(486,419)\"/>\n </svg>\n </div>\n <h1 class=\"title\">Your function is ready for traffic</h1>\n <div class=\"status\"><span class=\"status-dot\"></span>Running</div>\n </div>\n <footer>\n <div class=\"footer-content\">\n Powered by\n <svg viewBox=\"0 0 93 48\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M92.298 25.271a17.167 17.167 0 0 1-.814 5.312c-1.51 4.734-5.27 8.678-10.06 10.549-5.64 2.202-12.252 1.416-18.624-2.21l-4.649-2.67a16.424 16.424 0 0 1-3.563 3.064l-14.817 8.679-.027.015v-7.501l.027-.014 22.29-13.057a16.017 16.017 0 0 1-.713 3.206l4.656 2.65c5.95 3.386 10.388 2.85 13.065 1.806 2.991-1.167 5.323-3.59 6.245-6.483.692-2.15.679-4.467-.04-6.609-.955-2.88-3.319-5.275-6.324-6.41-2.688-1.014-7.132-1.494-13.04 1.962L29.7 38.747l-.043.028c-4.017 2.35-8.14 3.556-12.065 3.58a18.162 18.162 0 0 1-6.53-1.145C6.247 39.396 2.44 35.498.874 30.783A17.116 17.116 0 0 1 .81 20.166c1.51-4.733 5.272-8.676 10.063-10.548 5.64-2.202 12.252-1.416 18.623 2.212l4.649 2.67a16.377 16.377 0 0 1 3.563-3.067l.281-.163 1.726-1.011-7.37-4.197A3.238 3.238 0 0 1 35.551.437l10.591 6.06L56.52.457a3.238 3.238 0 0 1 3.27 5.588l-29.528 17.05c.132-1.017.36-2.019.683-2.992l-4.656-2.65c-5.946-3.383-10.384-2.847-13.061-1.803-2.991 1.167-5.325 3.59-6.247 6.481a10.623 10.623 0 0 0 .039 6.608c.956 2.882 3.321 5.277 6.324 6.41 2.689 1.012 7.136 1.495 13.042-1.966l36.256-21.208c4.017-2.349 8.14-3.555 12.067-3.579a18.112 18.112 0 0 1 6.53 1.145c4.812 1.813 8.62 5.712 10.187 10.426a17.23 17.23 0 0 1 .872 5.304Z\"/>\n </svg>\n </div>\n </footer>\n <script type=\"importmap\">{\"imports\":{\"three\":\"https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js\"}}</script>\n <script type=\"module\">\n import * as THREE from 'three';\n const COLORS={yellow:new THREE.Color(0xFFBE3C),green:new THREE.Color(0x059688),blue:new THREE.Color(0x3AA7EA),red:new THREE.Color(0xEF5858)};\n const vertexShader=\\`varying vec2 vUv;void main(){vUv=uv;gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);}\\`;\n const fragmentShader=\\`uniform float uTime;uniform vec2 uResolution;uniform vec3 uColor1;uniform vec3 uColor2;uniform vec3 uColor3;uniform vec3 uColor4;varying vec2 vUv;vec3 mod289(vec3 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 mod289(vec4 x){return x-floor(x*(1.0/289.0))*289.0;}vec4 permute(vec4 x){return mod289(((x*34.0)+1.0)*x);}vec4 taylorInvSqrt(vec4 r){return 1.79284291400159-0.85373472095314*r;}float snoise(vec3 v){const vec2 C=vec2(1.0/6.0,1.0/3.0);const vec4 D=vec4(0.0,0.5,1.0,2.0);vec3 i=floor(v+dot(v,C.yyy));vec3 x0=v-i+dot(i,C.xxx);vec3 g=step(x0.yzx,x0.xyz);vec3 l=1.0-g;vec3 i1=min(g.xyz,l.zxy);vec3 i2=max(g.xyz,l.zxy);vec3 x1=x0-i1+C.xxx;vec3 x2=x0-i2+C.yyy;vec3 x3=x0-D.yyy;i=mod289(i);vec4 p=permute(permute(permute(i.z+vec4(0.0,i1.z,i2.z,1.0))+i.y+vec4(0.0,i1.y,i2.y,1.0))+i.x+vec4(0.0,i1.x,i2.x,1.0));float n_=0.142857142857;vec3 ns=n_*D.wyz-D.xzx;vec4 j=p-49.0*floor(p*ns.z*ns.z);vec4 x_=floor(j*ns.z);vec4 y_=floor(j-7.0*x_);vec4 x=x_*ns.x+ns.yyyy;vec4 y=y_*ns.x+ns.yyyy;vec4 h=1.0-abs(x)-abs(y);vec4 b0=vec4(x.xy,y.xy);vec4 b1=vec4(x.zw,y.zw);vec4 s0=floor(b0)*2.0+1.0;vec4 s1=floor(b1)*2.0+1.0;vec4 sh=-step(h,vec4(0.0));vec4 a0=b0.xzyw+s0.xzyw*sh.xxyy;vec4 a1=b1.xzyw+s1.xzyw*sh.zzww;vec3 p0=vec3(a0.xy,h.x);vec3 p1=vec3(a0.zw,h.y);vec3 p2=vec3(a1.xy,h.z);vec3 p3=vec3(a1.zw,h.w);vec4 norm=taylorInvSqrt(vec4(dot(p0,p0),dot(p1,p1),dot(p2,p2),dot(p3,p3)));p0*=norm.x;p1*=norm.y;p2*=norm.z;p3*=norm.w;vec4 m=max(0.6-vec4(dot(x0,x0),dot(x1,x1),dot(x2,x2),dot(x3,x3)),0.0);m=m*m;return 42.0*dot(m*m,vec4(dot(p0,x0),dot(p1,x1),dot(p2,x2),dot(p3,x3)));}float metaball(vec2 p,vec2 center,float radius){float d=length(p-center);return radius/(d*d+0.0001);}void main(){vec2 uv=vUv;vec2 aspect=vec2(uResolution.x/uResolution.y,1.0);vec2 p=(uv-0.5)*aspect;float time=uTime*0.15;vec2 blob1=vec2(0.6*sin(time*0.7+snoise(vec3(time*0.2,0.0,0.0))),0.5*cos(time*0.5+snoise(vec3(0.0,time*0.2,0.0))));vec2 blob2=vec2(0.55*cos(time*0.6+1.5+snoise(vec3(time*0.15,1.0,0.0))),0.6*sin(time*0.8+2.0+snoise(vec3(1.0,time*0.15,0.0))));vec2 blob3=vec2(0.7*sin(time*0.5+3.0+snoise(vec3(time*0.1,2.0,0.0))),0.5*cos(time*0.7+1.0+snoise(vec3(2.0,time*0.1,0.0))));vec2 blob4=vec2(0.55*cos(time*0.8+4.5+snoise(vec3(time*0.12,3.0,0.0))),0.65*sin(time*0.6+0.5+snoise(vec3(3.0,time*0.12,0.0))));float size1=0.16+0.04*sin(time*1.2);float size2=0.14+0.03*cos(time*1.5);float size3=0.18+0.05*sin(time*0.9);float size4=0.12+0.04*cos(time*1.1);float m1=metaball(p,blob1,size1);float m2=metaball(p,blob2,size2);float m3=metaball(p,blob3,size3);float m4=metaball(p,blob4,size4);float field=m1+m2+m3+m4;float noise=snoise(vec3(p*3.0,time*0.3))*0.15;field+=noise;vec3 color=vec3(0.0);float total=m1+m2+m3+m4+0.0001;color+=uColor1*(m1/total);color+=uColor2*(m2/total);color+=uColor3*(m3/total);color+=uColor4*(m4/total);float gradientNoise=snoise(vec3(uv*2.0,time*0.1));color+=gradientNoise*0.05;float threshold=0.8;float edge=smoothstep(threshold-0.3,threshold+0.5,field);vec3 bg1=mix(uColor1,uColor3,uv.y)*0.6+0.4;vec3 bg2=mix(uColor2,uColor4,uv.x)*0.6+0.4;vec3 background=mix(bg1,bg2,0.5+0.5*sin(time*0.2));vec3 finalColor=mix(background,color,edge);float vignette=1.0-length(uv-0.5)*0.5;finalColor*=vignette;finalColor=pow(finalColor,vec3(0.95));gl_FragColor=vec4(finalColor,1.0);}\\`;\n class GradientAnimation{constructor(){this.canvas=document.getElementById('gradient-canvas');this.scene=new THREE.Scene();this.camera=new THREE.OrthographicCamera(-1,1,1,-1,0,1);this.renderer=new THREE.WebGLRenderer({canvas:this.canvas,antialias:true,alpha:false});this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2));this.renderer.setSize(window.innerWidth,window.innerHeight);this.uniforms={uTime:{value:0},uResolution:{value:new THREE.Vector2(window.innerWidth,window.innerHeight)},uColor1:{value:COLORS.yellow},uColor2:{value:COLORS.green},uColor3:{value:COLORS.blue},uColor4:{value:COLORS.red}};const geometry=new THREE.PlaneGeometry(2,2);const material=new THREE.ShaderMaterial({vertexShader,fragmentShader,uniforms:this.uniforms});this.mesh=new THREE.Mesh(geometry,material);this.scene.add(this.mesh);window.addEventListener('resize',this.onResize.bind(this));this.animate();}onResize(){this.renderer.setSize(window.innerWidth,window.innerHeight);this.uniforms.uResolution.value.set(window.innerWidth,window.innerHeight);}animate(){this.uniforms.uTime.value+=0.016;this.renderer.render(this.scene,this.camera);requestAnimationFrame(this.animate.bind(this));}}\n new GradientAnimation();\n </script>\n</body>\n</html>`;\n\n/**\n * Get the landing page HTML content\n * Exported so production runtime can also use it\n * @internal\n */\nexport function getLandingPageHtml(): string {\n return LANDING_PAGE_HTML;\n}\n\n/**\n * Favicon SVG - the {fn} icon used in the landing page\n */\nconst FAVICON_SVG = `<svg viewBox=\"0 0 1024 1024\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"1024\" height=\"1024\" fill=\"#3AA7EA\"/>\n <path fill=\"white\" d=\"M0 0 C20.93144435 -0.58142901 39.09496106 1.50604372 55.875 15.5625 C66.82790249 26.17665293 72.53226475 40.66646351 74.60546875 55.56640625 C74.87588186 58.00035983 74.87588186 58.00035983 76 60 C76.96454894 67.72509952 77.18355452 75.52548686 77.39453125 83.30078125 C77.46339082 85.43557289 77.53307981 87.57033791 77.60351562 89.70507812 C77.70976411 92.99051459 77.81152568 96.27576582 77.89868164 99.56176758 C78.52393733 129.23731142 78.52393733 129.23731142 88 157 C88.35578125 157.67804688 88.7115625 158.35609375 89.078125 159.0546875 C94.76089061 168.37922543 104.94901494 170.48725373 115 173 C115 182.57 115 192.14 115 202 C112.69 202.37125 110.38 202.7425 108 203.125 C99.905737 204.67003153 95.0680161 206.8924082 90.109375 213.53125 C83.71376381 223.52775152 81.23188184 234.44421869 79.9609375 246.09765625 C79.87667007 246.86579147 79.79240265 247.6339267 79.70558167 248.42533875 C78.67925596 258.36255872 78.32712705 268.3341428 77.9375 278.3125 C76.56010435 312.28921394 76.56010435 312.28921394 74.25 321.5 C74.0744458 322.21430176 73.8988916 322.92860352 73.71801758 323.66455078 C69.36621237 340.7251508 62.22279512 355.52722574 46.7734375 364.97265625 C31.08266768 373.31391199 17.46036093 374.45648002 0 374 C0 362.78 0 351.56 0 340 C4.95 339.67 9.9 339.34 15 339 C21.41425661 337.54221441 27.40557289 335.94604143 32 331 C41.96653782 315.14896379 41.37732492 296.30175799 42 278.25 C44.29042973 212.3198731 44.29042973 212.3198731 64.91015625 190 C66.29780265 187.98880883 66.29780265 187.98880883 65.37890625 185.48046875 C64.05564488 183.10009772 62.69232678 181.32846483 60.875 179.3125 C43.91950219 157.82609672 43.67363702 127.5168667 42.25390625 101.43359375 C42.19595886 100.36962875 42.13801147 99.30566376 42.07830811 98.2094574 C41.84407978 93.84466467 41.61402719 89.47975805 41.39819336 85.11401367 C40.99015593 64.27717646 40.99015593 64.27717646 32.98828125 45.5234375 C32 44 32 44 32 42 C31.42121094 41.71253906 30.84242188 41.42507813 30.24609375 41.12890625 C28.83602338 40.42019262 27.43139326 39.70043581 26.03515625 38.96484375 C25.38417969 38.62582031 24.73320313 38.28679687 24.0625 37.9375 C23.41410156 37.59589844 22.76570312 37.25429688 22.09765625 36.90234375 C15.27203813 33.966184 7.11372705 34.47424847 0 34 C0 22.78 0 11.56 0 0 Z\" transform=\"translate(654,325)\"/>\n <path fill=\"white\" d=\"M0 0 C3.444375 0.04125 6.88875 0.0825 10.4375 0.125 C10.4375 11.345 10.4375 22.565 10.4375 34.125 C7.83875 34.2075 5.24 34.29 2.5625 34.375 C-7.18272292 34.85729903 -15.63749007 36.71684985 -22.5625 44.125 C-31.49595906 57.5251886 -31.12984766 74.21365918 -31.625 89.6875 C-34.18432686 164.24320576 -34.18432686 164.24320576 -54.375 183.4765625 C-55.74969183 185.03433577 -55.74969183 185.03433577 -55.515625 186.95703125 C-54.17099734 190.0155081 -52.28807488 192.49561568 -50.3125 195.1875 C-32.54496946 220.15391355 -32.63824135 251.51444506 -31.51293945 280.92919922 C-31.08045868 292.11365858 -30.51897291 303.08447592 -28.5625 314.125 C-28.43262695 314.88192139 -28.30275391 315.63884277 -28.16894531 316.41870117 C-26.61388783 323.91215705 -23.50529382 330.13896804 -17.1875 334.5625 C-8.59143743 340.04835084 0.27828442 339.49004903 10.4375 340.125 C10.4375 351.345 10.4375 362.565 10.4375 374.125 C-11.03507606 374.69006779 -28.20349315 372.92712593 -45.375 358.5625 C-68.63112564 336.25560398 -67.21470802 299.23895394 -68.0625 269.5625 C-68.59361144 237.84268541 -68.59361144 237.84268541 -82.5625 210.125 C-89.22872268 204.50037462 -95.95018781 203.27807805 -104.5625 201.125 C-104.5625 191.885 -104.5625 182.645 -104.5625 173.125 C-102.0875 172.444375 -99.6125 171.76375 -97.0625 171.0625 C-88.61410179 168.53529591 -83.39407037 165.21504609 -78.3125 157.875 C-77.69451944 156.64176126 -77.11369297 155.38950152 -76.5625 154.125 C-76.05783203 152.97451172 -76.05783203 152.97451172 -75.54296875 151.80078125 C-70.10324087 138.17090127 -68.58488302 123.17691663 -68.1328125 108.6171875 C-68.0590342 106.55597377 -67.98479985 104.49477633 -67.91015625 102.43359375 C-67.79799647 99.2401961 -67.68897443 96.04681123 -67.58837891 92.85302734 C-67.22538737 81.52946225 -66.65494051 70.32073083 -65.13671875 59.0859375 C-64.95793686 57.75983963 -64.95793686 57.75983963 -64.77554321 56.4069519 C-62.24372342 39.06207822 -55.12155189 23.04594995 -40.9609375 12.1171875 C-28.07509054 3.53900119 -15.33988115 -0.26186367 0 0 Z\" transform=\"translate(359.5625,324.875)\"/>\n <path fill=\"white\" d=\"M0 0 C9.89334431 8.68950817 14.30034619 23.01452361 15.24373245 35.79419899 C15.49099471 41.77148785 15.42334062 47.74978768 15.37109375 53.73046875 C15.36548489 55.63859724 15.36122091 57.54673011 15.35823059 59.4548645 C15.34688325 64.42950786 15.31750548 69.40388024 15.28411865 74.37841797 C15.25319735 79.47359555 15.23967854 84.56881775 15.22460938 89.6640625 C15.19262409 99.62643911 15.13994121 109.58854505 15.078125 119.55078125 C3.528125 119.55078125 -8.021875 119.55078125 -19.921875 119.55078125 C-19.97085938 114.4203125 -20.01984375 109.28984375 -20.0703125 104.00390625 C-20.10574492 100.73175245 -20.14173112 97.45962313 -20.1796875 94.1875 C-20.23973228 89.00671097 -20.29785091 83.82595572 -20.34375 78.64501953 C-20.38093086 74.46275871 -20.42737419 70.28068941 -20.47993851 66.09859467 C-20.49830992 64.51204578 -20.51347972 62.92545612 -20.52521896 61.3388443 C-20.22141003 42.05064114 -20.22141003 42.05064114 -28.921875 25.55078125 C-33.2097739 21.98892101 -37.29807009 19.87523153 -42.921875 19.55078125 C-43.79714844 19.48890625 -44.67242188 19.42703125 -45.57421875 19.36328125 C-54.66067243 18.98906437 -62.9621186 20.4280254 -69.859375 26.73828125 C-76.14726535 33.73487866 -78.0525657 41.92333342 -78.12719727 51.07324219 C-78.13709686 51.82485123 -78.14699646 52.57646027 -78.15719604 53.35084534 C-78.18871966 55.82891721 -78.21353223 58.30700823 -78.23828125 60.78515625 C-78.25885867 62.50580334 -78.27985536 64.22644545 -78.30125427 65.94708252 C-78.35639351 70.47125217 -78.40583867 74.99546682 -78.45410156 79.51971436 C-78.51321858 84.95049451 -78.57940167 90.38119259 -78.64440155 95.81190491 C-78.74230855 104.0581468 -78.83123469 112.30444185 -78.921875 120.55078125 C-90.801875 120.55078125 -102.681875 120.55078125 -114.921875 120.55078125 C-114.921875 77.65078125 -114.921875 34.75078125 -114.921875 -9.44921875 C-103.701875 -9.44921875 -92.481875 -9.44921875 -80.921875 -9.44921875 C-79.96000569 -5.60174152 -79.61528473 -2.14754023 -79.359375 1.80078125 C-79.27558594 3.0640625 -79.19179688 4.32734375 -79.10546875 5.62890625 C-79.04488281 6.593125 -78.98429688 7.55734375 -78.921875 8.55078125 C-78.48875 7.72578125 -78.055625 6.90078125 -77.609375 6.05078125 C-71.50314599 -3.01214812 -59.57220635 -8.76116827 -49.16015625 -11.05859375 C-31.06340614 -13.24155516 -14.8555768 -11.20207112 0 0 Z\" transform=\"translate(613.921875,481.44921875)\"/>\n <path fill=\"white\" d=\"M0 0 C1.53906801 1.53906801 1.16955456 2.91263628 1.1875 5.0625 C1.1451715 9.92322255 0.65815533 14.68227908 0.0625 19.5 C-0.02427002 20.20648682 -0.11104004 20.91297363 -0.20043945 21.64086914 C-0.86920125 26.7384025 -0.86920125 26.7384025 -2 29 C-2.96808594 28.84144531 -3.93617188 28.68289063 -4.93359375 28.51953125 C-9.31081865 27.89956204 -13.64601408 27.74275212 -18.0625 27.6875 C-18.83916016 27.65849609 -19.61582031 27.62949219 -20.41601562 27.59960938 C-25.75566236 27.54083257 -28.83098013 28.36372264 -33 32 C-37.31404494 38.3211768 -37.31404494 38.3211768 -37 53 C-25.78 53 -14.56 53 -3 53 C-3 62.57 -3 72.14 -3 82 C-14.55 82 -26.1 82 -38 82 C-38 115 -38 148 -38 182 C-49.55 182 -61.1 182 -73 182 C-73 149 -73 116 -73 82 C-79.93 82 -86.86 82 -94 82 C-94 72.43 -94 62.86 -94 53 C-87.07 53 -80.14 53 -73 53 C-73.04125 50.6075 -73.0825 48.215 -73.125 45.75 C-73.17827085 31.60875021 -70.96095372 19.48048613 -61.0078125 8.81640625 C-54.5981324 3.0177657 -47.30019677 0.02408307 -39 -2 C-38.37625488 -2.17200928 -37.75250977 -2.34401855 -37.10986328 -2.52124023 C-25.33848182 -5.19234404 -11.53065338 -2.96722147 0 0 Z\" transform=\"translate(486,419)\"/>\n</svg>`;\n\n/**\n * Get the favicon SVG content\n * Exported so production runtime can also use it\n * @internal\n */\nexport function getFaviconSvg(): string {\n return FAVICON_SVG;\n}\n\n// ============================================\n// Types\n// ============================================\n\n/**\n * Options for creating the Express app\n * @internal\n */\nexport interface AppOptions {\n /** JSON parsing options */\n jsonParsingOptions?: JsonParsingOptions;\n /** Enable landing page for browser requests at root (default: true) */\n landingPageEnabled?: boolean;\n /** Directory to serve static files from (optional) */\n staticDir?: string;\n}\n\n/**\n * Options for setting up the request handler\n * @internal\n */\nexport interface RequestHandlerOptions {\n /** Function to load user code module (can be sync or async for ESM) */\n loadUserFunction?: () => SinchFunction | Promise<SinchFunction>;\n /** Function to build context for each request */\n buildContext?: (req: Request) => FunctionContext;\n /** Logger function */\n logger?: (...args: unknown[]) => void;\n /** Enable landing page for browser requests at root (default: true) */\n landingPageEnabled?: boolean;\n /** Called when request starts */\n onRequestStart?: (data: { functionName: string; req: Request }) => void;\n /** Called when request ends */\n onRequestEnd?: (data: {\n functionName: string;\n req: Request;\n response?: FormattedResponse;\n error?: Error;\n duration: number;\n statusCode: number;\n }) => void;\n}\n\n/**\n * Formatted response structure\n * @internal\n */\nexport interface FormattedResponse {\n statusCode: number;\n headers?: Record<string, string>;\n body?: unknown;\n}\n\n// ============================================\n// Constants\n// ============================================\n\n/** Voice callback function names @internal */\nexport const VOICE_CALLBACKS = ['ice', 'ace', 'pie', 'dice', 'notify'] as const;\n\n/** Notification-only events (don't require SVAML response) @internal */\nexport const NOTIFICATION_EVENTS = ['dice', 'notify'] as const;\n\nexport type VoiceCallback = (typeof VOICE_CALLBACKS)[number];\nexport type NotificationEvent = (typeof NOTIFICATION_EVENTS)[number];\n\n// ============================================\n// Helper Functions\n// ============================================\n\n/**\n * Check if a function name is a voice callback\n * @internal\n */\nexport function isVoiceCallback(functionName: string): functionName is VoiceCallback {\n return VOICE_CALLBACKS.includes(functionName as VoiceCallback);\n}\n\n/**\n * Check if a function is a notification-only event\n * @internal\n */\nexport function isNotificationEvent(functionName: string): functionName is NotificationEvent {\n return NOTIFICATION_EVENTS.includes(functionName as NotificationEvent);\n}\n\n/**\n * Extract function name from request path or body\n * @internal\n */\nexport function extractFunctionName(path: string, body?: { event?: string }): string {\n // Check if body contains an event type (voice callbacks)\n if (body?.event && isVoiceCallback(body.event)) {\n return body.event;\n }\n\n // Strip query string (req.originalUrl includes it, req.path does not)\n const pathname = path.split('?')[0];\n\n // Parse path for function name\n const segments = pathname.split('/').filter((s) => s && s !== '*');\n\n // Single segment paths map directly to function names\n if (segments.length === 1 && isVoiceCallback(segments[0])) {\n return segments[0];\n }\n\n // /webhook/conversation โ†’ conversationWebhook export\n // /webhook/<service> โ†’ <service>Webhook export\n if (segments.length >= 2 && segments[0] === 'webhook') {\n return `${segments[1]}Webhook`;\n }\n\n // /webhook alone โ†’ webhook export (backwards compat)\n if (segments.length === 1 && segments[0] === 'webhook') {\n return 'webhook';\n }\n\n // Default to last segment or 'default'\n return segments[segments.length - 1] || 'default';\n}\n\n/**\n * Generate unique request ID\n * @internal\n */\nexport function generateRequestId(): string {\n return `req_${Date.now()}_${Math.random().toString(36).substring(7)}`;\n}\n\n/**\n * Find the function file - checks dist/function.js first (TypeScript projects),\n * then falls back to function.js (JavaScript projects)\n */\nfunction findFunctionPath(): string {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const fs = requireCjs('fs') as typeof import('fs');\n const distPath = nodePath.join(process.cwd(), 'dist', 'function.js');\n const rootPath = nodePath.join(process.cwd(), 'function.js');\n\n if (fs.existsSync(distPath)) {\n return distPath;\n }\n return rootPath;\n}\n\n// ============================================\n// Response Formatting\n// ============================================\n\n/**\n * Format SVAML response for voice callbacks\n * @internal\n */\nexport function formatSvamlResponse(result: unknown, functionName: string): FormattedResponse {\n if (!result || typeof result !== 'object') {\n throw new Error(`Voice callback ${functionName} must return a valid SVAML object`);\n }\n\n const svaml = result as SvamletResponse;\n\n if (!svaml.action && !svaml.instructions) {\n throw new Error(\n `Voice callback ${functionName} must return SVAML with an action or instructions`\n );\n }\n\n // Ensure instructions array exists\n if (!svaml.instructions) {\n svaml.instructions = [];\n }\n\n return {\n statusCode: 200,\n headers: { 'Content-Type': 'application/json' },\n body: svaml,\n };\n}\n\n/**\n * Format custom endpoint response\n * @internal\n */\nexport function formatCustomResponse(result: unknown): FormattedResponse {\n if (!result || typeof result !== 'object') {\n return {\n statusCode: 200,\n headers: { 'Content-Type': 'application/json' },\n body: result,\n };\n }\n\n const response = result as {\n statusCode?: number;\n headers?: Record<string, string>;\n body?: unknown;\n };\n\n if (!response.statusCode) {\n return {\n statusCode: 200,\n headers: { 'Content-Type': 'application/json' },\n body: result,\n };\n }\n\n return {\n statusCode: response.statusCode,\n headers: response.headers,\n body: response.body,\n };\n}\n\n// ============================================\n// Request Validation\n// ============================================\n\n/**\n * Validate voice callback request\n * @internal\n */\nexport function validateVoiceRequest(body: unknown): {\n valid: boolean;\n error?: string;\n expectedEvents?: string[];\n} {\n if (!body || typeof body !== 'object') {\n return {\n valid: false,\n error: 'Missing request body',\n expectedEvents: [...VOICE_CALLBACKS],\n };\n }\n\n const data = body as { event?: string; callId?: string };\n\n if (!data.event) {\n return {\n valid: false,\n error: 'Missing event type in request body',\n expectedEvents: [...VOICE_CALLBACKS],\n };\n }\n\n if (!data.callId) {\n return {\n valid: false,\n error: 'Missing callId in request body',\n };\n }\n\n return { valid: true };\n}\n\n// ============================================\n// Context Building\n// ============================================\n\n/**\n * No-op cache implementation used by buildBaseContext\n * Real cache implementations are provided by the runtime packages.\n */\nconst noOpCache: IFunctionCache = {\n set: async () => {},\n get: async () => null,\n has: async () => false,\n delete: async () => false,\n extend: async () => false,\n keys: async () => [],\n getMany: async () => ({}),\n};\n\n/**\n * Build base context object for function execution\n *\n * Note: Call-specific data like callId is available on the callback event data,\n * not on the context object.\n * @internal\n */\nexport function buildBaseContext(\n req: Request,\n config: Partial<FunctionConfig> = {}\n): FunctionContext {\n return {\n requestId: (req.headers['x-request-id'] as string) || generateRequestId(),\n timestamp: new Date().toISOString(),\n env: process.env as Record<string, string>,\n config: {\n projectId: config.projectId || 'unknown',\n functionName: config.functionName || 'unknown',\n environment: config.environment || 'development',\n variables: config.variables,\n },\n cache: noOpCache,\n assets: (filename: string) => {\n const filePath = nodePath.join(process.cwd(), 'assets', filename);\n return nodeFs.promises.readFile(filePath, 'utf-8');\n },\n };\n}\n\n// ============================================\n// Request Handlers\n// ============================================\n\n/**\n * Handle voice callback execution\n * @internal\n */\nexport async function handleVoiceCallback(\n functionName: string,\n userFunction: SinchFunction,\n context: FunctionContext,\n callbackData: unknown,\n logger?: (...args: unknown[]) => void\n): Promise<FormattedResponse> {\n const handler = userFunction[functionName as keyof SinchFunction];\n\n if (!handler || typeof handler !== 'function') {\n throw new Error(`Function '${functionName}' not found in function.js`);\n }\n\n // Execute the function with proper typing based on event type\n let result: unknown;\n switch (functionName) {\n case 'ice':\n result = await (handler as SinchFunction['ice'])?.(context, callbackData as IceCallbackData);\n break;\n case 'ace':\n result = await (handler as SinchFunction['ace'])?.(context, callbackData as AceCallbackData);\n break;\n case 'pie':\n result = await (handler as SinchFunction['pie'])?.(context, callbackData as PieCallbackData);\n break;\n case 'dice':\n result = await (handler as SinchFunction['dice'])?.(\n context,\n callbackData as DiceCallbackData\n );\n break;\n case 'notify':\n result = await (handler as SinchFunction['notify'])?.(\n context,\n callbackData as NotifyCallbackData\n );\n break;\n default:\n throw new Error(`Unknown voice callback: ${functionName}`);\n }\n\n if (logger) {\n logger('Function result:', result);\n }\n\n // DICE and NOTIFY are notification-only events\n if (isNotificationEvent(functionName)) {\n if (logger) {\n logger(`${functionName.toUpperCase()} callback completed`);\n }\n return {\n statusCode: 200,\n headers: { 'Content-Type': 'application/json' },\n body: {},\n };\n }\n\n return formatSvamlResponse(result, functionName);\n}\n\n/**\n * Handle custom endpoint execution\n * @internal\n */\nexport async function handleCustomEndpoint(\n functionName: string,\n userFunction: SinchFunction,\n context: FunctionContext,\n request: FunctionRequest,\n logger?: (...args: unknown[]) => void\n): Promise<FormattedResponse> {\n // For custom endpoints, check for handler in user function.\n // For root path: 'default' is the canonical name but 'home' is the TS-friendly alias\n let handler = userFunction[functionName as keyof SinchFunction] as\n | ((ctx: FunctionContext, req: FunctionRequest) => Promise<unknown>)\n | undefined;\n\n if ((!handler || typeof handler !== 'function') && functionName === 'default') {\n handler = userFunction['home' as keyof SinchFunction] as typeof handler;\n }\n\n if (!handler || typeof handler !== 'function') {\n throw new Error(`Function '${functionName}' not found in function.js`);\n }\n\n const result = await handler(context, request);\n\n if (logger) {\n logger('Function result:', result);\n }\n\n return formatCustomResponse(result);\n}\n\n// ============================================\n// Express App Factory\n// ============================================\n\n/**\n * Create and configure Express app with standard middleware\n * @internal\n */\nexport function createApp(options: AppOptions = {}): Express {\n // Dynamic import to avoid requiring express at module load\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const express = requireCjs('express') as typeof import('express');\n\n const app = express();\n\n // Optional static file serving (before any other routes)\n // Auto-detect ./public if no explicit staticDir provided\n const staticDir =\n options.staticDir ?? (nodeFs.existsSync('./public') ? './public' : undefined);\n if (staticDir) {\n app.use(\n express.static(staticDir, {\n index: false, // Don't serve index.html for /, we handle that below\n dotfiles: 'ignore',\n })\n );\n }\n\n // Default JSON parsing options\n const jsonOptions = options.jsonParsingOptions || {\n limit: '10mb',\n allowJson5: true,\n camelCase: {\n deep: true,\n stopPaths: ['custom'],\n exclude: [],\n },\n };\n\n // Setup JSON parsing with camelCase transformation\n setupJsonParsing(app, jsonOptions);\n\n // URL encoding for form data\n app.use(express.urlencoded({ extended: true, limit: '10mb' }));\n\n return app;\n}\n\n/**\n * Setup the main request handler\n * @internal\n */\nexport function setupRequestHandler(app: Express, options: RequestHandlerOptions = {}): void {\n const {\n loadUserFunction = async () => {\n // Use dynamic import to support both ESM and CJS user functions\n // Convert to file URL for Windows compatibility\n const functionPath = findFunctionPath();\n const functionUrl = pathToFileURL(functionPath).href;\n const module = await import(functionUrl);\n return (module.default || module) as SinchFunction;\n },\n buildContext = buildBaseContext,\n logger = console.log,\n landingPageEnabled = true,\n onRequestStart = () => {},\n onRequestEnd = () => {},\n } = options;\n\n // Main request handler (Express v5 syntax - {*splat} matches root path too)\n app.use('/{*splat}', async (req: SinchRequest, res: Response) => {\n const startTime = Date.now();\n\n // Favicon: serve the {fn} icon as SVG (GET and HEAD)\n // MUST be checked BEFORE landing page - browsers send Accept: text/html for favicon too!\n // Note: With Express v5's /{*splat}, req.path may be \"/\" - use req.originalUrl instead\n if ((req.method === 'GET' || req.method === 'HEAD') && req.originalUrl === '/favicon.ico') {\n const svg = getFaviconSvg();\n res.type('image/svg+xml').send(svg);\n return;\n }\n\n // Landing page: serve HTML for browser requests to root path\n // This takes precedence over user's default handler for browser requests\n // Note: use req.originalUrl not req.path โ€” inside /{*splat}, req.path is always \"/\"\n if (req.method === 'GET' && req.originalUrl === '/' && landingPageEnabled) {\n const acceptHeader = req.headers.accept || '';\n if (acceptHeader.includes('text/html')) {\n const html = getLandingPageHtml();\n res.type('html').send(html);\n return;\n }\n }\n\n // Auto-serve public/index.html at GET / when landing page is disabled\n if (req.method === 'GET' && req.originalUrl === '/' && !landingPageEnabled) {\n const indexPath = nodePath.join(process.cwd(), 'public', 'index.html');\n if (nodeFs.existsSync(indexPath)) {\n res.type('html').sendFile(indexPath);\n return;\n }\n }\n\n try {\n const functionName = extractFunctionName(req.originalUrl, req.body as { event?: string });\n\n logger(`[${new Date().toISOString()}] ${req.method} ${req.path} -> ${functionName}`);\n\n onRequestStart({ functionName, req });\n\n // Build context for function\n const context = buildContext(req);\n\n // Load user function (supports both sync and async loaders)\n const userFunction = await Promise.resolve(loadUserFunction());\n\n let response: FormattedResponse;\n\n if (isVoiceCallback(functionName)) {\n // Validate voice request\n const validation = validateVoiceRequest(req.body);\n if (!validation.valid) {\n res.status(400).json({\n error: validation.error,\n ...(validation.expectedEvents && { expectedEvents: validation.expectedEvents }),\n });\n return;\n }\n\n // Handle voice callback\n response = await handleVoiceCallback(functionName, userFunction, context, req.body, logger);\n } else {\n // Handle custom endpoint\n const request: FunctionRequest = {\n method: req.method as FunctionRequest['method'],\n path: req.path,\n query: req.query as Record<string, string>,\n headers: req.headers as Record<string, string>,\n body: req.body,\n params: req.params as Record<string, string>,\n };\n\n response = await handleCustomEndpoint(functionName, userFunction, context, request, logger);\n }\n\n // Send response\n res.status(response.statusCode);\n\n if (response.headers) {\n for (const [key, value] of Object.entries(response.headers)) {\n res.setHeader(key, value);\n }\n }\n\n const contentType = response.headers?.['Content-Type'];\n const isJsonContent = contentType?.includes('application/json');\n const isHtmlContent = contentType?.includes('text/html');\n\n if (response.body === undefined) {\n res.end();\n } else if (isJsonContent) {\n res.json(response.body);\n } else if (isHtmlContent) {\n res.send(String(response.body));\n } else {\n res.send(response.body);\n }\n\n const duration = Date.now() - startTime;\n logger(`[${new Date().toISOString()}] Response sent: ${response.statusCode} (${duration}ms)`);\n\n onRequestEnd({\n functionName,\n req,\n response,\n duration,\n statusCode: response.statusCode,\n });\n } catch (error) {\n const duration = Date.now() - startTime;\n\n logger('Function execution error:', {\n error: (error as Error).message,\n stack: (error as Error).stack,\n function: extractFunctionName(req.originalUrl, req.body as { event?: string }),\n });\n\n res.status(500).json({\n error: 'Internal server error',\n message: (error as Error).message,\n ...(process.env.NODE_ENV === 'development' && { stack: (error as Error).stack }),\n });\n\n onRequestEnd({\n functionName: extractFunctionName(req.originalUrl, req.body as { event?: string }),\n req,\n error: error as Error,\n duration,\n statusCode: 500,\n });\n }\n });\n}\n","/**\n * Sinch SDK Client Factory for Sinch Functions\n *\n * Provides pre-initialized Sinch SDK clients based on available configuration.\n * Only initializes products that have required environment variables.\n *\n * Usage in functions:\n * - context.voice - Available when VOICE_APPLICATION_KEY is set\n * - context.conversation - Available when CONVERSATION_APP_ID is set\n * - context.sms - Available when SMS_SERVICE_PLAN_ID is set\n * - context.numbers - Available when ENABLE_NUMBERS_API is set\n */\n\nimport { SinchClient, validateAuthenticationHeader } from '@sinch/sdk-core';\nimport type { VoiceService } from '@sinch/voice';\nimport type { ConversationService } from '@sinch/conversation';\nimport type { SmsService } from '@sinch/sms';\nimport type { NumbersService } from '@sinch/numbers';\n\nexport interface SinchClients {\n voice?: VoiceService;\n conversation?: ConversationService;\n sms?: SmsService;\n numbers?: NumbersService;\n validateWebhookSignature?: (requestData: WebhookRequestData) => boolean;\n}\n\nexport interface WebhookRequestData {\n method: string;\n path: string;\n headers: Record<string, string>;\n body: string;\n}\n\n/**\n * Create Sinch product clients based on available configuration\n * Only initializes products that have required environment variables\n */\nfunction createSinchClients(): SinchClients {\n const clients: SinchClients = {};\n\n // Base credentials check - using new naming convention\n // PROJECT_ID_API_KEY and PROJECT_ID_API_SECRET belong to PROJECT_ID\n const hasCredentials =\n process.env.PROJECT_ID && process.env.PROJECT_ID_API_KEY && process.env.PROJECT_ID_API_SECRET;\n\n if (!hasCredentials) {\n // No Sinch credentials available, return empty object\n // This allows functions to work without Sinch integration\n return clients;\n }\n\n try {\n // Initialize base Sinch client with credentials\n const sinchClient = new SinchClient({\n projectId: process.env.PROJECT_ID!,\n keyId: process.env.PROJECT_ID_API_KEY!,\n keySecret: process.env.PROJECT_ID_API_SECRET!,\n });\n\n // Conversation API - only if app ID is configured\n if (process.env.CONVERSATION_APP_ID) {\n clients.conversation = sinchClient.conversation;\n console.log('[SINCH] Conversation API initialized');\n }\n\n // Voice API - only if voice application is configured\n if (process.env.VOICE_APPLICATION_KEY && process.env.VOICE_APPLICATION_SECRET) {\n // Initialize voice client with application credentials for webhook validation\n const voiceClient = new SinchClient({\n projectId: process.env.PROJECT_ID!,\n keyId: process.env.PROJECT_ID_API_KEY!,\n keySecret: process.env.PROJECT_ID_API_SECRET!,\n applicationKey: process.env.VOICE_APPLICATION_KEY,\n applicationSecret: process.env.VOICE_APPLICATION_SECRET,\n });\n\n clients.voice = voiceClient.voice;\n console.log('[SINCH] Voice API initialized with application credentials');\n }\n\n // SMS API - only if service plan is configured\n if (process.env.SMS_SERVICE_PLAN_ID) {\n clients.sms = sinchClient.sms;\n console.log('[SINCH] SMS API initialized');\n }\n\n // Numbers API - only if explicitly enabled\n if (process.env.ENABLE_NUMBERS_API === 'true') {\n clients.numbers = sinchClient.numbers;\n console.log('[SINCH] Numbers API initialized');\n }\n } catch (error: any) {\n console.error('[SINCH] Failed to initialize Sinch clients:', error.message);\n return {};\n }\n\n // Add the webhook validation function for Voice callbacks\n if (process.env.VOICE_APPLICATION_KEY && process.env.VOICE_APPLICATION_SECRET) {\n clients.validateWebhookSignature = (requestData: WebhookRequestData): boolean => {\n console.log('[SINCH] Validating Voice webhook signature');\n\n try {\n const result = validateAuthenticationHeader(\n process.env.VOICE_APPLICATION_KEY!,\n process.env.VOICE_APPLICATION_SECRET!,\n requestData.headers,\n requestData.body,\n requestData.path,\n requestData.method\n );\n\n console.log('[SINCH] Validation result:', result ? 'VALID' : 'INVALID');\n return result;\n } catch (error: any) {\n console.error('[SINCH] Validation error:', error.message);\n return false;\n }\n };\n }\n\n return clients;\n}\n\n// Lazy initialization with caching\nlet cachedClients: SinchClients | null = null;\n\n/**\n * Get or create Sinch clients (with caching)\n */\nexport function getSinchClients(): SinchClients {\n if (!cachedClients) {\n cachedClients = createSinchClients();\n }\n return cachedClients;\n}\n\n/**\n * Reset cached clients (useful for testing)\n */\nexport function resetSinchClients(): void {\n cachedClients = null;\n}\n\nexport default { getSinchClients, resetSinchClients };\n","/**\n * ElevenLabs State Management for Sinch Functions\n *\n * Singleton to store auto-configuration results for subsequent calls.\n */\n\n/**\n * State for ElevenLabs configuration\n */\nexport interface ElevenLabsStateData {\n /** Phone number ID from Sinch */\n phoneNumberId?: string;\n /** The phone number (E.164 format) */\n phoneNumber?: string;\n /** The ElevenLabs agent ID */\n agentId?: string;\n /** SIP address for the agent */\n sipAddress?: string;\n /** Whether auto-configuration has been completed */\n isConfigured: boolean;\n /** Timestamp of last configuration */\n configuredAt?: Date;\n}\n\n/**\n * Singleton class to manage ElevenLabs state across the runtime\n */\nclass ElevenLabsStateManager {\n private state: ElevenLabsStateData = {\n isConfigured: false,\n };\n\n /**\n * Get the current state\n */\n getState(): Readonly<ElevenLabsStateData> {\n return { ...this.state };\n }\n\n /**\n * Check if ElevenLabs is configured\n */\n isConfigured(): boolean {\n return this.state.isConfigured;\n }\n\n /**\n * Update state with auto-configuration results\n */\n setConfigured(data: Omit<ElevenLabsStateData, 'isConfigured' | 'configuredAt'>): void {\n this.state = {\n ...data,\n isConfigured: true,\n configuredAt: new Date(),\n };\n }\n\n /**\n * Clear the configuration state\n */\n clear(): void {\n this.state = {\n isConfigured: false,\n };\n }\n\n /**\n * Get the phone number ID for making calls\n */\n getPhoneNumberId(): string | undefined {\n return this.state.phoneNumberId;\n }\n\n /**\n * Get the SIP address for connecting to the agent\n */\n getSipAddress(): string | undefined {\n return this.state.sipAddress;\n }\n\n /**\n * Get the configured agent ID\n */\n getAgentId(): string | undefined {\n return this.state.agentId;\n }\n}\n\n/**\n * Singleton instance of ElevenLabs state\n */\nexport const ElevenLabsState = new ElevenLabsStateManager();\n\nexport default ElevenLabsState;\n","/**\n * ElevenLabs Client for Sinch Functions\n *\n * Provides methods for interacting with ElevenLabs Conversational AI API.\n */\n\nimport type {\n ElevenLabsCallOptions,\n ElevenLabsOutboundCallRequest,\n ElevenLabsOutboundCallResponse,\n ElevenLabsConversationDetails,\n ElevenLabsConversationResponse,\n ElevenLabsAutoConfigOptions,\n ElevenLabsAutoConfigResult,\n SipTrunkConfig,\n} from './models.js';\nimport { ElevenLabsState } from './state.js';\n\nconst ELEVENLABS_API_BASE = 'https://api.elevenlabs.io/v1';\nconst FETCH_TIMEOUT_MS = 10_000;\n\n/**\n * Client for interacting with ElevenLabs Conversational AI\n */\nexport class ElevenLabsClient {\n private readonly apiKey: string;\n\n constructor(apiKey?: string) {\n this.apiKey = apiKey || process.env.ELEVENLABS_API_KEY || '';\n if (!this.apiKey) {\n console.warn(\n '[ElevenLabs] No API key provided. Set ELEVENLABS_API_KEY environment variable.'\n );\n }\n }\n\n private get authHeaders(): Record<string, string> {\n return { 'xi-api-key': this.apiKey, 'Content-Type': 'application/json' };\n }\n\n /**\n * Initiate an outbound call to a phone number using an ElevenLabs agent\n */\n async makeCall(options: ElevenLabsCallOptions): Promise<ElevenLabsOutboundCallResponse> {\n const phoneNumberId = ElevenLabsState.getPhoneNumberId();\n\n const request: ElevenLabsOutboundCallRequest = {\n agent_id: options.agentId,\n customer_phone_number: options.toNumber,\n agent_phone_number_id: phoneNumberId,\n };\n\n if (options.dynamicVariables && Object.keys(options.dynamicVariables).length > 0) {\n request.custom_llm_extra_body = {\n dynamic_variables: options.dynamicVariables,\n };\n }\n\n const response = await fetch(`${ELEVENLABS_API_BASE}/convai/conversation/create_call`, {\n method: 'POST',\n headers: this.authHeaders,\n body: JSON.stringify(request),\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`ElevenLabs API error: ${response.status} - ${error}`);\n }\n\n return response.json() as Promise<ElevenLabsOutboundCallResponse>;\n }\n\n /**\n * Get conversation details including transcript and analysis\n */\n async getConversationDetails(conversationId: string): Promise<ElevenLabsConversationDetails> {\n const response = await fetch(\n `${ELEVENLABS_API_BASE}/convai/conversations/${encodeURIComponent(conversationId)}`,\n {\n headers: { 'xi-api-key': this.apiKey },\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n }\n );\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`ElevenLabs API error: ${response.status} - ${error}`);\n }\n\n const data = (await response.json()) as ElevenLabsConversationResponse;\n\n return this.mapConversationResponse(data);\n }\n\n /**\n * Auto-configure ElevenLabs with Sinch SIP trunk.\n *\n * Step 1: Get or import phone number with SIP trunk config\n * Step 2: Configure agent conversation-init webhook\n *\n * Called by tryAutoConfigureAsync (the orchestrator that reads env vars).\n */\n async autoConfigureAsync(\n options: ElevenLabsAutoConfigOptions\n ): Promise<ElevenLabsAutoConfigResult> {\n console.log(`[ElevenLabs] Starting auto-configuration for agent ${options.agentId}`);\n\n const phoneResult = await this.getOrImportPhoneNumber(options);\n\n if (options.webhookBaseUrl) {\n await this.configureAgentWebhooks(options.agentId, options.webhookBaseUrl);\n }\n\n console.log(\n `[ElevenLabs] Auto-configuration completed: PhoneNumberId=${phoneResult.phoneNumberId}`\n );\n\n return {\n success: true,\n phoneNumberId: phoneResult.phoneNumberId,\n phoneNumber: options.phoneNumber,\n sipAddress: options.sipAddress,\n };\n }\n\n /**\n * Check if phone number already exists in ElevenLabs; create or update it.\n * Matches C# GetOrImportPhoneNumberAsync.\n */\n private async getOrImportPhoneNumber(\n config: ElevenLabsAutoConfigOptions\n ): Promise<{ phoneNumberId: string }> {\n const listResponse = await fetch(`${ELEVENLABS_API_BASE}/convai/phone-numbers`, {\n headers: this.authHeaders,\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (!listResponse.ok) {\n throw new Error(`Failed to list phone numbers: ${listResponse.status}`);\n }\n\n const phoneNumbers = (await listResponse.json()) as Array<{\n phone_number_id: string;\n phone_number: string;\n }>;\n\n const sipConfig: SipTrunkConfig = {\n address: config.sipAddress,\n transport: 'tcp',\n media_encryption: 'disabled',\n credentials: { username: config.sipUsername, password: config.sipPassword },\n };\n\n const existing = phoneNumbers.find((p) => p.phone_number === config.phoneNumber);\n\n if (existing) {\n console.log(\n `[ElevenLabs] Phone number already exists (${existing.phone_number_id}), updating config`\n );\n await this.updatePhoneNumberConfig(existing.phone_number_id, config.agentId, sipConfig);\n return { phoneNumberId: existing.phone_number_id };\n }\n\n // NOTE: agent_id is NOT accepted by POST โ€” must be set via separate PATCH\n const label = `Sinch Functions - ${config.functionName || 'Sinch Function'}`;\n console.log('[ElevenLabs] Creating SIP trunk phone number');\n\n const createResponse = await fetch(`${ELEVENLABS_API_BASE}/convai/phone-numbers`, {\n method: 'POST',\n headers: this.authHeaders,\n body: JSON.stringify({\n phone_number: config.phoneNumber,\n label,\n provider: 'sip_trunk',\n supports_inbound: true,\n supports_outbound: true,\n inbound_trunk_config: { media_encryption: 'disabled' },\n outbound_trunk_config: sipConfig,\n }),\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n\n if (!createResponse.ok) {\n const err = await createResponse.text();\n throw new Error(`Failed to create phone number: ${createResponse.status} - ${err}`);\n }\n\n const created = (await createResponse.json()) as { phone_number_id: string };\n console.log('[ElevenLabs] Phone number created successfully');\n\n // Associate agent via separate PATCH (ElevenLabs requires this ordering)\n await this.updatePhoneNumberConfig(created.phone_number_id, config.agentId, sipConfig);\n\n return { phoneNumberId: created.phone_number_id };\n }\n\n /**\n * Update phone number with agent association and SIP trunk config.\n * Matches C# UpdatePhoneNumberConfigAsync.\n */\n private async updatePhoneNumberConfig(\n phoneNumberId: string,\n agentId: string,\n sipConfig: SipTrunkConfig\n ): Promise<void> {\n const response = await fetch(\n `${ELEVENLABS_API_BASE}/convai/phone-numbers/${encodeURIComponent(phoneNumberId)}`,\n {\n method: 'PATCH',\n headers: this.authHeaders,\n body: JSON.stringify({\n agent_id: agentId,\n outbound_trunk_config: sipConfig,\n }),\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n }\n );\n\n if (!response.ok) {\n await response.text(); // drain body\n console.warn(`[ElevenLabs] Failed to update phone number config: ${response.status}`);\n } else {\n console.log('[ElevenLabs] Phone number configuration updated');\n }\n }\n\n /**\n * Configure agent webhook for conversation-init events.\n * Matches C# ConfigureAgentWebhooksAsync.\n */\n private async configureAgentWebhooks(agentId: string, webhookBaseUrl: string): Promise<void> {\n const webhookUrl = `${webhookBaseUrl}/webhook/elevenlabs/conversation-init`;\n console.log(`[ElevenLabs] Configuring agent webhook`);\n\n const response = await fetch(\n `${ELEVENLABS_API_BASE}/convai/agents/${encodeURIComponent(agentId)}`,\n {\n method: 'PATCH',\n headers: this.authHeaders,\n body: JSON.stringify({\n platform_settings: {\n workspace_overrides: {\n conversation_initiation_client_data_webhook: {\n url: webhookUrl,\n request_headers: {},\n },\n },\n overrides: {\n enable_conversation_initiation_client_data_from_webhook: true,\n },\n },\n }),\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n }\n );\n\n if (!response.ok) {\n await response.text(); // drain body\n console.error(`[ElevenLabs] Failed to configure agent webhooks: ${response.status}`);\n // Don't throw โ€” webhooks are optional (matches C# behavior)\n } else {\n console.log('[ElevenLabs] Agent webhooks configured successfully');\n }\n }\n\n /**\n * Map API response to our interface\n */\n private mapConversationResponse(\n data: ElevenLabsConversationResponse\n ): ElevenLabsConversationDetails {\n return {\n conversationId: data.conversation_id,\n agentId: data.agent_id,\n status: data.status,\n metadata: data.metadata\n ? {\n callDurationSeconds: data.metadata.call_duration_secs,\n startTime: data.metadata.start_time_unix_secs\n ? new Date(data.metadata.start_time_unix_secs * 1000)\n : undefined,\n endTime: data.metadata.end_time_unix_secs\n ? new Date(data.metadata.end_time_unix_secs * 1000)\n : undefined,\n }\n : undefined,\n transcript: data.transcript?.map((t) => ({\n role: t.role as 'user' | 'agent',\n message: t.message,\n timeInCallSeconds: t.time_in_call_secs,\n })),\n analysis: data.analysis\n ? {\n summary: data.analysis.transcript_summary,\n customData: data.analysis.custom_data,\n }\n : undefined,\n };\n }\n}\n\n/**\n * Create an ElevenLabs client with the default API key\n */\nexport function createElevenLabsClient(apiKey?: string): ElevenLabsClient {\n return new ElevenLabsClient(apiKey);\n}\n\nexport default ElevenLabsClient;\n","/**\n * ElevenLabs Controller Base Class for Sinch Functions\n *\n * Provides webhook handling for ElevenLabs Conversational AI events.\n */\n\nimport type { Request, Response } from 'express';\nimport type {\n ConversationInitRequest,\n ConversationInitResponse,\n ElevenLabsPostCallWebhook,\n ElevenLabsPostCallAudioWebhook,\n ElevenLabsCallInitiationFailureWebhook,\n ElevenLabsWebhook,\n} from './webhooks.js';\n\n/**\n * Base controller for handling ElevenLabs webhooks\n *\n * @example\n * ```typescript\n * class MyElevenLabsHandler extends ElevenLabsController {\n * async handleConversationInit(request: ConversationInitRequest): Promise<ConversationInitResponse> {\n * // Customize the conversation based on caller\n * return {\n * dynamic_variables: {\n * customerName: await lookupCustomer(request.caller_id)\n * }\n * };\n * }\n *\n * async handlePostCall(webhook: ElevenLabsPostCallWebhook): Promise<void> {\n * // Save transcript to database\n * await saveTranscript(webhook.data);\n * }\n * }\n * ```\n */\nexport abstract class ElevenLabsController {\n /**\n * Handle conversation initialization webhook\n * Called when an inbound call is received - allows customizing the conversation\n *\n * @param request - The conversation init request with caller info\n * @returns Response with dynamic variables and/or config overrides\n */\n async handleConversationInit(\n request: ConversationInitRequest\n ): Promise<ConversationInitResponse> {\n // Default implementation returns empty response (use agent defaults)\n return {};\n }\n\n /**\n * Handle post-call webhook with transcript and analysis\n *\n * @param webhook - The post-call webhook payload\n */\n async handlePostCall(webhook: ElevenLabsPostCallWebhook): Promise<void> {\n // Default implementation logs the transcript\n console.log('[ElevenLabs] Post-call webhook received:', {\n conversationId: webhook.data.conversation_id,\n agentId: webhook.data.agent_id,\n status: webhook.data.status,\n duration: webhook.data.metadata.call_duration_secs,\n });\n }\n\n /**\n * Handle post-call audio webhook with recording\n *\n * @param webhook - The audio webhook with base64-encoded MP3\n */\n async handlePostCallAudio(webhook: ElevenLabsPostCallAudioWebhook): Promise<void> {\n // Default implementation logs receipt\n console.log('[ElevenLabs] Post-call audio received:', {\n conversationId: webhook.data.conversation_id,\n agentId: webhook.data.agent_id,\n });\n }\n\n /**\n * Handle call initiation failure webhook\n *\n * @param webhook - The failure webhook with error details\n */\n async handleCallInitiationFailure(\n webhook: ElevenLabsCallInitiationFailureWebhook\n ): Promise<void> {\n // Default implementation logs the error\n console.error('[ElevenLabs] Call initiation failed:', {\n agentId: webhook.data.agent_id,\n customerNumber: webhook.data.customer_phone_number,\n reason: webhook.data.failure_reason,\n });\n }\n\n /**\n * Express route handler for conversation init endpoint\n * Mount at: POST /elevenlabs/conversation-init\n */\n getConversationInitHandler() {\n return async (req: Request, res: Response): Promise<void> => {\n try {\n const request = req.body as ConversationInitRequest;\n const response = await this.handleConversationInit(request);\n res.json(response);\n } catch (error) {\n console.error('[ElevenLabs] Error in conversation init:', error);\n res.status(500).json({ error: 'Internal server error' });\n }\n };\n }\n\n /**\n * Express route handler for webhook endpoint\n * Mount at: POST /elevenlabs/webhook\n * Handles all webhook types based on the 'type' field\n */\n getWebhookHandler() {\n return async (req: Request, res: Response): Promise<void> => {\n try {\n const webhook = req.body as ElevenLabsWebhook;\n\n switch (webhook.type) {\n case 'post_call_transcription':\n await this.handlePostCall(webhook as ElevenLabsPostCallWebhook);\n break;\n case 'post_call_audio':\n await this.handlePostCallAudio(webhook as ElevenLabsPostCallAudioWebhook);\n break;\n case 'call_initiation_failure':\n await this.handleCallInitiationFailure(\n webhook as ElevenLabsCallInitiationFailureWebhook\n );\n break;\n default:\n console.warn('[ElevenLabs] Unknown webhook type:', (webhook as { type: string }).type);\n }\n\n res.status(200).send('OK');\n } catch (error) {\n console.error('[ElevenLabs] Error processing webhook:', error);\n res.status(500).json({ error: 'Internal server error' });\n }\n };\n }\n}\n\nexport default ElevenLabsController;\n","/**\n * ElevenLabs Auto-Configurator for Sinch Functions\n *\n * Reads environment variables, auto-discovers phone numbers via the Sinch Voice API,\n * and delegates to ElevenLabsClient.autoConfigureAsync().\n *\n * Environment variables:\n * - ELEVENLABS_AUTO_CONFIGURE: Set to \"true\" to enable\n * - ELEVENLABS_AGENT_ID: Required agent ID\n * - ELEVENLABS_API_KEY: Required API key\n * - SINCH_PHONE_NUMBER: Optional phone number (auto-discovered if not set)\n * - VOICE_APPLICATION_KEY: SIP trunk username\n * - VOICE_APPLICATION_SECRET: SIP trunk password\n */\n\nimport { ElevenLabsClient } from './client.js';\nimport { ElevenLabsState } from './state.js';\nimport type { ElevenLabsAutoConfigResult } from './models.js';\n\nconst FETCH_TIMEOUT_MS = 10_000;\n\n/** Mask a phone number for safe logging: +1555***4567 */\nfunction maskPhone(phone: string): string {\n if (phone.length <= 6) return '***';\n return phone.slice(0, 4) + '***' + phone.slice(-4);\n}\n\n/**\n * Try to auto-configure ElevenLabs from environment variables.\n * Returns null if ELEVENLABS_AUTO_CONFIGURE is not \"true\".\n *\n * @param webhookUrl - Base URL for webhook callbacks (must be HTTPS in production)\n * @param functionName - Optional name for labeling in ElevenLabs (max 100 chars)\n * @param sinchPhoneNumber - Optional phone number override (skips auto-discovery)\n */\nexport async function tryAutoConfigureAsync(\n webhookUrl: string,\n functionName?: string,\n sinchPhoneNumber?: string\n): Promise<ElevenLabsAutoConfigResult | null> {\n const autoConfig = process.env.ELEVENLABS_AUTO_CONFIGURE;\n if (!autoConfig || autoConfig.toLowerCase() !== 'true') {\n return null;\n }\n\n console.log('[ElevenLabs] Auto-configuration is enabled');\n\n const agentId = process.env.ELEVENLABS_AGENT_ID;\n const apiKey = process.env.ELEVENLABS_API_KEY;\n\n if (!agentId) {\n console.warn(\n '[ElevenLabs] Auto-configuration skipped: ELEVENLABS_AGENT_ID not set. ' +\n 'Please configure your agent ID in environment variables.'\n );\n return null;\n }\n\n if (!apiKey) {\n console.warn(\n '[ElevenLabs] Auto-configuration skipped: ELEVENLABS_API_KEY not set. ' +\n 'Please store your API key using: sinch secrets add ELEVENLABS_API_KEY sk_...'\n );\n return null;\n }\n\n let phoneNumber = sinchPhoneNumber ?? process.env.SINCH_PHONE_NUMBER;\n\n if (!phoneNumber) {\n console.log(\n '[ElevenLabs] SINCH_PHONE_NUMBER not configured, attempting auto-discovery from Voice API...'\n );\n phoneNumber = await autoDiscoverPhoneNumber();\n }\n\n if (!phoneNumber) {\n console.warn(\n '[ElevenLabs] Auto-configuration skipped: Sinch phone number not provided and auto-discovery failed. ' +\n 'Please set SINCH_PHONE_NUMBER or ensure Voice API credentials are configured.'\n );\n return null;\n }\n\n if (!webhookUrl) {\n console.warn('[ElevenLabs] Auto-configuration skipped: Webhook URL not provided.');\n return null;\n }\n\n try {\n new URL(webhookUrl);\n } catch {\n console.warn('[ElevenLabs] Auto-configuration skipped: Webhook URL is not a valid URL.');\n return null;\n }\n\n const voiceAppKey = process.env.VOICE_APPLICATION_KEY || '';\n const voiceAppSecret = process.env.VOICE_APPLICATION_SECRET || '';\n\n const safeName = functionName ? functionName.slice(0, 100) : 'Sinch Function';\n\n try {\n console.log(\n `[ElevenLabs] Starting auto-configuration: Agent=${agentId}, Number=${maskPhone(phoneNumber)}`\n );\n\n const client = new ElevenLabsClient(apiKey);\n\n const result = await client.autoConfigureAsync({\n agentId,\n phoneNumber,\n sipAddress: 'use1.vp.sip.sinch.com',\n sipUsername: voiceAppKey,\n sipPassword: voiceAppSecret,\n webhookBaseUrl: webhookUrl,\n functionName: safeName,\n });\n\n if (result.success) {\n ElevenLabsState.setConfigured({\n phoneNumberId: result.phoneNumberId,\n phoneNumber: result.phoneNumber,\n agentId,\n sipAddress: result.sipAddress,\n });\n\n console.log(\n `[ElevenLabs] Auto-configuration completed! Phone: ${maskPhone(result.phoneNumber ?? '')}, SIP: ${result.sipAddress}`\n );\n }\n\n return result;\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(\n `[ElevenLabs] Auto-configuration failed: ${message}. ` +\n 'The function will start but ElevenLabs integration may not work.'\n );\n return null;\n }\n}\n\n/**\n * Auto-discover phone number from the Sinch Voice API.\n *\n * The Node.js Sinch SDK does not expose applications.getNumbers() like C# does.\n * This calls the Voice REST API directly using the application key/secret for auth.\n */\nasync function autoDiscoverPhoneNumber(): Promise<string | undefined> {\n const appKey = process.env.VOICE_APPLICATION_KEY || '';\n const appSecret = process.env.VOICE_APPLICATION_SECRET || '';\n\n if (!appKey || !appSecret) {\n console.warn(\n '[ElevenLabs] Voice client not available for phone number auto-discovery. ' +\n 'Ensure VOICE_APPLICATION_KEY and VOICE_APPLICATION_SECRET are configured.'\n );\n return undefined;\n }\n\n try {\n const auth = Buffer.from(`${appKey}:${appSecret}`).toString('base64');\n const configResponse = await fetch(\n `https://callingapi.sinch.com/v1/configuration/numbers/`,\n {\n headers: { Authorization: `Basic ${auth}` },\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n }\n );\n\n if (!configResponse.ok) {\n console.warn(\n `[ElevenLabs] Failed to query Voice API for phone numbers: ${configResponse.status}`\n );\n return undefined;\n }\n\n const data = (await configResponse.json()) as {\n numbers?: Array<{ number?: string; applicationkey?: string }>;\n };\n\n const numbers = (data.numbers || [])\n .filter((n) => n.applicationkey === appKey)\n .map((n) => n.number)\n .filter(Boolean) as string[];\n\n if (numbers.length > 0) {\n console.log(`[ElevenLabs] Auto-discovered ${numbers.length} phone number(s), using first`);\n return numbers[0];\n }\n\n console.warn('[ElevenLabs] No phone numbers found for the configured Voice application');\n return undefined;\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(`[ElevenLabs] Failed to auto-discover phone number: ${message}`);\n return undefined;\n }\n}\n\n/**\n * @deprecated Use `tryAutoConfigureAsync` directly. This class wrapper is kept for backwards compatibility.\n */\nexport class ElevenLabsAutoConfigurator {\n static tryAutoConfigureAsync = tryAutoConfigureAsync;\n}\n","/**\n * Conversation Message Builder for Sinch Functions\n *\n * Fluent builder for creating Conversation API messages with more control.\n * Use static helpers in ConversationMessage for simple cases.\n */\n\nimport type { MessageInboundEvent } from './extensions.js';\nimport type { SendMessageRequest, ConversationChannel } from './message-helpers.js';\n\n/**\n * Configuration interface for the message builder\n */\nexport interface MessageBuilderConfig {\n CONVERSATION_APP_ID?: string;\n FROM_NUMBER?: string;\n}\n\n/**\n * Fluent builder for creating Conversation API messages.\n *\n * @example\n * ```typescript\n * // Simple case - use static helper\n * await context.conversation.messages.send(\n * ConversationMessage.textReply(inbound, \"Hello!\")\n * );\n *\n * // Complex case - use builder\n * const msg = new ConversationMessageBuilder(config)\n * .fromInbound(inbound)\n * .text(\"Hello!\")\n * .build();\n * await context.conversation.messages.send(msg);\n * ```\n */\nexport class ConversationMessageBuilder {\n private config: MessageBuilderConfig;\n private appId?: string;\n private channel?: string;\n private identity?: string;\n private conversationId?: string;\n private messageText?: string;\n\n /**\n * Create a new builder with configuration\n */\n constructor(config: MessageBuilderConfig = {}) {\n this.config = config;\n }\n\n /**\n * Pre-fill builder from an inbound message (for replies)\n */\n fromInbound(inbound: MessageInboundEvent): this {\n this.appId = inbound.app_id;\n this.channel = inbound.message?.channel_identity?.channel;\n this.identity = inbound.message?.channel_identity?.identity;\n this.conversationId = inbound.message?.conversation_id;\n return this;\n }\n\n /**\n * Set the app ID (defaults to CONVERSATION_APP_ID from config)\n */\n setAppId(appId: string): this {\n this.appId = appId;\n return this;\n }\n\n /**\n * Set the recipient channel and identity\n *\n * @param channel - Channel name (SMS, WHATSAPP, MESSENGER, etc.)\n * @param identity - Channel-specific identity (phone number, PSID, etc.)\n */\n to(channel: string, identity: string): this {\n this.channel = channel;\n this.identity = identity;\n return this;\n }\n\n /**\n * Set the conversation ID (for non-DISPATCH mode apps)\n */\n setConversationId(conversationId: string): this {\n this.conversationId = conversationId;\n return this;\n }\n\n /**\n * Set a text message\n */\n text(text: string): this {\n this.messageText = text;\n return this;\n }\n\n /**\n * Build the SendMessageRequest.\n * Automatically sets SMS_SENDER from config if sending to SMS channel.\n *\n * @returns A SendMessageRequest ready to send via context.conversation.messages.send()\n */\n build(): SendMessageRequest {\n const appId = this.appId || this.config.CONVERSATION_APP_ID;\n if (!appId) {\n throw new Error('AppId required - use setAppId() or set CONVERSATION_APP_ID in config');\n }\n\n if (!this.channel || !this.identity) {\n throw new Error('Recipient required - use to() or fromInbound()');\n }\n\n if (!this.messageText) {\n throw new Error('Message required - use text()');\n }\n\n const request: SendMessageRequest = {\n app_id: appId,\n message: {\n text_message: {\n text: this.messageText,\n },\n },\n recipient: {\n identified_by: {\n channel_identities: [\n {\n channel: this.channel as ConversationChannel,\n identity: this.identity,\n },\n ],\n },\n },\n };\n\n // Auto-set SMS_SENDER from config if sending to SMS channel\n if (this.channel.toUpperCase() === 'SMS') {\n const smsSender = this.config.FROM_NUMBER;\n if (smsSender) {\n request.channel_properties = {\n SMS_SENDER: smsSender,\n };\n }\n }\n\n return request;\n }\n}\n\n/**\n * Create a new conversation message builder\n */\nexport function createMessageBuilder(\n config: MessageBuilderConfig = {}\n): ConversationMessageBuilder {\n return new ConversationMessageBuilder(config);\n}\n\nexport default ConversationMessageBuilder;\n","/**\n * Conversation Message Static Helpers for Sinch Functions\n *\n * Static helpers for common Conversation API message patterns.\n * Returns SendMessageRequest objects ready to send via the Sinch SDK.\n */\n\nimport type { MessageInboundEvent } from './extensions.js';\n\n/**\n * Channel type for Conversation API\n */\nexport type ConversationChannel =\n | 'SMS'\n | 'WHATSAPP'\n | 'MESSENGER'\n | 'VIBER'\n | 'RCS'\n | 'INSTAGRAM'\n | 'MMS'\n | 'LINE'\n | 'KAKAOTALK'\n | 'TELEGRAM'\n | 'WECHAT'\n | 'APPLEBC'\n | 'GOOGLEBM'\n | string;\n\n/**\n * Simplified send message request type that works with SDK\n */\nexport interface SendMessageRequest {\n app_id: string;\n message: {\n text_message?: { text: string };\n };\n recipient: {\n identified_by: {\n channel_identities: Array<{\n channel: ConversationChannel;\n identity: string;\n }>;\n };\n };\n channel_properties?: Record<string, string>;\n}\n\n/**\n * Create a text reply to an inbound message (replies on same channel).\n * Automatically sets SMS_SENDER channel property if sending to SMS.\n *\n * @param inbound - The inbound message event to reply to\n * @param text - The reply text\n * @param smsSender - Optional SMS sender number\n * @returns A SendMessageRequest ready to send\n *\n * @example\n * ```typescript\n * await context.conversation.messages.send(\n * textReply(inbound, \"Thanks for your message!\", config.FROM_NUMBER)\n * );\n * ```\n */\nexport function textReply(\n inbound: MessageInboundEvent,\n text: string,\n smsSender?: string\n): SendMessageRequest {\n const channelIdentity = inbound.message?.channel_identity;\n if (!channelIdentity) {\n throw new Error('Inbound message has no channel identity');\n }\n\n const channel = channelIdentity.channel;\n const identity = channelIdentity.identity;\n\n if (!channel || !identity) {\n throw new Error('Inbound message has no channel or identity');\n }\n\n return createChannelMessage(inbound.app_id!, channel, identity, text, smsSender);\n}\n\n/**\n * Create an SMS message to a phone number.\n *\n * @param appId - The Conversation API app ID\n * @param phoneNumber - Phone number in E.164 format (e.g., +15551234567)\n * @param text - Message text\n * @param smsSender - SMS sender number (required for SMS channel)\n */\nexport function createSms(\n appId: string,\n phoneNumber: string,\n text: string,\n smsSender?: string\n): SendMessageRequest {\n return createChannelMessage(appId, 'SMS', phoneNumber, text, smsSender);\n}\n\n/**\n * Create a WhatsApp message to a phone number.\n *\n * @param appId - The Conversation API app ID\n * @param phoneNumber - Phone number in E.164 format (e.g., +15551234567)\n * @param text - Message text\n */\nexport function createWhatsApp(\n appId: string,\n phoneNumber: string,\n text: string\n): SendMessageRequest {\n return createChannelMessage(appId, 'WHATSAPP', phoneNumber, text);\n}\n\n/**\n * Create a Facebook Messenger message.\n *\n * @param appId - The Conversation API app ID\n * @param psid - The Page-Scoped ID of the user\n * @param text - Message text\n */\nexport function createMessenger(appId: string, psid: string, text: string): SendMessageRequest {\n return createChannelMessage(appId, 'MESSENGER', psid, text);\n}\n\n/**\n * Create a message for any channel.\n *\n * @param appId - The Conversation API app ID\n * @param channel - Channel name (SMS, WHATSAPP, MESSENGER, VIBER, etc.)\n * @param identity - Channel-specific identity (phone number, PSID, etc.)\n * @param text - Message text\n * @param smsSender - SMS sender number (only used for SMS channel)\n */\nexport function createChannelMessage(\n appId: string,\n channel: string,\n identity: string,\n text: string,\n smsSender?: string\n): SendMessageRequest {\n if (!appId) throw new Error('appId is required');\n if (!channel) throw new Error('channel is required');\n if (!identity) throw new Error('identity is required');\n if (!text) throw new Error('text is required');\n\n const request: SendMessageRequest = {\n app_id: appId,\n message: {\n text_message: {\n text,\n },\n },\n recipient: {\n identified_by: {\n channel_identities: [\n {\n channel: channel as ConversationChannel,\n identity,\n },\n ],\n },\n },\n };\n\n // Set SMS_SENDER channel property for SMS channel\n if (channel.toUpperCase() === 'SMS' && smsSender) {\n request.channel_properties = {\n SMS_SENDER: smsSender,\n };\n }\n\n return request;\n}\n\n/**\n * ConversationMessage namespace for static helpers\n */\nexport const ConversationMessage = {\n textReply,\n createSms,\n createWhatsApp,\n createMessenger,\n createChannelMessage,\n};\n\nexport default ConversationMessage;\n","/**\n * Conversation API Controller Base Class for Sinch Functions\n *\n * Provides webhook handling for Sinch Conversation API events.\n * Handles webhook routing and provides typed handlers for each event type.\n */\n\nimport type { Request, Response } from 'express';\nimport type { Conversation, ConversationService } from '@sinch/sdk-core';\nimport { ConversationMessageBuilder } from './message-builder.js';\nimport { textReply } from './message-helpers.js';\nimport type { MessageInboundEvent } from './extensions.js';\n\n/**\n * Conversation API event types\n */\nexport type MessageDeliveryEvent = Conversation.MessageDeliveryReceiptEvent;\nexport type EventInboundEvent = Conversation.EventInbound;\nexport type ConversationStartEvent = Conversation.ConversationStartEvent;\nexport type ConversationStopEvent = Conversation.ConversationStopEvent;\n\n/**\n * Configuration for the conversation controller\n */\nexport interface ConversationControllerConfig {\n CONVERSATION_APP_ID?: string;\n FROM_NUMBER?: string;\n VERBOSE?: string;\n}\n\n/**\n * Base controller for handling Sinch Conversation API webhooks.\n *\n * Derived classes override the virtual handlers they need.\n *\n * @example\n * ```typescript\n * class MyConversationHandler extends ConversationController {\n * constructor(conversation: ConversationService, config: ConversationControllerConfig) {\n * super(conversation, config);\n * }\n *\n * async handleMessageInbound(event: MessageInboundEvent): Promise<void> {\n * const text = getText(event);\n * if (!text) return;\n *\n * // Reply using helper method\n * await this.conversation.messages.send({\n * sendMessageRequestBody: this.reply(event, \"Thanks for your message!\")\n * });\n * }\n * }\n * ```\n */\nexport abstract class ConversationController {\n protected conversation?: ConversationService;\n protected config: ConversationControllerConfig;\n\n constructor(\n conversation: ConversationService | undefined,\n config: ConversationControllerConfig = {}\n ) {\n this.conversation = conversation;\n this.config = config;\n }\n\n /**\n * MESSAGE_INBOUND - Called when a user sends a message.\n * Override this to handle incoming messages from users.\n */\n async handleMessageInbound(event: MessageInboundEvent): Promise<void> {\n // Default: do nothing\n }\n\n /**\n * MESSAGE_DELIVERY - Called when message delivery status updates.\n * Override this to track delivery receipts.\n */\n async handleMessageDelivery(event: MessageDeliveryEvent): Promise<void> {\n // Default: do nothing\n }\n\n /**\n * EVENT_INBOUND - Called for events like composing indicators.\n * Override this to handle typing indicators, read receipts, etc.\n */\n async handleEventInbound(event: EventInboundEvent): Promise<void> {\n // Default: do nothing\n }\n\n /**\n * CONVERSATION_START - Called when a conversation begins.\n * Override this to handle conversation initialization.\n */\n async handleConversationStart(event: ConversationStartEvent): Promise<void> {\n // Default: do nothing\n }\n\n /**\n * CONVERSATION_STOP - Called when a conversation ends.\n * Override this to handle conversation cleanup.\n */\n async handleConversationStop(event: ConversationStopEvent): Promise<void> {\n // Default: do nothing\n }\n\n /**\n * Gets the sender number from configuration (FROM_NUMBER).\n * Used for setting SMS_SENDER channel property when sending to SMS channel.\n */\n get fromNumber(): string | undefined {\n return this.config.FROM_NUMBER;\n }\n\n /**\n * Create a text reply to an inbound message.\n * Automatically sets SMS_SENDER from FROM_NUMBER config.\n */\n reply(inbound: MessageInboundEvent, text: string) {\n return textReply(inbound, text, this.fromNumber);\n }\n\n /**\n * Create a ConversationMessageBuilder for building messages with full control.\n */\n createMessage(): ConversationMessageBuilder {\n return new ConversationMessageBuilder(this.config);\n }\n\n /**\n * Create a ConversationMessageBuilder pre-filled from an inbound message.\n */\n createReply(inbound: MessageInboundEvent): ConversationMessageBuilder {\n return new ConversationMessageBuilder(this.config).fromInbound(inbound);\n }\n\n /**\n * Express route handler for the webhook endpoint.\n * Mount at: POST /conversation\n *\n * Routes to appropriate handler based on event type.\n * Uses manual JSON parsing as workaround for SDK issues with extra fields.\n */\n getWebhookHandler() {\n return async (req: Request, res: Response): Promise<void> => {\n try {\n const body = req.body;\n const verbose = this.config.VERBOSE === 'true';\n\n if (!body) {\n res.status(400).json({ error: 'Empty request body' });\n return;\n }\n\n if (!this.conversation) {\n console.error('[Conversation] Client not configured');\n res.status(500).json({ error: 'Conversation API not configured' });\n return;\n }\n\n // Detect event type by checking message structure\n // MESSAGE_INBOUND: message.direction == \"TO_APP\" && message.contact_message exists\n if (body.message?.direction === 'TO_APP' && body.message?.contact_message) {\n if (verbose) {\n console.log('[Conversation] MESSAGE_INBOUND event detected');\n }\n await this.handleMessageInbound(body as MessageInboundEvent);\n res.status(200).send('OK');\n return;\n }\n\n // MESSAGE_DELIVERY: has message_delivery_report\n if (body.message_delivery_report) {\n if (verbose) {\n console.log('[Conversation] MESSAGE_DELIVERY event detected');\n }\n await this.handleMessageDelivery(body as MessageDeliveryEvent);\n res.status(200).send('OK');\n return;\n }\n\n // EVENT_INBOUND: has event.contact_event\n if (body.event?.contact_event) {\n if (verbose) {\n console.log('[Conversation] EVENT_INBOUND event detected');\n }\n await this.handleEventInbound(body as EventInboundEvent);\n res.status(200).send('OK');\n return;\n }\n\n // CONVERSATION_START/STOP: has conversation_event\n if (body.conversation_event) {\n const eventType = body.conversation_event.type;\n if (eventType === 'CONVERSATION_START') {\n if (verbose) {\n console.log('[Conversation] CONVERSATION_START event detected');\n }\n await this.handleConversationStart(body as ConversationStartEvent);\n } else if (eventType === 'CONVERSATION_STOP') {\n if (verbose) {\n console.log('[Conversation] CONVERSATION_STOP event detected');\n }\n await this.handleConversationStop(body as ConversationStopEvent);\n }\n res.status(200).send('OK');\n return;\n }\n\n // Unknown event type - log and ignore\n if (verbose) {\n console.log('[Conversation] Unknown event type, ignoring');\n }\n res.status(200).json({ status: 'ignored', reason: 'unknown_event_type' });\n } catch (error) {\n console.error('[Conversation] Error processing webhook:', error);\n res.status(500).json({ error: 'Internal server error' });\n }\n };\n }\n}\n\nexport default ConversationController;\n","/**\n * Conversation API Extension Methods for Sinch Functions\n *\n * Helper functions to simplify accessing nested properties in Conversation API events.\n * Works with Sinch SDK types from @sinch/conversation.\n */\n\nimport type { Conversation } from '@sinch/sdk-core';\n\n/**\n * Message inbound event from Conversation API\n */\nexport type MessageInboundEvent = Conversation.MessageInboundEvent;\n\n/**\n * Contact message content\n */\nexport type ContactMessage = Conversation.ContactMessage;\n\n/**\n * Media properties type (URL, thumbnail, filename)\n */\nexport type MediaProperties = Conversation.MediaProperties;\n\n/**\n * Location message item type (coordinates, title, label)\n */\nexport type LocationMessageItem = Conversation.LocationMessageItem;\n\n/**\n * Get the text content from an inbound message\n */\nexport function getText(event: MessageInboundEvent): string | undefined {\n return event.message?.contact_message?.text_message?.text;\n}\n\n/**\n * Get media content from an inbound message (images, videos, files)\n */\nexport function getMedia(event: MessageInboundEvent): MediaProperties | undefined {\n return event.message?.contact_message?.media_message;\n}\n\n/**\n * Get postback data from a button/quick reply click\n */\nexport function getPostbackData(event: MessageInboundEvent): string | undefined {\n return event.message?.contact_message?.choice_response_message?.postback_data;\n}\n\n/**\n * Get the contact ID of the sender\n */\nexport function getContactId(event: MessageInboundEvent): string | undefined {\n return event.message?.contact_id;\n}\n\n/**\n * Get the conversation ID (for non-DISPATCH mode apps)\n */\nexport function getConversationId(event: MessageInboundEvent): string | undefined {\n return event.message?.conversation_id;\n}\n\n/**\n * Get the channel name (SMS, WHATSAPP, MESSENGER, etc.)\n */\nexport function getChannel(event: MessageInboundEvent): string | undefined {\n return event.message?.channel_identity?.channel;\n}\n\n/**\n * Get the channel-specific identity (phone number, PSID, etc.)\n * This is the sender's identity (FROM)\n */\nexport function getIdentity(event: MessageInboundEvent): string | undefined {\n return event.message?.channel_identity?.identity;\n}\n\n/**\n * Get the destination number that the contact sent the message TO.\n * For SMS/MMS, this is your Sinch number that received the message.\n * Used automatically by reply() to set SMS_SENDER when replying.\n */\nexport function getTo(event: MessageInboundEvent): string | undefined {\n return event.message?.sender_id;\n}\n\n/**\n * Get location data if the message contains a location\n */\nexport function getLocation(event: MessageInboundEvent): LocationMessageItem | undefined {\n return event.message?.contact_message?.location_message;\n}\n\n/**\n * Check if the message is a text message\n */\nexport function isTextMessage(event: MessageInboundEvent): boolean {\n return event.message?.contact_message?.text_message !== undefined;\n}\n\n/**\n * Check if the message is a media message\n */\nexport function isMediaMessage(event: MessageInboundEvent): boolean {\n return event.message?.contact_message?.media_message !== undefined;\n}\n\n/**\n * Check if the message is a button/quick reply response\n */\nexport function isPostback(event: MessageInboundEvent): boolean {\n return event.message?.contact_message?.choice_response_message !== undefined;\n}\n\n/**\n * Extension helper object with all methods bound to an event\n */\nexport function createMessageHelper(event: MessageInboundEvent) {\n return {\n getText: () => getText(event),\n getMedia: () => getMedia(event),\n getPostbackData: () => getPostbackData(event),\n getContactId: () => getContactId(event),\n getConversationId: () => getConversationId(event),\n getChannel: () => getChannel(event),\n getIdentity: () => getIdentity(event),\n getTo: () => getTo(event),\n getLocation: () => getLocation(event),\n isTextMessage: () => isTextMessage(event),\n isMediaMessage: () => isMediaMessage(event),\n isPostback: () => isPostback(event),\n };\n}\n","/**\n * Voice Helper Utilities\n *\n * Helper functions for working with voice calls and SVAML responses.\n */\n\nimport { IceSvamlBuilder, PieSvamlBuilder } from '../builders/svaml.js';\n\n// ============================================\n// Phone Number Utilities\n// ============================================\n\n/**\n * Known country codes and their national number patterns\n */\nconst COUNTRY_CODES: Record<string, { code: string; format: (national: string) => string }> = {\n '+1': { code: 'US', format: (n) => `(${n.slice(0, 3)}) ${n.slice(3, 6)}-${n.slice(6)}` },\n '+44': { code: 'GB', format: (n) => `0${n.slice(0, 4)} ${n.slice(4)}` },\n '+46': {\n code: 'SE',\n format: (n) => `0${n.slice(0, 2)}-${n.slice(2, 5)} ${n.slice(5, 7)} ${n.slice(7)}`,\n },\n '+49': { code: 'DE', format: (n) => `0${n.slice(0, 3)} ${n.slice(3)}` },\n '+33': {\n code: 'FR',\n format: (n) =>\n `0${n.slice(0, 1)} ${n.slice(1, 3)} ${n.slice(3, 5)} ${n.slice(5, 7)} ${n.slice(7)}`,\n },\n '+61': { code: 'AU', format: (n) => `0${n.slice(0, 1)} ${n.slice(1, 5)} ${n.slice(5)}` },\n};\n\n/**\n * Converts an E.164 phone number to local/national format.\n *\n * @param phoneNumber - The phone number in E.164 format (e.g., \"+15551234567\")\n * @param defaultRegion - The default region code (default: \"US\")\n * @returns The phone number in national format, or the original if conversion fails\n *\n * @example\n * ```typescript\n * toLocalPhoneNumber('+15551234567'); // Returns \"(555) 123-4567\"\n * toLocalPhoneNumber('+442071234567'); // Returns \"020 7123 4567\"\n * ```\n */\nexport function toLocalPhoneNumber(phoneNumber: string, defaultRegion = 'US'): string {\n if (!phoneNumber || !phoneNumber.startsWith('+')) {\n return phoneNumber;\n }\n\n // Find matching country code (longest match first)\n const sortedCodes = Object.keys(COUNTRY_CODES).sort((a, b) => b.length - a.length);\n\n for (const prefix of sortedCodes) {\n if (phoneNumber.startsWith(prefix)) {\n const national = phoneNumber.slice(prefix.length);\n try {\n return COUNTRY_CODES[prefix].format(national);\n } catch {\n return phoneNumber;\n }\n }\n }\n\n // Unknown country code - just remove the + and return\n return phoneNumber.slice(1);\n}\n\n/**\n * Formats a phone number for display (adds dashes/spaces for readability)\n *\n * @param phoneNumber - Phone number in any format\n * @returns Formatted phone number\n */\nexport function formatPhoneNumber(phoneNumber: string): string {\n // Remove all non-digit characters except +\n const cleaned = phoneNumber.replace(/[^\\d+]/g, '');\n\n if (cleaned.startsWith('+')) {\n return toLocalPhoneNumber(cleaned);\n }\n\n // US format for 10-digit numbers\n if (cleaned.length === 10) {\n return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6)}`;\n }\n\n // Return as-is for other formats\n return phoneNumber;\n}\n\n// ============================================\n// Error Response Helpers\n// ============================================\n\n/**\n * Helper methods for creating common error responses\n */\nexport const VoiceErrorHelper = {\n /**\n * Create a standard error response that plays a message and hangs up\n *\n * @param message - Error message to speak\n * @param locale - Language locale (default: \"en-US\")\n * @returns SVAML response object\n */\n createErrorResponse(message: string, locale = 'en-US'): ReturnType<IceSvamlBuilder['build']> {\n return new IceSvamlBuilder().say(message, locale).hangup().build();\n },\n\n /**\n * Create a service unavailable response\n *\n * @param locale - Language locale (default: \"en-US\")\n * @returns SVAML response object\n */\n serviceUnavailable(locale = 'en-US'): ReturnType<IceSvamlBuilder['build']> {\n return this.createErrorResponse(\n \"We're sorry, our service is temporarily unavailable. Please try again later.\",\n locale\n );\n },\n\n /**\n * Create an invalid input response for PIE handlers\n *\n * @param locale - Language locale (default: \"en-US\")\n * @returns SVAML response object\n */\n invalidInput(locale = 'en-US'): ReturnType<PieSvamlBuilder['build']> {\n return new PieSvamlBuilder()\n .say('Invalid selection. Please try again.', locale)\n .continue()\n .build();\n },\n\n /**\n * Create a timeout response for PIE handlers\n *\n * @param locale - Language locale (default: \"en-US\")\n * @returns SVAML response object\n */\n timeout(locale = 'en-US'): ReturnType<PieSvamlBuilder['build']> {\n return new PieSvamlBuilder()\n .say('We did not receive a response. Please try again.', locale)\n .continue()\n .build();\n },\n\n /**\n * Create a goodbye response that thanks the caller and hangs up\n *\n * @param locale - Language locale (default: \"en-US\")\n * @returns SVAML response object\n */\n goodbye(locale = 'en-US'): ReturnType<IceSvamlBuilder['build']> {\n return new IceSvamlBuilder().say('Thank you for calling. Goodbye!', locale).hangup().build();\n },\n};\n\n// ============================================\n// Call State Utilities\n// ============================================\n\n/**\n * Formats duration in seconds to human-readable format\n *\n * @param seconds - Duration in seconds\n * @returns Formatted duration string (e.g., \"2m 30s\")\n */\nexport function formatDuration(seconds: number): string {\n if (seconds < 60) {\n return `${Math.round(seconds)}s`;\n }\n\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = Math.round(seconds % 60);\n\n if (remainingSeconds === 0) {\n return `${minutes}m`;\n }\n\n return `${minutes}m ${remainingSeconds}s`;\n}\n\n/**\n * Extracts the caller's phone number from CLI (Caller ID)\n *\n * @param cli - Caller ID string\n * @returns Normalized phone number\n */\nexport function extractCallerNumber(cli: string | undefined): string | undefined {\n if (!cli) return undefined;\n\n // Remove any non-digit characters except +\n return cli.replace(/[^\\d+]/g, '');\n}\n","/**\n * Simple template renderer for HTML files\n * Replaces {{variableName}} placeholders with actual values\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nexport class TemplateRender {\n /**\n * Load and render an HTML template with variables\n * @param templatePath - Path to the HTML template file\n * @param variables - Object containing variables to replace in template\n * @returns Rendered HTML string\n */\n static render(templatePath: string, variables: Record<string, any> = {}): string {\n try {\n // Read the template file\n const template = fs.readFileSync(templatePath, 'utf8');\n\n // Replace all {{variableName}} placeholders with actual values\n let rendered = template;\n for (const [key, value] of Object.entries(variables)) {\n const placeholder = `{{${key}}}`;\n const regex = new RegExp(placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g');\n rendered = rendered.replace(regex, String(value));\n }\n\n return rendered;\n } catch (error: any) {\n console.error('Error rendering template:', error);\n throw new Error(`Failed to render template: ${templatePath}`);\n }\n }\n\n /**\n * Get the absolute path to a template file relative to the current directory\n * @param templateName - Name of the template file (e.g., 'index.html')\n * @param baseDir - Base directory to search from (defaults to cwd)\n * @returns Absolute path to the template file\n */\n static getTemplatePath(templateName: string, baseDir?: string): string {\n const searchDir = baseDir || process.cwd();\n // Look in utils/pages directory (matching original structure)\n const pagesPath = path.join(searchDir, 'utils', 'pages', templateName);\n if (fs.existsSync(pagesPath)) {\n return pagesPath;\n }\n // Also try direct pages directory\n const directPath = path.join(searchDir, 'pages', templateName);\n if (fs.existsSync(directPath)) {\n return directPath;\n }\n // Fallback to the original path pattern\n return path.join(searchDir, 'utils', 'pages', templateName);\n }\n}\n\nexport default TemplateRender;\n","/**\n * Version extractor utility for reading template versions from README.md files\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\nexport class VersionExtractor {\n /**\n * Extract version from README.md file in the template directory\n * Looks for \"Template Version: X.X.X\" pattern in the last few lines\n * @param templateDir - Path to the template directory containing README.md\n * @returns Version string or default fallback\n */\n static getTemplateVersion(templateDir: string = process.cwd()): string {\n try {\n const readmePath = path.join(templateDir, 'README.md');\n\n if (!fs.existsSync(readmePath)) {\n console.warn('README.md not found, using default version');\n return 'v1.0.0';\n }\n\n const readmeContent = fs.readFileSync(readmePath, 'utf8');\n const lines = readmeContent.split('\\n');\n\n // Look for version pattern in the last few lines\n const versionPattern = /Template Version:\\s*([\\d.]+)/i;\n\n for (let i = lines.length - 1; i >= Math.max(0, lines.length - 10); i--) {\n const match = lines[i].match(versionPattern);\n if (match) {\n return `v${match[1]}`;\n }\n }\n\n console.warn('Version pattern not found in README.md, using default');\n return 'v1.0.0';\n } catch (error: any) {\n console.error('Error reading template version:', error.message);\n return 'v1.0.0';\n }\n }\n}\n\nexport default VersionExtractor;\n","/**\n * Function loader utilities - shared between dev and prod runtimes\n */\n\nimport path from 'path';\n\n/**\n * Get the path to the compiled function file.\n * TypeScript projects compile to dist/function.js\n */\nexport function findFunctionPath(): string {\n return path.join(process.cwd(), 'dist', 'function.js');\n}\n","/**\n * HTTP request/response types for custom API endpoints\n */\n\n/**\n * HTTP methods supported by function endpoints\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\n/**\n * HTTP request for custom endpoints\n *\n * Abstraction over Express request for user-friendly API handling.\n */\nexport interface FunctionRequest {\n /** HTTP method */\n method: HttpMethod;\n /** Request path */\n path: string;\n /** Query parameters */\n query?: Record<string, string | string[]>;\n /** Request headers (lowercase keys) */\n headers?: Record<string, string>;\n /** Request body (parsed JSON) */\n body?: unknown;\n /** Route parameters (e.g., /users/:id) */\n params?: Record<string, string>;\n}\n\n/**\n * HTTP response for custom endpoints\n *\n * Return this from custom API handlers to control the response.\n */\nexport interface FunctionResponse {\n /** HTTP status code (default: 200) */\n statusCode: number;\n /** Response headers */\n headers?: Record<string, string>;\n /** Response body (will be JSON serialized) */\n body?: unknown;\n}\n\n/**\n * Create a success response\n */\nexport function ok<T>(body: T, headers?: Record<string, string>): FunctionResponse {\n return { statusCode: 200, body, headers };\n}\n\n/**\n * Create a created response (201)\n */\nexport function created<T>(body: T, headers?: Record<string, string>): FunctionResponse {\n return { statusCode: 201, body, headers };\n}\n\n/**\n * Create a no content response (204)\n */\nexport function noContent(): FunctionResponse {\n return { statusCode: 204 };\n}\n\n/**\n * Create a bad request response (400)\n */\nexport function badRequest(message: string): FunctionResponse {\n return { statusCode: 400, body: { error: message } };\n}\n\n/**\n * Create a not found response (404)\n */\nexport function notFound(message = 'Not found'): FunctionResponse {\n return { statusCode: 404, body: { error: message } };\n}\n\n/**\n * Create an internal error response (500)\n */\nexport function internalError(message = 'Internal server error'): FunctionResponse {\n return { statusCode: 500, body: { error: message } };\n}\n\n/**\n * Create a response with custom status code\n */\nexport function createResponse<T>(\n statusCode: number,\n body?: T,\n headers?: Record<string, string>\n): FunctionResponse {\n return { statusCode, body, headers };\n}\n\n/**\n * Create a JSON response\n */\nexport function createJsonResponse<T>(body: T, statusCode = 200): FunctionResponse {\n return {\n statusCode,\n headers: { 'Content-Type': 'application/json' },\n body,\n };\n}\n\n/**\n * Create an error response\n */\nexport function createErrorResponse(message: string, statusCode = 400): FunctionResponse {\n return {\n statusCode,\n headers: { 'Content-Type': 'application/json' },\n body: { error: message },\n };\n}\n","/**\n * Local cache implementation for development\n *\n * Uses in-memory Map with TTL support to simulate production cache behavior.\n * In production, the package is swapped to @sinch/functions-runtime-prod\n * which provides DaprCache instead.\n */\n\nimport type { IFunctionCache } from '@sinch/functions-runtime-shared';\n\ninterface CacheEntry<T> {\n value: T;\n expiresAt: number;\n}\n\n// Global cache store - persists across hot reloads in development\nconst globalCache = new Map<string, CacheEntry<unknown>>();\n\n/**\n * Local cache client for development\n *\n * Implements IFunctionCache using an in-memory Map with TTL support.\n * Data is lost when the process restarts.\n *\n * @internal Dev-only implementation โ€” access cache via `context.cache`\n */\nexport class LocalCache implements IFunctionCache {\n private cache: Map<string, CacheEntry<unknown>>;\n\n constructor() {\n this.cache = globalCache;\n }\n\n async set<T = unknown>(key: string, value: T, ttlSeconds = 3600): Promise<void> {\n this.cache.set(key, {\n value,\n expiresAt: Date.now() + ttlSeconds * 1000,\n });\n }\n\n async get<T = unknown>(key: string): Promise<T | null> {\n const item = this.cache.get(key);\n if (!item || Date.now() > item.expiresAt) {\n this.cache.delete(key);\n return null;\n }\n return item.value as T;\n }\n\n async has(key: string): Promise<boolean> {\n const value = await this.get(key);\n return value !== null;\n }\n\n async delete(key: string): Promise<boolean> {\n return this.cache.delete(key);\n }\n\n async extend(key: string, additionalSeconds: number): Promise<boolean> {\n const item = this.cache.get(key);\n if (!item || Date.now() > item.expiresAt) {\n return false;\n }\n item.expiresAt += additionalSeconds * 1000;\n return true;\n }\n\n async keys(pattern = '*'): Promise<string[]> {\n const allKeys = Array.from(this.cache.keys());\n\n // Clean up expired keys while we're at it\n const now = Date.now();\n for (const key of allKeys) {\n const item = this.cache.get(key);\n if (item && now > item.expiresAt) {\n this.cache.delete(key);\n }\n }\n\n const validKeys = Array.from(this.cache.keys());\n\n if (pattern === '*') {\n return validKeys;\n }\n\n // Simple wildcard pattern matching\n const regex = new RegExp('^' + pattern.replace(/\\*/g, '.*') + '$');\n return validKeys.filter((key) => regex.test(key));\n }\n\n async getMany<T = unknown>(keys: string[]): Promise<Record<string, T | null>> {\n const results: Record<string, T | null> = {};\n for (const key of keys) {\n results[key] = await this.get<T>(key);\n }\n return results;\n }\n\n /**\n * Clear all entries from the cache\n * (Utility method for testing)\n */\n async clear(): Promise<void> {\n this.cache.clear();\n }\n\n /**\n * Get the number of entries in the cache\n * (Utility method for debugging)\n */\n get size(): number {\n return this.cache.size;\n }\n}\n\n/**\n * Factory function to create a cache client\n *\n * @param _projectId - Project ID (unused in local development)\n * @param _functionName - Function name (unused in local development)\n * @internal Dev-only factory โ€” access cache via `context.cache`\n */\nexport function createCacheClient(_projectId?: string, _functionName?: string): IFunctionCache {\n return new LocalCache();\n}\n","/**\n * Tunnel Client for Sinch Functions\n *\n * Connects to the Sinch tunnel gateway via WebSocket to receive\n * incoming voice and conversation callbacks during local development.\n *\n * Features:\n * - Voice webhook auto-configuration\n * - Conversation webhook auto-configuration with cleanup\n * - ElevenLabs auto-configuration (when enabled)\n * - Stale webhook cleanup on connect\n * - Webhook cleanup on disconnect\n *\n * @internal Dev-only โ€” used by `sinch functions dev`, not by user code\n */\n\nimport WebSocket from 'ws';\nimport axios from 'axios';\nimport {\n WebhookConfig,\n configureConversationWebhooks,\n cleanupConversationWebhook,\n configureElevenLabs,\n} from './webhook-config.js';\n\n// Default tunnel gateway URL (production) - internal override via TUNNEL_GATEWAY_URL\nconst TUNNEL_GATEWAY_DEFAULT = 'https://tunnel.fn.sinch.com';\n\ninterface TunnelMessage {\n type: 'welcome' | 'request' | 'ping' | 'pong' | 'response';\n id?: string;\n tunnelId?: string;\n publicUrl?: string;\n method?: string;\n path?: string;\n query?: string;\n headers?: Record<string, string>;\n body?: string;\n statusCode?: number;\n}\n\n/** @internal */\nexport class TunnelClient {\n private ws: WebSocket | null = null;\n private tunnelUrl: string | null = null;\n private tunnelId: string | null = null;\n private isConnected = false;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 10;\n private reconnectDelay = 5000;\n private heartbeatInterval: NodeJS.Timeout | null = null;\n private localPort: number;\n private webhookConfig: WebhookConfig = {};\n private welcomeResolver: ((value: boolean) => void) | null = null;\n\n constructor(localPort = 3000) {\n this.localPort = localPort;\n }\n\n private getTunnelGatewayUrl(): string {\n // Check for explicit TUNNEL_GATEWAY_URL (undocumented, for internal testing only)\n const explicitUrl = process.env.TUNNEL_GATEWAY_URL;\n if (explicitUrl) {\n return explicitUrl;\n }\n\n // Always use production gateway\n return TUNNEL_GATEWAY_DEFAULT;\n }\n\n private generateTunnelId(): string {\n // Generate a ULID (Universally Unique Lexicographically Sortable Identifier)\n // Format: 26 characters using Crockford's Base32\n const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';\n\n // Timestamp component (10 chars) - milliseconds since Unix epoch\n const timestamp = Date.now();\n let timestampPart = '';\n let t = timestamp;\n for (let i = 0; i < 10; i++) {\n timestampPart = ENCODING[t % 32] + timestampPart;\n t = Math.floor(t / 32);\n }\n\n // Random component (16 chars)\n const randomBytes = new Uint8Array(10);\n crypto.getRandomValues(randomBytes);\n let randomPart = '';\n for (let i = 0; i < 10; i++) {\n // Use each byte to generate approximately 1.6 chars (8 bits -> ~1.6 base32 chars)\n // We'll use a simpler approach: take 5 bits at a time\n const byte = randomBytes[i];\n randomPart += ENCODING[byte >> 3]; // Upper 5 bits\n if (randomPart.length < 16) {\n randomPart += ENCODING[((byte & 0x07) << 2) | (i + 1 < 10 ? randomBytes[i + 1] >> 6 : 0)];\n }\n }\n // Trim to exactly 16 characters\n randomPart = randomPart.substring(0, 16);\n\n return timestampPart + randomPart;\n }\n\n async connect(): Promise<void> {\n // Check if tunnel is enabled\n if (process.env.SINCH_TUNNEL !== 'true') {\n console.log('Tunnel is disabled (set SINCH_TUNNEL=true to enable)');\n return;\n }\n\n // Get tunnel gateway URL (no auth required for new gateway)\n const gatewayUrl = this.getTunnelGatewayUrl();\n\n // Generate tunnel ID for this connection\n this.tunnelId = this.generateTunnelId();\n\n // Build WebSocket URL: wss://tunnel.fn-dev.sinch.com/ws?tunnel={tunnelId}\n const gatewayUri = new URL(gatewayUrl);\n const wsUrl = new URL(gatewayUrl);\n wsUrl.protocol = gatewayUri.protocol === 'https:' ? 'wss:' : 'ws:';\n wsUrl.pathname = '/ws';\n wsUrl.searchParams.set('tunnel', this.tunnelId);\n const tunnelEndpoint = wsUrl.toString();\n\n console.log(`Connecting to tunnel gateway at ${tunnelEndpoint}...`);\n\n try {\n // No auth header needed for new gateway\n this.ws = new WebSocket(tunnelEndpoint);\n\n // Create promise to wait for welcome message\n const welcomePromise = new Promise<boolean>((resolve, reject) => {\n this.welcomeResolver = resolve;\n // Timeout after 10 seconds\n setTimeout(() => reject(new Error('Timed out waiting for welcome message')), 10000);\n });\n\n this.ws.on('open', () => {\n this.isConnected = true;\n this.reconnectAttempts = 0;\n console.log('WebSocket connected, waiting for welcome message...');\n });\n\n this.ws.on('message', async (data: WebSocket.Data) => {\n try {\n const message: TunnelMessage = JSON.parse(data.toString());\n await this.handleMessage(message);\n } catch (error) {\n console.error('Error processing tunnel message:', error);\n }\n });\n\n this.ws.on('close', async () => {\n this.isConnected = false;\n console.log('Tunnel connection closed');\n this.stopHeartbeat();\n this.scheduleReconnect();\n });\n\n this.ws.on('error', (error: Error) => {\n console.error('Tunnel connection error:', error.message);\n });\n\n // Wait for welcome message\n await welcomePromise;\n\n if (!this.tunnelUrl) {\n throw new Error('Did not receive tunnel URL from gateway');\n }\n\n console.log('Tunnel connected successfully!');\n\n // Start heartbeat\n this.startHeartbeat();\n\n // Configure all webhooks\n await this.configureWebhooks();\n } catch (error: any) {\n console.error('Failed to establish tunnel connection:', error.message);\n this.scheduleReconnect();\n }\n }\n\n private async handleMessage(message: TunnelMessage): Promise<void> {\n switch (message.type) {\n case 'welcome':\n this.handleWelcomeMessage(message);\n break;\n case 'request':\n await this.handleRequest(message);\n break;\n case 'ping':\n this.sendPong();\n break;\n }\n }\n\n private handleWelcomeMessage(message: TunnelMessage): void {\n // Extract tunnelId and publicUrl from welcome message\n // { \"type\": \"welcome\", \"tunnelId\": \"01HQXK5M3N...\", \"publicUrl\": \"https://tunnel.fn-dev.sinch.com/ingress/01HQXK5M3N...\" }\n this.tunnelId = message.tunnelId || null;\n this.tunnelUrl = message.publicUrl || null;\n\n console.log(`Received welcome: tunnelId=${this.tunnelId}`);\n\n // Signal that welcome was received\n if (this.welcomeResolver) {\n this.welcomeResolver(true);\n this.welcomeResolver = null;\n }\n }\n\n private async handleRequest(message: TunnelMessage): Promise<void> {\n console.log(`Forwarding ${message.method} request to ${message.path}`);\n\n try {\n // Forward to local Express server\n const localUrl = `http://localhost:${this.localPort}${message.path}${message.query || ''}`;\n\n const axiosConfig: any = {\n method: message.method,\n url: localUrl,\n headers: {},\n };\n\n // Copy ALL headers\n if (message.headers) {\n axiosConfig.headers = { ...message.headers };\n }\n\n // Add body if present\n if (message.body) {\n axiosConfig.data = message.body;\n }\n\n const response = await axios(axiosConfig);\n\n // Collect headers - axios uses lowercase, normalize to proper case for common ones\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(response.headers)) {\n if (value) {\n // Normalize common headers to proper case\n const normalizedKey =\n key.toLowerCase() === 'content-type'\n ? 'Content-Type'\n : key.toLowerCase() === 'content-length'\n ? 'Content-Length'\n : key;\n headers[normalizedKey] = String(value);\n }\n }\n\n // Ensure Content-Type is set for JSON responses\n if (!headers['Content-Type'] && response.data) {\n headers['Content-Type'] = 'application/json';\n }\n\n const body =\n typeof response.data === 'string' ? response.data : JSON.stringify(response.data);\n\n // Send response back through tunnel\n const responseMessage: TunnelMessage = {\n type: 'response',\n id: message.id,\n statusCode: response.status,\n headers,\n body,\n };\n\n this.ws?.send(JSON.stringify(responseMessage));\n } catch (error: any) {\n console.error('Error forwarding request:', error.message);\n\n // Send error response\n const errorResponse: TunnelMessage = {\n type: 'response',\n id: message.id,\n statusCode: error.response?.status || 502,\n headers: { 'Content-Type': 'text/plain' },\n body: 'Error forwarding request to local server',\n };\n\n this.ws?.send(JSON.stringify(errorResponse));\n }\n }\n\n private sendPong(): void {\n const pongMessage: TunnelMessage = { type: 'pong' };\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(pongMessage));\n }\n }\n\n private startHeartbeat(): void {\n this.heartbeatInterval = setInterval(() => {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n const pingMessage: TunnelMessage = { type: 'ping' };\n this.ws.send(JSON.stringify(pingMessage));\n }\n }, 30000);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n }\n\n /**\n * Configure all webhooks (Voice, Conversation, ElevenLabs)\n */\n private async configureWebhooks(): Promise<void> {\n // New format: AUTO_CONFIGURE=true + SINCH_SERVICES=voice,conversation\n // Old format: AUTO_CONFIGURE_VOICE, AUTO_CONFIGURE_CONVERSATION (backwards compat)\n const hasNewFormat = 'AUTO_CONFIGURE' in process.env;\n const autoEnabled = process.env.AUTO_CONFIGURE === 'true';\n const sinchServices = (process.env.SINCH_SERVICES ?? '').split(',').map((s) => s.trim());\n\n const autoConfigVoice = hasNewFormat\n ? autoEnabled && sinchServices.includes('voice')\n : process.env.AUTO_CONFIGURE_VOICE !== 'false' && !!process.env.VOICE_APPLICATION_KEY;\n\n const autoConfigConversation = hasNewFormat\n ? autoEnabled && sinchServices.includes('conversation')\n : process.env.AUTO_CONFIGURE_CONVERSATION !== 'false' && !!process.env.CONVERSATION_APP_ID;\n\n // Configure Voice webhooks\n if (autoConfigVoice && process.env.VOICE_APPLICATION_KEY) {\n await this.configureVoiceWebhooks();\n }\n\n // Configure Conversation webhooks\n if (autoConfigConversation && process.env.CONVERSATION_APP_ID) {\n await configureConversationWebhooks(this.tunnelUrl!, this.webhookConfig);\n }\n\n // Configure ElevenLabs (if enabled)\n if (process.env.ELEVENLABS_AUTO_CONFIGURE === 'true') {\n await configureElevenLabs();\n }\n }\n\n /**\n * Cleanup webhooks on disconnect\n */\n private async cleanupWebhooks(): Promise<void> {\n await cleanupConversationWebhook(this.webhookConfig);\n }\n\n private async configureVoiceWebhooks(): Promise<void> {\n try {\n const appKey = process.env.VOICE_APPLICATION_KEY;\n const appSecret = process.env.VOICE_APPLICATION_SECRET;\n\n if (!appKey || !appSecret) {\n console.log('๐Ÿ’ก Voice API not configured - skipping phone number display');\n return;\n }\n\n // Update webhook URLs to tunnel URL\n try {\n const updateUrl = `https://callingapi.sinch.com/v1/configuration/callbacks/applications/${appKey}/`;\n const auth = Buffer.from(`${appKey}:${appSecret}`).toString('base64');\n\n await axios.post(\n updateUrl,\n {\n url: {\n primary: this.tunnelUrl,\n fallback: null,\n },\n },\n {\n headers: {\n Authorization: `Basic ${auth}`,\n 'Content-Type': 'application/json',\n },\n }\n );\n\n console.log('โœ… Updated voice webhook URL');\n } catch (error: any) {\n console.log('โš ๏ธ Could not update webhook URL:', error.message);\n }\n\n // List numbers using Voice API\n try {\n const listUrl = `https://callingapi.sinch.com/v1/configuration/numbers/`;\n const auth = Buffer.from(`${appKey}:${appSecret}`).toString('base64');\n\n const response = await axios.get(listUrl, {\n headers: {\n Authorization: `Basic ${auth}`,\n },\n });\n\n const numbers = response.data?.numbers || [];\n const appNumbers = numbers.filter((n: any) => n.applicationkey === appKey);\n\n if (appNumbers.length > 0) {\n console.log('๐Ÿ“ฑ Test Phone Numbers:');\n appNumbers.forEach((num: any) => {\n console.log(` โ˜Ž๏ธ ${num.number}`);\n });\n console.log('๐Ÿ’ก Call any of these numbers to test your voice function!');\n } else {\n console.log('โš ๏ธ No phone numbers assigned to this application yet');\n console.log('๐Ÿ’ก Add numbers at https://dashboard.sinch.com/voice/apps');\n }\n } catch (error: any) {\n console.log('๐Ÿ’ก Could not fetch phone numbers:', error.message);\n }\n } catch (error) {\n console.log('๐Ÿ’ก Could not fetch phone numbers (Voice API may not be configured)');\n }\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n console.error('Max reconnection attempts reached. Giving up.');\n return;\n }\n\n this.reconnectAttempts++;\n const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1), 30000);\n\n console.log(`Attempting to reconnect in ${delay / 1000} seconds...`);\n setTimeout(() => this.connect(), delay);\n }\n\n async disconnect(): Promise<void> {\n this.stopHeartbeat();\n await this.cleanupWebhooks();\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n this.isConnected = false;\n }\n\n getTunnelUrl(): string | null {\n return this.tunnelUrl;\n }\n\n getIsConnected(): boolean {\n return this.isConnected;\n }\n}\n\n// Export singleton factory\nlet tunnelInstance: TunnelClient | null = null;\n\n/** @internal */\nexport function getTunnelClient(localPort = 3000): TunnelClient {\n if (!tunnelInstance) {\n tunnelInstance = new TunnelClient(localPort);\n }\n return tunnelInstance;\n}\n\nexport default TunnelClient;\n","/**\n * Webhook Configuration Helpers for Tunnel Client\n *\n * Additional webhook configuration for Conversation API and ElevenLabs.\n * Used by TunnelClient to auto-configure webhooks on connect.\n */\n\nimport { SinchClient } from '@sinch/sdk-core';\n\nexport interface WebhookConfig {\n conversationWebhookId?: string;\n voiceConfigured?: boolean;\n}\n\n/**\n * Configure Conversation API webhooks to point to tunnel URL\n * Cleans up stale tunnel webhooks and creates a fresh one\n */\nexport async function configureConversationWebhooks(\n tunnelUrl: string,\n config: WebhookConfig\n): Promise<void> {\n try {\n const conversationAppId = process.env.CONVERSATION_APP_ID;\n const projectId = process.env.PROJECT_ID;\n const keyId = process.env.PROJECT_ID_API_KEY;\n const keySecret = process.env.PROJECT_ID_API_SECRET;\n\n if (!conversationAppId || !projectId || !keyId || !keySecret) {\n console.log('๐Ÿ’ก Conversation API not fully configured - skipping webhook setup');\n return;\n }\n\n const webhookUrl = `${tunnelUrl}/webhook/conversation`;\n console.log(`๐Ÿ’ฌ Conversation webhook URL: ${webhookUrl}`);\n\n // Create Sinch client for Conversation API\n const sinchClient = new SinchClient({\n projectId,\n keyId,\n keySecret,\n });\n\n // List existing webhooks\n const webhooksResult = await sinchClient.conversation.webhooks.list({\n app_id: conversationAppId,\n });\n const existingWebhooks = webhooksResult.webhooks || [];\n\n // Clean up stale tunnel webhooks (matching /api/ingress/ pattern)\n const tunnelWebhooks = existingWebhooks.filter((w: any) => w.target?.includes('/api/ingress/'));\n\n for (const staleWebhook of tunnelWebhooks) {\n try {\n await sinchClient.conversation.webhooks.delete({ webhook_id: staleWebhook.id! });\n console.log(`๐Ÿงน Cleaned up stale tunnel webhook: ${staleWebhook.id}`);\n } catch (err: any) {\n // Ignore errors deleting stale webhooks\n }\n }\n\n // Create fresh webhook\n const createResult = await sinchClient.conversation.webhooks.create({\n webhookCreateRequestBody: {\n app_id: conversationAppId,\n target: webhookUrl,\n target_type: 'HTTP',\n triggers: ['MESSAGE_INBOUND'],\n },\n });\n\n config.conversationWebhookId = createResult.id;\n console.log(`โœ… Created Conversation webhook: ${webhookUrl}`);\n console.log('๐Ÿ’ฌ Send a message to your Conversation app to test!');\n } catch (error: any) {\n console.log('โš ๏ธ Could not configure Conversation webhooks:', error.message);\n }\n}\n\n/**\n * Delete the Conversation webhook created for this tunnel session\n */\nexport async function cleanupConversationWebhook(config: WebhookConfig): Promise<void> {\n if (!config.conversationWebhookId) return;\n\n try {\n const conversationAppId = process.env.CONVERSATION_APP_ID;\n const projectId = process.env.PROJECT_ID;\n const keyId = process.env.PROJECT_ID_API_KEY;\n const keySecret = process.env.PROJECT_ID_API_SECRET;\n\n if (!conversationAppId || !projectId || !keyId || !keySecret) return;\n\n const sinchClient = new SinchClient({\n projectId,\n keyId,\n keySecret,\n });\n\n await sinchClient.conversation.webhooks.delete({ webhook_id: config.conversationWebhookId });\n\n console.log('๐Ÿงน Cleaned up tunnel webhook');\n config.conversationWebhookId = undefined;\n } catch (error: any) {\n // Ignore errors - webhook may already be deleted\n }\n}\n\n/**\n * Configure ElevenLabs auto-configuration (if enabled)\n */\nexport async function configureElevenLabs(): Promise<void> {\n try {\n const agentId = process.env.ELEVENLABS_AGENT_ID;\n const apiKey = process.env.ELEVENLABS_API_KEY;\n\n if (!agentId || !apiKey) {\n console.log('๐Ÿ’ก ElevenLabs not fully configured - skipping auto-configuration');\n return;\n }\n\n // Import ElevenLabs client dynamically to avoid circular dependencies\n // const { ElevenLabsClient } = await import('@sinch/functions-runtime-shared');\n\n // ElevenLabsClient is imported but full auto-config not yet implemented\n void apiKey; // Prevent unused variable warning\n\n // ElevenLabs auto-configuration placeholder\n console.log('๐Ÿค– ElevenLabs auto-configuration enabled');\n console.log(` Agent ID: ${agentId}`);\n } catch (error: any) {\n console.log('โš ๏ธ Could not configure ElevenLabs:', error.message);\n }\n}\n","/**\n * Secrets Loader for Local Development\n *\n * Loads secrets from OS keychain (Windows Credential Manager, macOS Keychain, Linux Secret Service)\n * using the same storage pattern as the Sinch CLI. This enables F5 debugging in VS Code\n * without needing to run 'sinch functions dev'.\n *\n * Security: Only loads secrets that are declared in .env file (empty values)\n * In production, secrets are injected by the platform, so this is development-only.\n *\n * @internal Dev-only โ€” used by the runtime dev server, not by user code\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport os from 'os';\n\n/** @internal */\nexport class SecretsLoader {\n // Same service name as CLI uses\n private SERVICE_NAME = 'sinch-functions-cli';\n private username = os.userInfo().username;\n\n /**\n * Load secrets from OS keychain for variables declared in .env\n * Only loads secrets that have empty values in .env (security best practice)\n */\n async loadFromKeychain(): Promise<boolean> {\n // Only load in development mode\n if (process.env.NODE_ENV === 'production') {\n return false;\n }\n\n try {\n // Try to load keytar if available (optional dependency)\n let keytar: any;\n try {\n keytar = await import('keytar');\n } catch (error: any) {\n if (error.code === 'MODULE_NOT_FOUND' || error.code === 'ERR_MODULE_NOT_FOUND') {\n // Keytar not installed - this is OK, it's optional\n console.debug('[Secrets] Keytar not available - secrets not loaded');\n return false;\n } else {\n console.error('[Secrets] Error loading keytar:', error.message);\n }\n return false;\n }\n\n // Read .env file to find which secrets to load\n const envPath = path.join(process.cwd(), '.env');\n if (!fs.existsSync(envPath)) {\n console.debug('[Secrets] No .env file found, skipping keychain load');\n return false;\n }\n\n // Parse .env file to find empty variables that might be secrets\n const envContent = fs.readFileSync(envPath, 'utf8');\n // Handle both Windows (CRLF) and Unix (LF) line endings\n const envLines = envContent.replace(/\\r\\n/g, '\\n').split('\\n');\n const secretsToLoad: string[] = [];\n\n envLines.forEach((line) => {\n // Remove any trailing carriage returns and trim\n const trimmedLine = line.replace(/\\r$/, '').trim();\n if (trimmedLine && !trimmedLine.startsWith('#')) {\n const equalIndex = trimmedLine.indexOf('=');\n if (equalIndex !== -1) {\n const envKey = trimmedLine.substring(0, equalIndex).trim();\n const envValue = trimmedLine.substring(equalIndex + 1).trim();\n\n // If value is empty, this might be a secret to load from keychain\n if (envKey && envValue === '' && !process.env[envKey]) {\n secretsToLoad.push(envKey);\n }\n }\n }\n });\n\n if (secretsToLoad.length === 0) {\n console.debug('[Secrets] No empty variables found in .env');\n return false;\n }\n\n let secretsLoaded = 0;\n\n // Handle special Sinch secrets with their specific keychain patterns\n if (secretsToLoad.includes('PROJECT_ID_API_SECRET')) {\n const apiSecret = await keytar.getPassword(this.SERVICE_NAME, `${this.username}-keySecret`);\n if (apiSecret) {\n process.env.PROJECT_ID_API_SECRET = apiSecret;\n console.log('โœ… Loaded PROJECT_ID_API_SECRET from secure storage');\n secretsLoaded++;\n }\n }\n\n if (secretsToLoad.includes('VOICE_APPLICATION_SECRET')) {\n // Get application key from environment or sinch.json\n const applicationKey =\n process.env.VOICE_APPLICATION_KEY || this.getApplicationKeyFromConfig();\n if (applicationKey) {\n const appSecret = await keytar.getPassword(this.SERVICE_NAME, applicationKey);\n if (appSecret) {\n process.env.VOICE_APPLICATION_SECRET = appSecret;\n console.log('โœ… Loaded VOICE_APPLICATION_SECRET from secure storage');\n secretsLoaded++;\n }\n }\n }\n\n // Handle custom secrets added via 'sinch functions secrets add'\n const functionName = this.getFunctionNameFromConfig();\n for (const secretName of secretsToLoad) {\n // Skip the special Sinch secrets we already handled\n if (secretName === 'PROJECT_ID_API_SECRET' || secretName === 'VOICE_APPLICATION_SECRET') {\n continue;\n }\n\n // Try to load custom secret using function-specific key\n if (functionName) {\n const value = await keytar.getPassword(\n this.SERVICE_NAME,\n `${functionName}-${secretName}`\n );\n if (value) {\n process.env[secretName] = value;\n console.log(`โœ… Loaded ${secretName} from secure storage`);\n secretsLoaded++;\n }\n }\n }\n\n if (secretsLoaded === 0) {\n console.log('โ„น๏ธ No secrets found in secure storage for declared variables');\n console.log('๐Ÿ’ก To configure Sinch auth: sinch auth login');\n console.log('๐Ÿ’ก To add custom secrets: sinch functions secrets add <KEY> <VALUE>');\n }\n\n return secretsLoaded > 0;\n } catch (error: any) {\n // Other unexpected error - log but don't fail\n console.error('[Secrets] Unexpected error:', error.message);\n console.log('๐Ÿ’ก To manage secrets manually, use: sinch functions secrets');\n return false;\n }\n }\n\n /**\n * Helper to get application key from sinch.json\n */\n private getApplicationKeyFromConfig(): string | null {\n try {\n const sinchJsonPath = path.join(process.cwd(), 'sinch.json');\n if (fs.existsSync(sinchJsonPath)) {\n const sinchConfig = JSON.parse(fs.readFileSync(sinchJsonPath, 'utf8'));\n return sinchConfig.voiceAppId || sinchConfig.applicationKey || null;\n }\n } catch (error: any) {\n console.debug('[Secrets] Could not read sinch.json:', error.message);\n }\n return null;\n }\n\n /**\n * Helper to get function name from sinch.json\n */\n private getFunctionNameFromConfig(): string | null {\n try {\n const sinchJsonPath = path.join(process.cwd(), 'sinch.json');\n if (fs.existsSync(sinchJsonPath)) {\n const sinchConfig = JSON.parse(fs.readFileSync(sinchJsonPath, 'utf8'));\n return sinchConfig.name || null;\n }\n } catch (error: any) {\n console.debug('[Secrets] Could not read sinch.json:', error.message);\n }\n return null;\n }\n\n /**\n * Load custom secrets added via 'sinch functions secrets' command\n */\n async loadCustomSecrets(secretNames: string[] = []): Promise<Record<string, string>> {\n const secrets: Record<string, string> = {};\n\n try {\n const keytar = await import('keytar');\n const functionName = this.getFunctionNameFromConfig();\n\n if (!functionName) {\n console.debug('[Secrets] Could not determine function name for custom secrets');\n return secrets;\n }\n\n for (const secretName of secretNames) {\n // Custom secrets are stored with function-specific pattern\n const value = await keytar.getPassword(this.SERVICE_NAME, `${functionName}-${secretName}`);\n if (value) {\n secrets[secretName] = value;\n process.env[secretName] = value; // Also inject into process.env\n }\n }\n } catch (error: any) {\n console.debug('[Secrets] Could not load custom secrets:', error.message);\n }\n\n return secrets;\n }\n\n /**\n * Check if keytar is available\n */\n async isAvailable(): Promise<boolean> {\n try {\n await import('keytar');\n return true;\n } catch {\n return false;\n }\n }\n}\n\n// Export singleton instance\nexport const secretsLoader = new SecretsLoader();\n\nexport default secretsLoader;\n"],"mappings":"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","names":["AgentProvider","createRequire","requireCjs","path","fs","createResponse","FETCH_TIMEOUT_MS","fs","path","path","SinchClient","fs","path"]}