@sinch/functions-runtime 0.3.8 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { ConversationService } from '@sinch/conversation';
4
4
  import { NumbersService } from '@sinch/numbers';
5
+ import { Conversation, ConversationService } from '@sinch/sdk-core';
5
6
  import { SmsService } from '@sinch/sms';
6
7
  import { Voice, VoiceService } from '@sinch/voice';
7
8
  import { Express as Express$1, NextFunction, Request as Request$1, Response as Response$1 } from 'express';
@@ -377,7 +378,15 @@ export declare const MenuTemplates: {
377
378
  */
378
379
  readonly numericInput: (prompt: string, digits?: number) => MenuStructure;
379
380
  };
380
- declare enum AgentProvider {
381
+ /**
382
+ * Connect Agent Action for SVAML Builders
383
+ *
384
+ * Provides the ability to connect voice calls to AI agents via SIP.
385
+ */
386
+ /**
387
+ * Supported AI agent providers
388
+ */
389
+ export declare enum AgentProvider {
381
390
  ElevenLabs = "elevenlabs"
382
391
  }
383
392
  /**
@@ -557,6 +566,21 @@ export declare class IceSvamlBuilder extends BaseSvamlBuilder<IceSvamlBuilder> {
557
566
  *
558
567
  * @param number - E.164 formatted phone number (e.g., '+15551234567')
559
568
  * @param options - Connection options
569
+ *
570
+ * @example
571
+ * ```typescript
572
+ * // Simple connect
573
+ * new IceSvamlBuilder().connectPstn('+15551234567').build();
574
+ *
575
+ * // With options: caller ID, timeout, and AMD
576
+ * new IceSvamlBuilder()
577
+ * .connectPstn('+15551234567', {
578
+ * cli: '+15559876543',
579
+ * timeout: 30,
580
+ * amd: { enabled: true },
581
+ * })
582
+ * .build();
583
+ * ```
560
584
  */
561
585
  connectPstn(number: string, options?: ConnectPstnOptions): this;
562
586
  /**
@@ -585,6 +609,22 @@ export declare class IceSvamlBuilder extends BaseSvamlBuilder<IceSvamlBuilder> {
585
609
  *
586
610
  * @param menus - Array of menu definitions or MenuStructure from createMenu().build()
587
611
  * @param options - Menu options
612
+ *
613
+ * @example
614
+ * ```typescript
615
+ * // Using MenuTemplates
616
+ * new IceSvamlBuilder()
617
+ * .runMenu(MenuTemplates.business('Acme Corp'))
618
+ * .build();
619
+ *
620
+ * // Using createMenu builder
621
+ * const menu = createMenu()
622
+ * .prompt('Press 1 for sales, 2 for support.')
623
+ * .option('1', 'return(sales)')
624
+ * .option('2', 'return(support)')
625
+ * .build();
626
+ * new IceSvamlBuilder().runMenu(menu).build();
627
+ * ```
588
628
  */
589
629
  runMenu(menus: Menu[] | MenuStructure, options?: RunMenuOptions): this;
590
630
  /**
@@ -592,6 +632,14 @@ export declare class IceSvamlBuilder extends BaseSvamlBuilder<IceSvamlBuilder> {
592
632
  *
593
633
  * @param holdPrompt - Prompt to play while on hold
594
634
  * @param options - Park options
635
+ *
636
+ * @example
637
+ * ```typescript
638
+ * // Park with hold music prompt
639
+ * new IceSvamlBuilder()
640
+ * .park('Please hold while we connect you.', { maxDuration: 120 })
641
+ * .build();
642
+ * ```
595
643
  */
596
644
  park(holdPrompt?: string, options?: ParkOptions): this;
597
645
  /**
@@ -712,15 +760,30 @@ export declare function createPieBuilder(): PieSvamlBuilder;
712
760
  /**
713
761
  * Cache interface for Sinch Functions
714
762
  *
715
- * Both dev (LocalCache) and prod (DaprCache) implement this interface,
763
+ * Both dev (LocalCache) and prod (ApiBackedCache) implement this interface,
716
764
  * allowing seamless package swap during deployment.
717
765
  */
718
766
  /**
719
767
  * Function cache interface
720
768
  *
721
769
  * Provides key-value storage with TTL support.
722
- * In development, uses in-memory storage.
723
- * In production, uses Dapr state store.
770
+ * In development, uses in-memory storage (data lost on restart).
771
+ * In production, uses persistent shared storage across instances.
772
+ *
773
+ * Access via `context.cache` — do not construct directly.
774
+ *
775
+ * @example
776
+ * ```typescript
777
+ * // Store a session with 30-minute TTL
778
+ * await context.cache.set('session:abc', { userId: 'u1' }, 1800);
779
+ *
780
+ * // Retrieve it later
781
+ * const session = await context.cache.get<{ userId: string }>('session:abc');
782
+ *
783
+ * // List and batch retrieve
784
+ * const keys = await context.cache.keys('session:*');
785
+ * const all = await context.cache.getMany(keys);
786
+ * ```
724
787
  */
725
788
  export interface IFunctionCache {
726
789
  /**
@@ -729,6 +792,11 @@ export interface IFunctionCache {
729
792
  * @param key - Cache key
730
793
  * @param value - Value to store (will be JSON serialized)
731
794
  * @param ttlSeconds - Time to live in seconds (default: 3600)
795
+ *
796
+ * @example
797
+ * ```typescript
798
+ * await context.cache.set('user:123', { name: 'Alice' }, 3600);
799
+ * ```
732
800
  */
733
801
  set<T = unknown>(key: string, value: T, ttlSeconds?: number): Promise<void>;
734
802
  /**
@@ -736,6 +804,12 @@ export interface IFunctionCache {
736
804
  *
737
805
  * @param key - Cache key
738
806
  * @returns The stored value or null if not found/expired
807
+ *
808
+ * @example
809
+ * ```typescript
810
+ * const user = await context.cache.get<{ name: string }>('user:123');
811
+ * if (user) console.log(user.name);
812
+ * ```
739
813
  */
740
814
  get<T = unknown>(key: string): Promise<T | null>;
741
815
  /**
@@ -757,6 +831,12 @@ export interface IFunctionCache {
757
831
  * @param key - Cache key
758
832
  * @param additionalSeconds - Additional seconds to add to TTL
759
833
  * @returns true if the key exists and TTL was extended
834
+ *
835
+ * @example
836
+ * ```typescript
837
+ * // Keep session alive for another 10 minutes
838
+ * await context.cache.extend('session:abc', 600);
839
+ * ```
760
840
  */
761
841
  extend(key: string, additionalSeconds: number): Promise<boolean>;
762
842
  /**
@@ -764,6 +844,11 @@ export interface IFunctionCache {
764
844
  *
765
845
  * @param pattern - Pattern with * wildcard (default: '*')
766
846
  * @returns Array of matching keys
847
+ *
848
+ * @example
849
+ * ```typescript
850
+ * const sessionKeys = await context.cache.keys('session:*');
851
+ * ```
767
852
  */
768
853
  keys(pattern?: string): Promise<string[]>;
769
854
  /**
@@ -771,9 +856,55 @@ export interface IFunctionCache {
771
856
  *
772
857
  * @param keys - Array of keys to retrieve
773
858
  * @returns Object with keys and their values (or null if not found)
859
+ *
860
+ * @example
861
+ * ```typescript
862
+ * const keys = await context.cache.keys('user:*');
863
+ * const users = await context.cache.getMany<User>(keys);
864
+ * ```
774
865
  */
775
866
  getMany<T = unknown>(keys: string[]): Promise<Record<string, T | null>>;
776
867
  }
868
+ /**
869
+ * Storage interface for Sinch Functions
870
+ *
871
+ * Both dev (LocalStorage) and prod (S3Storage) implement this interface,
872
+ * allowing seamless package swap during deployment.
873
+ */
874
+ /**
875
+ * Function storage interface
876
+ *
877
+ * Provides file/blob storage for persistent data.
878
+ * In development, uses the local filesystem (./storage/ directory).
879
+ * In production, uses S3 with local disk caching for reads.
880
+ *
881
+ * Access via `context.storage` — do not construct directly.
882
+ *
883
+ * @example
884
+ * ```typescript
885
+ * // Write a file
886
+ * await context.storage.write('reports/daily.json', JSON.stringify(data));
887
+ *
888
+ * // Read it back
889
+ * const buf = await context.storage.read('reports/daily.json');
890
+ * const data = JSON.parse(buf.toString());
891
+ *
892
+ * // List files
893
+ * const files = await context.storage.list('reports/');
894
+ *
895
+ * // Check existence and delete
896
+ * if (await context.storage.exists('reports/old.json')) {
897
+ * await context.storage.delete('reports/old.json');
898
+ * }
899
+ * ```
900
+ */
901
+ export interface IFunctionStorage {
902
+ write(key: string, data: string | Buffer): Promise<void>;
903
+ read(key: string): Promise<Buffer>;
904
+ list(prefix?: string): Promise<string[]>;
905
+ exists(key: string): Promise<boolean>;
906
+ delete(key: string): Promise<void>;
907
+ }
777
908
  /**
778
909
  * Function configuration with environment variables
779
910
  */
@@ -790,13 +921,30 @@ export interface FunctionConfig {
790
921
  /**
791
922
  * Main function context object passed to all handlers
792
923
  *
793
- * Note: Call-specific data like callId is available on the callback event data,
924
+ * Every handler receives this as its first argument. It provides access to
925
+ * configuration, cache, SDK clients, and environment variables.
926
+ *
927
+ * @remarks
928
+ * Call-specific data like callId is available on the callback event data,
794
929
  * not on the context object.
930
+ *
931
+ * @example
932
+ * ```typescript
933
+ * export async function ice(context, event) {
934
+ * const greeting = context.config.variables?.GREETING ?? 'Hello!';
935
+ * await context.cache.set('lastCaller', event.cli, 3600);
936
+ * return new IceSvamlBuilder().say(greeting).hangup().build();
937
+ * }
938
+ * ```
795
939
  */
796
940
  export interface FunctionContext {
797
941
  /** Configuration including environment variables */
798
942
  config: FunctionConfig;
799
- /** Cache client for persistent data */
943
+ /**
944
+ * Key-value cache with TTL support.
945
+ * In-memory during development, persistent and shared in production.
946
+ * @see {@link IFunctionCache} for available methods
947
+ */
800
948
  cache: IFunctionCache;
801
949
  /** Request ID for tracing */
802
950
  requestId?: string;
@@ -804,14 +952,57 @@ export interface FunctionContext {
804
952
  timestamp?: string;
805
953
  /** Environment variables */
806
954
  env?: Record<string, string | undefined>;
807
- /** Sinch Voice SDK client (if available) */
955
+ /**
956
+ * Sinch Voice SDK client.
957
+ * Available when `VOICE_APPLICATION_KEY` and `VOICE_APPLICATION_SECRET` are set.
958
+ */
808
959
  voice?: VoiceService;
809
- /** Sinch Conversation SDK client (if available) */
960
+ /**
961
+ * Sinch Conversation SDK client.
962
+ * Available when `CONVERSATION_APP_ID` is set.
963
+ */
810
964
  conversation?: ConversationService;
811
- /** Sinch SMS SDK client (if available) */
965
+ /**
966
+ * Sinch SMS SDK client.
967
+ * Available when `SMS_SERVICE_PLAN_ID` is set.
968
+ */
812
969
  sms?: SmsService;
813
- /** Sinch Numbers SDK client (if available) */
970
+ /**
971
+ * Sinch Numbers SDK client.
972
+ * Available when `ENABLE_NUMBERS_API=true` is set.
973
+ */
814
974
  numbers?: NumbersService;
975
+ /**
976
+ * Persistent file/blob storage.
977
+ * Local filesystem during development, S3-backed in production.
978
+ * @see {@link IFunctionStorage} for available methods
979
+ */
980
+ storage: IFunctionStorage;
981
+ /**
982
+ * File path to a SQLite database for persistent structured data.
983
+ * The database file is managed by a Litestream sidecar in production
984
+ * (continuous WAL replication to S3). In development, it's a local file.
985
+ *
986
+ * Use any SQLite library — `sql.js` (pure WASM, no native deps) or
987
+ * `better-sqlite3` (native C++, fastest but requires build tooling).
988
+ *
989
+ * @example
990
+ * ```typescript
991
+ * // sql.js (recommended — works everywhere)
992
+ * import initSqlJs from 'sql.js';
993
+ * const SQL = await initSqlJs();
994
+ * const buf = existsSync(context.database) ? readFileSync(context.database) : undefined;
995
+ * const db = new SQL.Database(buf);
996
+ * db.run('CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY, value TEXT)');
997
+ * writeFileSync(context.database, Buffer.from(db.export()));
998
+ *
999
+ * // better-sqlite3 (fastest — needs python3/make/g++)
1000
+ * import Database from 'better-sqlite3';
1001
+ * const db = new Database(context.database);
1002
+ * db.exec('CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY, value TEXT)');
1003
+ * ```
1004
+ */
1005
+ database: string;
815
1006
  /** Read a file from the assets/ directory (private, not served over HTTP) */
816
1007
  assets(filename: string): Promise<string>;
817
1008
  }
@@ -1041,6 +1232,7 @@ export interface VoiceFunction {
1041
1232
  export type SinchFunction = VoiceFunction;
1042
1233
  /**
1043
1234
  * Options for camelCase key transformation
1235
+ * @internal
1044
1236
  */
1045
1237
  export interface CamelCaseOptions {
1046
1238
  /** Transform nested objects */
@@ -1052,6 +1244,7 @@ export interface CamelCaseOptions {
1052
1244
  }
1053
1245
  /**
1054
1246
  * Options for JSON parsing middleware
1247
+ * @internal
1055
1248
  */
1056
1249
  export interface JsonParsingOptions {
1057
1250
  /** Maximum body size (default: '10mb') */
@@ -1063,6 +1256,7 @@ export interface JsonParsingOptions {
1063
1256
  }
1064
1257
  /**
1065
1258
  * Extended Express Request with rawBody for signature validation
1259
+ * @internal
1066
1260
  */
1067
1261
  export interface SinchRequest extends Request {
1068
1262
  rawBody?: string;
@@ -1075,26 +1269,44 @@ export interface SinchRequest extends Request {
1075
1269
  * - snake_case: call_id -> callId
1076
1270
  * - kebab-case: call-id -> callId
1077
1271
  * - lowercase concatenated: callid -> callId
1272
+ * @internal
1078
1273
  */
1079
1274
  export declare function toCamelCase(str: string): string;
1080
1275
  /**
1081
1276
  * Deep transform object keys to camelCase
1277
+ * @internal
1082
1278
  */
1083
1279
  export declare function transformKeys<T>(obj: T, options?: CamelCaseOptions): T;
1084
1280
  /**
1085
1281
  * Parse JSON with fallback to basic JSON5 support
1282
+ * @internal
1086
1283
  */
1087
1284
  export declare function parseJson(text: string, allowJson5?: boolean): unknown;
1088
1285
  /**
1089
1286
  * Create Express middleware for lenient JSON parsing with camelCase transformation
1287
+ * @internal
1090
1288
  */
1091
1289
  export declare function createLenientJsonParser(options?: JsonParsingOptions): (req: SinchRequest, res: Response, next: NextFunction) => void;
1092
1290
  /**
1093
1291
  * Setup Express app with JSON parsing middleware
1292
+ * @internal
1094
1293
  */
1095
1294
  export declare function setupJsonParsing(app: Express, options?: JsonParsingOptions): Express;
1295
+ /**
1296
+ * Get the landing page HTML content
1297
+ * Exported so production runtime can also use it
1298
+ * @internal
1299
+ */
1300
+ export declare function getLandingPageHtml(): string;
1301
+ /**
1302
+ * Get the favicon SVG content
1303
+ * Exported so production runtime can also use it
1304
+ * @internal
1305
+ */
1306
+ export declare function getFaviconSvg(): string;
1096
1307
  /**
1097
1308
  * Options for creating the Express app
1309
+ * @internal
1098
1310
  */
1099
1311
  export interface AppOptions {
1100
1312
  /** JSON parsing options */
@@ -1106,6 +1318,7 @@ export interface AppOptions {
1106
1318
  }
1107
1319
  /**
1108
1320
  * Options for setting up the request handler
1321
+ * @internal
1109
1322
  */
1110
1323
  export interface RequestHandlerOptions {
1111
1324
  /** Function to load user code module (can be sync or async for ESM) */
@@ -1133,13 +1346,14 @@ export interface RequestHandlerOptions {
1133
1346
  }
1134
1347
  /**
1135
1348
  * Formatted response structure
1349
+ * @internal
1136
1350
  */
1137
1351
  export interface FormattedResponse {
1138
1352
  statusCode: number;
1139
1353
  headers?: Record<string, string>;
1140
1354
  body?: unknown;
1141
1355
  }
1142
- /** Voice callback function names */
1356
+ /** Voice callback function names @internal */
1143
1357
  export declare const VOICE_CALLBACKS: readonly [
1144
1358
  "ice",
1145
1359
  "ace",
@@ -1147,7 +1361,7 @@ export declare const VOICE_CALLBACKS: readonly [
1147
1361
  "dice",
1148
1362
  "notify"
1149
1363
  ];
1150
- /** Notification-only events (don't require SVAML response) */
1364
+ /** Notification-only events (don't require SVAML response) @internal */
1151
1365
  export declare const NOTIFICATION_EVENTS: readonly [
1152
1366
  "dice",
1153
1367
  "notify"
@@ -1156,32 +1370,39 @@ export type VoiceCallback = (typeof VOICE_CALLBACKS)[number];
1156
1370
  export type NotificationEvent = (typeof NOTIFICATION_EVENTS)[number];
1157
1371
  /**
1158
1372
  * Check if a function name is a voice callback
1373
+ * @internal
1159
1374
  */
1160
1375
  export declare function isVoiceCallback(functionName: string): functionName is VoiceCallback;
1161
1376
  /**
1162
1377
  * Check if a function is a notification-only event
1378
+ * @internal
1163
1379
  */
1164
1380
  export declare function isNotificationEvent(functionName: string): functionName is NotificationEvent;
1165
1381
  /**
1166
1382
  * Extract function name from request path or body
1383
+ * @internal
1167
1384
  */
1168
1385
  export declare function extractFunctionName(path: string, body?: {
1169
1386
  event?: string;
1170
1387
  }): string;
1171
1388
  /**
1172
1389
  * Generate unique request ID
1390
+ * @internal
1173
1391
  */
1174
1392
  export declare function generateRequestId(): string;
1175
1393
  /**
1176
1394
  * Format SVAML response for voice callbacks
1395
+ * @internal
1177
1396
  */
1178
1397
  export declare function formatSvamlResponse(result: unknown, functionName: string): FormattedResponse;
1179
1398
  /**
1180
1399
  * Format custom endpoint response
1400
+ * @internal
1181
1401
  */
1182
1402
  export declare function formatCustomResponse(result: unknown): FormattedResponse;
1183
1403
  /**
1184
1404
  * Validate voice callback request
1405
+ * @internal
1185
1406
  */
1186
1407
  export declare function validateVoiceRequest(body: unknown): {
1187
1408
  valid: boolean;
@@ -1193,22 +1414,27 @@ export declare function validateVoiceRequest(body: unknown): {
1193
1414
  *
1194
1415
  * Note: Call-specific data like callId is available on the callback event data,
1195
1416
  * not on the context object.
1417
+ * @internal
1196
1418
  */
1197
1419
  export declare function buildBaseContext(req: Request, config?: Partial<FunctionConfig>): FunctionContext;
1198
1420
  /**
1199
1421
  * Handle voice callback execution
1422
+ * @internal
1200
1423
  */
1201
1424
  export declare function handleVoiceCallback(functionName: string, userFunction: SinchFunction, context: FunctionContext, callbackData: unknown, logger?: (...args: unknown[]) => void): Promise<FormattedResponse>;
1202
1425
  /**
1203
1426
  * Handle custom endpoint execution
1427
+ * @internal
1204
1428
  */
1205
1429
  export declare function handleCustomEndpoint(functionName: string, userFunction: SinchFunction, context: FunctionContext, request: FunctionRequest, logger?: (...args: unknown[]) => void): Promise<FormattedResponse>;
1206
1430
  /**
1207
1431
  * Create and configure Express app with standard middleware
1432
+ * @internal
1208
1433
  */
1209
1434
  export declare function createApp(options?: AppOptions): Express;
1210
1435
  /**
1211
1436
  * Setup the main request handler
1437
+ * @internal
1212
1438
  */
1213
1439
  export declare function setupRequestHandler(app: Express, options?: RequestHandlerOptions): void;
1214
1440
  export interface SinchClients {
@@ -1233,83 +1459,868 @@ export declare function getSinchClients(): SinchClients;
1233
1459
  */
1234
1460
  export declare function resetSinchClients(): void;
1235
1461
  /**
1236
- * Simple template renderer for HTML files
1237
- * Replaces {{variableName}} placeholders with actual values
1462
+ * ElevenLabs API Models for Sinch Functions
1463
+ *
1464
+ * TypeScript interfaces matching the C# models for ElevenLabs integration.
1465
+ */
1466
+ /**
1467
+ * Options for initiating an outbound call via ElevenLabs
1238
1468
  */
1239
- export declare class TemplateRender {
1469
+ export interface ElevenLabsCallOptions {
1470
+ /** The ElevenLabs agent ID to use for the call */
1471
+ agentId: string;
1472
+ /** The phone number to call (E.164 format) */
1473
+ toNumber: string;
1474
+ /** The caller ID to display (E.164 format) */
1475
+ fromNumber: string;
1476
+ /** Dynamic variables to pass to the agent */
1477
+ dynamicVariables?: Record<string, string>;
1478
+ }
1479
+ /**
1480
+ * Response from ElevenLabs outbound call API
1481
+ */
1482
+ export interface ElevenLabsOutboundCallResponse {
1483
+ call_id: string;
1484
+ agent_id: string;
1485
+ customer_phone_number: string;
1486
+ agent_phone_number?: string;
1487
+ status: string;
1488
+ }
1489
+ /**
1490
+ * Conversation details from ElevenLabs
1491
+ */
1492
+ export interface ElevenLabsConversationDetails {
1493
+ conversationId: string;
1494
+ agentId: string;
1495
+ status: string;
1496
+ metadata?: ConversationMetadata;
1497
+ transcript?: TranscriptMessage[];
1498
+ analysis?: ConversationAnalysis;
1499
+ }
1500
+ /**
1501
+ * Call metadata
1502
+ */
1503
+ export interface ConversationMetadata {
1504
+ callDurationSeconds?: number;
1505
+ startTime?: Date;
1506
+ endTime?: Date;
1507
+ }
1508
+ /**
1509
+ * A single transcript message
1510
+ */
1511
+ export interface TranscriptMessage {
1512
+ role: "user" | "agent";
1513
+ message: string;
1514
+ timeInCallSeconds?: number;
1515
+ }
1516
+ /**
1517
+ * Conversation analysis results
1518
+ */
1519
+ export interface ConversationAnalysis {
1520
+ summary?: string;
1521
+ customData?: Record<string, unknown>;
1522
+ }
1523
+ /**
1524
+ * Options for auto-configuring ElevenLabs with Sinch SIP trunk.
1525
+ * Matches the C# ElevenLabsAutoConfigOptions.
1526
+ */
1527
+ export interface ElevenLabsAutoConfigOptions {
1528
+ /** The ElevenLabs agent ID to configure */
1529
+ agentId: string;
1530
+ /** Sinch phone number in E.164 format (e.g. +15551234567) */
1531
+ phoneNumber: string;
1532
+ /** SIP trunk address (e.g. "use1.vp.sip.sinch.com") */
1533
+ sipAddress: string;
1534
+ /** SIP trunk username (VOICE_APPLICATION_KEY) */
1535
+ sipUsername: string;
1536
+ /** SIP trunk password (VOICE_APPLICATION_SECRET) */
1537
+ sipPassword: string;
1538
+ /** Base URL for webhook callbacks. If not provided, webhooks won't be configured */
1539
+ webhookBaseUrl?: string;
1540
+ /** Function name used as label in ElevenLabs (default: "Sinch Function") */
1541
+ functionName?: string;
1542
+ }
1543
+ /**
1544
+ * Result of auto-configuration
1545
+ */
1546
+ export interface ElevenLabsAutoConfigResult {
1547
+ success: boolean;
1548
+ phoneNumberId?: string;
1549
+ phoneNumber?: string;
1550
+ sipAddress?: string;
1551
+ agentId?: string;
1552
+ error?: string;
1553
+ }
1554
+ /**
1555
+ * Client for interacting with ElevenLabs Conversational AI
1556
+ */
1557
+ export declare class ElevenLabsClient {
1558
+ private readonly apiKey;
1559
+ constructor(apiKey?: string);
1560
+ private get authHeaders();
1561
+ /**
1562
+ * Initiate an outbound call to a phone number using an ElevenLabs agent
1563
+ */
1564
+ makeCall(options: ElevenLabsCallOptions): Promise<ElevenLabsOutboundCallResponse>;
1565
+ /**
1566
+ * Get conversation details including transcript and analysis
1567
+ */
1568
+ getConversationDetails(conversationId: string): Promise<ElevenLabsConversationDetails>;
1569
+ /**
1570
+ * Auto-configure ElevenLabs with Sinch SIP trunk.
1571
+ *
1572
+ * Step 1: Get or import phone number with SIP trunk config
1573
+ * Step 2: Configure agent conversation-init webhook
1574
+ *
1575
+ * Called by tryAutoConfigureAsync (the orchestrator that reads env vars).
1576
+ */
1577
+ autoConfigureAsync(options: ElevenLabsAutoConfigOptions): Promise<ElevenLabsAutoConfigResult>;
1578
+ /**
1579
+ * Check if phone number already exists in ElevenLabs; create or update it.
1580
+ * Matches C# GetOrImportPhoneNumberAsync.
1581
+ */
1582
+ private getOrImportPhoneNumber;
1240
1583
  /**
1241
- * Load and render an HTML template with variables
1242
- * @param templatePath - Path to the HTML template file
1243
- * @param variables - Object containing variables to replace in template
1244
- * @returns Rendered HTML string
1584
+ * Update phone number with agent association and SIP trunk config.
1585
+ * Matches C# UpdatePhoneNumberConfigAsync.
1245
1586
  */
1246
- static render(templatePath: string, variables?: Record<string, any>): string;
1587
+ private updatePhoneNumberConfig;
1247
1588
  /**
1248
- * Get the absolute path to a template file relative to the current directory
1249
- * @param templateName - Name of the template file (e.g., 'index.html')
1250
- * @param baseDir - Base directory to search from (defaults to cwd)
1251
- * @returns Absolute path to the template file
1589
+ * Configure agent webhook for conversation-init events.
1590
+ * Matches C# ConfigureAgentWebhooksAsync.
1252
1591
  */
1253
- static getTemplatePath(templateName: string, baseDir?: string): string;
1592
+ private configureAgentWebhooks;
1593
+ /**
1594
+ * Map API response to our interface
1595
+ */
1596
+ private mapConversationResponse;
1597
+ }
1598
+ /**
1599
+ * Create an ElevenLabs client with the default API key
1600
+ */
1601
+ export declare function createElevenLabsClient(apiKey?: string): ElevenLabsClient;
1602
+ /**
1603
+ * ElevenLabs Webhook Models for Sinch Functions
1604
+ *
1605
+ * TypeScript interfaces for ElevenLabs webhook payloads.
1606
+ */
1607
+ /**
1608
+ * Conversation initialization request from ElevenLabs
1609
+ * Sent when an inbound call is received
1610
+ */
1611
+ export interface ConversationInitRequest {
1612
+ /** The agent ID handling the call */
1613
+ agent_id: string;
1614
+ /** The caller's phone number */
1615
+ caller_id?: string;
1616
+ /** The called number */
1617
+ called_number?: string;
1618
+ /** SIP call ID */
1619
+ call_sid?: string;
1620
+ }
1621
+ /**
1622
+ * Response for conversation initialization
1623
+ * Allows customizing the conversation for this specific caller
1624
+ */
1625
+ export interface ConversationInitResponse {
1626
+ /** Dynamic variables to use in the conversation */
1627
+ dynamic_variables?: Record<string, string>;
1628
+ /** Override agent configuration for this call */
1629
+ conversation_config_override?: ConversationConfigOverride;
1630
+ }
1631
+ /**
1632
+ * Configuration override for a specific conversation
1633
+ */
1634
+ export interface ConversationConfigOverride {
1635
+ agent?: AgentOverride;
1636
+ tts?: TtsOverride;
1637
+ turn?: TurnOverride;
1638
+ }
1639
+ /**
1640
+ * Agent-level configuration override
1641
+ */
1642
+ export interface AgentOverride {
1643
+ /** Custom first message for this call */
1644
+ first_message?: string;
1645
+ /** Language override (e.g., "en", "es") */
1646
+ language?: string;
1647
+ /** Custom prompt override */
1648
+ prompt?: string;
1254
1649
  }
1255
1650
  /**
1256
- * Version extractor utility for reading template versions from README.md files
1651
+ * Text-to-speech configuration override
1257
1652
  */
1258
- export declare class VersionExtractor {
1653
+ export interface TtsOverride {
1654
+ /** Voice ID to use */
1655
+ voice_id?: string;
1656
+ /** Voice settings */
1657
+ voice_settings?: {
1658
+ stability?: number;
1659
+ similarity_boost?: number;
1660
+ };
1661
+ }
1662
+ /**
1663
+ * Turn-taking configuration override
1664
+ */
1665
+ export interface TurnOverride {
1666
+ /** Silence threshold in milliseconds */
1667
+ silence_threshold_ms?: number;
1668
+ }
1669
+ /**
1670
+ * Post-call webhook payload from ElevenLabs
1671
+ */
1672
+ export interface ElevenLabsPostCallWebhook {
1673
+ type: "post_call_transcription";
1674
+ event_timestamp: string;
1675
+ data: ConversationData;
1676
+ }
1677
+ /**
1678
+ * Conversation data in post-call webhook
1679
+ */
1680
+ export interface ConversationData {
1681
+ agent_id: string;
1682
+ conversation_id: string;
1683
+ status: string;
1684
+ user_id?: string;
1685
+ transcript: TranscriptTurn[];
1686
+ metadata: WebhookConversationMetadata;
1687
+ analysis?: WebhookConversationAnalysis;
1688
+ }
1689
+ /**
1690
+ * A single turn in the transcript
1691
+ */
1692
+ export interface TranscriptTurn {
1693
+ role: "user" | "agent";
1694
+ message: string;
1695
+ time_in_call_secs: number;
1696
+ }
1697
+ /**
1698
+ * Conversation metadata in webhook
1699
+ */
1700
+ export interface WebhookConversationMetadata {
1701
+ start_time_unix_secs: number;
1702
+ call_duration_secs: number;
1703
+ cost?: number;
1704
+ termination_reason?: string;
1705
+ }
1706
+ /**
1707
+ * Conversation analysis in webhook
1708
+ */
1709
+ export interface WebhookConversationAnalysis {
1710
+ evaluation_criteria_results?: EvaluationCriteriaResult[];
1711
+ data_collection_results?: DataCollectionResult[];
1712
+ call_successful?: boolean;
1713
+ transcript_summary?: string;
1714
+ }
1715
+ /**
1716
+ * Result of an evaluation criteria check
1717
+ */
1718
+ export interface EvaluationCriteriaResult {
1719
+ criteria_id: string;
1720
+ result: "success" | "failure" | "unknown";
1721
+ rationale?: string;
1722
+ }
1723
+ /**
1724
+ * Result of data collection
1725
+ */
1726
+ export interface DataCollectionResult {
1727
+ data_collection_id: string;
1728
+ value: string;
1729
+ json_schema?: Record<string, unknown>;
1730
+ rationale?: string;
1731
+ }
1732
+ /**
1733
+ * Post-call audio webhook payload
1734
+ */
1735
+ export interface ElevenLabsPostCallAudioWebhook {
1736
+ type: "post_call_audio";
1737
+ event_timestamp: string;
1738
+ data: {
1739
+ conversation_id: string;
1740
+ agent_id: string;
1741
+ /** Base64-encoded MP3 audio */
1742
+ audio_base64: string;
1743
+ };
1744
+ }
1745
+ /**
1746
+ * Call initiation failure webhook
1747
+ */
1748
+ export interface ElevenLabsCallInitiationFailureWebhook {
1749
+ type: "call_initiation_failure";
1750
+ event_timestamp: string;
1751
+ data: {
1752
+ agent_id: string;
1753
+ customer_phone_number: string;
1754
+ failure_reason: string;
1755
+ metadata?: Record<string, unknown>;
1756
+ };
1757
+ }
1758
+ /**
1759
+ * Union type for all ElevenLabs webhook types
1760
+ */
1761
+ export type ElevenLabsWebhook = ElevenLabsPostCallWebhook | ElevenLabsPostCallAudioWebhook | ElevenLabsCallInitiationFailureWebhook;
1762
+ /**
1763
+ * Base controller for handling ElevenLabs webhooks
1764
+ *
1765
+ * @example
1766
+ * ```typescript
1767
+ * class MyElevenLabsHandler extends ElevenLabsController {
1768
+ * async handleConversationInit(request: ConversationInitRequest): Promise<ConversationInitResponse> {
1769
+ * // Customize the conversation based on caller
1770
+ * return {
1771
+ * dynamic_variables: {
1772
+ * customerName: await lookupCustomer(request.caller_id)
1773
+ * }
1774
+ * };
1775
+ * }
1776
+ *
1777
+ * async handlePostCall(webhook: ElevenLabsPostCallWebhook): Promise<void> {
1778
+ * // Save transcript to database
1779
+ * await saveTranscript(webhook.data);
1780
+ * }
1781
+ * }
1782
+ * ```
1783
+ */
1784
+ export declare abstract class ElevenLabsController {
1785
+ /**
1786
+ * Handle conversation initialization webhook
1787
+ * Called when an inbound call is received - allows customizing the conversation
1788
+ *
1789
+ * @param request - The conversation init request with caller info
1790
+ * @returns Response with dynamic variables and/or config overrides
1791
+ */
1792
+ handleConversationInit(request: ConversationInitRequest): Promise<ConversationInitResponse>;
1259
1793
  /**
1260
- * Extract version from README.md file in the template directory
1261
- * Looks for "Template Version: X.X.X" pattern in the last few lines
1262
- * @param templateDir - Path to the template directory containing README.md
1263
- * @returns Version string or default fallback
1794
+ * Handle post-call webhook with transcript and analysis
1795
+ *
1796
+ * @param webhook - The post-call webhook payload
1264
1797
  */
1265
- static getTemplateVersion(templateDir?: string): string;
1798
+ handlePostCall(webhook: ElevenLabsPostCallWebhook): Promise<void>;
1799
+ /**
1800
+ * Handle post-call audio webhook with recording
1801
+ *
1802
+ * @param webhook - The audio webhook with base64-encoded MP3
1803
+ */
1804
+ handlePostCallAudio(webhook: ElevenLabsPostCallAudioWebhook): Promise<void>;
1805
+ /**
1806
+ * Handle call initiation failure webhook
1807
+ *
1808
+ * @param webhook - The failure webhook with error details
1809
+ */
1810
+ handleCallInitiationFailure(webhook: ElevenLabsCallInitiationFailureWebhook): Promise<void>;
1811
+ /**
1812
+ * Express route handler for conversation init endpoint
1813
+ * Mount at: POST /elevenlabs/conversation-init
1814
+ */
1815
+ getConversationInitHandler(): (req: Request, res: Response) => Promise<void>;
1816
+ /**
1817
+ * Express route handler for webhook endpoint
1818
+ * Mount at: POST /elevenlabs/webhook
1819
+ * Handles all webhook types based on the 'type' field
1820
+ */
1821
+ getWebhookHandler(): (req: Request, res: Response) => Promise<void>;
1266
1822
  }
1267
- export interface DefaultEndpointOptions {
1268
- serviceName?: string;
1269
- companyName?: string;
1270
- templateVersion?: string;
1271
- availableEndpoints?: Record<string, string>;
1823
+ /**
1824
+ * Try to auto-configure ElevenLabs from environment variables.
1825
+ * Returns null if ELEVENLABS_AUTO_CONFIGURE is not "true".
1826
+ *
1827
+ * @param webhookUrl - Base URL for webhook callbacks (must be HTTPS in production)
1828
+ * @param functionName - Optional name for labeling in ElevenLabs (max 100 chars)
1829
+ * @param sinchPhoneNumber - Optional phone number override (skips auto-discovery)
1830
+ */
1831
+ export declare function tryAutoConfigureAsync(webhookUrl: string, functionName?: string, sinchPhoneNumber?: string): Promise<ElevenLabsAutoConfigResult | null>;
1832
+ /**
1833
+ * @deprecated Use `tryAutoConfigureAsync` directly. This class wrapper is kept for backwards compatibility.
1834
+ */
1835
+ export declare class ElevenLabsAutoConfigurator {
1836
+ static tryAutoConfigureAsync: typeof tryAutoConfigureAsync;
1272
1837
  }
1273
- export interface HttpRequest {
1274
- method: string;
1275
- path: string;
1276
- query?: Record<string, any>;
1277
- headers?: Record<string, string>;
1278
- body?: any;
1279
- params?: Record<string, string>;
1838
+ /**
1839
+ * ElevenLabs State Management for Sinch Functions
1840
+ *
1841
+ * Singleton to store auto-configuration results for subsequent calls.
1842
+ */
1843
+ /**
1844
+ * State for ElevenLabs configuration
1845
+ */
1846
+ export interface ElevenLabsStateData {
1847
+ /** Phone number ID from Sinch */
1848
+ phoneNumberId?: string;
1849
+ /** The phone number (E.164 format) */
1850
+ phoneNumber?: string;
1851
+ /** The ElevenLabs agent ID */
1852
+ agentId?: string;
1853
+ /** SIP address for the agent */
1854
+ sipAddress?: string;
1855
+ /** Whether auto-configuration has been completed */
1856
+ isConfigured: boolean;
1857
+ /** Timestamp of last configuration */
1858
+ configuredAt?: Date;
1280
1859
  }
1281
- export interface HttpResponse {
1282
- statusCode: number;
1283
- headers: Record<string, string>;
1284
- body: any;
1860
+ declare class ElevenLabsStateManager {
1861
+ private state;
1862
+ /**
1863
+ * Get the current state
1864
+ */
1865
+ getState(): Readonly<ElevenLabsStateData>;
1866
+ /**
1867
+ * Check if ElevenLabs is configured
1868
+ */
1869
+ isConfigured(): boolean;
1870
+ /**
1871
+ * Update state with auto-configuration results
1872
+ */
1873
+ setConfigured(data: Omit<ElevenLabsStateData, "isConfigured" | "configuredAt">): void;
1874
+ /**
1875
+ * Clear the configuration state
1876
+ */
1877
+ clear(): void;
1878
+ /**
1879
+ * Get the phone number ID for making calls
1880
+ */
1881
+ getPhoneNumberId(): string | undefined;
1882
+ /**
1883
+ * Get the SIP address for connecting to the agent
1884
+ */
1885
+ getSipAddress(): string | undefined;
1886
+ /**
1887
+ * Get the configured agent ID
1888
+ */
1889
+ getAgentId(): string | undefined;
1890
+ }
1891
+ /**
1892
+ * Singleton instance of ElevenLabs state
1893
+ */
1894
+ export declare const ElevenLabsState: ElevenLabsStateManager;
1895
+ /**
1896
+ * Message inbound event from Conversation API
1897
+ */
1898
+ export type MessageInboundEvent = Conversation.MessageInboundEvent;
1899
+ /**
1900
+ * Contact message content
1901
+ */
1902
+ export type ContactMessage = Conversation.ContactMessage;
1903
+ /**
1904
+ * Media properties type (URL, thumbnail, filename)
1905
+ */
1906
+ export type MediaProperties = Conversation.MediaProperties;
1907
+ /**
1908
+ * Location message item type (coordinates, title, label)
1909
+ */
1910
+ export type LocationMessageItem = Conversation.LocationMessageItem;
1911
+ /**
1912
+ * Get the text content from an inbound message
1913
+ */
1914
+ export declare function getText(event: MessageInboundEvent): string | undefined;
1915
+ /**
1916
+ * Get media content from an inbound message (images, videos, files)
1917
+ */
1918
+ export declare function getMedia(event: MessageInboundEvent): MediaProperties | undefined;
1919
+ /**
1920
+ * Get postback data from a button/quick reply click
1921
+ */
1922
+ export declare function getPostbackData(event: MessageInboundEvent): string | undefined;
1923
+ /**
1924
+ * Get the contact ID of the sender
1925
+ */
1926
+ export declare function getContactId(event: MessageInboundEvent): string | undefined;
1927
+ /**
1928
+ * Get the conversation ID (for non-DISPATCH mode apps)
1929
+ */
1930
+ export declare function getConversationId(event: MessageInboundEvent): string | undefined;
1931
+ /**
1932
+ * Get the channel name (SMS, WHATSAPP, MESSENGER, etc.)
1933
+ */
1934
+ export declare function getChannel(event: MessageInboundEvent): string | undefined;
1935
+ /**
1936
+ * Get the channel-specific identity (phone number, PSID, etc.)
1937
+ * This is the sender's identity (FROM)
1938
+ */
1939
+ export declare function getIdentity(event: MessageInboundEvent): string | undefined;
1940
+ /**
1941
+ * Get the destination number that the contact sent the message TO.
1942
+ * For SMS/MMS, this is your Sinch number that received the message.
1943
+ * Used automatically by reply() to set SMS_SENDER when replying.
1944
+ */
1945
+ export declare function getTo(event: MessageInboundEvent): string | undefined;
1946
+ /**
1947
+ * Get location data if the message contains a location
1948
+ */
1949
+ export declare function getLocation(event: MessageInboundEvent): LocationMessageItem | undefined;
1950
+ /**
1951
+ * Check if the message is a text message
1952
+ */
1953
+ export declare function isTextMessage(event: MessageInboundEvent): boolean;
1954
+ /**
1955
+ * Check if the message is a media message
1956
+ */
1957
+ export declare function isMediaMessage(event: MessageInboundEvent): boolean;
1958
+ /**
1959
+ * Check if the message is a button/quick reply response
1960
+ */
1961
+ export declare function isPostback(event: MessageInboundEvent): boolean;
1962
+ /**
1963
+ * Extension helper object with all methods bound to an event
1964
+ */
1965
+ export declare function createMessageHelper(event: MessageInboundEvent): {
1966
+ getText: () => string | undefined;
1967
+ getMedia: () => Conversation.MediaProperties | undefined;
1968
+ getPostbackData: () => string | undefined;
1969
+ getContactId: () => string | undefined;
1970
+ getConversationId: () => string | undefined;
1971
+ getChannel: () => string | undefined;
1972
+ getIdentity: () => string | undefined;
1973
+ getTo: () => string | undefined;
1974
+ getLocation: () => Conversation.LocationMessageItem | undefined;
1975
+ isTextMessage: () => boolean;
1976
+ isMediaMessage: () => boolean;
1977
+ isPostback: () => boolean;
1978
+ };
1979
+ /**
1980
+ * Channel type for Conversation API
1981
+ */
1982
+ export type ConversationChannel = "SMS" | "WHATSAPP" | "MESSENGER" | "VIBER" | "RCS" | "INSTAGRAM" | "MMS" | "LINE" | "KAKAOTALK" | "TELEGRAM" | "WECHAT" | "APPLEBC" | "GOOGLEBM" | string;
1983
+ /**
1984
+ * Simplified send message request type that works with SDK
1985
+ */
1986
+ export interface SendMessageRequest {
1987
+ app_id: string;
1988
+ message: {
1989
+ text_message?: {
1990
+ text: string;
1991
+ };
1992
+ };
1993
+ recipient: {
1994
+ identified_by: {
1995
+ channel_identities: Array<{
1996
+ channel: ConversationChannel;
1997
+ identity: string;
1998
+ }>;
1999
+ };
2000
+ };
2001
+ channel_properties?: Record<string, string>;
2002
+ }
2003
+ /**
2004
+ * Create a text reply to an inbound message (replies on same channel).
2005
+ * Automatically sets SMS_SENDER channel property if sending to SMS.
2006
+ *
2007
+ * @param inbound - The inbound message event to reply to
2008
+ * @param text - The reply text
2009
+ * @param smsSender - Optional SMS sender number
2010
+ * @returns A SendMessageRequest ready to send
2011
+ *
2012
+ * @example
2013
+ * ```typescript
2014
+ * await context.conversation.messages.send(
2015
+ * textReply(inbound, "Thanks for your message!", config.FROM_NUMBER)
2016
+ * );
2017
+ * ```
2018
+ */
2019
+ export declare function textReply(inbound: MessageInboundEvent, text: string, smsSender?: string): SendMessageRequest;
2020
+ /**
2021
+ * Create an SMS message to a phone number.
2022
+ *
2023
+ * @param appId - The Conversation API app ID
2024
+ * @param phoneNumber - Phone number in E.164 format (e.g., +15551234567)
2025
+ * @param text - Message text
2026
+ * @param smsSender - SMS sender number (required for SMS channel)
2027
+ */
2028
+ export declare function createSms(appId: string, phoneNumber: string, text: string, smsSender?: string): SendMessageRequest;
2029
+ /**
2030
+ * Create a WhatsApp message to a phone number.
2031
+ *
2032
+ * @param appId - The Conversation API app ID
2033
+ * @param phoneNumber - Phone number in E.164 format (e.g., +15551234567)
2034
+ * @param text - Message text
2035
+ */
2036
+ export declare function createWhatsApp(appId: string, phoneNumber: string, text: string): SendMessageRequest;
2037
+ /**
2038
+ * Create a Facebook Messenger message.
2039
+ *
2040
+ * @param appId - The Conversation API app ID
2041
+ * @param psid - The Page-Scoped ID of the user
2042
+ * @param text - Message text
2043
+ */
2044
+ export declare function createMessenger(appId: string, psid: string, text: string): SendMessageRequest;
2045
+ /**
2046
+ * Create a message for any channel.
2047
+ *
2048
+ * @param appId - The Conversation API app ID
2049
+ * @param channel - Channel name (SMS, WHATSAPP, MESSENGER, VIBER, etc.)
2050
+ * @param identity - Channel-specific identity (phone number, PSID, etc.)
2051
+ * @param text - Message text
2052
+ * @param smsSender - SMS sender number (only used for SMS channel)
2053
+ */
2054
+ export declare function createChannelMessage(appId: string, channel: string, identity: string, text: string, smsSender?: string): SendMessageRequest;
2055
+ /**
2056
+ * ConversationMessage namespace for static helpers
2057
+ */
2058
+ export declare const ConversationMessage: {
2059
+ textReply: typeof textReply;
2060
+ createSms: typeof createSms;
2061
+ createWhatsApp: typeof createWhatsApp;
2062
+ createMessenger: typeof createMessenger;
2063
+ createChannelMessage: typeof createChannelMessage;
2064
+ };
2065
+ /**
2066
+ * Configuration interface for the message builder
2067
+ */
2068
+ export interface MessageBuilderConfig {
2069
+ CONVERSATION_APP_ID?: string;
2070
+ FROM_NUMBER?: string;
1285
2071
  }
1286
- export declare class DefaultEndpointHandler {
2072
+ /**
2073
+ * Fluent builder for creating Conversation API messages.
2074
+ *
2075
+ * @example
2076
+ * ```typescript
2077
+ * // Simple case - use static helper
2078
+ * await context.conversation.messages.send(
2079
+ * ConversationMessage.textReply(inbound, "Hello!")
2080
+ * );
2081
+ *
2082
+ * // Complex case - use builder
2083
+ * const msg = new ConversationMessageBuilder(config)
2084
+ * .fromInbound(inbound)
2085
+ * .text("Hello!")
2086
+ * .build();
2087
+ * await context.conversation.messages.send(msg);
2088
+ * ```
2089
+ */
2090
+ export declare class ConversationMessageBuilder {
2091
+ private config;
2092
+ private appId?;
2093
+ private channel?;
2094
+ private identity?;
2095
+ private conversationId?;
2096
+ private messageText?;
2097
+ /**
2098
+ * Create a new builder with configuration
2099
+ */
2100
+ constructor(config?: MessageBuilderConfig);
1287
2101
  /**
1288
- * Handle the default endpoint with content negotiation
1289
- * @param context - Function context with config and cache
1290
- * @param request - HTTP request object with method, path, query, headers, body, params
1291
- * @param options - Configuration options for the response
1292
- * @returns HTTP response object with statusCode, headers, and body
2102
+ * Pre-fill builder from an inbound message (for replies)
1293
2103
  */
1294
- static handle(context: FunctionContext, request: HttpRequest, options?: DefaultEndpointOptions): Promise<HttpResponse>;
2104
+ fromInbound(inbound: MessageInboundEvent): this;
2105
+ /**
2106
+ * Set the app ID (defaults to CONVERSATION_APP_ID from config)
2107
+ */
2108
+ setAppId(appId: string): this;
2109
+ /**
2110
+ * Set the recipient channel and identity
2111
+ *
2112
+ * @param channel - Channel name (SMS, WHATSAPP, MESSENGER, etc.)
2113
+ * @param identity - Channel-specific identity (phone number, PSID, etc.)
2114
+ */
2115
+ to(channel: string, identity: string): this;
2116
+ /**
2117
+ * Set the conversation ID (for non-DISPATCH mode apps)
2118
+ */
2119
+ setConversationId(conversationId: string): this;
2120
+ /**
2121
+ * Set a text message
2122
+ */
2123
+ text(text: string): this;
2124
+ /**
2125
+ * Build the SendMessageRequest.
2126
+ * Automatically sets SMS_SENDER from config if sending to SMS channel.
2127
+ *
2128
+ * @returns A SendMessageRequest ready to send via context.conversation.messages.send()
2129
+ */
2130
+ build(): SendMessageRequest;
2131
+ }
2132
+ /**
2133
+ * Create a new conversation message builder
2134
+ */
2135
+ export declare function createMessageBuilder(config?: MessageBuilderConfig): ConversationMessageBuilder;
2136
+ /**
2137
+ * Conversation API event types
2138
+ */
2139
+ export type MessageDeliveryEvent = Conversation.MessageDeliveryReceiptEvent;
2140
+ export type EventInboundEvent = Conversation.EventInbound;
2141
+ export type ConversationStartEvent = Conversation.ConversationStartEvent;
2142
+ export type ConversationStopEvent = Conversation.ConversationStopEvent;
2143
+ /**
2144
+ * Configuration for the conversation controller
2145
+ */
2146
+ export interface ConversationControllerConfig {
2147
+ CONVERSATION_APP_ID?: string;
2148
+ FROM_NUMBER?: string;
2149
+ VERBOSE?: string;
1295
2150
  }
1296
- /** @deprecated Import from '@sinch/voice' instead: `import type { Voice } from '@sinch/voice'` then use `Voice.IceRequest` */
2151
+ /**
2152
+ * Base controller for handling Sinch Conversation API webhooks.
2153
+ *
2154
+ * Derived classes override the virtual handlers they need.
2155
+ *
2156
+ * @example
2157
+ * ```typescript
2158
+ * class MyConversationHandler extends ConversationController {
2159
+ * constructor(conversation: ConversationService, config: ConversationControllerConfig) {
2160
+ * super(conversation, config);
2161
+ * }
2162
+ *
2163
+ * async handleMessageInbound(event: MessageInboundEvent): Promise<void> {
2164
+ * const text = getText(event);
2165
+ * if (!text) return;
2166
+ *
2167
+ * // Reply using helper method
2168
+ * await this.conversation.messages.send({
2169
+ * sendMessageRequestBody: this.reply(event, "Thanks for your message!")
2170
+ * });
2171
+ * }
2172
+ * }
2173
+ * ```
2174
+ */
2175
+ export declare abstract class ConversationController {
2176
+ protected conversation?: ConversationService;
2177
+ protected config: ConversationControllerConfig;
2178
+ constructor(conversation: ConversationService | undefined, config?: ConversationControllerConfig);
2179
+ /**
2180
+ * MESSAGE_INBOUND - Called when a user sends a message.
2181
+ * Override this to handle incoming messages from users.
2182
+ */
2183
+ handleMessageInbound(event: MessageInboundEvent): Promise<void>;
2184
+ /**
2185
+ * MESSAGE_DELIVERY - Called when message delivery status updates.
2186
+ * Override this to track delivery receipts.
2187
+ */
2188
+ handleMessageDelivery(event: MessageDeliveryEvent): Promise<void>;
2189
+ /**
2190
+ * EVENT_INBOUND - Called for events like composing indicators.
2191
+ * Override this to handle typing indicators, read receipts, etc.
2192
+ */
2193
+ handleEventInbound(event: EventInboundEvent): Promise<void>;
2194
+ /**
2195
+ * CONVERSATION_START - Called when a conversation begins.
2196
+ * Override this to handle conversation initialization.
2197
+ */
2198
+ handleConversationStart(event: ConversationStartEvent): Promise<void>;
2199
+ /**
2200
+ * CONVERSATION_STOP - Called when a conversation ends.
2201
+ * Override this to handle conversation cleanup.
2202
+ */
2203
+ handleConversationStop(event: ConversationStopEvent): Promise<void>;
2204
+ /**
2205
+ * Gets the sender number from configuration (FROM_NUMBER).
2206
+ * Used for setting SMS_SENDER channel property when sending to SMS channel.
2207
+ */
2208
+ get fromNumber(): string | undefined;
2209
+ /**
2210
+ * Create a text reply to an inbound message.
2211
+ * Automatically sets SMS_SENDER from FROM_NUMBER config.
2212
+ */
2213
+ reply(inbound: MessageInboundEvent, text: string): SendMessageRequest;
2214
+ /**
2215
+ * Create a ConversationMessageBuilder for building messages with full control.
2216
+ */
2217
+ createMessage(): ConversationMessageBuilder;
2218
+ /**
2219
+ * Create a ConversationMessageBuilder pre-filled from an inbound message.
2220
+ */
2221
+ createReply(inbound: MessageInboundEvent): ConversationMessageBuilder;
2222
+ /**
2223
+ * Express route handler for the webhook endpoint.
2224
+ * Mount at: POST /conversation
2225
+ *
2226
+ * Routes to appropriate handler based on event type.
2227
+ * Uses manual JSON parsing as workaround for SDK issues with extra fields.
2228
+ */
2229
+ getWebhookHandler(): (req: Request, res: Response) => Promise<void>;
2230
+ }
2231
+ /**
2232
+ * Converts an E.164 phone number to local/national format.
2233
+ *
2234
+ * @param phoneNumber - The phone number in E.164 format (e.g., "+15551234567")
2235
+ * @param defaultRegion - The default region code (default: "US")
2236
+ * @returns The phone number in national format, or the original if conversion fails
2237
+ *
2238
+ * @example
2239
+ * ```typescript
2240
+ * toLocalPhoneNumber('+15551234567'); // Returns "(555) 123-4567"
2241
+ * toLocalPhoneNumber('+442071234567'); // Returns "020 7123 4567"
2242
+ * ```
2243
+ */
2244
+ export declare function toLocalPhoneNumber(phoneNumber: string, defaultRegion?: string): string;
2245
+ /**
2246
+ * Formats a phone number for display (adds dashes/spaces for readability)
2247
+ *
2248
+ * @param phoneNumber - Phone number in any format
2249
+ * @returns Formatted phone number
2250
+ */
2251
+ export declare function formatPhoneNumber(phoneNumber: string): string;
2252
+ /**
2253
+ * Helper methods for creating common error responses
2254
+ */
2255
+ export declare const VoiceErrorHelper: {
2256
+ /**
2257
+ * Create a standard error response that plays a message and hangs up
2258
+ *
2259
+ * @param message - Error message to speak
2260
+ * @param locale - Language locale (default: "en-US")
2261
+ * @returns SVAML response object
2262
+ */
2263
+ createErrorResponse(message: string, locale?: string): ReturnType<IceSvamlBuilder["build"]>;
2264
+ /**
2265
+ * Create a service unavailable response
2266
+ *
2267
+ * @param locale - Language locale (default: "en-US")
2268
+ * @returns SVAML response object
2269
+ */
2270
+ serviceUnavailable(locale?: string): ReturnType<IceSvamlBuilder["build"]>;
2271
+ /**
2272
+ * Create an invalid input response for PIE handlers
2273
+ *
2274
+ * @param locale - Language locale (default: "en-US")
2275
+ * @returns SVAML response object
2276
+ */
2277
+ invalidInput(locale?: string): ReturnType<PieSvamlBuilder["build"]>;
2278
+ /**
2279
+ * Create a timeout response for PIE handlers
2280
+ *
2281
+ * @param locale - Language locale (default: "en-US")
2282
+ * @returns SVAML response object
2283
+ */
2284
+ timeout(locale?: string): ReturnType<PieSvamlBuilder["build"]>;
2285
+ /**
2286
+ * Create a goodbye response that thanks the caller and hangs up
2287
+ *
2288
+ * @param locale - Language locale (default: "en-US")
2289
+ * @returns SVAML response object
2290
+ */
2291
+ goodbye(locale?: string): ReturnType<IceSvamlBuilder["build"]>;
2292
+ };
2293
+ /**
2294
+ * Formats duration in seconds to human-readable format
2295
+ *
2296
+ * @param seconds - Duration in seconds
2297
+ * @returns Formatted duration string (e.g., "2m 30s")
2298
+ */
2299
+ export declare function formatDuration(seconds: number): string;
2300
+ /**
2301
+ * Extracts the caller's phone number from CLI (Caller ID)
2302
+ *
2303
+ * @param cli - Caller ID string
2304
+ * @returns Normalized phone number
2305
+ */
2306
+ export declare function extractCallerNumber(cli: string | undefined): string | undefined;
2307
+ /** @deprecated Import from '@sinch/voice' instead: `import type { Voice } from '@sinch/voice'` then use `Voice.IceRequest` @internal */
1297
2308
  export type IceCallbackData = Voice.IceRequest;
1298
- /** @deprecated Import from '@sinch/voice' instead */
2309
+ /** @deprecated Import from '@sinch/voice' instead @internal */
1299
2310
  export type AceCallbackData = Voice.AceRequest;
1300
- /** @deprecated Import from '@sinch/voice' instead */
2311
+ /** @deprecated Import from '@sinch/voice' instead @internal */
1301
2312
  export type PieCallbackData = Voice.PieRequest;
1302
- /** @deprecated Import from '@sinch/voice' instead */
2313
+ /** @deprecated Import from '@sinch/voice' instead @internal */
1303
2314
  export type DiceCallbackData = Voice.DiceRequest;
1304
- /** @deprecated Import from '@sinch/voice' instead */
2315
+ /** @deprecated Import from '@sinch/voice' instead @internal */
1305
2316
  export type NotifyCallbackData = Voice.NotifyRequest;
1306
- /** @deprecated Import from '@sinch/voice' instead */
2317
+ /** @deprecated Import from '@sinch/voice' instead @internal */
1307
2318
  export type MenuResult = Voice.MenuResult;
1308
- /** @deprecated Import from '@sinch/voice' instead */
2319
+ /** @deprecated Import from '@sinch/voice' instead @internal */
1309
2320
  export type AmdResult = Voice.AnsweringMachineDetection;
1310
- /** @deprecated Import from '@sinch/voice' instead */
2321
+ /** @deprecated Import from '@sinch/voice' instead @internal */
1311
2322
  export type DisconnectReason = Voice.DiceReasonEnum;
1312
- /** @deprecated Import from '@sinch/voice' instead */
2323
+ /** @deprecated Import from '@sinch/voice' instead @internal */
1313
2324
  export type CallResult = Voice.ResultEnum;
1314
2325
  /**
1315
2326
  * Union type for all voice callback data
@@ -1320,6 +2331,8 @@ export type VoiceCallbackData = Voice.IceRequest | Voice.AceRequest | Voice.PieR
1320
2331
  *
1321
2332
  * Implements IFunctionCache using an in-memory Map with TTL support.
1322
2333
  * Data is lost when the process restarts.
2334
+ *
2335
+ * @internal Dev-only implementation — access cache via `context.cache`
1323
2336
  */
1324
2337
  export declare class LocalCache implements IFunctionCache {
1325
2338
  private cache;
@@ -1347,8 +2360,21 @@ export declare class LocalCache implements IFunctionCache {
1347
2360
  *
1348
2361
  * @param _projectId - Project ID (unused in local development)
1349
2362
  * @param _functionName - Function name (unused in local development)
2363
+ * @internal Dev-only factory — access cache via `context.cache`
1350
2364
  */
1351
2365
  export declare function createCacheClient(_projectId?: string, _functionName?: string): IFunctionCache;
2366
+ export declare class LocalStorage implements IFunctionStorage {
2367
+ private baseDir;
2368
+ constructor(baseDir?: string);
2369
+ private resolvePath;
2370
+ write(key: string, data: string | Buffer): Promise<void>;
2371
+ read(key: string): Promise<Buffer>;
2372
+ list(prefix?: string): Promise<string[]>;
2373
+ exists(key: string): Promise<boolean>;
2374
+ delete(key: string): Promise<void>;
2375
+ private walkDir;
2376
+ }
2377
+ export declare function createStorageClient(baseDir?: string): LocalStorage;
1352
2378
  /**
1353
2379
  * Tunnel Client for Sinch Functions
1354
2380
  *
@@ -1361,7 +2387,10 @@ export declare function createCacheClient(_projectId?: string, _functionName?: s
1361
2387
  * - ElevenLabs auto-configuration (when enabled)
1362
2388
  * - Stale webhook cleanup on connect
1363
2389
  * - Webhook cleanup on disconnect
2390
+ *
2391
+ * @internal Dev-only — used by `sinch functions dev`, not by user code
1364
2392
  */
2393
+ /** @internal */
1365
2394
  export declare class TunnelClient {
1366
2395
  private ws;
1367
2396
  private tunnelUrl;
@@ -1398,6 +2427,7 @@ export declare class TunnelClient {
1398
2427
  getTunnelUrl(): string | null;
1399
2428
  getIsConnected(): boolean;
1400
2429
  }
2430
+ /** @internal */
1401
2431
  export declare function getTunnelClient(localPort?: number): TunnelClient;
1402
2432
  /**
1403
2433
  * Secrets Loader for Local Development
@@ -1408,7 +2438,10 @@ export declare function getTunnelClient(localPort?: number): TunnelClient;
1408
2438
  *
1409
2439
  * Security: Only loads secrets that are declared in .env file (empty values)
1410
2440
  * In production, secrets are injected by the platform, so this is development-only.
2441
+ *
2442
+ * @internal Dev-only — used by the runtime dev server, not by user code
1411
2443
  */
2444
+ /** @internal */
1412
2445
  export declare class SecretsLoader {
1413
2446
  private SERVICE_NAME;
1414
2447
  private username;
@@ -1430,7 +2463,10 @@ export declare class SecretsLoader {
1430
2463
  */
1431
2464
  loadCustomSecrets(secretNames?: string[]): Promise<Record<string, string>>;
1432
2465
  /**
1433
- * Check if keytar is available
2466
+ * Check if the native keychain is available.
2467
+ * Always true — no native npm deps required. The underlying OS tool
2468
+ * (secret-tool, security, CredManager) may still be absent, in which
2469
+ * case getPassword() silently returns null per credential.
1434
2470
  */
1435
2471
  isAvailable(): Promise<boolean>;
1436
2472
  }