@voice-ai-labs/web-sdk 0.5.0 → 0.7.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/README.md CHANGED
@@ -267,12 +267,17 @@ const stats = await voiceai.analytics.getStatsSummary();
267
267
 
268
268
  ## Webhooks
269
269
 
270
- Configure webhooks to receive real-time notifications when call events occur.
270
+ Configure webhooks when creating or updating an agent.
271
271
 
272
- ### Configure Webhook Events
272
+ `webhooks.events` and `webhooks.tools` use different contracts:
273
+
274
+ - `webhooks.events` supports `secret` (write-only on create/update) and `has_secret` (read-only on fetch).
275
+ - `webhooks.tools` define outbound API calls and do not use `secret`.
276
+
277
+ ### Configure Webhook Events and Tools
273
278
 
274
279
  ```typescript
275
- // Create agent with webhook events
280
+ // Create agent with webhook events and tools
276
281
  const agent = await voiceai.agents.create({
277
282
  name: 'Support Agent',
278
283
  config: {
@@ -280,11 +285,36 @@ const agent = await voiceai.agents.create({
280
285
  webhooks: {
281
286
  events: {
282
287
  url: 'https://your-server.com/webhooks/voice-events',
283
- secret: 'your-hmac-secret', // Optional: for signature verification
288
+ secret: 'your-hmac-secret', // Event webhook signing secret
284
289
  events: ['call.started', 'call.completed'], // Or omit for all events
285
290
  timeout: 5,
286
291
  enabled: true
287
- }
292
+ },
293
+ tools: [
294
+ {
295
+ name: 'get_account_status',
296
+ description: 'Fetches current account status for a customer.',
297
+ url: 'https://your-server.com/webhooks/tools/account-status',
298
+ parameters: {
299
+ customer_id: 'string'
300
+ },
301
+ method: 'POST',
302
+ execution_mode: 'sync',
303
+ auth_type: 'api_key',
304
+ auth_token: 'your-api-key',
305
+ headers: {
306
+ 'X-Service-Version': '2026-02'
307
+ },
308
+ response: {
309
+ type: 'object',
310
+ properties: {
311
+ status: { type: 'string' },
312
+ tier: { type: 'string' }
313
+ }
314
+ },
315
+ timeout: 10
316
+ }
317
+ ]
288
318
  }
289
319
  }
290
320
  });
@@ -297,12 +327,33 @@ await voiceai.agents.update(agentId, {
297
327
  url: 'https://your-server.com/webhooks',
298
328
  events: ['call.completed'], // Only receive call.completed
299
329
  enabled: true
300
- }
330
+ },
331
+ tools: [
332
+ {
333
+ name: 'search_knowledge_base',
334
+ description: 'Searches KB and returns ranked snippets.',
335
+ url: 'https://your-server.com/webhooks/tools/search-kb',
336
+ parameters: {
337
+ query: 'string',
338
+ top_k: 'number'
339
+ },
340
+ method: 'GET',
341
+ execution_mode: 'async',
342
+ auth_type: 'custom_headers',
343
+ headers: {
344
+ 'X-Internal-Token': 'your-internal-token'
345
+ },
346
+ timeout: 20
347
+ }
348
+ ]
301
349
  }
302
350
  }
303
351
  });
304
352
  ```
305
353
 
354
+ Required fields for each webhook tool: `name`, `description`, `parameters`, `url`, `method`, `execution_mode`, `auth_type`.
355
+ Optional fields: `auth_token`, `headers`, `response`, `timeout`.
356
+
306
357
  ### Event Types
307
358
 
308
359
  | Event | Description |
@@ -310,9 +361,9 @@ await voiceai.agents.update(agentId, {
310
361
  | `call.started` | Call connected, agent ready |
311
362
  | `call.completed` | Call ended, includes transcript and usage data |
312
363
 
313
- ### Webhook Payload
364
+ ### Event Webhook Payload
314
365
 
315
- Your server receives POST requests with this structure:
366
+ Your event webhook URL receives POST requests with this structure:
316
367
 
317
368
  ```typescript
318
369
  interface WebhookEvent {
@@ -328,14 +379,57 @@ interface WebhookEvent {
328
379
  }
329
380
  ```
330
381
 
331
- ### Signature Verification
382
+ ### Webhook Tool Request Shape
383
+
384
+ For webhook tools, Voice.ai makes outbound HTTP requests directly to each tool `url`.
385
+
386
+ - `method: 'GET'`: tool arguments are sent as query parameters.
387
+ - `method: 'POST' | 'PUT' | 'PATCH' | 'DELETE'`: tool arguments are sent as JSON body.
388
+ - Metadata headers are always sent:
389
+ - `X-VoiceAI-Request-Id`
390
+ - `X-VoiceAI-Tool-Name`
391
+ - `X-VoiceAI-Agent-Id`
392
+ - `X-VoiceAI-Call-Id`
393
+
394
+ ```http
395
+ GET /webhooks/tools/search-kb?query=refund+policy&top_k=3
396
+ X-VoiceAI-Request-Id: req_123
397
+ X-VoiceAI-Tool-Name: search_knowledge_base
398
+ X-VoiceAI-Agent-Id: agent_123
399
+ X-VoiceAI-Call-Id: call_123
400
+ ```
401
+
402
+ ```http
403
+ POST /webhooks/tools/account-status
404
+ Content-Type: application/json
405
+ X-VoiceAI-Request-Id: req_456
406
+ X-VoiceAI-Tool-Name: get_account_status
407
+ X-VoiceAI-Agent-Id: agent_123
408
+ X-VoiceAI-Call-Id: call_123
409
+
410
+ {"customer_id":"cust_789"}
411
+ ```
412
+
413
+ ### Webhook Tool Authentication
414
+
415
+ - `auth_type: 'none'`: no auth headers added.
416
+ - `auth_type: 'bearer_token'`: sends `Authorization: Bearer <auth_token>`.
417
+ - `auth_type: 'api_key'`: sends `X-API-Key: <auth_token>`.
418
+ - `auth_type: 'custom_headers'`: sends your configured `headers` map.
419
+
420
+ ### Webhook Tool Response Behavior
421
+
422
+ - `execution_mode: 'sync'`: waits for downstream response body; non-2xx fails the tool call.
423
+ - `execution_mode: 'async'`: treats any 2xx as accepted and does not require a response payload.
424
+
425
+ ### Signature Verification (Event Webhooks)
332
426
 
333
- If you configure a `secret`, verify the HMAC-SHA256 signature:
427
+ If you configure `webhooks.events.secret`, verify the HMAC-SHA256 signature:
334
428
 
335
429
  ```typescript
336
430
  import crypto from 'crypto';
337
431
 
338
- function verifyWebhook(body: string, headers: Headers, secret: string): boolean {
432
+ function verifyEventWebhook(body: string, headers: Headers, secret: string): boolean {
339
433
  const signature = headers.get('x-webhook-signature');
340
434
  const timestamp = headers.get('x-webhook-timestamp');
341
435
 
package/dist/index.esm.js CHANGED
@@ -7200,6 +7200,7 @@ var LoggerNames;
7200
7200
  LoggerNames["PCManager"] = "livekit-pc-manager";
7201
7201
  LoggerNames["PCTransport"] = "livekit-pc-transport";
7202
7202
  LoggerNames["E2EE"] = "lk-e2ee";
7203
+ LoggerNames["DataTracks"] = "livekit-data-tracks";
7203
7204
  })(LoggerNames || (LoggerNames = {}));
7204
7205
  let livekitLogger = loglevelExports.getLogger('livekit');
7205
7206
  Object.values(LoggerNames).map(name => loglevelExports.getLogger(name));
@@ -10701,7 +10702,7 @@ function getMatch(exp, ua) {
10701
10702
  }
10702
10703
  function getOSVersion(ua) {
10703
10704
  return ua.includes('mac os') ? getMatch(/\(.+?(\d+_\d+(:?_\d+)?)/, ua, 1).replace(/_/g, '.') : undefined;
10704
- }var version$1 = "2.17.1";const version = version$1;
10705
+ }var version$1 = "2.17.2";const version = version$1;
10705
10706
  const protocolVersion = 16;/** Base error that all LiveKit specific custom errors inherit from. */
10706
10707
  class LivekitError extends Error {
10707
10708
  constructor(code, message, options) {
@@ -15625,6 +15626,7 @@ class PCTransport extends eventsExports.EventEmitter {
15625
15626
  yield this._pc.setRemoteDescription(currentSD);
15626
15627
  } else {
15627
15628
  this.renegotiate = true;
15629
+ this.log.debug('requesting renegotiation', Object.assign({}, this.logContext));
15628
15630
  return;
15629
15631
  }
15630
15632
  } else if (!this._pc || this._pc.signalingState === 'closed') {
@@ -16225,25 +16227,41 @@ class PCTransportManager {
16225
16227
  negotiate(abortController) {
16226
16228
  return __awaiter(this, void 0, void 0, function* () {
16227
16229
  return new TypedPromise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
16228
- const negotiationTimeout = setTimeout(() => {
16230
+ let negotiationTimeout = setTimeout(() => {
16229
16231
  reject(new NegotiationError('negotiation timed out'));
16230
16232
  }, this.peerConnectionTimeout);
16231
- const abortHandler = () => {
16233
+ const cleanup = () => {
16232
16234
  clearTimeout(negotiationTimeout);
16235
+ this.publisher.off(PCEvents.NegotiationStarted, onNegotiationStarted);
16236
+ abortController.signal.removeEventListener('abort', abortHandler);
16237
+ };
16238
+ const abortHandler = () => {
16239
+ cleanup();
16233
16240
  reject(new NegotiationError('negotiation aborted'));
16234
16241
  };
16235
- abortController.signal.addEventListener('abort', abortHandler);
16236
- this.publisher.once(PCEvents.NegotiationStarted, () => {
16242
+ // Reset the timeout each time a renegotiation cycle starts. This
16243
+ // prevents premature timeouts when the negotiation machinery is
16244
+ // actively renegotiating (offers going out, answers coming back) but
16245
+ // NegotiationComplete hasn't fired yet because new requirements keep
16246
+ // arriving between offer/answer round-trips.
16247
+ const onNegotiationStarted = () => {
16237
16248
  if (abortController.signal.aborted) {
16238
16249
  return;
16239
16250
  }
16240
- this.publisher.once(PCEvents.NegotiationComplete, () => {
16241
- clearTimeout(negotiationTimeout);
16242
- resolve();
16243
- });
16251
+ clearTimeout(negotiationTimeout);
16252
+ negotiationTimeout = setTimeout(() => {
16253
+ cleanup();
16254
+ reject(new NegotiationError('negotiation timed out'));
16255
+ }, this.peerConnectionTimeout);
16256
+ };
16257
+ abortController.signal.addEventListener('abort', abortHandler);
16258
+ this.publisher.on(PCEvents.NegotiationStarted, onNegotiationStarted);
16259
+ this.publisher.once(PCEvents.NegotiationComplete, () => {
16260
+ cleanup();
16261
+ resolve();
16244
16262
  });
16245
16263
  yield this.publisher.negotiate(e => {
16246
- clearTimeout(negotiationTimeout);
16264
+ cleanup();
16247
16265
  if (e instanceof Error) {
16248
16266
  reject(e);
16249
16267
  } else {
@@ -16739,6 +16757,7 @@ class LocalTrack extends Track {
16739
16757
  let loggerOptions = arguments.length > 4 ? arguments[4] : undefined;
16740
16758
  super(mediaTrack, kind, loggerOptions);
16741
16759
  this.manuallyStopped = false;
16760
+ this.pendingDeviceChange = false;
16742
16761
  this._isUpstreamPaused = false;
16743
16762
  this.handleTrackMuteEvent = () => this.debouncedTrackMuteHandler().catch(() => this.log.debug('track mute bounce got cancelled by an unmute event', this.logContext));
16744
16763
  this.debouncedTrackMuteHandler = r(() => __awaiter(this, void 0, void 0, function* () {
@@ -16914,6 +16933,7 @@ class LocalTrack extends Track {
16914
16933
  // when track is muted, underlying media stream track is stopped and
16915
16934
  // will be restarted later
16916
16935
  if (this.isMuted) {
16936
+ this.pendingDeviceChange = true;
16917
16937
  return true;
16918
16938
  }
16919
16939
  yield this.restartTrack();
@@ -17033,6 +17053,7 @@ class LocalTrack extends Track {
17033
17053
  this.log.debug('re-acquired MediaStreamTrack', this.logContext);
17034
17054
  yield this.setMediaStreamTrack(newTrack);
17035
17055
  this._constraints = constraints;
17056
+ this.pendingDeviceChange = false;
17036
17057
  this.emit(TrackEvent.Restarted, this);
17037
17058
  if (this.manuallyStopped) {
17038
17059
  this.log.warn('track was stopped during a restart, stopping restarted track', this.logContext);
@@ -17411,8 +17432,7 @@ class LocalTrack extends Track {
17411
17432
  this.log.debug('Track already unmuted', this.logContext);
17412
17433
  return this;
17413
17434
  }
17414
- const deviceHasChanged = this._constraints.deviceId && this._mediaStreamTrack.getSettings().deviceId !== unwrapConstraint(this._constraints.deviceId);
17415
- if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended' || deviceHasChanged) && !this.isUserProvided) {
17435
+ if (this.source === Track.Source.Microphone && (this.stopOnMute || this._mediaStreamTrack.readyState === 'ended' || this.pendingDeviceChange) && !this.isUserProvided) {
17416
17436
  this.log.debug('reacquiring mic track', this.logContext);
17417
17437
  yield this.restartTrack();
17418
17438
  }
@@ -19739,8 +19759,8 @@ class RTCEngine extends eventsExports.EventEmitter {
19739
19759
  if (!this.pcManager) {
19740
19760
  return false;
19741
19761
  }
19742
- // primary connection
19743
- if (this.pcManager.currentState !== PCTransportState.CONNECTED) {
19762
+ const allowedConnectionStates = [PCTransportState.CONNECTING, PCTransportState.CONNECTED];
19763
+ if (!allowedConnectionStates.includes(this.pcManager.currentState)) {
19744
19764
  return false;
19745
19765
  }
19746
19766
  // ensure signal is connected
@@ -19774,6 +19794,7 @@ class RTCEngine extends eventsExports.EventEmitter {
19774
19794
  reject(new NegotiationError('cannot negotiate on closed engine'));
19775
19795
  }
19776
19796
  this.on(EngineEvent.Closing, handleClosed);
19797
+ this.on(EngineEvent.Restarting, handleClosed);
19777
19798
  this.pcManager.publisher.once(PCEvents.RTPVideoPayloadTypes, rtpTypes => {
19778
19799
  const rtpMap = new Map();
19779
19800
  rtpTypes.forEach(rtp => {
@@ -19788,6 +19809,12 @@ class RTCEngine extends eventsExports.EventEmitter {
19788
19809
  yield this.pcManager.negotiate(abortController);
19789
19810
  resolve();
19790
19811
  } catch (e) {
19812
+ if (abortController.signal.aborted) {
19813
+ // negotiation was aborted due to engine close or restart, resolve
19814
+ // cleanly to avoid triggering a cascading reconnect loop
19815
+ resolve();
19816
+ return;
19817
+ }
19791
19818
  if (e instanceof NegotiationError) {
19792
19819
  this.fullReconnectOnNext = true;
19793
19820
  }
@@ -19799,6 +19826,7 @@ class RTCEngine extends eventsExports.EventEmitter {
19799
19826
  }
19800
19827
  } finally {
19801
19828
  this.off(EngineEvent.Closing, handleClosed);
19829
+ this.off(EngineEvent.Restarting, handleClosed);
19802
19830
  }
19803
19831
  }));
19804
19832
  });
@@ -26016,7 +26044,7 @@ class Room extends eventsExports.EventEmitter {
26016
26044
  numFailures: consecutiveFailures,
26017
26045
  engine: this.engine ? {
26018
26046
  closed: this.engine.isClosed,
26019
- transportsConnected: this.engine.verifyTransport()
26047
+ transportsConnectedOrConnecting: this.engine.verifyTransport()
26020
26048
  } : undefined
26021
26049
  }));
26022
26050
  if (consecutiveFailures >= 3) {
@@ -26212,7 +26240,56 @@ function mapArgs(args) {
26212
26240
  return arg;
26213
26241
  });
26214
26242
  }// This file was generated from JSON Schema using quicktype, do not modify it directly.
26215
- var CheckStatus;
26243
+ var DataTrackDeserializeErrorReason;
26244
+ (function (DataTrackDeserializeErrorReason) {
26245
+ DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["TooShort"] = 0] = "TooShort";
26246
+ DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["HeaderOverrun"] = 1] = "HeaderOverrun";
26247
+ DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["MissingExtWords"] = 2] = "MissingExtWords";
26248
+ DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["UnsupportedVersion"] = 3] = "UnsupportedVersion";
26249
+ DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["InvalidHandle"] = 4] = "InvalidHandle";
26250
+ DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["MalformedExt"] = 5] = "MalformedExt";
26251
+ })(DataTrackDeserializeErrorReason || (DataTrackDeserializeErrorReason = {}));
26252
+ var DataTrackSerializeErrorReason;
26253
+ (function (DataTrackSerializeErrorReason) {
26254
+ DataTrackSerializeErrorReason[DataTrackSerializeErrorReason["TooSmallForHeader"] = 0] = "TooSmallForHeader";
26255
+ DataTrackSerializeErrorReason[DataTrackSerializeErrorReason["TooSmallForPayload"] = 1] = "TooSmallForPayload";
26256
+ })(DataTrackSerializeErrorReason || (DataTrackSerializeErrorReason = {}));
26257
+ var DataTrackExtensionTag;
26258
+ (function (DataTrackExtensionTag) {
26259
+ DataTrackExtensionTag[DataTrackExtensionTag["UserTimestamp"] = 2] = "UserTimestamp";
26260
+ DataTrackExtensionTag[DataTrackExtensionTag["E2ee"] = 1] = "E2ee";
26261
+ })(DataTrackExtensionTag || (DataTrackExtensionTag = {}));
26262
+ DataTrackExtensionTag.UserTimestamp;
26263
+ DataTrackExtensionTag.E2ee;
26264
+ var DataTrackHandleErrorReason;
26265
+ (function (DataTrackHandleErrorReason) {
26266
+ DataTrackHandleErrorReason[DataTrackHandleErrorReason["Reserved"] = 0] = "Reserved";
26267
+ DataTrackHandleErrorReason[DataTrackHandleErrorReason["TooLarge"] = 1] = "TooLarge";
26268
+ })(DataTrackHandleErrorReason || (DataTrackHandleErrorReason = {}));
26269
+ /** Marker indicating a packet's position in relation to a frame. */
26270
+ var FrameMarker;
26271
+ (function (FrameMarker) {
26272
+ /** Packet is the first in a frame. */
26273
+ FrameMarker[FrameMarker["Start"] = 0] = "Start";
26274
+ /** Packet is within a frame. */
26275
+ FrameMarker[FrameMarker["Inter"] = 1] = "Inter";
26276
+ /** Packet is the last in a frame. */
26277
+ FrameMarker[FrameMarker["Final"] = 2] = "Final";
26278
+ /** Packet is the only one in a frame. */
26279
+ FrameMarker[FrameMarker["Single"] = 3] = "Single";
26280
+ })(FrameMarker || (FrameMarker = {}));
26281
+ var DataTrackPacketizerReason;
26282
+ (function (DataTrackPacketizerReason) {
26283
+ DataTrackPacketizerReason[DataTrackPacketizerReason["MtuTooShort"] = 0] = "MtuTooShort";
26284
+ })(DataTrackPacketizerReason || (DataTrackPacketizerReason = {}));getLogger(LoggerNames.DataTracks);
26285
+ /** Reason why a frame was dropped. */
26286
+ var DataTrackDepacketizerDropReason;
26287
+ (function (DataTrackDepacketizerDropReason) {
26288
+ DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["Interrupted"] = 0] = "Interrupted";
26289
+ DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["UnknownFrame"] = 1] = "UnknownFrame";
26290
+ DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["BufferFull"] = 2] = "BufferFull";
26291
+ DataTrackDepacketizerDropReason[DataTrackDepacketizerDropReason["Incomplete"] = 3] = "Incomplete";
26292
+ })(DataTrackDepacketizerDropReason || (DataTrackDepacketizerDropReason = {}));var CheckStatus;
26216
26293
  (function (CheckStatus) {
26217
26294
  CheckStatus[CheckStatus["IDLE"] = 0] = "IDLE";
26218
26295
  CheckStatus[CheckStatus["RUNNING"] = 1] = "RUNNING";
@@ -27131,44 +27208,7 @@ class JWSSignatureVerificationFailed extends JOSEError {
27131
27208
  _defineProperty(this, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
27132
27209
  }
27133
27210
  }
27134
- _defineProperty(JWSSignatureVerificationFailed, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');var DataTrackHandleErrorReason;
27135
- (function (DataTrackHandleErrorReason) {
27136
- DataTrackHandleErrorReason[DataTrackHandleErrorReason["Reserved"] = 0] = "Reserved";
27137
- DataTrackHandleErrorReason[DataTrackHandleErrorReason["TooLarge"] = 1] = "TooLarge";
27138
- })(DataTrackHandleErrorReason || (DataTrackHandleErrorReason = {}));
27139
- var DataTrackDeserializeErrorReason;
27140
- (function (DataTrackDeserializeErrorReason) {
27141
- DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["TooShort"] = 0] = "TooShort";
27142
- DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["HeaderOverrun"] = 1] = "HeaderOverrun";
27143
- DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["MissingExtWords"] = 2] = "MissingExtWords";
27144
- DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["UnsupportedVersion"] = 3] = "UnsupportedVersion";
27145
- DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["InvalidHandle"] = 4] = "InvalidHandle";
27146
- DataTrackDeserializeErrorReason[DataTrackDeserializeErrorReason["MalformedExt"] = 5] = "MalformedExt";
27147
- })(DataTrackDeserializeErrorReason || (DataTrackDeserializeErrorReason = {}));
27148
- var DataTrackSerializeErrorReason;
27149
- (function (DataTrackSerializeErrorReason) {
27150
- DataTrackSerializeErrorReason[DataTrackSerializeErrorReason["TooSmallForHeader"] = 0] = "TooSmallForHeader";
27151
- DataTrackSerializeErrorReason[DataTrackSerializeErrorReason["TooSmallForPayload"] = 1] = "TooSmallForPayload";
27152
- })(DataTrackSerializeErrorReason || (DataTrackSerializeErrorReason = {}));
27153
- var DataTrackExtensionTag;
27154
- (function (DataTrackExtensionTag) {
27155
- DataTrackExtensionTag[DataTrackExtensionTag["UserTimestamp"] = 2] = "UserTimestamp";
27156
- DataTrackExtensionTag[DataTrackExtensionTag["E2ee"] = 1] = "E2ee";
27157
- })(DataTrackExtensionTag || (DataTrackExtensionTag = {}));
27158
- DataTrackExtensionTag.UserTimestamp;
27159
- DataTrackExtensionTag.E2ee;
27160
- /** Marker indicating a packet's position in relation to a frame. */
27161
- var FrameMarker;
27162
- (function (FrameMarker) {
27163
- /** Packet is the first in a frame. */
27164
- FrameMarker[FrameMarker["Start"] = 0] = "Start";
27165
- /** Packet is within a frame. */
27166
- FrameMarker[FrameMarker["Inter"] = 1] = "Inter";
27167
- /** Packet is the last in a frame. */
27168
- FrameMarker[FrameMarker["Final"] = 2] = "Final";
27169
- /** Packet is the only one in a frame. */
27170
- FrameMarker[FrameMarker["Single"] = 3] = "Single";
27171
- })(FrameMarker || (FrameMarker = {}));
27211
+ _defineProperty(JWSSignatureVerificationFailed, "code", 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED');
27172
27212
 
27173
27213
  /**
27174
27214
  * Base HTTP Client for Voice.ai API