@sinch/functions-runtime 0.4.4 → 0.4.5
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/bin/sinch-runtime.js +9 -3
- package/dist/bin/sinch-runtime.js.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bin/sinch-runtime.ts","../../../runtime-shared/src/ai/connect-agent.ts","../../../runtime-shared/src/host/middleware.ts","../../../runtime-shared/src/auth/basic-auth.ts","../../../runtime-shared/src/security/index.ts","../../../runtime-shared/src/sinch/index.ts","../../../runtime-shared/src/host/app.ts","../../../runtime-shared/src/ai/elevenlabs/state.ts","../../../runtime-shared/src/utils/templateRender.ts","../../../runtime-shared/src/utils/versionExtractor.ts","../../../runtime-shared/src/utils/functionLoader.ts","../../src/cache/local.ts","../../src/storage/local.ts","../../src/secrets/index.ts","../../src/secrets/keychain.ts","../../src/tunnel/index.ts","../../src/tunnel/webhook-config.ts"],"sourcesContent":["/**\n * Sinch Functions Runtime CLI Entry Point\n *\n * This is the main entry point for running Sinch Functions locally.\n * It creates an Express server, loads the user's function.js, and\n * handles voice callbacks and custom endpoints.\n *\n * Usage:\n * sinch-runtime [--port <port>] [--verbose]\n */\n\nimport path from 'path';\nimport { createRequire } from 'module';\nimport { pathToFileURL } from 'url';\nconst requireCjs = createRequire(import.meta.url);\nimport fs from 'fs';\nimport {\n createApp,\n setupRequestHandler,\n createSinchRuntime,\n installWebSocketHandlers,\n buildBaseContext,\n isVoiceCallback,\n getSinchClients,\n} from '@sinch/functions-runtime-shared';\nimport type { FunctionContext, SetupResult } from '@sinch/functions-runtime-shared';\nimport { createCacheClient } from '../cache/local.js';\nimport { createStorageClient } from '../storage/local.js';\nimport { secretsLoader } from '../secrets/index.js';\nimport { TunnelClient } from '../tunnel/index.js';\nimport type { Request } from 'express';\n\n// ============================================\n// Configuration\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 const distPath = path.join(process.cwd(), 'dist', 'function.js');\n const rootPath = path.join(process.cwd(), 'function.js');\n\n if (fs.existsSync(distPath)) {\n return distPath;\n }\n return rootPath;\n}\n\ninterface RuntimeConfig {\n projectId: string;\n projectName: string;\n functionId: string;\n}\n\n/**\n * Load runtime configuration from environment\n */\nfunction loadRuntimeConfig(): RuntimeConfig {\n return {\n projectId: process.env.PROJECT_ID || process.env.SINCH_PROJECT_ID || 'local-project',\n projectName: process.env.PROJECT_NAME || process.env.SINCH_PROJECT_NAME || 'Local Function',\n functionId: process.env.FUNCTION_ID || process.env.SINCH_FUNCTION_ID || 'local-dev',\n };\n}\n\n// ============================================\n// Context Builder\n// ============================================\n\n/**\n * Build context with local development additions\n */\nconst storage = createStorageClient();\nconst databasePath = path.join(process.cwd(), '.sinch', 'data', 'app.db');\n\nfunction buildLocalContext(req: Request, runtimeConfig: RuntimeConfig): FunctionContext {\n const baseContext = buildBaseContext(req);\n const cache = createCacheClient();\n const sinchClients = getSinchClients();\n\n return {\n ...baseContext,\n cache,\n storage,\n database: databasePath,\n ...sinchClients,\n env: process.env as Record<string, string>,\n config: {\n projectId: runtimeConfig.projectId,\n functionName: runtimeConfig.functionId,\n environment: 'development' as const,\n variables: process.env as Record<string, string>,\n },\n };\n}\n\n// ============================================\n// Startup Display\n// ============================================\n\n/**\n * Display configuration summary on startup\n */\nfunction displayStartupInfo(config: RuntimeConfig, verbose: boolean, _port: number): void {\n if (verbose) {\n console.log('\\n=== SINCH FUNCTIONS CONFIGURATION ===');\n\n // System Fields\n console.log('\\nSystem Fields:');\n console.log(` Project Name: ${config.projectName}`);\n console.log(` Project ID: ${config.projectId}`);\n console.log(` Function ID: ${config.functionId}`);\n console.log(` Environment: ${process.env.NODE_ENV || 'development'}`);\n\n // Environment Variables\n displayEnvironmentVariables();\n\n // Application Credentials\n displayApplicationCredentials();\n\n console.log('\\n========================================\\n');\n }\n}\n\n/**\n * Display environment variables from .env file\n */\nfunction displayEnvironmentVariables(): void {\n console.log('\\nEnvironment Variables:');\n\n try {\n const envPath = path.join(process.cwd(), '.env');\n if (!fs.existsSync(envPath)) {\n console.log(' (no .env file found)');\n return;\n }\n\n const envContent = fs.readFileSync(envPath, 'utf8');\n const envLines = envContent.split('\\n');\n\n const variables: Array<{ key: string; value: string }> = [];\n const secrets: Array<{ key: string; status: string }> = [];\n\n for (const line of envLines) {\n const trimmedLine = line.trim();\n if (!trimmedLine || trimmedLine.startsWith('#')) continue;\n\n const [key, ...valueParts] = trimmedLine.split('=');\n if (!key) continue;\n\n const envKey = key.trim();\n const envValue = valueParts.join('=').trim();\n\n if (envValue === '' && process.env[envKey]) {\n secrets.push({ key: envKey, status: '[LOADED]' });\n } else if (envValue !== '') {\n variables.push({ key: envKey, value: process.env[envKey] || envValue });\n } else {\n secrets.push({ key: envKey, status: '[MISSING]' });\n }\n }\n\n if (variables.length > 0) {\n console.log('\\n Variables:');\n for (const { key, value } of variables) {\n console.log(` ${key}: ${value}`);\n }\n }\n\n if (secrets.length > 0) {\n console.log('\\n Secrets:');\n for (const { key, status } of secrets) {\n console.log(` ${key}: ${status}`);\n }\n }\n\n if (variables.length === 0 && secrets.length === 0) {\n console.log(' (no environment variables defined in .env)');\n }\n } catch {\n console.log(' (could not read .env file)');\n }\n}\n\n/**\n * Display application credentials status\n */\nfunction displayApplicationCredentials(): void {\n console.log('\\nApplication Credentials:');\n\n const hasKey = process.env.VOICE_APPLICATION_KEY;\n const hasSecret = process.env.VOICE_APPLICATION_SECRET;\n\n if (hasKey && hasSecret) {\n console.log(` Application Key: ${process.env.VOICE_APPLICATION_KEY}`);\n console.log(' Application Secret: [LOADED]');\n console.log(' Voice features: ENABLED');\n } else if (hasKey && !hasSecret) {\n console.log(` Application Key: ${process.env.VOICE_APPLICATION_KEY}`);\n console.log(' Application Secret: [MISSING]');\n console.log(' Voice features: DISABLED');\n console.log(' Tip: Run \"sinch auth login\" to configure secrets');\n } else {\n console.log(' Not configured');\n console.log(' Voice features: DISABLED');\n console.log(' Tip: Add VOICE_APPLICATION_KEY to .env and run \"sinch auth login\"');\n }\n}\n\n/**\n * Display detected functions and their test endpoints from function.js\n */\nasync function displayDetectedFunctions(port: number): Promise<void> {\n try {\n const functionPath = findFunctionPath();\n if (!fs.existsSync(functionPath)) return;\n\n // Use dynamic import to support ESM user functions\n // Convert to file URL for Windows compatibility\n const functionUrl = pathToFileURL(functionPath).href;\n const module = await import(functionUrl);\n const userFunction = (module.default || module) as Record<string, unknown>;\n const functions = Object.keys(userFunction).filter((k) => typeof userFunction[k] === 'function');\n\n if (functions.length > 0) {\n console.log('\\nDetected functions:');\n for (const fn of functions) {\n const type = isVoiceCallback(fn) ? 'voice' : 'custom';\n console.log(` ${fn} (${type}): POST http://localhost:${port}/${fn}`);\n }\n }\n } catch {\n // Ignore errors during startup\n }\n}\n\n// ============================================\n// Main Entry Point\n// ============================================\n\nasync function main(): Promise<void> {\n // Parse command line arguments\n const args = process.argv.slice(2);\n const verbose =\n args.includes('--verbose') || args.includes('-v') || process.env.VERBOSE === 'true';\n const portArg = args.indexOf('--port');\n const port =\n portArg !== -1 ? parseInt(args[portArg + 1], 10) : parseInt(process.env.PORT || '3000', 10);\n\n // Load dotenv if available\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const dotenv = requireCjs('dotenv') as typeof import('dotenv');\n dotenv.config({ path: '.env.development' });\n dotenv.config();\n } catch {\n // dotenv not available, continue without it\n }\n\n // Load secrets from OS keychain (populates process.env with empty .env values)\n await secretsLoader.loadFromKeychain();\n\n // Ensure storage and data directories exist\n fs.mkdirSync(path.join(process.cwd(), '.sinch', 'storage'), { recursive: true });\n fs.mkdirSync(path.join(process.cwd(), '.sinch', 'data'), { recursive: true });\n\n // Load runtime configuration\n const config = loadRuntimeConfig();\n\n // Static file serving (optional)\n const staticDir = process.env.STATIC_DIR;\n const landingPageEnabled = process.env.LANDING_PAGE_ENABLED !== 'false';\n\n // Create Express app with middleware\n const app = createApp({ staticDir, landingPageEnabled });\n\n const authKey = process.env.PROJECT_ID_API_KEY;\n const authSecret = process.env.PROJECT_ID_API_SECRET;\n\n // Load user module once — extract both function handlers and auth config\n let userAuthConfig: import('@sinch/functions-runtime-shared').AuthConfig | undefined;\n const loadUserFunction = async () => {\n const functionPath = findFunctionPath();\n const functionUrl = pathToFileURL(functionPath).href;\n const module = await import(functionUrl);\n // Read auth config on first load (Node ESM cache deduplicates subsequent imports)\n if (userAuthConfig === undefined) {\n userAuthConfig = module.auth || module.default?.auth;\n if (userAuthConfig && verbose) {\n console.log(`[AUTH] Auth config loaded: ${JSON.stringify(userAuthConfig)}`);\n }\n }\n return module.default || module;\n };\n\n // Pre-load to extract auth config and setup hook before setting up routes\n await loadUserFunction();\n\n // Call user's setup() export if present (startup hooks, WebSocket handlers)\n let setupResult: SetupResult | undefined;\n const rawModule = await import(pathToFileURL(findFunctionPath()).href);\n const setupFn = rawModule.setup || rawModule.default?.setup;\n if (typeof setupFn === 'function') {\n const { runtime, result } = createSinchRuntime();\n await Promise.resolve(setupFn(runtime));\n setupResult = result;\n if (verbose) {\n console.log(`[SETUP] Registered ${result.startupHandlers.length} startup handler(s), ${result.wsHandlers.size} WebSocket endpoint(s)`);\n }\n }\n\n // Setup request handler with local-specific options\n setupRequestHandler(app, {\n landingPageEnabled,\n authConfig: userAuthConfig,\n authKey,\n authSecret,\n loadUserFunction,\n buildContext: (req: Request) => buildLocalContext(req, config),\n logger: console.log,\n onRequestStart: ({ req }) => {\n if (verbose) {\n console.log('Request headers:', req.headers);\n console.log('Request body:', req.body);\n }\n },\n onRequestEnd: ({ functionName: fn, duration, statusCode }) => {\n if (verbose) {\n console.log(`Function: ${fn}, Duration: ${duration}ms, Status: ${statusCode}`);\n }\n },\n });\n\n // Health check endpoint\n app.get('/_health', (_req, res) => {\n res.json({\n status: 'healthy',\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n });\n });\n\n // Display configuration\n displayStartupInfo(config, verbose, port);\n\n // Run startup handlers before accepting requests\n if (setupResult?.startupHandlers.length) {\n const context = buildLocalContext({} as Request, config);\n for (const handler of setupResult.startupHandlers) {\n await handler(context);\n }\n console.log(`[SETUP] Startup hooks completed`);\n }\n\n // Start the server\n const server = app.listen(port, async () => {\n console.log(`Function server running on http://localhost:${port}`);\n\n // Display detected functions and their test endpoints\n await displayDetectedFunctions(port);\n if (!verbose) {\n console.log('\\nTip: Set VERBOSE=true or use --verbose for detailed output');\n }\n\n // Install WebSocket handlers if any were registered\n if (setupResult?.wsHandlers.size) {\n installWebSocketHandlers(server, setupResult.wsHandlers, console.log);\n }\n\n // Start tunnel if enabled\n if (process.env.SINCH_TUNNEL === 'true') {\n console.log('\\nStarting tunnel...');\n const tunnelClient = new TunnelClient(port);\n await tunnelClient.connect();\n\n // Handle graceful shutdown\n process.on('beforeExit', async () => {\n await tunnelClient.disconnect();\n });\n }\n });\n}\n\n// Start the application\nmain().catch((error) => {\n console.error('Failed to start server:', error);\n process.exit(1);\n});\n\n// Graceful shutdown\nprocess.on('SIGTERM', () => {\n console.log('SIGTERM signal received: closing HTTP server');\n process.exit(0);\n});\n\nprocess.on('SIGINT', () => {\n console.log('\\nSIGINT signal received: closing HTTP server');\n process.exit(0);\n});\n","/**\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 * 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","import { timingSafeEqual } from 'node:crypto';\n\n/**\n * Declarative auth configuration exported by user functions.\n * - string[] — protect specific handler names\n * - '*' — protect all handlers\n */\nexport type AuthConfig = string[] | '*';\n\n/**\n * Validates a Basic Auth header against expected credentials.\n *\n * @param authHeader - The Authorization header value (e.g. \"Basic dXNlcjpwYXNz\")\n * @param expectedKey - The expected key (username)\n * @param expectedSecret - The expected secret (password)\n * @returns true if credentials match, false otherwise\n */\nexport function validateBasicAuth(\n authHeader: string | undefined,\n expectedKey: string,\n expectedSecret: string\n): boolean {\n if (!authHeader) {\n return false;\n }\n\n // RFC 7235: auth-scheme is case-insensitive\n if (!authHeader.toLowerCase().startsWith('basic ')) {\n return false;\n }\n\n const decoded = Buffer.from(authHeader.slice(6), 'base64').toString('utf-8');\n\n const colonIndex = decoded.indexOf(':');\n if (colonIndex === -1) {\n return false;\n }\n\n const providedKey = decoded.slice(0, colonIndex);\n const providedSecret = decoded.slice(colonIndex + 1);\n\n // Constant-time comparison to prevent timing attacks\n const expectedKeyBuf = Buffer.from(expectedKey);\n const providedKeyBuf = Buffer.from(providedKey);\n const expectedSecretBuf = Buffer.from(expectedSecret);\n const providedSecretBuf = Buffer.from(providedSecret);\n\n // timingSafeEqual requires same-length buffers; pad shorter to match longer\n const keyMatch =\n expectedKeyBuf.length === providedKeyBuf.length &&\n timingSafeEqual(expectedKeyBuf, providedKeyBuf);\n\n const secretMatch =\n expectedSecretBuf.length === providedSecretBuf.length &&\n timingSafeEqual(expectedSecretBuf, providedSecretBuf);\n\n return keyMatch && secretMatch;\n}\n","/**\n * Security Configuration for Sinch Functions\n *\n * Provides webhook signature validation modes and helpers.\n */\n\n/**\n * Webhook protection mode\n * - \"never\": No validation (development only)\n * - \"deploy\": Validate in production (default)\n * - \"always\": Always validate\n */\nexport type WebhookProtectionMode = 'never' | 'deploy' | 'always';\n\n/**\n * Security configuration options for webhook validation.\n * Controls signature verification for both Voice and Conversation webhooks.\n */\nexport interface SecurityOptions {\n /**\n * Controls webhook signature validation for all webhook types.\n * @default 'deploy'\n */\n webhookProtection: WebhookProtectionMode;\n}\n\n/**\n * Default security options\n */\nexport const defaultSecurityOptions: SecurityOptions = {\n webhookProtection: 'deploy',\n};\n\n/**\n * Determines if webhook validation should be performed based on current environment\n *\n * @param mode - The protection mode from configuration\n * @param isDevelopment - Whether running in development environment\n * @returns True if validation should be performed\n */\nexport function shouldValidateWebhook(\n mode: WebhookProtectionMode | string | undefined,\n isDevelopment: boolean\n): boolean {\n const normalizedMode = (mode || 'deploy').toLowerCase() as WebhookProtectionMode;\n\n switch (normalizedMode) {\n case 'never':\n return false;\n case 'always':\n return true;\n case 'deploy':\n default:\n return !isDevelopment;\n }\n}\n\n/**\n * Get the protection mode from environment or configuration\n *\n * @param config - Configuration object with WebhookProtection key (legacy: ProtectVoiceCallbacks)\n * @returns The protection mode\n */\nconst VALID_MODES: WebhookProtectionMode[] = ['never', 'deploy', 'always'];\n\nexport function getProtectionMode(config?: Record<string, unknown>): WebhookProtectionMode {\n // New unified env var takes precedence\n const envValue = process.env.WEBHOOK_PROTECTION ?? process.env.PROTECT_VOICE_CALLBACKS;\n if (envValue) {\n const normalized = envValue.toLowerCase();\n if (VALID_MODES.includes(normalized as WebhookProtectionMode)) {\n return normalized as WebhookProtectionMode;\n }\n console.warn(`[SECURITY] Unknown WEBHOOK_PROTECTION value \"${envValue}\", defaulting to \"deploy\"`);\n return 'deploy';\n }\n\n // New config key, then legacy\n const configValue =\n config?.WebhookProtection ?? config?.webhookProtection ??\n config?.ProtectVoiceCallbacks ?? config?.protectVoiceCallbacks;\n if (typeof configValue === 'string') {\n const normalized = configValue.toLowerCase();\n if (VALID_MODES.includes(normalized as WebhookProtectionMode)) {\n return normalized as WebhookProtectionMode;\n }\n console.warn(`[SECURITY] Unknown webhook protection value \"${configValue}\", defaulting to \"deploy\"`);\n return 'deploy';\n }\n\n return 'deploy';\n}\n\n/**\n * Create security options from environment and configuration\n *\n * @param config - Optional configuration object\n * @returns Security options\n */\nexport function createSecurityOptions(config?: Record<string, unknown>): SecurityOptions {\n return {\n webhookProtection: getProtectionMode(config),\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, ConversationCallbackWebhooks } 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 validateConversationWebhook?: (headers: Record<string, string | string[] | undefined>, body: unknown) => 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 // Conversation webhook HMAC validation — independent of API credentials\n if (process.env.CONVERSATION_WEBHOOK_SECRET) {\n const callbackProcessor = new ConversationCallbackWebhooks(process.env.CONVERSATION_WEBHOOK_SECRET);\n clients.validateConversationWebhook = (headers, body): boolean => {\n try {\n const result = callbackProcessor.validateAuthenticationHeader(\n headers as Record<string, string>,\n body\n );\n console.log('[SINCH] Conversation webhook validation:', result ? 'VALID' : 'INVALID');\n return result;\n } catch (error: unknown) {\n console.error('[SINCH] Conversation validation error:', error instanceof Error ? error.message : error);\n return false;\n }\n };\n }\n\n if (!hasCredentials) {\n // No Sinch API credentials — SDK clients won't initialize,\n // but webhook validation (above) still works with just a secret\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 * 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, SinchRuntime, WebSocketHandler } from '../types/context.js';\nimport type { IFunctionCache } from '../cache/types.js';\nimport type { IFunctionStorage } from '../storage/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 { validateBasicAuth, type AuthConfig } from '../auth/basic-auth.js';\nimport { getProtectionMode, shouldValidateWebhook } from '../security/index.js';\nimport { getSinchClients } from '../sinch/index.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 /** Declarative auth config from user module (string[] or '*') */\n authConfig?: AuthConfig;\n /** API key for Basic Auth validation */\n authKey?: string;\n /** API secret for Basic Auth validation */\n authSecret?: string;\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 * No-op storage implementation used by buildBaseContext\n * Real storage implementations are provided by the runtime packages.\n */\nconst noOpStorage: IFunctionStorage = {\n write: async () => {},\n read: async () => Buffer.alloc(0),\n list: async () => [],\n exists: async () => false,\n delete: 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 storage: noOpStorage,\n database: '',\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 // ICE is required — error if missing\n if (functionName === 'ice') {\n throw new Error(`Voice callback 'ice' not found — export an ice() function in function.ts`);\n }\n // Optional callbacks (ace, dice, pie, notify) — return 200 silently\n if (logger) {\n logger(`${functionName.toUpperCase()} callback not implemented — returning 200`);\n }\n return { statusCode: 200, body: {}, headers: {} };\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 const available = Object.keys(userFunction).filter(k => typeof userFunction[k] === 'function');\n const pathHint = functionName.endsWith('Webhook')\n ? `/webhook/${functionName.replace('Webhook', '')}`\n : `/${functionName}`;\n throw new Error(\n `No export '${functionName}' found for path ${pathHint}. ` +\n `Available exports: [${available.join(', ')}]. ` +\n `Custom endpoints require a named export matching the last path segment.`\n );\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 Hook (startup + WebSocket)\n// ============================================\n\n/**\n * Result of calling the user's setup() export\n * @internal\n */\nexport interface SetupResult {\n startupHandlers: Array<(context: FunctionContext) => Promise<void> | void>;\n wsHandlers: Map<string, WebSocketHandler>;\n}\n\n/**\n * Create a SinchRuntime object that collects registrations from user's setup() export.\n * @internal\n */\nexport function createSinchRuntime(): { runtime: SinchRuntime; result: SetupResult } {\n const result: SetupResult = {\n startupHandlers: [],\n wsHandlers: new Map(),\n };\n\n const runtime: SinchRuntime = {\n onStartup(handler) {\n result.startupHandlers.push(handler);\n },\n onWebSocket(path, handler) {\n // Normalize path to start with /\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n result.wsHandlers.set(normalizedPath, handler);\n },\n };\n\n return { runtime, result };\n}\n\n/**\n * Install WebSocket upgrade handlers on an HTTP server.\n * @internal\n */\nexport function installWebSocketHandlers(\n server: import('http').Server,\n wsHandlers: Map<string, WebSocketHandler>,\n logger: (...args: unknown[]) => void = console.log\n): void {\n if (wsHandlers.size === 0) return;\n\n // Lazy-import ws to avoid requiring it when not used\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { WebSocketServer } = requireCjs('ws') as typeof import('ws');\n\n const wss = new WebSocketServer({ noServer: true });\n\n server.on('upgrade', (req, socket, head) => {\n const pathname = new URL(req.url || '/', `http://${req.headers.host}`).pathname;\n const handler = wsHandlers.get(pathname);\n\n if (handler) {\n logger(`[WS] Upgrade request for ${pathname}`);\n wss.handleUpgrade(req, socket, head, (ws) => {\n handler(ws, req);\n });\n } else {\n logger(`[WS] No handler for ${pathname} — rejecting upgrade`);\n socket.destroy();\n }\n });\n\n logger(`[WS] WebSocket endpoints registered: ${[...wsHandlers.keys()].join(', ')}`);\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 authConfig,\n authKey,\n authSecret,\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 // Declarative auth check — validate Basic Auth if handler is protected\n if (authConfig && authKey && authSecret) {\n const needsAuth = authConfig === '*' || (Array.isArray(authConfig) && authConfig.includes(functionName));\n if (needsAuth) {\n const isValid = validateBasicAuth(req.headers.authorization, authKey, authSecret);\n if (!isValid) {\n logger(`[AUTH] Rejected unauthorized request to ${functionName}`);\n res.status(401)\n .set('WWW-Authenticate', 'Basic realm=\"sinch-function\"')\n .json({ error: 'Unauthorized' });\n return;\n }\n }\n }\n\n // Webhook HMAC signature validation (gated by protection mode)\n const protectionMode = getProtectionMode();\n const isDev = process.env.NODE_ENV !== 'production' && process.env.ASPNETCORE_ENVIRONMENT !== 'Production';\n if (shouldValidateWebhook(protectionMode, isDev)) {\n const sinchClients = getSinchClients();\n\n // Voice webhook signature validation\n if (isVoiceCallback(functionName) && sinchClients.validateWebhookSignature) {\n const rawBody = (req as SinchRequest).rawBody ?? JSON.stringify(req.body);\n const isValid = sinchClients.validateWebhookSignature({\n method: req.method,\n path: req.path,\n headers: req.headers as Record<string, string>,\n body: rawBody,\n });\n if (!isValid) {\n logger('[SECURITY] Voice webhook signature validation failed');\n res.status(401).json({ error: 'Invalid webhook signature' });\n return;\n }\n }\n\n // Conversation webhook signature validation\n if (functionName === 'conversationWebhook' && sinchClients.validateConversationWebhook) {\n const isValid = sinchClients.validateConversationWebhook(req.headers, req.body);\n if (!isValid) {\n logger('[SECURITY] Conversation webhook signature validation failed');\n res.status(401).json({ error: 'Invalid webhook signature' });\n return;\n }\n }\n }\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 * 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 * 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 * 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 ApiBackedCache 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","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport type { IFunctionStorage } from '@sinch/functions-runtime-shared';\n\nexport class LocalStorage implements IFunctionStorage {\n private baseDir: string;\n\n constructor(baseDir?: string) {\n this.baseDir = baseDir ?? path.join(process.cwd(), '.sinch', 'storage');\n }\n\n private resolvePath(key: string): string {\n const sanitized = key.replace(/^\\/+/, '').replace(/\\.\\./g, '_');\n return path.join(this.baseDir, sanitized);\n }\n\n async write(key: string, data: string | Buffer): Promise<void> {\n const filePath = this.resolvePath(key);\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, data);\n }\n\n async read(key: string): Promise<Buffer> {\n const filePath = this.resolvePath(key);\n return fs.readFile(filePath);\n }\n\n async list(prefix?: string): Promise<string[]> {\n const results: string[] = [];\n await this.walkDir(this.baseDir, '', results);\n\n if (prefix) {\n return results.filter((f) => f.startsWith(prefix));\n }\n return results;\n }\n\n async exists(key: string): Promise<boolean> {\n const filePath = this.resolvePath(key);\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n }\n\n async delete(key: string): Promise<void> {\n const filePath = this.resolvePath(key);\n await fs.rm(filePath, { force: true });\n }\n\n private async walkDir(dir: string, relative: string, results: string[]): Promise<void> {\n let entries;\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const rel = relative ? `${relative}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n await this.walkDir(path.join(dir, entry.name), rel, results);\n } else {\n results.push(rel);\n }\n }\n }\n}\n\nexport function createStorageClient(baseDir?: string): LocalStorage {\n return new LocalStorage(baseDir);\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';\nimport { getPassword } from './keychain.js';\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 // 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 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 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 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 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 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 the native keychain is available.\n * Always true — no native npm deps required. The underlying OS tool\n * (secret-tool, security, CredManager) may still be absent, in which\n * case getPassword() silently returns null per credential.\n */\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n// Export singleton instance\nexport const secretsLoader = new SecretsLoader();\n\nexport default secretsLoader;\n","/**\n * Native OS Credential Storage\n *\n * Read/write/delete passwords in the OS keychain without any native npm dependencies.\n * Ported from sinch-cli/src/lib/keychain.ts.\n *\n * - Windows: PowerShell + Win32 CredManager API (advapi32.dll)\n * - macOS: `security` CLI (Keychain Access)\n * - Linux: `secret-tool` CLI (libsecret)\n *\n * @internal Dev-only — used by SecretsLoader for F5 debugging\n */\n\nimport { execFile, spawn } from 'child_process';\nimport { promisify } from 'util';\n\nconst execFileAsync = promisify(execFile);\n\ninterface KeychainBackend {\n getPassword(service: string, account: string): Promise<string | null>;\n setPassword(service: string, account: string, password: string): Promise<void>;\n deletePassword(service: string, account: string): Promise<boolean>;\n}\n\n// Helper: base64-encode a string for safe PowerShell parameter injection\nfunction b64(value: string): string {\n return Buffer.from(value, 'utf8').toString('base64');\n}\n\nfunction psParam(name: string, value: string): string {\n return `$${name} = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${b64(value)}'));`;\n}\n\n// --- Windows: PowerShell + Win32 CredManager API ---\n\nconst WIN32_CRED_READ_SCRIPT = `\nAdd-Type -TypeDefinition @'\nusing System;\nusing System.Runtime.InteropServices;\npublic class CredManager {\n [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]\n private struct CREDENTIAL {\n public int Flags;\n public int Type;\n public IntPtr TargetName;\n public IntPtr Comment;\n public long LastWritten;\n public int CredentialBlobSize;\n public IntPtr CredentialBlob;\n public int Persist;\n public int AttributeCount;\n public IntPtr Attributes;\n public IntPtr TargetAlias;\n public IntPtr UserName;\n }\n [DllImport(\"advapi32.dll\", SetLastError=true, CharSet=CharSet.Unicode)]\n private static extern bool CredReadW(string target, int type, int flags, out IntPtr cred);\n [DllImport(\"advapi32.dll\")]\n private static extern void CredFree(IntPtr cred);\n public static string Read(string target) {\n IntPtr credPtr;\n if (!CredReadW(target, 1, 0, out credPtr)) return null;\n try {\n CREDENTIAL c = (CREDENTIAL)Marshal.PtrToStructure(credPtr, typeof(CREDENTIAL));\n if (c.CredentialBlobSize > 0 && c.CredentialBlob != IntPtr.Zero)\n return Marshal.PtrToStringUni(c.CredentialBlob, c.CredentialBlobSize / 2);\n return \"\";\n } finally { CredFree(credPtr); }\n }\n}\n'@\n$r = [CredManager]::Read($target)\nif ($r -ne $null) { [Console]::Write($r) }\nelse { exit 1 }\n`;\n\nconst WIN32_CRED_WRITE_SCRIPT = `\nAdd-Type -TypeDefinition @'\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Text;\npublic class CredWriter {\n [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]\n private struct CREDENTIAL {\n public int Flags;\n public int Type;\n public string TargetName;\n public string Comment;\n public long LastWritten;\n public int CredentialBlobSize;\n public IntPtr CredentialBlob;\n public int Persist;\n public int AttributeCount;\n public IntPtr Attributes;\n public string TargetAlias;\n public string UserName;\n }\n [DllImport(\"advapi32.dll\", SetLastError=true, CharSet=CharSet.Unicode)]\n private static extern bool CredWriteW(ref CREDENTIAL cred, int flags);\n public static bool Write(string target, string password) {\n byte[] blob = Encoding.Unicode.GetBytes(password);\n CREDENTIAL c = new CREDENTIAL();\n c.Type = 1;\n c.TargetName = target;\n c.CredentialBlobSize = blob.Length;\n c.CredentialBlob = Marshal.AllocHGlobal(blob.Length);\n Marshal.Copy(blob, 0, c.CredentialBlob, blob.Length);\n c.Persist = 2;\n try { return CredWriteW(ref c, 0); }\n finally { Marshal.FreeHGlobal(c.CredentialBlob); }\n }\n}\n'@\nif (-not [CredWriter]::Write($target, $password)) { exit 1 }\n`;\n\nconst WIN32_CRED_DELETE_SCRIPT = `\nAdd-Type -TypeDefinition @'\nusing System;\nusing System.Runtime.InteropServices;\npublic class CredDeleter {\n [DllImport(\"advapi32.dll\", SetLastError=true, CharSet=CharSet.Unicode)]\n private static extern bool CredDeleteW(string target, int type, int flags);\n public static bool Delete(string target) { return CredDeleteW(target, 1, 0); }\n}\n'@\nif (-not [CredDeleter]::Delete($target)) { exit 1 }\n`;\n\nfunction winTarget(service: string, account: string): string {\n return `${service}/${account}`;\n}\n\nconst windowsKeychain: KeychainBackend = {\n async getPassword(service: string, account: string): Promise<string | null> {\n try {\n const params = psParam('target', winTarget(service, account));\n const { stdout } = await execFileAsync(\n 'powershell.exe',\n ['-NoProfile', '-NonInteractive', '-Command', params + WIN32_CRED_READ_SCRIPT],\n { timeout: 15000, windowsHide: true },\n );\n return stdout;\n } catch {\n return null;\n }\n },\n\n async setPassword(service: string, account: string, password: string): Promise<void> {\n const params = psParam('target', winTarget(service, account)) + psParam('password', password);\n await execFileAsync(\n 'powershell.exe',\n ['-NoProfile', '-NonInteractive', '-Command', params + WIN32_CRED_WRITE_SCRIPT],\n { timeout: 15000, windowsHide: true },\n );\n },\n\n async deletePassword(service: string, account: string): Promise<boolean> {\n try {\n const params = psParam('target', winTarget(service, account));\n await execFileAsync(\n 'powershell.exe',\n ['-NoProfile', '-NonInteractive', '-Command', params + WIN32_CRED_DELETE_SCRIPT],\n { timeout: 15000, windowsHide: true },\n );\n return true;\n } catch {\n return false;\n }\n },\n};\n\n// --- macOS: security CLI ---\n\nconst macKeychain: KeychainBackend = {\n async getPassword(service: string, account: string): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\n 'security',\n ['find-generic-password', '-s', service, '-a', account, '-w'],\n { timeout: 15000 },\n );\n return stdout.trimEnd();\n } catch {\n return null;\n }\n },\n\n async setPassword(service: string, account: string, password: string): Promise<void> {\n await execFileAsync(\n 'security',\n ['add-generic-password', '-U', '-s', service, '-a', account, '-w', password],\n { timeout: 15000 },\n );\n },\n\n async deletePassword(service: string, account: string): Promise<boolean> {\n try {\n await execFileAsync(\n 'security',\n ['delete-generic-password', '-s', service, '-a', account],\n { timeout: 15000 },\n );\n return true;\n } catch {\n return false;\n }\n },\n};\n\n// --- Linux: secret-tool CLI ---\n\nconst linuxKeychain: KeychainBackend = {\n async getPassword(service: string, account: string): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\n 'secret-tool',\n ['lookup', 'service', service, 'account', account],\n { timeout: 15000 },\n );\n return stdout.trimEnd();\n } catch {\n return null;\n }\n },\n\n // secret-tool reads password from stdin (avoids exposing it in process args)\n async setPassword(service: string, account: string, password: string): Promise<void> {\n const child = spawn(\n 'secret-tool',\n ['store', '--label', `${service}/${account}`, 'service', service, 'account', account],\n { stdio: ['pipe', 'pipe', 'pipe'] },\n );\n child.stdin.write(password);\n child.stdin.end();\n await new Promise<void>((resolve, reject) => {\n child.on('close', (code: number) =>\n code === 0 ? resolve() : reject(new Error('secret-tool store failed')),\n );\n child.on('error', reject);\n });\n },\n\n async deletePassword(service: string, account: string): Promise<boolean> {\n try {\n await execFileAsync(\n 'secret-tool',\n ['clear', 'service', service, 'account', account],\n { timeout: 15000 },\n );\n return true;\n } catch {\n return false;\n }\n },\n};\n\n// --- Platform dispatch ---\n\nfunction getBackend(): KeychainBackend {\n switch (process.platform) {\n case 'win32':\n return windowsKeychain;\n case 'darwin':\n return macKeychain;\n default:\n return linuxKeychain;\n }\n}\n\nconst backend = getBackend();\n\nexport async function getPassword(service: string, account: string): Promise<string | null> {\n return backend.getPassword(service, account);\n}\n\nexport async function setPassword(service: string, account: string, password: string): Promise<void> {\n return backend.setPassword(service, account, password);\n}\n\nexport async function deletePassword(service: string, account: string): Promise<boolean> {\n return backend.deletePassword(service, account);\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 /**\n * Build a full tunnel URL with optional sub-path and tunnel query param.\n * e.g. buildTunnelUrl('/webhook/conversation') →\n * https://tunnel.fn.sinch.com/ingress/webhook/conversation?tunnel=01KKT...\n */\n private buildTunnelUrl(path?: string): string {\n const base = this.tunnelUrl!.replace(/\\/$/, '');\n return `${base}${path || ''}?tunnel=${this.tunnelId}`;\n }\n\n private handleWelcomeMessage(message: TunnelMessage): void {\n // Extract tunnelId and publicUrl (base ingress URL without query param)\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 const verbose = process.env.VERBOSE === 'true';\n console.log(`Forwarding ${message.method} request to ${message.path}`);\n if (verbose && message.body) {\n console.log(` ← Request body: ${message.body.substring(0, 2000)}`);\n }\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 if (verbose) {\n console.log(` → Response ${response.status}: ${body.substring(0, 2000)}`);\n }\n this.ws?.send(JSON.stringify(responseMessage));\n } catch (error: any) {\n console.error(`Error forwarding request: ${error.message} (${error.response?.status || 'no response'})`);\n if (verbose && error.response?.data) {\n console.error(` → Error body: ${typeof error.response.data === 'string' ? error.response.data : JSON.stringify(error.response.data)}`.substring(0, 2000));\n }\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.buildTunnelUrl('/webhook/conversation'), 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.buildTunnelUrl(),\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 if (!this.tunnelUrl || !this.tunnelId) return null;\n return this.buildTunnelUrl();\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';\nimport { randomBytes } from 'crypto';\nimport { resetSinchClients } from '@sinch/functions-runtime-shared';\n\nexport interface WebhookConfig {\n conversationWebhookId?: string;\n originalTarget?: string;\n voiceConfigured?: boolean;\n}\n\n/** Matches deployed function URLs like *.fn-dev.sinch.com, *.fn.sinch.com */\nconst SINCH_FN_URL_PATTERN = /\\.fn(-\\w+)?\\.sinch\\.com/;\n\nfunction isOurWebhook(target: string | undefined): boolean {\n return !!target && SINCH_FN_URL_PATTERN.test(target);\n}\n\nfunction isTunnelUrl(target: string | undefined): boolean {\n return !!target && target.includes('tunnel.fn');\n}\n\n/**\n * Configure Conversation API webhooks to point to tunnel URL.\n * Finds the existing deployed webhook and updates its target to the tunnel URL.\n * The original target is saved so it can be restored on disconnect.\n */\nexport async function configureConversationWebhooks(\n webhookUrl: 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 console.log(`💬 Conversation webhook URL: ${webhookUrl}`);\n\n const sinchClient = new SinchClient({\n projectId,\n keyId,\n keySecret,\n });\n\n // List existing webhooks for this app\n const webhooksResult = await sinchClient.conversation.webhooks.list({\n app_id: conversationAppId,\n });\n const existingWebhooks = webhooksResult.webhooks || [];\n\n // Find the deployed webhook (matches *.fn[-env].sinch.com)\n const deployedWebhook = existingWebhooks.find(\n (w: { target?: string }) => isOurWebhook(w.target)\n );\n\n if (!deployedWebhook || !deployedWebhook.id) {\n console.log('⚠️ No deployed webhook found — deploy first');\n return;\n }\n\n // Save original state so we can restore on disconnect\n config.conversationWebhookId = deployedWebhook.id;\n config.originalTarget = deployedWebhook.target;\n\n // Generate HMAC secret for this tunnel session (256-bit)\n const hmacSecret = randomBytes(32).toString('hex');\n process.env.CONVERSATION_WEBHOOK_SECRET = hmacSecret;\n resetSinchClients(); // Invalidate cached validator so it picks up the new secret\n\n // Update the webhook target and secret\n await sinchClient.conversation.webhooks.update({\n webhook_id: deployedWebhook.id,\n webhookUpdateRequestBody: {\n target: webhookUrl,\n secret: hmacSecret,\n },\n update_mask: ['target', 'secret'],\n });\n\n console.log(`✅ Updated Conversation webhook to tunnel: ${webhookUrl}`);\n console.log('🔒 HMAC secret configured for webhook signature validation');\n console.log('💬 Send a message to your Conversation app to test!');\n } catch (error: unknown) {\n console.log('⚠️ Could not configure Conversation webhooks:', error instanceof Error ? error.message : error);\n }\n}\n\n/**\n * Restore the Conversation webhook target to its original deployed URL.\n * Handles crash recovery: if the saved originalTarget is itself a tunnel URL,\n * derives the deployed URL from FUNCTION_NAME or FUNCTION_ID.\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 // Determine the target to restore\n let restoreTarget = config.originalTarget;\n\n if (!restoreTarget || isTunnelUrl(restoreTarget)) {\n // Crash recovery: originalTarget is a tunnel URL (stale from previous crash)\n // Derive the deployed URL from env vars\n const functionName = process.env.FUNCTION_NAME || process.env.FUNCTION_ID;\n if (functionName) {\n restoreTarget = `https://${functionName}.fn-dev.sinch.com/webhook/conversation`;\n console.log(`🔧 Derived restore target from env: ${restoreTarget}`);\n } else {\n console.log('⚠️ Cannot restore webhook — no FUNCTION_NAME or FUNCTION_ID available');\n return;\n }\n }\n\n await sinchClient.conversation.webhooks.update({\n webhook_id: config.conversationWebhookId,\n webhookUpdateRequestBody: {\n target: restoreTarget,\n },\n update_mask: ['target'],\n });\n\n console.log(`🔄 Restored webhook target to: ${restoreTarget}`);\n config.conversationWebhookId = undefined;\n config.originalTarget = undefined;\n delete process.env.CONVERSATION_WEBHOOK_SECRET;\n resetSinchClients();\n } catch (error: unknown) {\n console.log('⚠️ Could not restore Conversation webhook:', error instanceof Error ? error.message : error);\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: unknown) {\n console.log('⚠️ Could not configure ElevenLabs:', error instanceof Error ? error.message : error);\n }\n}\n"],"mappings":"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","names":["path","createRequire","pathToFileURL","fs","AgentProvider","createRequire","requireCjs","path","fs","fs","path","path","fs","path","fs","path","path","fs","SinchClient","SinchClient","randomBytes","path","requireCjs","createRequire","findFunctionPath","path","fs","pathToFileURL"]}
|
|
1
|
+
{"version":3,"sources":["../../src/bin/sinch-runtime.ts","../../../runtime-shared/src/ai/connect-agent.ts","../../../runtime-shared/src/host/middleware.ts","../../../runtime-shared/src/auth/basic-auth.ts","../../../runtime-shared/src/security/index.ts","../../../runtime-shared/src/sinch/index.ts","../../../runtime-shared/src/host/app.ts","../../../runtime-shared/src/ai/elevenlabs/state.ts","../../../runtime-shared/src/utils/templateRender.ts","../../../runtime-shared/src/utils/versionExtractor.ts","../../../runtime-shared/src/utils/functionLoader.ts","../../src/cache/local.ts","../../src/storage/local.ts","../../src/secrets/index.ts","../../src/secrets/keychain.ts","../../src/tunnel/index.ts","../../src/tunnel/webhook-config.ts"],"sourcesContent":["/**\n * Sinch Functions Runtime CLI Entry Point\n *\n * This is the main entry point for running Sinch Functions locally.\n * It creates an Express server, loads the user's function.js, and\n * handles voice callbacks and custom endpoints.\n *\n * Usage:\n * sinch-runtime [--port <port>] [--verbose]\n */\n\nimport path from 'path';\nimport { createRequire } from 'module';\nimport { pathToFileURL } from 'url';\nconst requireCjs = createRequire(import.meta.url);\nimport fs from 'fs';\nimport {\n createApp,\n setupRequestHandler,\n createSinchRuntime,\n installWebSocketHandlers,\n buildBaseContext,\n isVoiceCallback,\n getSinchClients,\n} from '@sinch/functions-runtime-shared';\nimport type { FunctionContext, SetupResult } from '@sinch/functions-runtime-shared';\nimport { createCacheClient } from '../cache/local.js';\nimport { createStorageClient } from '../storage/local.js';\nimport { secretsLoader } from '../secrets/index.js';\nimport { TunnelClient } from '../tunnel/index.js';\nimport type { Request } from 'express';\n\n// ============================================\n// Configuration\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 const distPath = path.join(process.cwd(), 'dist', 'function.js');\n const rootPath = path.join(process.cwd(), 'function.js');\n\n if (fs.existsSync(distPath)) {\n return distPath;\n }\n return rootPath;\n}\n\ninterface RuntimeConfig {\n projectId: string;\n projectName: string;\n functionId: string;\n}\n\n/**\n * Load runtime configuration from environment\n */\nfunction loadRuntimeConfig(): RuntimeConfig {\n return {\n projectId: process.env.PROJECT_ID || process.env.SINCH_PROJECT_ID || 'local-project',\n projectName: process.env.PROJECT_NAME || process.env.SINCH_PROJECT_NAME || 'Local Function',\n functionId: process.env.FUNCTION_ID || process.env.SINCH_FUNCTION_ID || 'local-dev',\n };\n}\n\n// ============================================\n// Context Builder\n// ============================================\n\n/**\n * Build context with local development additions\n */\nconst storage = createStorageClient();\nconst databasePath = path.join(process.cwd(), '.sinch', 'data', 'app.db');\n\nfunction buildLocalContext(req: Request, runtimeConfig: RuntimeConfig): FunctionContext {\n const baseContext = buildBaseContext(req);\n const cache = createCacheClient();\n const sinchClients = getSinchClients();\n\n return {\n ...baseContext,\n cache,\n storage,\n database: databasePath,\n ...sinchClients,\n env: process.env as Record<string, string>,\n config: {\n projectId: runtimeConfig.projectId,\n functionName: runtimeConfig.functionId,\n environment: 'development' as const,\n variables: process.env as Record<string, string>,\n },\n };\n}\n\n// ============================================\n// Startup Display\n// ============================================\n\n/**\n * Display configuration summary on startup\n */\nfunction displayStartupInfo(config: RuntimeConfig, verbose: boolean, _port: number): void {\n if (verbose) {\n console.log('\\n=== SINCH FUNCTIONS CONFIGURATION ===');\n\n // System Fields\n console.log('\\nSystem Fields:');\n console.log(` Project Name: ${config.projectName}`);\n console.log(` Project ID: ${config.projectId}`);\n console.log(` Function ID: ${config.functionId}`);\n console.log(` Environment: ${process.env.NODE_ENV || 'development'}`);\n\n // Environment Variables\n displayEnvironmentVariables();\n\n // Application Credentials\n displayApplicationCredentials();\n\n console.log('\\n========================================\\n');\n }\n}\n\n/**\n * Display environment variables from .env file\n */\nfunction displayEnvironmentVariables(): void {\n console.log('\\nEnvironment Variables:');\n\n try {\n const envPath = path.join(process.cwd(), '.env');\n if (!fs.existsSync(envPath)) {\n console.log(' (no .env file found)');\n return;\n }\n\n const envContent = fs.readFileSync(envPath, 'utf8');\n const envLines = envContent.split('\\n');\n\n const variables: Array<{ key: string; value: string }> = [];\n const secrets: Array<{ key: string; status: string }> = [];\n\n for (const line of envLines) {\n const trimmedLine = line.trim();\n if (!trimmedLine || trimmedLine.startsWith('#')) continue;\n\n const [key, ...valueParts] = trimmedLine.split('=');\n if (!key) continue;\n\n const envKey = key.trim();\n const envValue = valueParts.join('=').trim();\n\n if (envValue === '' && process.env[envKey]) {\n secrets.push({ key: envKey, status: '[LOADED]' });\n } else if (envValue !== '') {\n variables.push({ key: envKey, value: process.env[envKey] || envValue });\n } else {\n secrets.push({ key: envKey, status: '[MISSING]' });\n }\n }\n\n if (variables.length > 0) {\n console.log('\\n Variables:');\n for (const { key, value } of variables) {\n console.log(` ${key}: ${value}`);\n }\n }\n\n if (secrets.length > 0) {\n console.log('\\n Secrets:');\n for (const { key, status } of secrets) {\n console.log(` ${key}: ${status}`);\n }\n }\n\n if (variables.length === 0 && secrets.length === 0) {\n console.log(' (no environment variables defined in .env)');\n }\n } catch {\n console.log(' (could not read .env file)');\n }\n}\n\n/**\n * Display application credentials status\n */\nfunction displayApplicationCredentials(): void {\n console.log('\\nApplication Credentials:');\n\n const hasKey = process.env.VOICE_APPLICATION_KEY;\n const hasSecret = process.env.VOICE_APPLICATION_SECRET;\n\n if (hasKey && hasSecret) {\n console.log(` Application Key: ${process.env.VOICE_APPLICATION_KEY}`);\n console.log(' Application Secret: [LOADED]');\n console.log(' Voice features: ENABLED');\n } else if (hasKey && !hasSecret) {\n console.log(` Application Key: ${process.env.VOICE_APPLICATION_KEY}`);\n console.log(' Application Secret: [MISSING]');\n console.log(' Voice features: DISABLED');\n console.log(' Tip: Run \"sinch auth login\" to configure secrets');\n } else {\n console.log(' Not configured');\n console.log(' Voice features: DISABLED');\n console.log(' Tip: Add VOICE_APPLICATION_KEY to .env and run \"sinch auth login\"');\n }\n}\n\n/**\n * Display detected functions and their test endpoints from function.js\n */\nasync function displayDetectedFunctions(port: number): Promise<void> {\n try {\n const functionPath = findFunctionPath();\n if (!fs.existsSync(functionPath)) return;\n\n // Use dynamic import to support ESM user functions\n // Convert to file URL for Windows compatibility\n const functionUrl = pathToFileURL(functionPath).href;\n const module = await import(functionUrl);\n const userFunction = (module.default || module) as Record<string, unknown>;\n const functions = Object.keys(userFunction).filter((k) => typeof userFunction[k] === 'function');\n\n if (functions.length > 0) {\n console.log('\\nDetected functions:');\n for (const fn of functions) {\n const type = isVoiceCallback(fn) ? 'voice' : 'custom';\n console.log(` ${fn} (${type}): POST http://localhost:${port}/${fn}`);\n }\n }\n } catch {\n // Ignore errors during startup\n }\n}\n\n// ============================================\n// Main Entry Point\n// ============================================\n\nasync function main(): Promise<void> {\n // Parse command line arguments\n const args = process.argv.slice(2);\n const verbose =\n args.includes('--verbose') || args.includes('-v') || process.env.VERBOSE === 'true';\n const portArg = args.indexOf('--port');\n const port =\n portArg !== -1 ? parseInt(args[portArg + 1], 10) : parseInt(process.env.PORT || '3000', 10);\n\n // Load dotenv if available\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const dotenv = requireCjs('dotenv') as typeof import('dotenv');\n dotenv.config({ path: '.env.development' });\n dotenv.config();\n } catch {\n // dotenv not available, continue without it\n }\n\n // Load secrets from OS keychain (populates process.env with empty .env values)\n await secretsLoader.loadFromKeychain();\n\n // Ensure storage and data directories exist\n fs.mkdirSync(path.join(process.cwd(), '.sinch', 'storage'), { recursive: true });\n fs.mkdirSync(path.join(process.cwd(), '.sinch', 'data'), { recursive: true });\n\n // Load runtime configuration\n const config = loadRuntimeConfig();\n\n // Static file serving (optional)\n const staticDir = process.env.STATIC_DIR;\n const landingPageEnabled = process.env.LANDING_PAGE_ENABLED !== 'false';\n\n // Create Express app with middleware\n const app = createApp({ staticDir, landingPageEnabled });\n\n const authKey = process.env.PROJECT_ID_API_KEY;\n const authSecret = process.env.PROJECT_ID_API_SECRET;\n\n // Load user module once — extract both function handlers and auth config\n let userAuthConfig: import('@sinch/functions-runtime-shared').AuthConfig | undefined;\n const loadUserFunction = async () => {\n const functionPath = findFunctionPath();\n const functionUrl = pathToFileURL(functionPath).href;\n const module = await import(functionUrl);\n // Read auth config on first load (Node ESM cache deduplicates subsequent imports)\n if (userAuthConfig === undefined) {\n userAuthConfig = module.auth || module.default?.auth;\n if (userAuthConfig && verbose) {\n console.log(`[AUTH] Auth config loaded: ${JSON.stringify(userAuthConfig)}`);\n }\n }\n return module.default || module;\n };\n\n // Pre-load to extract auth config and setup hook before setting up routes\n await loadUserFunction();\n\n // Call user's setup() export if present (startup hooks, WebSocket handlers)\n let setupResult: SetupResult | undefined;\n const rawModule = await import(pathToFileURL(findFunctionPath()).href);\n const setupFn = rawModule.setup || rawModule.default?.setup;\n if (typeof setupFn === 'function') {\n const { runtime, result } = createSinchRuntime();\n await Promise.resolve(setupFn(runtime));\n setupResult = result;\n if (verbose) {\n console.log(`[SETUP] Registered ${result.startupHandlers.length} startup handler(s), ${result.wsHandlers.size} WebSocket endpoint(s)`);\n }\n }\n\n // Setup request handler with local-specific options\n setupRequestHandler(app, {\n landingPageEnabled,\n authConfig: userAuthConfig,\n authKey,\n authSecret,\n loadUserFunction,\n buildContext: (req: Request) => buildLocalContext(req, config),\n logger: console.log,\n onRequestStart: ({ req }) => {\n if (verbose) {\n console.log('Request headers:', req.headers);\n console.log('Request body:', req.body);\n }\n },\n onRequestEnd: ({ functionName: fn, duration, statusCode }) => {\n if (verbose) {\n console.log(`Function: ${fn}, Duration: ${duration}ms, Status: ${statusCode}`);\n }\n },\n });\n\n // Health check endpoint\n app.get('/_health', (_req, res) => {\n res.json({\n status: 'healthy',\n timestamp: new Date().toISOString(),\n uptime: process.uptime(),\n });\n });\n\n // Display configuration\n displayStartupInfo(config, verbose, port);\n\n // Run startup handlers before accepting requests\n if (setupResult?.startupHandlers.length) {\n const context = buildLocalContext({} as Request, config);\n for (const handler of setupResult.startupHandlers) {\n await handler(context);\n }\n console.log(`[SETUP] Startup hooks completed`);\n }\n\n // Start the server\n const server = app.listen(port, async () => {\n console.log(`Function server running on http://localhost:${port}`);\n\n // Display detected functions and their test endpoints\n await displayDetectedFunctions(port);\n if (!verbose) {\n console.log('\\nTip: Set VERBOSE=true or use --verbose for detailed output');\n }\n\n // Install WebSocket handlers if any were registered\n if (setupResult?.wsHandlers.size) {\n installWebSocketHandlers(server, setupResult.wsHandlers, console.log);\n }\n\n // Start tunnel if enabled\n if (process.env.SINCH_TUNNEL === 'true') {\n console.log('\\nStarting tunnel...');\n const tunnelClient = new TunnelClient(port);\n await tunnelClient.connect();\n\n // Handle graceful shutdown\n process.on('beforeExit', async () => {\n await tunnelClient.disconnect();\n });\n }\n });\n}\n\n// Start the application\nmain().catch((error) => {\n console.error('Failed to start server:', error);\n process.exit(1);\n});\n\n// Graceful shutdown\nprocess.on('SIGTERM', () => {\n console.log('SIGTERM signal received: closing HTTP server');\n process.exit(0);\n});\n\nprocess.on('SIGINT', () => {\n console.log('\\nSIGINT signal received: closing HTTP server');\n process.exit(0);\n});\n","/**\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 * 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 // Only camelCase voice callbacks\n const VOICE_EVENTS = ['ice', 'ace', 'pie', 'dice', 'notify'];\n const isVoice = req.body.event && VOICE_EVENTS.includes(req.body.event);\n if (isVoice) {\n req.body = transformKeys(req.body, opts.camelCase);\n }\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 // Only camelCase voice callbacks — Sinch Voice API sends lowercase keys\n // (callid, applicationkey) that need fixing. All other payloads (webhooks,\n // custom endpoints) are left as-received.\n const VOICE_EVENTS = ['ice', 'ace', 'pie', 'dice', 'notify'];\n const evt = parsed && typeof parsed === 'object' && 'event' in parsed ? (parsed as Record<string, unknown>).event : null;\n const isVoice = typeof evt === 'string' && VOICE_EVENTS.includes(evt);\n if (isVoice) {\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","import { timingSafeEqual } from 'node:crypto';\n\n/**\n * Declarative auth configuration exported by user functions.\n * - string[] — protect specific handler names\n * - '*' — protect all handlers\n */\nexport type AuthConfig = string[] | '*';\n\n/**\n * Validates a Basic Auth header against expected credentials.\n *\n * @param authHeader - The Authorization header value (e.g. \"Basic dXNlcjpwYXNz\")\n * @param expectedKey - The expected key (username)\n * @param expectedSecret - The expected secret (password)\n * @returns true if credentials match, false otherwise\n */\nexport function validateBasicAuth(\n authHeader: string | undefined,\n expectedKey: string,\n expectedSecret: string\n): boolean {\n if (!authHeader) {\n return false;\n }\n\n // RFC 7235: auth-scheme is case-insensitive\n if (!authHeader.toLowerCase().startsWith('basic ')) {\n return false;\n }\n\n const decoded = Buffer.from(authHeader.slice(6), 'base64').toString('utf-8');\n\n const colonIndex = decoded.indexOf(':');\n if (colonIndex === -1) {\n return false;\n }\n\n const providedKey = decoded.slice(0, colonIndex);\n const providedSecret = decoded.slice(colonIndex + 1);\n\n // Constant-time comparison to prevent timing attacks\n const expectedKeyBuf = Buffer.from(expectedKey);\n const providedKeyBuf = Buffer.from(providedKey);\n const expectedSecretBuf = Buffer.from(expectedSecret);\n const providedSecretBuf = Buffer.from(providedSecret);\n\n // timingSafeEqual requires same-length buffers; pad shorter to match longer\n const keyMatch =\n expectedKeyBuf.length === providedKeyBuf.length &&\n timingSafeEqual(expectedKeyBuf, providedKeyBuf);\n\n const secretMatch =\n expectedSecretBuf.length === providedSecretBuf.length &&\n timingSafeEqual(expectedSecretBuf, providedSecretBuf);\n\n return keyMatch && secretMatch;\n}\n","/**\n * Security Configuration for Sinch Functions\n *\n * Provides webhook signature validation modes and helpers.\n */\n\n/**\n * Webhook protection mode\n * - \"never\": No validation (development only)\n * - \"deploy\": Validate in production (default)\n * - \"always\": Always validate\n */\nexport type WebhookProtectionMode = 'never' | 'deploy' | 'always';\n\n/**\n * Security configuration options for webhook validation.\n * Controls signature verification for both Voice and Conversation webhooks.\n */\nexport interface SecurityOptions {\n /**\n * Controls webhook signature validation for all webhook types.\n * @default 'deploy'\n */\n webhookProtection: WebhookProtectionMode;\n}\n\n/**\n * Default security options\n */\nexport const defaultSecurityOptions: SecurityOptions = {\n webhookProtection: 'deploy',\n};\n\n/**\n * Determines if webhook validation should be performed based on current environment\n *\n * @param mode - The protection mode from configuration\n * @param isDevelopment - Whether running in development environment\n * @returns True if validation should be performed\n */\nexport function shouldValidateWebhook(\n mode: WebhookProtectionMode | string | undefined,\n isDevelopment: boolean\n): boolean {\n const normalizedMode = (mode || 'deploy').toLowerCase() as WebhookProtectionMode;\n\n switch (normalizedMode) {\n case 'never':\n return false;\n case 'always':\n return true;\n case 'deploy':\n default:\n return !isDevelopment;\n }\n}\n\n/**\n * Get the protection mode from environment or configuration\n *\n * @param config - Configuration object with WebhookProtection key (legacy: ProtectVoiceCallbacks)\n * @returns The protection mode\n */\nconst VALID_MODES: WebhookProtectionMode[] = ['never', 'deploy', 'always'];\n\nexport function getProtectionMode(config?: Record<string, unknown>): WebhookProtectionMode {\n // New unified env var takes precedence\n const envValue = process.env.WEBHOOK_PROTECTION ?? process.env.PROTECT_VOICE_CALLBACKS;\n if (envValue) {\n const normalized = envValue.toLowerCase();\n if (VALID_MODES.includes(normalized as WebhookProtectionMode)) {\n return normalized as WebhookProtectionMode;\n }\n console.warn(`[SECURITY] Unknown WEBHOOK_PROTECTION value \"${envValue}\", defaulting to \"deploy\"`);\n return 'deploy';\n }\n\n // New config key, then legacy\n const configValue =\n config?.WebhookProtection ?? config?.webhookProtection ??\n config?.ProtectVoiceCallbacks ?? config?.protectVoiceCallbacks;\n if (typeof configValue === 'string') {\n const normalized = configValue.toLowerCase();\n if (VALID_MODES.includes(normalized as WebhookProtectionMode)) {\n return normalized as WebhookProtectionMode;\n }\n console.warn(`[SECURITY] Unknown webhook protection value \"${configValue}\", defaulting to \"deploy\"`);\n return 'deploy';\n }\n\n return 'deploy';\n}\n\n/**\n * Create security options from environment and configuration\n *\n * @param config - Optional configuration object\n * @returns Security options\n */\nexport function createSecurityOptions(config?: Record<string, unknown>): SecurityOptions {\n return {\n webhookProtection: getProtectionMode(config),\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, ConversationCallbackWebhooks } 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 validateConversationWebhook?: (headers: Record<string, string | string[] | undefined>, body: unknown) => 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 // Conversation webhook HMAC validation — independent of API credentials\n if (process.env.CONVERSATION_WEBHOOK_SECRET) {\n const callbackProcessor = new ConversationCallbackWebhooks(process.env.CONVERSATION_WEBHOOK_SECRET);\n clients.validateConversationWebhook = (headers, body): boolean => {\n try {\n const result = callbackProcessor.validateAuthenticationHeader(\n headers as Record<string, string>,\n body\n );\n console.log('[SINCH] Conversation webhook validation:', result ? 'VALID' : 'INVALID');\n return result;\n } catch (error: unknown) {\n console.error('[SINCH] Conversation validation error:', error instanceof Error ? error.message : error);\n return false;\n }\n };\n }\n\n if (!hasCredentials) {\n // No Sinch API credentials — SDK clients won't initialize,\n // but webhook validation (above) still works with just a secret\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 * 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, SinchRuntime, WebSocketHandler } from '../types/context.js';\nimport type { IFunctionCache } from '../cache/types.js';\nimport type { IFunctionStorage } from '../storage/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 { validateBasicAuth, type AuthConfig } from '../auth/basic-auth.js';\nimport { getProtectionMode, shouldValidateWebhook } from '../security/index.js';\nimport { getSinchClients } from '../sinch/index.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 /** Declarative auth config from user module (string[] or '*') */\n authConfig?: AuthConfig;\n /** API key for Basic Auth validation */\n authKey?: string;\n /** API secret for Basic Auth validation */\n authSecret?: string;\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 * No-op storage implementation used by buildBaseContext\n * Real storage implementations are provided by the runtime packages.\n */\nconst noOpStorage: IFunctionStorage = {\n write: async () => {},\n read: async () => Buffer.alloc(0),\n list: async () => [],\n exists: async () => false,\n delete: 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 storage: noOpStorage,\n database: '',\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 // ICE is required — error if missing\n if (functionName === 'ice') {\n throw new Error(`Voice callback 'ice' not found — export an ice() function in function.ts`);\n }\n // Optional callbacks (ace, dice, pie, notify) — return 200 silently\n if (logger) {\n logger(`${functionName.toUpperCase()} callback not implemented — returning 200`);\n }\n return { statusCode: 200, body: {}, headers: {} };\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 const available = Object.keys(userFunction).filter(k => typeof userFunction[k] === 'function');\n const pathHint = functionName.endsWith('Webhook')\n ? `/webhook/${functionName.replace('Webhook', '')}`\n : `/${functionName}`;\n throw new Error(\n `No export '${functionName}' found for path ${pathHint}. ` +\n `Available exports: [${available.join(', ')}]. ` +\n `Custom endpoints require a named export matching the last path segment.`\n );\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 Hook (startup + WebSocket)\n// ============================================\n\n/**\n * Result of calling the user's setup() export\n * @internal\n */\nexport interface SetupResult {\n startupHandlers: Array<(context: FunctionContext) => Promise<void> | void>;\n wsHandlers: Map<string, WebSocketHandler>;\n}\n\n/**\n * Create a SinchRuntime object that collects registrations from user's setup() export.\n * @internal\n */\nexport function createSinchRuntime(): { runtime: SinchRuntime; result: SetupResult } {\n const result: SetupResult = {\n startupHandlers: [],\n wsHandlers: new Map(),\n };\n\n const runtime: SinchRuntime = {\n onStartup(handler) {\n result.startupHandlers.push(handler);\n },\n onWebSocket(path, handler) {\n // Normalize path to start with /\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n result.wsHandlers.set(normalizedPath, handler);\n },\n };\n\n return { runtime, result };\n}\n\n/**\n * Install WebSocket upgrade handlers on an HTTP server.\n * @internal\n */\nexport function installWebSocketHandlers(\n server: import('http').Server,\n wsHandlers: Map<string, WebSocketHandler>,\n logger: (...args: unknown[]) => void = console.log\n): void {\n if (wsHandlers.size === 0) return;\n\n // Lazy-import ws to avoid requiring it when not used\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { WebSocketServer } = requireCjs('ws') as typeof import('ws');\n\n const wss = new WebSocketServer({ noServer: true });\n\n server.on('upgrade', (req, socket, head) => {\n const pathname = new URL(req.url || '/', `http://${req.headers.host}`).pathname;\n const handler = wsHandlers.get(pathname);\n\n if (handler) {\n logger(`[WS] Upgrade request for ${pathname}`);\n wss.handleUpgrade(req, socket, head, (ws) => {\n handler(ws, req);\n });\n } else {\n logger(`[WS] No handler for ${pathname} — rejecting upgrade`);\n socket.destroy();\n }\n });\n\n logger(`[WS] WebSocket endpoints registered: ${[...wsHandlers.keys()].join(', ')}`);\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 authConfig,\n authKey,\n authSecret,\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 // Declarative auth check — validate Basic Auth if handler is protected\n if (authConfig && authKey && authSecret) {\n const needsAuth = authConfig === '*' || (Array.isArray(authConfig) && authConfig.includes(functionName));\n if (needsAuth) {\n const isValid = validateBasicAuth(req.headers.authorization, authKey, authSecret);\n if (!isValid) {\n logger(`[AUTH] Rejected unauthorized request to ${functionName}`);\n res.status(401)\n .set('WWW-Authenticate', 'Basic realm=\"sinch-function\"')\n .json({ error: 'Unauthorized' });\n return;\n }\n }\n }\n\n // Webhook HMAC signature validation (gated by protection mode)\n const protectionMode = getProtectionMode();\n const isDev = process.env.NODE_ENV !== 'production' && process.env.ASPNETCORE_ENVIRONMENT !== 'Production';\n if (shouldValidateWebhook(protectionMode, isDev)) {\n const sinchClients = getSinchClients();\n\n // Voice webhook signature validation\n if (isVoiceCallback(functionName) && sinchClients.validateWebhookSignature) {\n const rawBody = (req as SinchRequest).rawBody ?? JSON.stringify(req.body);\n const isValid = sinchClients.validateWebhookSignature({\n method: req.method,\n path: req.path,\n headers: req.headers as Record<string, string>,\n body: rawBody,\n });\n if (!isValid) {\n logger('[SECURITY] Voice webhook signature validation failed');\n res.status(401).json({ error: 'Invalid webhook signature' });\n return;\n }\n }\n\n // Conversation webhook signature validation\n if (functionName === 'conversationWebhook' && sinchClients.validateConversationWebhook) {\n const isValid = sinchClients.validateConversationWebhook(req.headers, req.body);\n if (!isValid) {\n logger('[SECURITY] Conversation webhook signature validation failed');\n res.status(401).json({ error: 'Invalid webhook signature' });\n return;\n }\n }\n }\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 * 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 * 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 * 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 ApiBackedCache 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","import * as fs from 'fs/promises';\nimport * as path from 'path';\nimport type { IFunctionStorage } from '@sinch/functions-runtime-shared';\n\nexport class LocalStorage implements IFunctionStorage {\n private baseDir: string;\n\n constructor(baseDir?: string) {\n this.baseDir = baseDir ?? path.join(process.cwd(), '.sinch', 'storage');\n }\n\n private resolvePath(key: string): string {\n const sanitized = key.replace(/^\\/+/, '').replace(/\\.\\./g, '_');\n return path.join(this.baseDir, sanitized);\n }\n\n async write(key: string, data: string | Buffer): Promise<void> {\n const filePath = this.resolvePath(key);\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, data);\n }\n\n async read(key: string): Promise<Buffer> {\n const filePath = this.resolvePath(key);\n return fs.readFile(filePath);\n }\n\n async list(prefix?: string): Promise<string[]> {\n const results: string[] = [];\n await this.walkDir(this.baseDir, '', results);\n\n if (prefix) {\n return results.filter((f) => f.startsWith(prefix));\n }\n return results;\n }\n\n async exists(key: string): Promise<boolean> {\n const filePath = this.resolvePath(key);\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n }\n\n async delete(key: string): Promise<void> {\n const filePath = this.resolvePath(key);\n await fs.rm(filePath, { force: true });\n }\n\n private async walkDir(dir: string, relative: string, results: string[]): Promise<void> {\n let entries;\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const rel = relative ? `${relative}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n await this.walkDir(path.join(dir, entry.name), rel, results);\n } else {\n results.push(rel);\n }\n }\n }\n}\n\nexport function createStorageClient(baseDir?: string): LocalStorage {\n return new LocalStorage(baseDir);\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';\nimport { getPassword } from './keychain.js';\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 // 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 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 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 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 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 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 the native keychain is available.\n * Always true — no native npm deps required. The underlying OS tool\n * (secret-tool, security, CredManager) may still be absent, in which\n * case getPassword() silently returns null per credential.\n */\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n// Export singleton instance\nexport const secretsLoader = new SecretsLoader();\n\nexport default secretsLoader;\n","/**\n * Native OS Credential Storage\n *\n * Read/write/delete passwords in the OS keychain without any native npm dependencies.\n * Ported from sinch-cli/src/lib/keychain.ts.\n *\n * - Windows: PowerShell + Win32 CredManager API (advapi32.dll)\n * - macOS: `security` CLI (Keychain Access)\n * - Linux: `secret-tool` CLI (libsecret)\n *\n * @internal Dev-only — used by SecretsLoader for F5 debugging\n */\n\nimport { execFile, spawn } from 'child_process';\nimport { promisify } from 'util';\n\nconst execFileAsync = promisify(execFile);\n\ninterface KeychainBackend {\n getPassword(service: string, account: string): Promise<string | null>;\n setPassword(service: string, account: string, password: string): Promise<void>;\n deletePassword(service: string, account: string): Promise<boolean>;\n}\n\n// Helper: base64-encode a string for safe PowerShell parameter injection\nfunction b64(value: string): string {\n return Buffer.from(value, 'utf8').toString('base64');\n}\n\nfunction psParam(name: string, value: string): string {\n return `$${name} = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${b64(value)}'));`;\n}\n\n// --- Windows: PowerShell + Win32 CredManager API ---\n\nconst WIN32_CRED_READ_SCRIPT = `\nAdd-Type -TypeDefinition @'\nusing System;\nusing System.Runtime.InteropServices;\npublic class CredManager {\n [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]\n private struct CREDENTIAL {\n public int Flags;\n public int Type;\n public IntPtr TargetName;\n public IntPtr Comment;\n public long LastWritten;\n public int CredentialBlobSize;\n public IntPtr CredentialBlob;\n public int Persist;\n public int AttributeCount;\n public IntPtr Attributes;\n public IntPtr TargetAlias;\n public IntPtr UserName;\n }\n [DllImport(\"advapi32.dll\", SetLastError=true, CharSet=CharSet.Unicode)]\n private static extern bool CredReadW(string target, int type, int flags, out IntPtr cred);\n [DllImport(\"advapi32.dll\")]\n private static extern void CredFree(IntPtr cred);\n public static string Read(string target) {\n IntPtr credPtr;\n if (!CredReadW(target, 1, 0, out credPtr)) return null;\n try {\n CREDENTIAL c = (CREDENTIAL)Marshal.PtrToStructure(credPtr, typeof(CREDENTIAL));\n if (c.CredentialBlobSize > 0 && c.CredentialBlob != IntPtr.Zero)\n return Marshal.PtrToStringUni(c.CredentialBlob, c.CredentialBlobSize / 2);\n return \"\";\n } finally { CredFree(credPtr); }\n }\n}\n'@\n$r = [CredManager]::Read($target)\nif ($r -ne $null) { [Console]::Write($r) }\nelse { exit 1 }\n`;\n\nconst WIN32_CRED_WRITE_SCRIPT = `\nAdd-Type -TypeDefinition @'\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Text;\npublic class CredWriter {\n [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]\n private struct CREDENTIAL {\n public int Flags;\n public int Type;\n public string TargetName;\n public string Comment;\n public long LastWritten;\n public int CredentialBlobSize;\n public IntPtr CredentialBlob;\n public int Persist;\n public int AttributeCount;\n public IntPtr Attributes;\n public string TargetAlias;\n public string UserName;\n }\n [DllImport(\"advapi32.dll\", SetLastError=true, CharSet=CharSet.Unicode)]\n private static extern bool CredWriteW(ref CREDENTIAL cred, int flags);\n public static bool Write(string target, string password) {\n byte[] blob = Encoding.Unicode.GetBytes(password);\n CREDENTIAL c = new CREDENTIAL();\n c.Type = 1;\n c.TargetName = target;\n c.CredentialBlobSize = blob.Length;\n c.CredentialBlob = Marshal.AllocHGlobal(blob.Length);\n Marshal.Copy(blob, 0, c.CredentialBlob, blob.Length);\n c.Persist = 2;\n try { return CredWriteW(ref c, 0); }\n finally { Marshal.FreeHGlobal(c.CredentialBlob); }\n }\n}\n'@\nif (-not [CredWriter]::Write($target, $password)) { exit 1 }\n`;\n\nconst WIN32_CRED_DELETE_SCRIPT = `\nAdd-Type -TypeDefinition @'\nusing System;\nusing System.Runtime.InteropServices;\npublic class CredDeleter {\n [DllImport(\"advapi32.dll\", SetLastError=true, CharSet=CharSet.Unicode)]\n private static extern bool CredDeleteW(string target, int type, int flags);\n public static bool Delete(string target) { return CredDeleteW(target, 1, 0); }\n}\n'@\nif (-not [CredDeleter]::Delete($target)) { exit 1 }\n`;\n\nfunction winTarget(service: string, account: string): string {\n return `${service}/${account}`;\n}\n\nconst windowsKeychain: KeychainBackend = {\n async getPassword(service: string, account: string): Promise<string | null> {\n try {\n const params = psParam('target', winTarget(service, account));\n const { stdout } = await execFileAsync(\n 'powershell.exe',\n ['-NoProfile', '-NonInteractive', '-Command', params + WIN32_CRED_READ_SCRIPT],\n { timeout: 15000, windowsHide: true },\n );\n return stdout;\n } catch {\n return null;\n }\n },\n\n async setPassword(service: string, account: string, password: string): Promise<void> {\n const params = psParam('target', winTarget(service, account)) + psParam('password', password);\n await execFileAsync(\n 'powershell.exe',\n ['-NoProfile', '-NonInteractive', '-Command', params + WIN32_CRED_WRITE_SCRIPT],\n { timeout: 15000, windowsHide: true },\n );\n },\n\n async deletePassword(service: string, account: string): Promise<boolean> {\n try {\n const params = psParam('target', winTarget(service, account));\n await execFileAsync(\n 'powershell.exe',\n ['-NoProfile', '-NonInteractive', '-Command', params + WIN32_CRED_DELETE_SCRIPT],\n { timeout: 15000, windowsHide: true },\n );\n return true;\n } catch {\n return false;\n }\n },\n};\n\n// --- macOS: security CLI ---\n\nconst macKeychain: KeychainBackend = {\n async getPassword(service: string, account: string): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\n 'security',\n ['find-generic-password', '-s', service, '-a', account, '-w'],\n { timeout: 15000 },\n );\n return stdout.trimEnd();\n } catch {\n return null;\n }\n },\n\n async setPassword(service: string, account: string, password: string): Promise<void> {\n await execFileAsync(\n 'security',\n ['add-generic-password', '-U', '-s', service, '-a', account, '-w', password],\n { timeout: 15000 },\n );\n },\n\n async deletePassword(service: string, account: string): Promise<boolean> {\n try {\n await execFileAsync(\n 'security',\n ['delete-generic-password', '-s', service, '-a', account],\n { timeout: 15000 },\n );\n return true;\n } catch {\n return false;\n }\n },\n};\n\n// --- Linux: secret-tool CLI ---\n\nconst linuxKeychain: KeychainBackend = {\n async getPassword(service: string, account: string): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\n 'secret-tool',\n ['lookup', 'service', service, 'account', account],\n { timeout: 15000 },\n );\n return stdout.trimEnd();\n } catch {\n return null;\n }\n },\n\n // secret-tool reads password from stdin (avoids exposing it in process args)\n async setPassword(service: string, account: string, password: string): Promise<void> {\n const child = spawn(\n 'secret-tool',\n ['store', '--label', `${service}/${account}`, 'service', service, 'account', account],\n { stdio: ['pipe', 'pipe', 'pipe'] },\n );\n child.stdin.write(password);\n child.stdin.end();\n await new Promise<void>((resolve, reject) => {\n child.on('close', (code: number) =>\n code === 0 ? resolve() : reject(new Error('secret-tool store failed')),\n );\n child.on('error', reject);\n });\n },\n\n async deletePassword(service: string, account: string): Promise<boolean> {\n try {\n await execFileAsync(\n 'secret-tool',\n ['clear', 'service', service, 'account', account],\n { timeout: 15000 },\n );\n return true;\n } catch {\n return false;\n }\n },\n};\n\n// --- Platform dispatch ---\n\nfunction getBackend(): KeychainBackend {\n switch (process.platform) {\n case 'win32':\n return windowsKeychain;\n case 'darwin':\n return macKeychain;\n default:\n return linuxKeychain;\n }\n}\n\nconst backend = getBackend();\n\nexport async function getPassword(service: string, account: string): Promise<string | null> {\n return backend.getPassword(service, account);\n}\n\nexport async function setPassword(service: string, account: string, password: string): Promise<void> {\n return backend.setPassword(service, account, password);\n}\n\nexport async function deletePassword(service: string, account: string): Promise<boolean> {\n return backend.deletePassword(service, account);\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 /**\n * Build a full tunnel URL with optional sub-path and tunnel query param.\n * e.g. buildTunnelUrl('/webhook/conversation') →\n * https://tunnel.fn.sinch.com/ingress/webhook/conversation?tunnel=01KKT...\n */\n private buildTunnelUrl(path?: string): string {\n const base = this.tunnelUrl!.replace(/\\/$/, '');\n return `${base}${path || ''}?tunnel=${this.tunnelId}`;\n }\n\n private handleWelcomeMessage(message: TunnelMessage): void {\n // Extract tunnelId and publicUrl (base ingress URL without query param)\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 const verbose = process.env.VERBOSE === 'true';\n console.log(`Forwarding ${message.method} request to ${message.path}`);\n if (verbose && message.body) {\n console.log(` ← Request body: ${message.body.substring(0, 2000)}`);\n }\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 if (verbose) {\n console.log(` → Response ${response.status}: ${body.substring(0, 2000)}`);\n }\n this.ws?.send(JSON.stringify(responseMessage));\n } catch (error: any) {\n console.error(`Error forwarding request: ${error.message} (${error.response?.status || 'no response'})`);\n if (verbose && error.response?.data) {\n console.error(` → Error body: ${typeof error.response.data === 'string' ? error.response.data : JSON.stringify(error.response.data)}`.substring(0, 2000));\n }\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.buildTunnelUrl('/webhook/conversation'), 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.buildTunnelUrl(),\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 if (!this.tunnelUrl || !this.tunnelId) return null;\n return this.buildTunnelUrl();\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';\nimport { randomBytes } from 'crypto';\nimport { resetSinchClients } from '@sinch/functions-runtime-shared';\n\nexport interface WebhookConfig {\n conversationWebhookId?: string;\n originalTarget?: string;\n voiceConfigured?: boolean;\n}\n\n/** Matches deployed function URLs like *.fn-dev.sinch.com, *.fn.sinch.com */\nconst SINCH_FN_URL_PATTERN = /\\.fn(-\\w+)?\\.sinch\\.com/;\n\nfunction isOurWebhook(target: string | undefined): boolean {\n return !!target && SINCH_FN_URL_PATTERN.test(target);\n}\n\nfunction isTunnelUrl(target: string | undefined): boolean {\n return !!target && target.includes('tunnel.fn');\n}\n\n/**\n * Configure Conversation API webhooks to point to tunnel URL.\n * Finds the existing deployed webhook and updates its target to the tunnel URL.\n * The original target is saved so it can be restored on disconnect.\n */\nexport async function configureConversationWebhooks(\n webhookUrl: 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 console.log(`💬 Conversation webhook URL: ${webhookUrl}`);\n\n const sinchClient = new SinchClient({\n projectId,\n keyId,\n keySecret,\n });\n\n // List existing webhooks for this app\n const webhooksResult = await sinchClient.conversation.webhooks.list({\n app_id: conversationAppId,\n });\n const existingWebhooks = webhooksResult.webhooks || [];\n\n // Find the deployed webhook (matches *.fn[-env].sinch.com)\n const deployedWebhook = existingWebhooks.find(\n (w: { target?: string }) => isOurWebhook(w.target)\n );\n\n if (!deployedWebhook || !deployedWebhook.id) {\n console.log('⚠️ No deployed webhook found — deploy first');\n return;\n }\n\n // Save original state so we can restore on disconnect\n config.conversationWebhookId = deployedWebhook.id;\n config.originalTarget = deployedWebhook.target;\n\n // Generate HMAC secret for this tunnel session (256-bit)\n const hmacSecret = randomBytes(32).toString('hex');\n process.env.CONVERSATION_WEBHOOK_SECRET = hmacSecret;\n resetSinchClients(); // Invalidate cached validator so it picks up the new secret\n\n // Update the webhook target and secret\n await sinchClient.conversation.webhooks.update({\n webhook_id: deployedWebhook.id,\n webhookUpdateRequestBody: {\n target: webhookUrl,\n secret: hmacSecret,\n },\n update_mask: ['target', 'secret'],\n });\n\n console.log(`✅ Updated Conversation webhook to tunnel: ${webhookUrl}`);\n console.log('🔒 HMAC secret configured for webhook signature validation');\n console.log('💬 Send a message to your Conversation app to test!');\n } catch (error: unknown) {\n console.log('⚠️ Could not configure Conversation webhooks:', error instanceof Error ? error.message : error);\n }\n}\n\n/**\n * Restore the Conversation webhook target to its original deployed URL.\n * Handles crash recovery: if the saved originalTarget is itself a tunnel URL,\n * derives the deployed URL from FUNCTION_NAME or FUNCTION_ID.\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 // Determine the target to restore\n let restoreTarget = config.originalTarget;\n\n if (!restoreTarget || isTunnelUrl(restoreTarget)) {\n // Crash recovery: originalTarget is a tunnel URL (stale from previous crash)\n // Derive the deployed URL from env vars\n const functionName = process.env.FUNCTION_NAME || process.env.FUNCTION_ID;\n if (functionName) {\n restoreTarget = `https://${functionName}.fn-dev.sinch.com/webhook/conversation`;\n console.log(`🔧 Derived restore target from env: ${restoreTarget}`);\n } else {\n console.log('⚠️ Cannot restore webhook — no FUNCTION_NAME or FUNCTION_ID available');\n return;\n }\n }\n\n await sinchClient.conversation.webhooks.update({\n webhook_id: config.conversationWebhookId,\n webhookUpdateRequestBody: {\n target: restoreTarget,\n },\n update_mask: ['target'],\n });\n\n console.log(`🔄 Restored webhook target to: ${restoreTarget}`);\n config.conversationWebhookId = undefined;\n config.originalTarget = undefined;\n delete process.env.CONVERSATION_WEBHOOK_SECRET;\n resetSinchClients();\n } catch (error: unknown) {\n console.log('⚠️ Could not restore Conversation webhook:', error instanceof Error ? error.message : error);\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: unknown) {\n console.log('⚠️ Could not configure ElevenLabs:', error instanceof Error ? error.message : error);\n }\n}\n"],"mappings":"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","names":["path","createRequire","pathToFileURL","fs","AgentProvider","createRequire","requireCjs","path","fs","fs","path","path","fs","path","fs","path","path","fs","SinchClient","SinchClient","randomBytes","path","requireCjs","createRequire","findFunctionPath","path","fs","pathToFileURL"]}
|