@voice-ai-labs/web-sdk 0.9.1 → 1.0.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.js CHANGED
@@ -10706,7 +10706,7 @@ function getMatch(exp, ua) {
10706
10706
  }
10707
10707
  function getOSVersion(ua) {
10708
10708
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
10709
- }var version$1 = "2.17.3";const version = version$1;
10709
+ }var version$1 = "2.18.0";const version = version$1;
10710
10710
  const protocolVersion = 16;/** Base error that all LiveKit specific custom errors inherit from. */
10711
10711
  class LivekitError extends Error {
10712
10712
  constructor(code, message, options) {
@@ -18659,6 +18659,9 @@ class RTCEngine extends eventsExports.EventEmitter {
18659
18659
  get isClosed() {
18660
18660
  return this._isClosed;
18661
18661
  }
18662
+ get isNewlyCreated() {
18663
+ return this._isNewlyCreated;
18664
+ }
18662
18665
  get pendingReconnect() {
18663
18666
  return !!this.reconnectTimeout;
18664
18667
  }
@@ -18676,6 +18679,7 @@ class RTCEngine extends eventsExports.EventEmitter {
18676
18679
  this.subscriberPrimary = false;
18677
18680
  this.pcState = PCState.New;
18678
18681
  this._isClosed = true;
18682
+ this._isNewlyCreated = true;
18679
18683
  this.pendingTrackResolvers = {};
18680
18684
  this.reconnectAttempts = 0;
18681
18685
  this.reconnectStart = 0;
@@ -18933,7 +18937,7 @@ class RTCEngine extends eventsExports.EventEmitter {
18933
18937
  room: (_b = (_a = this.latestJoinResponse) === null || _a === void 0 ? void 0 : _a.room) === null || _b === void 0 ? void 0 : _b.name,
18934
18938
  roomID: (_d = (_c = this.latestJoinResponse) === null || _c === void 0 ? void 0 : _c.room) === null || _d === void 0 ? void 0 : _d.sid,
18935
18939
  participant: (_f = (_e = this.latestJoinResponse) === null || _e === void 0 ? void 0 : _e.participant) === null || _f === void 0 ? void 0 : _f.identity,
18936
- pID: this.participantSid
18940
+ participantID: this.participantSid
18937
18941
  };
18938
18942
  }
18939
18943
  join(url_1, token_1, opts_1, abortSignal_1) {
@@ -18941,6 +18945,7 @@ class RTCEngine extends eventsExports.EventEmitter {
18941
18945
  var _this2 = this;
18942
18946
  let useV0Path = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
18943
18947
  return function* () {
18948
+ _this2._isNewlyCreated = false;
18944
18949
  _this2.url = url;
18945
18950
  _this2.token = token;
18946
18951
  _this2.signalOpts = opts;
@@ -20596,7 +20601,7 @@ class OutgoingDataStreamManager {
20596
20601
  mimeType: info.mimeType,
20597
20602
  topic: info.topic,
20598
20603
  timestamp: numberToBigInt(info.timestamp),
20599
- totalLength: numberToBigInt(options === null || options === void 0 ? void 0 : options.totalSize),
20604
+ totalLength: numberToBigInt(info.size),
20600
20605
  attributes: info.attributes,
20601
20606
  contentHeader: {
20602
20607
  case: 'textHeader',
@@ -20706,7 +20711,7 @@ class OutgoingDataStreamManager {
20706
20711
  }
20707
20712
  streamBytes(options) {
20708
20713
  return __awaiter(this, void 0, void 0, function* () {
20709
- var _a, _b, _c, _d, _e, _f;
20714
+ var _a, _b, _c, _d, _e;
20710
20715
  const streamId = (_a = options === null || options === void 0 ? void 0 : options.streamId) !== null && _a !== void 0 ? _a : crypto.randomUUID();
20711
20716
  const destinationIdentities = options === null || options === void 0 ? void 0 : options.destinationIdentities;
20712
20717
  const info = {
@@ -20720,7 +20725,7 @@ class OutgoingDataStreamManager {
20720
20725
  encryptionType: ((_e = this.engine.e2eeManager) === null || _e === void 0 ? void 0 : _e.isDataChannelEncryptionEnabled) ? Encryption_Type.GCM : Encryption_Type.NONE
20721
20726
  };
20722
20727
  const header = new DataStream_Header({
20723
- totalLength: numberToBigInt((_f = info.size) !== null && _f !== void 0 ? _f : 0),
20728
+ totalLength: numberToBigInt(info.size),
20724
20729
  mimeType: info.mimeType,
20725
20730
  streamId,
20726
20731
  topic: info.topic,
@@ -24093,7 +24098,7 @@ class Participant extends eventsExports.EventEmitter {
24093
24098
  }
24094
24099
  get logContext() {
24095
24100
  return Object.assign(Object.assign({}, super.logContext), {
24096
- rpID: this.sid,
24101
+ remoteParticipantID: this.sid,
24097
24102
  remoteParticipant: this.identity
24098
24103
  });
24099
24104
  }
@@ -25249,7 +25254,7 @@ class Room extends eventsExports.EventEmitter {
25249
25254
  room: this.name,
25250
25255
  roomID: (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.sid,
25251
25256
  participant: this.localParticipant.identity,
25252
- pID: this.localParticipant.sid
25257
+ participantID: this.localParticipant.sid
25253
25258
  };
25254
25259
  }
25255
25260
  /**
@@ -25303,7 +25308,7 @@ class Room extends eventsExports.EventEmitter {
25303
25308
  return (_b = (_a = this.roomInfo) === null || _a === void 0 ? void 0 : _a.numPublishers) !== null && _b !== void 0 ? _b : 0;
25304
25309
  }
25305
25310
  maybeCreateEngine() {
25306
- if (this.engine && !this.engine.isClosed) {
25311
+ if (this.engine && (this.engine.isNewlyCreated || !this.engine.isClosed)) {
25307
25312
  return;
25308
25313
  }
25309
25314
  this.engine = new RTCEngine(this.options);
@@ -25756,7 +25761,7 @@ class Room extends eventsExports.EventEmitter {
25756
25761
  }
25757
25762
  if (!trackId.startsWith('TR')) {
25758
25763
  this.log.warn("Tried to add a track whose 'sid' could not be determined for a participant, that's not present. Sid: ".concat(participantSid, ", streamId: ").concat(streamId, ", trackId: ").concat(trackId), Object.assign(Object.assign({}, this.logContext), {
25759
- rpID: participantSid,
25764
+ remoteParticipantID: participantSid,
25760
25765
  streamId,
25761
25766
  trackId
25762
25767
  }));
@@ -26299,6 +26304,11 @@ function mapArgs(args) {
26299
26304
  return arg;
26300
26305
  });
26301
26306
  }// This file was generated from JSON Schema using quicktype, do not modify it directly.
26307
+ var DataTrackHandleErrorReason;
26308
+ (function (DataTrackHandleErrorReason) {
26309
+ DataTrackHandleErrorReason[DataTrackHandleErrorReason["Reserved"] = 0] = "Reserved";
26310
+ DataTrackHandleErrorReason[DataTrackHandleErrorReason["TooLarge"] = 1] = "TooLarge";
26311
+ })(DataTrackHandleErrorReason || (DataTrackHandleErrorReason = {}));
26302
26312
  var DataTrackDeserializeErrorReason;
26303
26313
  (function (DataTrackDeserializeErrorReason) {
26304
26314
  DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["TooShort"] = 0] = "TooShort";
@@ -26320,11 +26330,6 @@ var DataTrackExtensionTag;
26320
26330
  })(DataTrackExtensionTag || (DataTrackExtensionTag = {}));
26321
26331
  DataTrackExtensionTag.UserTimestamp;
26322
26332
  DataTrackExtensionTag.E2ee;
26323
- var DataTrackHandleErrorReason;
26324
- (function (DataTrackHandleErrorReason) {
26325
- DataTrackHandleErrorReason[DataTrackHandleErrorReason["Reserved"] = 0] = "Reserved";
26326
- DataTrackHandleErrorReason[DataTrackHandleErrorReason["TooLarge"] = 1] = "TooLarge";
26327
- })(DataTrackHandleErrorReason || (DataTrackHandleErrorReason = {}));
26328
26333
  /** Marker indicating a packet's position in relation to a frame. */
26329
26334
  var FrameMarker;
26330
26335
  (function (FrameMarker) {
@@ -26348,7 +26353,17 @@ var DataTrackDepacketizerDropReason;
26348
26353
  DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["UnknownFrame"] = 1] = "UnknownFrame";
26349
26354
  DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["BufferFull"] = 2] = "BufferFull";
26350
26355
  DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["Incomplete"] = 3] = "Incomplete";
26351
- })(DataTrackDepacketizerDropReason || (DataTrackDepacketizerDropReason = {}));var DataTrackPublishErrorReason;
26356
+ })(DataTrackDepacketizerDropReason || (DataTrackDepacketizerDropReason = {}));var DataTrackSubscribeErrorReason;
26357
+ (function (DataTrackSubscribeErrorReason) {
26358
+ /** The track has been unpublished and is no longer available */
26359
+ DataTrackSubscribeErrorReason[DataTrackSubscribeErrorReason["Unpublished"] = 0] = "Unpublished";
26360
+ /** Request to subscribe to data track timed-out */
26361
+ DataTrackSubscribeErrorReason[DataTrackSubscribeErrorReason["Timeout"] = 1] = "Timeout";
26362
+ /** Cannot subscribe to data track when disconnected */
26363
+ DataTrackSubscribeErrorReason[DataTrackSubscribeErrorReason["Disconnected"] = 2] = "Disconnected";
26364
+ /** Subscription to data track cancelled by caller */
26365
+ DataTrackSubscribeErrorReason[DataTrackSubscribeErrorReason["Cancelled"] = 4] = "Cancelled";
26366
+ })(DataTrackSubscribeErrorReason || (DataTrackSubscribeErrorReason = {}));getLogger(LoggerNames.DataTracks);getLogger(LoggerNames.DataTracks);var DataTrackPublishErrorReason;
26352
26367
  (function (DataTrackPublishErrorReason) {
26353
26368
  /**
26354
26369
  * Local participant does not have permission to publish data tracks.
@@ -27324,15 +27339,33 @@ class VoiceAIError extends Error {
27324
27339
  */
27325
27340
  class BaseClient {
27326
27341
  constructor(config) {
27327
- this.apiKey = config.apiKey;
27342
+ this.apiKey = config.apiKey || '';
27343
+ this.authToken = config.authToken;
27344
+ this.getAuthToken = config.getAuthToken;
27328
27345
  this.apiUrl = config.apiUrl;
27329
27346
  }
27347
+ async resolveBearerToken() {
27348
+ if (this.apiKey) {
27349
+ return this.apiKey;
27350
+ }
27351
+ if (this.authToken) {
27352
+ return this.authToken;
27353
+ }
27354
+ if (this.getAuthToken) {
27355
+ const resolvedToken = await this.getAuthToken();
27356
+ if (typeof resolvedToken === 'string' && resolvedToken.trim()) {
27357
+ return resolvedToken;
27358
+ }
27359
+ }
27360
+ throw new VoiceAIError('Authentication required. Configure apiKey, authToken, or getAuthToken.', 401, 'UNAUTHORIZED');
27361
+ }
27330
27362
  /**
27331
27363
  * Build headers with authentication
27332
27364
  */
27333
- getHeaders(contentType = 'application/json') {
27365
+ async getHeaders(contentType = 'application/json') {
27366
+ const bearerToken = await this.resolveBearerToken();
27334
27367
  const headers = {
27335
- 'Authorization': `Bearer ${this.apiKey}`,
27368
+ 'Authorization': `Bearer ${bearerToken}`,
27336
27369
  };
27337
27370
  if (contentType) {
27338
27371
  headers['Content-Type'] = contentType;
@@ -27362,7 +27395,7 @@ class BaseClient {
27362
27395
  }
27363
27396
  // Handle specific error codes
27364
27397
  if (response.status === 401) {
27365
- throw new VoiceAIError('Authentication failed. Please check your API key.', 401, 'UNAUTHORIZED');
27398
+ throw new VoiceAIError('Authentication failed. Please check your API key or auth token.', 401, 'UNAUTHORIZED');
27366
27399
  }
27367
27400
  if (response.status === 403) {
27368
27401
  const detail = errorData?.detail || errorData?.error;
@@ -27403,7 +27436,7 @@ class BaseClient {
27403
27436
  }
27404
27437
  const response = await fetch(url.toString(), {
27405
27438
  method: 'GET',
27406
- headers: this.getHeaders(),
27439
+ headers: await this.getHeaders(),
27407
27440
  });
27408
27441
  return this.handleResponse(response);
27409
27442
  }
@@ -27426,7 +27459,7 @@ class BaseClient {
27426
27459
  }
27427
27460
  const response = await fetch(url.toString(), {
27428
27461
  method: 'GET',
27429
- headers: this.getHeaders(),
27462
+ headers: await this.getHeaders(),
27430
27463
  });
27431
27464
  if (!response.ok) {
27432
27465
  let errorData = null;
@@ -27446,7 +27479,7 @@ class BaseClient {
27446
27479
  async post(path, body) {
27447
27480
  const response = await fetch(`${this.apiUrl}${path}`, {
27448
27481
  method: 'POST',
27449
- headers: this.getHeaders(),
27482
+ headers: await this.getHeaders(),
27450
27483
  body: body !== undefined ? JSON.stringify(body) : undefined,
27451
27484
  });
27452
27485
  return this.handleResponse(response);
@@ -27457,7 +27490,7 @@ class BaseClient {
27457
27490
  async postFormData(path, formData) {
27458
27491
  // Don't set Content-Type header - browser will set it with boundary
27459
27492
  const headers = {
27460
- 'Authorization': `Bearer ${this.apiKey}`,
27493
+ 'Authorization': `Bearer ${await this.resolveBearerToken()}`,
27461
27494
  };
27462
27495
  const response = await fetch(`${this.apiUrl}${path}`, {
27463
27496
  method: 'POST',
@@ -27472,7 +27505,7 @@ class BaseClient {
27472
27505
  async put(path, body) {
27473
27506
  const response = await fetch(`${this.apiUrl}${path}`, {
27474
27507
  method: 'PUT',
27475
- headers: this.getHeaders(),
27508
+ headers: await this.getHeaders(),
27476
27509
  body: body !== undefined ? JSON.stringify(body) : undefined,
27477
27510
  });
27478
27511
  return this.handleResponse(response);
@@ -27483,7 +27516,7 @@ class BaseClient {
27483
27516
  async patch(path, body) {
27484
27517
  const response = await fetch(`${this.apiUrl}${path}`, {
27485
27518
  method: 'PATCH',
27486
- headers: this.getHeaders(),
27519
+ headers: await this.getHeaders(),
27487
27520
  body: body !== undefined ? JSON.stringify(body) : undefined,
27488
27521
  });
27489
27522
  return this.handleResponse(response);
@@ -27494,7 +27527,7 @@ class BaseClient {
27494
27527
  async httpDelete(path) {
27495
27528
  const response = await fetch(`${this.apiUrl}${path}`, {
27496
27529
  method: 'DELETE',
27497
- headers: this.getHeaders(),
27530
+ headers: await this.getHeaders(),
27498
27531
  });
27499
27532
  return this.handleResponse(response);
27500
27533
  }
@@ -27504,7 +27537,7 @@ class BaseClient {
27504
27537
  async postForBlob(path, body) {
27505
27538
  const response = await fetch(`${this.apiUrl}${path}`, {
27506
27539
  method: 'POST',
27507
- headers: this.getHeaders(),
27540
+ headers: await this.getHeaders(),
27508
27541
  body: body !== undefined ? JSON.stringify(body) : undefined,
27509
27542
  });
27510
27543
  if (!response.ok) {
@@ -27526,7 +27559,7 @@ class BaseClient {
27526
27559
  async postForStream(path, body) {
27527
27560
  const response = await fetch(`${this.apiUrl}${path}`, {
27528
27561
  method: 'POST',
27529
- headers: this.getHeaders(),
27562
+ headers: await this.getHeaders(),
27530
27563
  body: body !== undefined ? JSON.stringify(body) : undefined,
27531
27564
  });
27532
27565
  if (!response.ok) {
@@ -27791,6 +27824,7 @@ class AgentClient extends BaseClient {
27791
27824
  * Provides methods for:
27792
27825
  * - Getting call history with filters
27793
27826
  * - Getting transcript URLs
27827
+ * - Getting recording status and URLs
27794
27828
  * - Getting agent stats summary
27795
27829
  */
27796
27830
  /**
@@ -27841,6 +27875,12 @@ class AnalyticsClient extends BaseClient {
27841
27875
  params.end_date = options.end_date;
27842
27876
  if (options?.agent_ids)
27843
27877
  params.agent_ids = options.agent_ids;
27878
+ if (options?.agent_name)
27879
+ params.agent_name = options.agent_name;
27880
+ if (options?.sort_by)
27881
+ params.sort_by = options.sort_by;
27882
+ if (options?.sort_dir)
27883
+ params.sort_dir = options.sort_dir;
27844
27884
  return this.get('/agent/call-history', params);
27845
27885
  }
27846
27886
  /**
@@ -27860,6 +27900,24 @@ class AnalyticsClient extends BaseClient {
27860
27900
  async getTranscriptUrl(callId) {
27861
27901
  return this.get(`/agent/call-history/${callId}/transcript`);
27862
27902
  }
27903
+ /**
27904
+ * Get recording status or download URL for a call
27905
+ *
27906
+ * @param callId - The call identifier
27907
+ * @returns Object with recording status and optional URL
27908
+ *
27909
+ * @example
27910
+ * ```typescript
27911
+ * const recording = await client.analytics.getRecordingUrl("call_12345");
27912
+ *
27913
+ * if (recording.status === 'ready' && recording.url) {
27914
+ * window.open(recording.url, '_blank');
27915
+ * }
27916
+ * ```
27917
+ */
27918
+ async getRecordingUrl(callId) {
27919
+ return this.get(`/agent/call-history/${callId}/recording`);
27920
+ }
27863
27921
  /**
27864
27922
  * Get agent stats summary
27865
27923
  *
@@ -28004,6 +28062,29 @@ class KnowledgeBaseClient extends BaseClient {
28004
28062
  }
28005
28063
  }
28006
28064
 
28065
+ class GoogleManagedToolsClient extends BaseClient {
28066
+ constructor(config) {
28067
+ super(config);
28068
+ }
28069
+ async startOAuth(agentId, options = {}) {
28070
+ return this.post(`/google/${encodeURIComponent(agentId)}/oauth/start`, {
28071
+ return_path: options.returnUrl,
28072
+ managed_tools: options.managedTools,
28073
+ });
28074
+ }
28075
+ async getStatus(agentId) {
28076
+ return this.get(`/google/${encodeURIComponent(agentId)}/status`);
28077
+ }
28078
+ async disconnect(agentId) {
28079
+ return this.httpDelete(`/google/${encodeURIComponent(agentId)}/disconnect`);
28080
+ }
28081
+ }
28082
+ class ManagedToolsClient {
28083
+ constructor(config) {
28084
+ this.google = new GoogleManagedToolsClient(config);
28085
+ }
28086
+ }
28087
+
28007
28088
  /**
28008
28089
  * Phone Number Management Client
28009
28090
  *
@@ -28310,7 +28391,7 @@ class TTSClient extends BaseClient {
28310
28391
  /**
28311
28392
  * Clone a voice from a reference audio file
28312
28393
  *
28313
- * Accepts an audio file (MP3, WAV, or OGG, max 7.5MB) and creates
28394
+ * Accepts an audio file (MP3, WAV, or M4A, max 7.5MB) and creates
28314
28395
  * a cloned voice. The voice starts in PENDING status and moves to
28315
28396
  * PROCESSING, then AVAILABLE once ready.
28316
28397
  *
@@ -28443,6 +28524,648 @@ class TTSClient extends BaseClient {
28443
28524
  }
28444
28525
  }
28445
28526
 
28527
+ const IANA_TIMEZONE_IDS = Object.freeze([
28528
+ "Africa/Abidjan",
28529
+ "Africa/Accra",
28530
+ "Africa/Addis_Ababa",
28531
+ "Africa/Algiers",
28532
+ "Africa/Asmera",
28533
+ "Africa/Bamako",
28534
+ "Africa/Bangui",
28535
+ "Africa/Banjul",
28536
+ "Africa/Bissau",
28537
+ "Africa/Blantyre",
28538
+ "Africa/Brazzaville",
28539
+ "Africa/Bujumbura",
28540
+ "Africa/Cairo",
28541
+ "Africa/Casablanca",
28542
+ "Africa/Ceuta",
28543
+ "Africa/Conakry",
28544
+ "Africa/Dakar",
28545
+ "Africa/Dar_es_Salaam",
28546
+ "Africa/Djibouti",
28547
+ "Africa/Douala",
28548
+ "Africa/El_Aaiun",
28549
+ "Africa/Freetown",
28550
+ "Africa/Gaborone",
28551
+ "Africa/Harare",
28552
+ "Africa/Johannesburg",
28553
+ "Africa/Juba",
28554
+ "Africa/Kampala",
28555
+ "Africa/Khartoum",
28556
+ "Africa/Kigali",
28557
+ "Africa/Kinshasa",
28558
+ "Africa/Lagos",
28559
+ "Africa/Libreville",
28560
+ "Africa/Lome",
28561
+ "Africa/Luanda",
28562
+ "Africa/Lubumbashi",
28563
+ "Africa/Lusaka",
28564
+ "Africa/Malabo",
28565
+ "Africa/Maputo",
28566
+ "Africa/Maseru",
28567
+ "Africa/Mbabane",
28568
+ "Africa/Mogadishu",
28569
+ "Africa/Monrovia",
28570
+ "Africa/Nairobi",
28571
+ "Africa/Ndjamena",
28572
+ "Africa/Niamey",
28573
+ "Africa/Nouakchott",
28574
+ "Africa/Ouagadougou",
28575
+ "Africa/Porto-Novo",
28576
+ "Africa/Sao_Tome",
28577
+ "Africa/Tripoli",
28578
+ "Africa/Tunis",
28579
+ "Africa/Windhoek",
28580
+ "America/Adak",
28581
+ "America/Anchorage",
28582
+ "America/Anguilla",
28583
+ "America/Antigua",
28584
+ "America/Araguaina",
28585
+ "America/Argentina/La_Rioja",
28586
+ "America/Argentina/Rio_Gallegos",
28587
+ "America/Argentina/Salta",
28588
+ "America/Argentina/San_Juan",
28589
+ "America/Argentina/San_Luis",
28590
+ "America/Argentina/Tucuman",
28591
+ "America/Argentina/Ushuaia",
28592
+ "America/Aruba",
28593
+ "America/Asuncion",
28594
+ "America/Bahia",
28595
+ "America/Bahia_Banderas",
28596
+ "America/Barbados",
28597
+ "America/Belem",
28598
+ "America/Belize",
28599
+ "America/Blanc-Sablon",
28600
+ "America/Boa_Vista",
28601
+ "America/Bogota",
28602
+ "America/Boise",
28603
+ "America/Buenos_Aires",
28604
+ "America/Cambridge_Bay",
28605
+ "America/Campo_Grande",
28606
+ "America/Cancun",
28607
+ "America/Caracas",
28608
+ "America/Catamarca",
28609
+ "America/Cayenne",
28610
+ "America/Cayman",
28611
+ "America/Chicago",
28612
+ "America/Chihuahua",
28613
+ "America/Ciudad_Juarez",
28614
+ "America/Coral_Harbour",
28615
+ "America/Cordoba",
28616
+ "America/Costa_Rica",
28617
+ "America/Creston",
28618
+ "America/Cuiaba",
28619
+ "America/Curacao",
28620
+ "America/Danmarkshavn",
28621
+ "America/Dawson",
28622
+ "America/Dawson_Creek",
28623
+ "America/Denver",
28624
+ "America/Detroit",
28625
+ "America/Dominica",
28626
+ "America/Edmonton",
28627
+ "America/Eirunepe",
28628
+ "America/El_Salvador",
28629
+ "America/Fort_Nelson",
28630
+ "America/Fortaleza",
28631
+ "America/Glace_Bay",
28632
+ "America/Godthab",
28633
+ "America/Goose_Bay",
28634
+ "America/Grand_Turk",
28635
+ "America/Grenada",
28636
+ "America/Guadeloupe",
28637
+ "America/Guatemala",
28638
+ "America/Guayaquil",
28639
+ "America/Guyana",
28640
+ "America/Halifax",
28641
+ "America/Havana",
28642
+ "America/Hermosillo",
28643
+ "America/Indiana/Knox",
28644
+ "America/Indiana/Marengo",
28645
+ "America/Indiana/Petersburg",
28646
+ "America/Indiana/Tell_City",
28647
+ "America/Indiana/Vevay",
28648
+ "America/Indiana/Vincennes",
28649
+ "America/Indiana/Winamac",
28650
+ "America/Indianapolis",
28651
+ "America/Inuvik",
28652
+ "America/Iqaluit",
28653
+ "America/Jamaica",
28654
+ "America/Jujuy",
28655
+ "America/Juneau",
28656
+ "America/Kentucky/Monticello",
28657
+ "America/Kralendijk",
28658
+ "America/La_Paz",
28659
+ "America/Lima",
28660
+ "America/Los_Angeles",
28661
+ "America/Louisville",
28662
+ "America/Lower_Princes",
28663
+ "America/Maceio",
28664
+ "America/Managua",
28665
+ "America/Manaus",
28666
+ "America/Marigot",
28667
+ "America/Martinique",
28668
+ "America/Matamoros",
28669
+ "America/Mazatlan",
28670
+ "America/Mendoza",
28671
+ "America/Menominee",
28672
+ "America/Merida",
28673
+ "America/Metlakatla",
28674
+ "America/Mexico_City",
28675
+ "America/Miquelon",
28676
+ "America/Moncton",
28677
+ "America/Monterrey",
28678
+ "America/Montevideo",
28679
+ "America/Montserrat",
28680
+ "America/Nassau",
28681
+ "America/New_York",
28682
+ "America/Nome",
28683
+ "America/Noronha",
28684
+ "America/North_Dakota/Beulah",
28685
+ "America/North_Dakota/Center",
28686
+ "America/North_Dakota/New_Salem",
28687
+ "America/Ojinaga",
28688
+ "America/Panama",
28689
+ "America/Paramaribo",
28690
+ "America/Phoenix",
28691
+ "America/Port-au-Prince",
28692
+ "America/Port_of_Spain",
28693
+ "America/Porto_Velho",
28694
+ "America/Puerto_Rico",
28695
+ "America/Punta_Arenas",
28696
+ "America/Rankin_Inlet",
28697
+ "America/Recife",
28698
+ "America/Regina",
28699
+ "America/Resolute",
28700
+ "America/Rio_Branco",
28701
+ "America/Santarem",
28702
+ "America/Santiago",
28703
+ "America/Santo_Domingo",
28704
+ "America/Sao_Paulo",
28705
+ "America/Scoresbysund",
28706
+ "America/Sitka",
28707
+ "America/St_Barthelemy",
28708
+ "America/St_Johns",
28709
+ "America/St_Kitts",
28710
+ "America/St_Lucia",
28711
+ "America/St_Thomas",
28712
+ "America/St_Vincent",
28713
+ "America/Swift_Current",
28714
+ "America/Tegucigalpa",
28715
+ "America/Thule",
28716
+ "America/Tijuana",
28717
+ "America/Toronto",
28718
+ "America/Tortola",
28719
+ "America/Vancouver",
28720
+ "America/Whitehorse",
28721
+ "America/Winnipeg",
28722
+ "America/Yakutat",
28723
+ "Antarctica/Casey",
28724
+ "Antarctica/Davis",
28725
+ "Antarctica/DumontDUrville",
28726
+ "Antarctica/Macquarie",
28727
+ "Antarctica/Mawson",
28728
+ "Antarctica/McMurdo",
28729
+ "Antarctica/Palmer",
28730
+ "Antarctica/Rothera",
28731
+ "Antarctica/Syowa",
28732
+ "Antarctica/Troll",
28733
+ "Antarctica/Vostok",
28734
+ "Arctic/Longyearbyen",
28735
+ "Asia/Aden",
28736
+ "Asia/Almaty",
28737
+ "Asia/Amman",
28738
+ "Asia/Anadyr",
28739
+ "Asia/Aqtau",
28740
+ "Asia/Aqtobe",
28741
+ "Asia/Ashgabat",
28742
+ "Asia/Atyrau",
28743
+ "Asia/Baghdad",
28744
+ "Asia/Bahrain",
28745
+ "Asia/Baku",
28746
+ "Asia/Bangkok",
28747
+ "Asia/Barnaul",
28748
+ "Asia/Beirut",
28749
+ "Asia/Bishkek",
28750
+ "Asia/Brunei",
28751
+ "Asia/Calcutta",
28752
+ "Asia/Chita",
28753
+ "Asia/Colombo",
28754
+ "Asia/Damascus",
28755
+ "Asia/Dhaka",
28756
+ "Asia/Dili",
28757
+ "Asia/Dubai",
28758
+ "Asia/Dushanbe",
28759
+ "Asia/Famagusta",
28760
+ "Asia/Gaza",
28761
+ "Asia/Hebron",
28762
+ "Asia/Hong_Kong",
28763
+ "Asia/Hovd",
28764
+ "Asia/Irkutsk",
28765
+ "Asia/Jakarta",
28766
+ "Asia/Jayapura",
28767
+ "Asia/Jerusalem",
28768
+ "Asia/Kabul",
28769
+ "Asia/Kamchatka",
28770
+ "Asia/Karachi",
28771
+ "Asia/Katmandu",
28772
+ "Asia/Khandyga",
28773
+ "Asia/Krasnoyarsk",
28774
+ "Asia/Kuala_Lumpur",
28775
+ "Asia/Kuching",
28776
+ "Asia/Kuwait",
28777
+ "Asia/Macau",
28778
+ "Asia/Magadan",
28779
+ "Asia/Makassar",
28780
+ "Asia/Manila",
28781
+ "Asia/Muscat",
28782
+ "Asia/Nicosia",
28783
+ "Asia/Novokuznetsk",
28784
+ "Asia/Novosibirsk",
28785
+ "Asia/Omsk",
28786
+ "Asia/Oral",
28787
+ "Asia/Phnom_Penh",
28788
+ "Asia/Pontianak",
28789
+ "Asia/Pyongyang",
28790
+ "Asia/Qatar",
28791
+ "Asia/Qostanay",
28792
+ "Asia/Qyzylorda",
28793
+ "Asia/Rangoon",
28794
+ "Asia/Riyadh",
28795
+ "Asia/Saigon",
28796
+ "Asia/Sakhalin",
28797
+ "Asia/Samarkand",
28798
+ "Asia/Seoul",
28799
+ "Asia/Shanghai",
28800
+ "Asia/Singapore",
28801
+ "Asia/Srednekolymsk",
28802
+ "Asia/Taipei",
28803
+ "Asia/Tashkent",
28804
+ "Asia/Tbilisi",
28805
+ "Asia/Tehran",
28806
+ "Asia/Thimphu",
28807
+ "Asia/Tokyo",
28808
+ "Asia/Tomsk",
28809
+ "Asia/Ulaanbaatar",
28810
+ "Asia/Urumqi",
28811
+ "Asia/Ust-Nera",
28812
+ "Asia/Vientiane",
28813
+ "Asia/Vladivostok",
28814
+ "Asia/Yakutsk",
28815
+ "Asia/Yekaterinburg",
28816
+ "Asia/Yerevan",
28817
+ "Atlantic/Azores",
28818
+ "Atlantic/Bermuda",
28819
+ "Atlantic/Canary",
28820
+ "Atlantic/Cape_Verde",
28821
+ "Atlantic/Faeroe",
28822
+ "Atlantic/Madeira",
28823
+ "Atlantic/Reykjavik",
28824
+ "Atlantic/South_Georgia",
28825
+ "Atlantic/St_Helena",
28826
+ "Atlantic/Stanley",
28827
+ "Australia/Adelaide",
28828
+ "Australia/Brisbane",
28829
+ "Australia/Broken_Hill",
28830
+ "Australia/Darwin",
28831
+ "Australia/Eucla",
28832
+ "Australia/Hobart",
28833
+ "Australia/Lindeman",
28834
+ "Australia/Lord_Howe",
28835
+ "Australia/Melbourne",
28836
+ "Australia/Perth",
28837
+ "Australia/Sydney",
28838
+ "Europe/Amsterdam",
28839
+ "Europe/Andorra",
28840
+ "Europe/Astrakhan",
28841
+ "Europe/Athens",
28842
+ "Europe/Belgrade",
28843
+ "Europe/Berlin",
28844
+ "Europe/Bratislava",
28845
+ "Europe/Brussels",
28846
+ "Europe/Bucharest",
28847
+ "Europe/Budapest",
28848
+ "Europe/Busingen",
28849
+ "Europe/Chisinau",
28850
+ "Europe/Copenhagen",
28851
+ "Europe/Dublin",
28852
+ "Europe/Gibraltar",
28853
+ "Europe/Guernsey",
28854
+ "Europe/Helsinki",
28855
+ "Europe/Isle_of_Man",
28856
+ "Europe/Istanbul",
28857
+ "Europe/Jersey",
28858
+ "Europe/Kaliningrad",
28859
+ "Europe/Kiev",
28860
+ "Europe/Kirov",
28861
+ "Europe/Lisbon",
28862
+ "Europe/Ljubljana",
28863
+ "Europe/London",
28864
+ "Europe/Luxembourg",
28865
+ "Europe/Madrid",
28866
+ "Europe/Malta",
28867
+ "Europe/Mariehamn",
28868
+ "Europe/Minsk",
28869
+ "Europe/Monaco",
28870
+ "Europe/Moscow",
28871
+ "Europe/Oslo",
28872
+ "Europe/Paris",
28873
+ "Europe/Podgorica",
28874
+ "Europe/Prague",
28875
+ "Europe/Riga",
28876
+ "Europe/Rome",
28877
+ "Europe/Samara",
28878
+ "Europe/San_Marino",
28879
+ "Europe/Sarajevo",
28880
+ "Europe/Saratov",
28881
+ "Europe/Simferopol",
28882
+ "Europe/Skopje",
28883
+ "Europe/Sofia",
28884
+ "Europe/Stockholm",
28885
+ "Europe/Tallinn",
28886
+ "Europe/Tirane",
28887
+ "Europe/Ulyanovsk",
28888
+ "Europe/Vaduz",
28889
+ "Europe/Vatican",
28890
+ "Europe/Vienna",
28891
+ "Europe/Vilnius",
28892
+ "Europe/Volgograd",
28893
+ "Europe/Warsaw",
28894
+ "Europe/Zagreb",
28895
+ "Europe/Zurich",
28896
+ "Indian/Antananarivo",
28897
+ "Indian/Chagos",
28898
+ "Indian/Christmas",
28899
+ "Indian/Cocos",
28900
+ "Indian/Comoro",
28901
+ "Indian/Kerguelen",
28902
+ "Indian/Mahe",
28903
+ "Indian/Maldives",
28904
+ "Indian/Mauritius",
28905
+ "Indian/Mayotte",
28906
+ "Indian/Reunion",
28907
+ "Pacific/Apia",
28908
+ "Pacific/Auckland",
28909
+ "Pacific/Bougainville",
28910
+ "Pacific/Chatham",
28911
+ "Pacific/Easter",
28912
+ "Pacific/Efate",
28913
+ "Pacific/Enderbury",
28914
+ "Pacific/Fakaofo",
28915
+ "Pacific/Fiji",
28916
+ "Pacific/Funafuti",
28917
+ "Pacific/Galapagos",
28918
+ "Pacific/Gambier",
28919
+ "Pacific/Guadalcanal",
28920
+ "Pacific/Guam",
28921
+ "Pacific/Honolulu",
28922
+ "Pacific/Kiritimati",
28923
+ "Pacific/Kosrae",
28924
+ "Pacific/Kwajalein",
28925
+ "Pacific/Majuro",
28926
+ "Pacific/Marquesas",
28927
+ "Pacific/Midway",
28928
+ "Pacific/Nauru",
28929
+ "Pacific/Niue",
28930
+ "Pacific/Norfolk",
28931
+ "Pacific/Noumea",
28932
+ "Pacific/Pago_Pago",
28933
+ "Pacific/Palau",
28934
+ "Pacific/Pitcairn",
28935
+ "Pacific/Ponape",
28936
+ "Pacific/Port_Moresby",
28937
+ "Pacific/Rarotonga",
28938
+ "Pacific/Saipan",
28939
+ "Pacific/Tahiti",
28940
+ "Pacific/Tarawa",
28941
+ "Pacific/Tongatapu",
28942
+ "Pacific/Truk",
28943
+ "Pacific/Wake",
28944
+ "Pacific/Wallis",
28945
+ ]);
28946
+ function parseOffsetMinutes(rawOffset) {
28947
+ if (rawOffset === "GMT" || rawOffset === "UTC") {
28948
+ return 0;
28949
+ }
28950
+ const match = rawOffset.match(/^(?:GMT|UTC)([+-])(\d{1,2})(?::?(\d{2}))?$/);
28951
+ if (!match) {
28952
+ return 0;
28953
+ }
28954
+ const sign = match[1] === "-" ? -1 : 1;
28955
+ const hours = Number.parseInt(match[2] || "0", 10);
28956
+ const minutes = Number.parseInt(match[3] || "0", 10);
28957
+ return sign * (hours * 60 + minutes);
28958
+ }
28959
+ function getTimezoneOffsetMinutes(timezoneId, date = new Date()) {
28960
+ try {
28961
+ const parts = new Intl.DateTimeFormat("en-US", {
28962
+ timeZone: timezoneId,
28963
+ timeZoneName: "shortOffset",
28964
+ hour: "2-digit",
28965
+ minute: "2-digit",
28966
+ hourCycle: "h23",
28967
+ }).formatToParts(date);
28968
+ const offsetPart = parts.find((part) => part.type === "timeZoneName")?.value;
28969
+ return offsetPart ? parseOffsetMinutes(offsetPart) : 0;
28970
+ }
28971
+ catch {
28972
+ return 0;
28973
+ }
28974
+ }
28975
+ function formatUtcOffset(offsetMinutes) {
28976
+ const sign = offsetMinutes >= 0 ? "+" : "-";
28977
+ const absoluteMinutes = Math.abs(offsetMinutes);
28978
+ const hours = String(Math.floor(absoluteMinutes / 60)).padStart(2, "0");
28979
+ const minutes = String(absoluteMinutes % 60).padStart(2, "0");
28980
+ return `UTC${sign}${hours}:${minutes}`;
28981
+ }
28982
+ const IANA_TIMEZONE_OPTIONS = Object.freeze([...IANA_TIMEZONE_IDS]
28983
+ .map((timezoneId) => {
28984
+ const offsetMinutes = getTimezoneOffsetMinutes(timezoneId);
28985
+ return {
28986
+ value: timezoneId,
28987
+ label: `${formatUtcOffset(offsetMinutes)} • ${timezoneId}`,
28988
+ offsetMinutes,
28989
+ };
28990
+ })
28991
+ .sort((left, right) => left.offsetMinutes - right.offsetMinutes || left.value.localeCompare(right.value)));
28992
+
28993
+ const GOOGLE_IDENTITY_SCOPES = [
28994
+ 'openid',
28995
+ 'https://www.googleapis.com/auth/userinfo.email',
28996
+ 'https://www.googleapis.com/auth/userinfo.profile',
28997
+ ];
28998
+ const GOOGLE_CALENDAR_SCOPE = 'https://www.googleapis.com/auth/calendar';
28999
+ const GOOGLE_SHEETS_SCOPE = 'https://www.googleapis.com/auth/spreadsheets';
29000
+ const GOOGLE_GMAIL_READ_SCOPE = 'https://www.googleapis.com/auth/gmail.readonly';
29001
+ const GOOGLE_GMAIL_SEND_SCOPE = 'https://www.googleapis.com/auth/gmail.send';
29002
+ const GOOGLE_CALENDAR_OPERATION_OPTIONS = [
29003
+ {
29004
+ value: 'google_calendar_check_availability',
29005
+ label: 'Check availability',
29006
+ description: 'Check whether a calendar is free during a time window.',
29007
+ },
29008
+ {
29009
+ value: 'google_calendar_list_upcoming_events',
29010
+ label: 'List upcoming',
29011
+ description: 'Read the next upcoming events from the calendar.',
29012
+ },
29013
+ {
29014
+ value: 'google_calendar_create_event',
29015
+ label: 'Create event',
29016
+ description: 'Create a new calendar event.',
29017
+ },
29018
+ {
29019
+ value: 'google_calendar_update_event',
29020
+ label: 'Update event',
29021
+ description: 'Modify an existing calendar event.',
29022
+ },
29023
+ {
29024
+ value: 'google_calendar_cancel_event',
29025
+ label: 'Cancel event',
29026
+ description: 'Cancel or delete an existing calendar event.',
29027
+ },
29028
+ ];
29029
+ const GOOGLE_SHEETS_OPERATION_OPTIONS = [
29030
+ {
29031
+ value: 'google_sheets_append_row',
29032
+ label: 'Append row',
29033
+ description: 'Write a new row into a spreadsheet.',
29034
+ },
29035
+ {
29036
+ value: 'google_sheets_list_sheets',
29037
+ label: 'List sheets',
29038
+ description: 'List worksheet tabs and spreadsheet metadata.',
29039
+ },
29040
+ {
29041
+ value: 'google_sheets_read_rows',
29042
+ label: 'Read rows',
29043
+ description: 'Read rows from a worksheet range.',
29044
+ },
29045
+ ];
29046
+ const GOOGLE_GMAIL_OPERATION_OPTIONS = [
29047
+ {
29048
+ value: 'google_gmail_search_messages',
29049
+ label: 'Search messages',
29050
+ description: 'Search Gmail and return readable message summaries.',
29051
+ },
29052
+ {
29053
+ value: 'google_gmail_get_message',
29054
+ label: 'Get message',
29055
+ description: 'Fetch a specific Gmail message by ID.',
29056
+ },
29057
+ {
29058
+ value: 'google_gmail_send_email',
29059
+ label: 'Send email',
29060
+ description: 'Send an email from the connected Gmail account.',
29061
+ },
29062
+ ];
29063
+ const GOOGLE_MANAGED_OPERATION_OPTIONS = {
29064
+ google_calendar: GOOGLE_CALENDAR_OPERATION_OPTIONS,
29065
+ google_sheets: GOOGLE_SHEETS_OPERATION_OPTIONS,
29066
+ google_gmail: GOOGLE_GMAIL_OPERATION_OPTIONS,
29067
+ };
29068
+ const GOOGLE_GMAIL_REQUIRED_SCOPES_BY_OPERATION = {
29069
+ google_gmail_search_messages: [GOOGLE_GMAIL_READ_SCOPE],
29070
+ google_gmail_get_message: [GOOGLE_GMAIL_READ_SCOPE],
29071
+ google_gmail_send_email: [GOOGLE_GMAIL_SEND_SCOPE],
29072
+ };
29073
+ const GOOGLE_CALENDAR_REQUIRED_SCOPES_BY_OPERATION = {
29074
+ google_calendar_check_availability: [GOOGLE_CALENDAR_SCOPE],
29075
+ google_calendar_list_upcoming_events: [GOOGLE_CALENDAR_SCOPE],
29076
+ google_calendar_create_event: [GOOGLE_CALENDAR_SCOPE],
29077
+ google_calendar_update_event: [GOOGLE_CALENDAR_SCOPE],
29078
+ google_calendar_cancel_event: [GOOGLE_CALENDAR_SCOPE],
29079
+ };
29080
+ const GOOGLE_SHEETS_REQUIRED_SCOPES_BY_OPERATION = {
29081
+ google_sheets_append_row: [GOOGLE_SHEETS_SCOPE],
29082
+ google_sheets_list_sheets: [GOOGLE_SHEETS_SCOPE],
29083
+ google_sheets_read_rows: [GOOGLE_SHEETS_SCOPE],
29084
+ };
29085
+ function uniqueStrings(values) {
29086
+ const orderedValues = [];
29087
+ const seen = new Set();
29088
+ for (const value of values) {
29089
+ if (typeof value !== 'string' || !value.trim() || seen.has(value)) {
29090
+ continue;
29091
+ }
29092
+ seen.add(value);
29093
+ orderedValues.push(value);
29094
+ }
29095
+ return orderedValues;
29096
+ }
29097
+ function getManagedToolSelectedOperations(selectedOperations, options) {
29098
+ const orderedValues = options.map((option) => option.value);
29099
+ if (!Array.isArray(selectedOperations)) {
29100
+ return orderedValues;
29101
+ }
29102
+ const allowed = new Set(orderedValues);
29103
+ const selected = new Set();
29104
+ for (const operation of selectedOperations) {
29105
+ if (typeof operation === 'string' && allowed.has(operation)) {
29106
+ selected.add(operation);
29107
+ }
29108
+ }
29109
+ return orderedValues.filter((operation) => selected.has(operation));
29110
+ }
29111
+ function toggleManagedToolOperation(selectedOperations, options, operation, checked) {
29112
+ const nextSelected = new Set(getManagedToolSelectedOperations(selectedOperations, options));
29113
+ if (checked) {
29114
+ nextSelected.add(operation);
29115
+ }
29116
+ else {
29117
+ nextSelected.delete(operation);
29118
+ }
29119
+ return options
29120
+ .map((option) => option.value)
29121
+ .filter((value) => nextSelected.has(value));
29122
+ }
29123
+ function getRequiredGoogleScopes(managedTools) {
29124
+ const requiredScopes = [...GOOGLE_IDENTITY_SCOPES];
29125
+ if (managedTools?.google_calendar?.enabled) {
29126
+ for (const operation of getManagedToolSelectedOperations(managedTools.google_calendar.selected_operations, GOOGLE_CALENDAR_OPERATION_OPTIONS)) {
29127
+ requiredScopes.push(...(GOOGLE_CALENDAR_REQUIRED_SCOPES_BY_OPERATION[operation] || []));
29128
+ }
29129
+ }
29130
+ if (managedTools?.google_sheets?.enabled) {
29131
+ for (const operation of getManagedToolSelectedOperations(managedTools.google_sheets.selected_operations, GOOGLE_SHEETS_OPERATION_OPTIONS)) {
29132
+ requiredScopes.push(...(GOOGLE_SHEETS_REQUIRED_SCOPES_BY_OPERATION[operation] || []));
29133
+ }
29134
+ }
29135
+ if (managedTools?.google_gmail?.enabled) {
29136
+ for (const operation of getManagedToolSelectedOperations(managedTools.google_gmail.selected_operations, GOOGLE_GMAIL_OPERATION_OPTIONS)) {
29137
+ requiredScopes.push(...(GOOGLE_GMAIL_REQUIRED_SCOPES_BY_OPERATION[operation] || []));
29138
+ }
29139
+ }
29140
+ return uniqueStrings(requiredScopes);
29141
+ }
29142
+ function getMissingGoogleScopes(requiredScopes, grantedScopes) {
29143
+ const grantedScopeSet = new Set(uniqueStrings(grantedScopes || []));
29144
+ return uniqueStrings(requiredScopes || []).filter((scope) => !grantedScopeSet.has(scope));
29145
+ }
29146
+ function getMissingGoogleScopesForManagedTools(managedTools, grantedScopes) {
29147
+ return getMissingGoogleScopes(getRequiredGoogleScopes(managedTools), grantedScopes);
29148
+ }
29149
+ function isGoogleReconnectRequired(managedTools, grantedScopes, connected) {
29150
+ return connected && getMissingGoogleScopesForManagedTools(managedTools, grantedScopes).length > 0;
29151
+ }
29152
+ function getGoogleReconnectState(managedTools, status) {
29153
+ const required_scopes = getRequiredGoogleScopes(managedTools);
29154
+ const granted_scopes = status?.granted_scopes || [];
29155
+ const missing_scopes = getMissingGoogleScopes(required_scopes, granted_scopes);
29156
+ return {
29157
+ required_scopes,
29158
+ missing_scopes,
29159
+ reconnect_required: (Boolean(status?.connected) && missing_scopes.length > 0) ||
29160
+ Boolean(status?.reconnect_required),
29161
+ };
29162
+ }
29163
+ function hasEnabledGoogleManagedTools(managedTools) {
29164
+ return Boolean(managedTools?.google_calendar?.enabled ||
29165
+ managedTools?.google_sheets?.enabled ||
29166
+ managedTools?.google_gmail?.enabled);
29167
+ }
29168
+
28446
29169
  /**
28447
29170
  * VoiceAgentWidget - UI widget for Voice.ai
28448
29171
  *
@@ -28905,33 +29628,39 @@ class VoiceAI {
28905
29628
  /** Agent management - create, update, deploy, pause, delete agents. */
28906
29629
  get agents() {
28907
29630
  if (!this._agents)
28908
- throw new VoiceAIError('API key required for agents API. Pass apiKey in the constructor.');
29631
+ throw new VoiceAIError('API key required for agents API, or pass authToken/getAuthToken in the constructor.');
28909
29632
  return this._agents;
28910
29633
  }
28911
29634
  /** Analytics - call history, transcripts, stats. */
28912
29635
  get analytics() {
28913
29636
  if (!this._analytics)
28914
- throw new VoiceAIError('API key required for analytics API. Pass apiKey in the constructor.');
29637
+ throw new VoiceAIError('API key required for analytics API, or pass authToken/getAuthToken in the constructor.');
28915
29638
  return this._analytics;
28916
29639
  }
28917
29640
  /** Knowledge Base - manage RAG documents. */
28918
29641
  get knowledgeBase() {
28919
29642
  if (!this._knowledgeBase)
28920
- throw new VoiceAIError('API key required for knowledgeBase API. Pass apiKey in the constructor.');
29643
+ throw new VoiceAIError('API key required for knowledgeBase API, or pass authToken/getAuthToken in the constructor.');
28921
29644
  return this._knowledgeBase;
28922
29645
  }
28923
29646
  /** Phone Numbers - search, select, release phone numbers. */
28924
29647
  get phoneNumbers() {
28925
29648
  if (!this._phoneNumbers)
28926
- throw new VoiceAIError('API key required for phoneNumbers API. Pass apiKey in the constructor.');
29649
+ throw new VoiceAIError('API key required for phoneNumbers API, or pass authToken/getAuthToken in the constructor.');
28927
29650
  return this._phoneNumbers;
28928
29651
  }
28929
29652
  /** Text-to-Speech - generate speech, manage voices, clone voices. */
28930
29653
  get tts() {
28931
29654
  if (!this._tts)
28932
- throw new VoiceAIError('API key required for tts API. Pass apiKey in the constructor.');
29655
+ throw new VoiceAIError('API key required for tts API, or pass authToken/getAuthToken in the constructor.');
28933
29656
  return this._tts;
28934
29657
  }
29658
+ /** Managed tools - provider-specific OAuth/status/disconnect helpers. */
29659
+ get managedTools() {
29660
+ if (!this._managedTools)
29661
+ throw new VoiceAIError('API key required for managedTools API, or pass authToken/getAuthToken in the constructor.');
29662
+ return this._managedTools;
29663
+ }
28935
29664
  /**
28936
29665
  * Create a new VoiceAI client
28937
29666
  *
@@ -28957,15 +29686,23 @@ class VoiceAI {
28957
29686
  this.agentParticipantId = null;
28958
29687
  this.audioLevelInterval = null;
28959
29688
  this.apiKey = config.apiKey || '';
29689
+ this.authToken = config.authToken;
29690
+ this.getAuthToken = config.getAuthToken;
28960
29691
  this.apiUrl = config.apiUrl || DEFAULT_API_URL;
28961
- // Initialize API clients when apiKey is provided
28962
- if (this.apiKey) {
28963
- const clientConfig = { apiKey: this.apiKey, apiUrl: this.apiUrl };
29692
+ // Initialize API clients when auth is provided
29693
+ if (this.apiKey || this.authToken || this.getAuthToken) {
29694
+ const clientConfig = {
29695
+ apiKey: this.apiKey,
29696
+ authToken: this.authToken,
29697
+ getAuthToken: this.getAuthToken,
29698
+ apiUrl: this.apiUrl,
29699
+ };
28964
29700
  this._agents = new AgentClient(clientConfig);
28965
29701
  this._analytics = new AnalyticsClient(clientConfig);
28966
29702
  this._knowledgeBase = new KnowledgeBaseClient(clientConfig);
28967
29703
  this._phoneNumbers = new PhoneNumberClient(clientConfig);
28968
29704
  this._tts = new TTSClient(clientConfig);
29705
+ this._managedTools = new ManagedToolsClient(clientConfig);
28969
29706
  }
28970
29707
  }
28971
29708
  // ==========================================================================
@@ -29311,11 +30048,11 @@ class VoiceAI {
29311
30048
  if (this.cachedConnectionDetails && !this.isTokenExpired(this.cachedConnectionDetails.participantToken)) {
29312
30049
  return this.cachedConnectionDetails;
29313
30050
  }
29314
- // Mode 2: Direct API call with API key (constructor or per-call)
29315
- if (!this.apiKey && !options.apiKey) {
30051
+ // Mode 2: Direct API call with API key or bearer auth (constructor or per-call)
30052
+ if (!(await this.resolveAuthToken(options))) {
29316
30053
  throw new Error('No authentication method configured. Use one of:\n' +
29317
30054
  '1. connectRoom() with pre-fetched details from your backend\n' +
29318
- '2. API key: new VoiceAI({ apiKey: "vk_..." }) or connect({ apiKey: "vk_..." })');
30055
+ '2. API key or auth token: new VoiceAI({ apiKey: "vk_..." }) / new VoiceAI({ authToken: "..." })');
29319
30056
  }
29320
30057
  const connectionDetails = await this.fetchConnectionDetails(options);
29321
30058
  this.cachedConnectionDetails = connectionDetails;
@@ -29330,11 +30067,28 @@ class VoiceAI {
29330
30067
  * Used by the public getConnectionDetails() method.
29331
30068
  */
29332
30069
  async fetchConnectionDetails(options) {
29333
- if (!this.apiKey && !options.apiKey) {
29334
- throw new Error('API key is required for getConnectionDetails(). Pass { apiKey: "vk_..." } to the constructor or options.');
30070
+ if (!(await this.resolveAuthToken(options))) {
30071
+ throw new Error('API key is required for getConnectionDetails(), or pass authToken/getAuthToken to the constructor.');
29335
30072
  }
29336
30073
  return this.fetchConnectionDetailsFromApi(options);
29337
30074
  }
30075
+ async resolveAuthToken(options = {}) {
30076
+ if (options.apiKey)
30077
+ return options.apiKey;
30078
+ if (options.authToken)
30079
+ return options.authToken;
30080
+ if (this.apiKey)
30081
+ return this.apiKey;
30082
+ if (this.authToken)
30083
+ return this.authToken;
30084
+ if (this.getAuthToken) {
30085
+ const resolvedToken = await this.getAuthToken();
30086
+ if (typeof resolvedToken === 'string' && resolvedToken.trim()) {
30087
+ return resolvedToken;
30088
+ }
30089
+ }
30090
+ return '';
30091
+ }
29338
30092
  async fetchConnectionDetailsFromApi(options) {
29339
30093
  const url = options.apiUrl || this.apiUrl;
29340
30094
  // Use test-connection-details for testMode (allows testing paused/undeployed agents)
@@ -29351,13 +30105,13 @@ class VoiceAI {
29351
30105
  if (options.dynamicVariables) {
29352
30106
  requestData.dynamic_variables = options.dynamicVariables;
29353
30107
  }
29354
- const apiKey = options.apiKey || this.apiKey;
29355
- this.effectiveApiKey = apiKey;
30108
+ const authToken = await this.resolveAuthToken(options);
30109
+ this.effectiveApiKey = authToken;
29356
30110
  const response = await fetch(endpoint, {
29357
30111
  method: 'POST',
29358
30112
  headers: {
29359
30113
  'Content-Type': 'application/json',
29360
- 'Authorization': `Bearer ${apiKey}`
30114
+ 'Authorization': `Bearer ${authToken}`
29361
30115
  },
29362
30116
  body: JSON.stringify(requestData)
29363
30117
  });
@@ -29631,9 +30385,27 @@ function generateOptimalAudioOptions(options) {
29631
30385
  return { ...optimalOptions, ...options };
29632
30386
  }
29633
30387
 
30388
+ exports.GOOGLE_CALENDAR_OPERATION_OPTIONS = GOOGLE_CALENDAR_OPERATION_OPTIONS;
30389
+ exports.GOOGLE_CALENDAR_SCOPE = GOOGLE_CALENDAR_SCOPE;
30390
+ exports.GOOGLE_GMAIL_OPERATION_OPTIONS = GOOGLE_GMAIL_OPERATION_OPTIONS;
30391
+ exports.GOOGLE_GMAIL_READ_SCOPE = GOOGLE_GMAIL_READ_SCOPE;
30392
+ exports.GOOGLE_GMAIL_SEND_SCOPE = GOOGLE_GMAIL_SEND_SCOPE;
30393
+ exports.GOOGLE_IDENTITY_SCOPES = GOOGLE_IDENTITY_SCOPES;
30394
+ exports.GOOGLE_MANAGED_OPERATION_OPTIONS = GOOGLE_MANAGED_OPERATION_OPTIONS;
30395
+ exports.GOOGLE_SHEETS_OPERATION_OPTIONS = GOOGLE_SHEETS_OPERATION_OPTIONS;
30396
+ exports.GOOGLE_SHEETS_SCOPE = GOOGLE_SHEETS_SCOPE;
30397
+ exports.IANA_TIMEZONE_OPTIONS = IANA_TIMEZONE_OPTIONS;
29634
30398
  exports.VoiceAI = VoiceAI;
29635
30399
  exports.VoiceAIError = VoiceAIError;
29636
30400
  exports.VoiceAgentWidget = VoiceAgentWidget;
29637
30401
  exports.default = VoiceAI;
29638
30402
  exports.generateOptimalAudioOptions = generateOptimalAudioOptions;
30403
+ exports.getGoogleReconnectState = getGoogleReconnectState;
30404
+ exports.getManagedToolSelectedOperations = getManagedToolSelectedOperations;
30405
+ exports.getMissingGoogleScopes = getMissingGoogleScopes;
30406
+ exports.getMissingGoogleScopesForManagedTools = getMissingGoogleScopesForManagedTools;
30407
+ exports.getRequiredGoogleScopes = getRequiredGoogleScopes;
30408
+ exports.hasEnabledGoogleManagedTools = hasEnabledGoogleManagedTools;
30409
+ exports.isGoogleReconnectRequired = isGoogleReconnectRequired;
30410
+ exports.toggleManagedToolOperation = toggleManagedToolOperation;
29639
30411
  //# sourceMappingURL=index.js.map