genesys-cloud-streaming-client 17.2.7 → 17.2.8-develop.120

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.
Files changed (37) hide show
  1. package/dist/cjs/client.d.ts +2 -0
  2. package/dist/cjs/client.js +45 -16
  3. package/dist/cjs/index.d.ts +1 -1
  4. package/dist/cjs/index.js +2 -1
  5. package/dist/cjs/types/interfaces.d.ts +4 -0
  6. package/dist/cjs/types/interfaces.js +6 -1
  7. package/dist/cjs/utils.d.ts +6 -0
  8. package/dist/cjs/utils.js +20 -1
  9. package/dist/deploy-info.json +5 -5
  10. package/dist/es/client.d.ts +2 -0
  11. package/dist/es/client.js +46 -17
  12. package/dist/es/index.bundle.js +76 -26
  13. package/dist/es/index.d.ts +1 -1
  14. package/dist/es/index.js +1 -1
  15. package/dist/es/types/interfaces.d.ts +4 -0
  16. package/dist/es/types/interfaces.js +5 -0
  17. package/dist/es/utils.d.ts +6 -0
  18. package/dist/es/utils.js +18 -0
  19. package/dist/npm/CHANGELOG.md +6 -0
  20. package/dist/npm/client.d.ts +2 -0
  21. package/dist/npm/client.js +45 -16
  22. package/dist/npm/index.d.ts +1 -1
  23. package/dist/npm/index.js +2 -1
  24. package/dist/npm/module.js +1 -1
  25. package/dist/npm/types/interfaces.d.ts +4 -0
  26. package/dist/npm/types/interfaces.js +6 -1
  27. package/dist/npm/utils.d.ts +6 -0
  28. package/dist/npm/utils.js +20 -1
  29. package/dist/streaming-client.browser.ie.js +6 -6
  30. package/dist/streaming-client.browser.js +6 -6
  31. package/dist/v17/streaming-client.browser.ie.js +6 -6
  32. package/dist/v17/streaming-client.browser.js +6 -6
  33. package/dist/v17.2.8/streaming-client.browser.ie.js +32 -0
  34. package/dist/v17.2.8/streaming-client.browser.js +32 -0
  35. package/package.json +119 -117
  36. package/dist/v17.2.7/streaming-client.browser.ie.js +0 -32
  37. package/dist/v17.2.7/streaming-client.browser.js +0 -32
@@ -56,6 +56,8 @@ export declare class Client extends EventEmitter {
56
56
  private getStartingDelay;
57
57
  connect(connectOpts?: StreamingClientConnectOptions): Promise<void>;
58
58
  private backoffConnectRetryHandler;
59
+ private networkErrorNeedsAuth;
60
+ private saslErrorIsRetryable;
59
61
  private makeConnectionAttempt;
60
62
  private setupConnectionMonitoring;
61
63
  private prepareForConnect;
@@ -11,6 +11,7 @@ const ping_1 = require("./ping");
11
11
  const server_monitor_1 = require("./server-monitor");
12
12
  const utils_1 = require("./utils");
13
13
  const http_client_1 = require("./http-client");
14
+ const interfaces_1 = require("./types/interfaces");
14
15
  const events_1 = tslib_1.__importDefault(require("events"));
15
16
  const connection_manager_1 = require("./connection-manager");
16
17
  const exponential_backoff_1 = require("exponential-backoff");
@@ -331,15 +332,17 @@ class Client extends events_1.default {
331
332
  });
332
333
  }
333
334
  catch (err) {
334
- let error = err;
335
+ let errorForThrowing;
336
+ let errorForLogging = err;
335
337
  if (!err) {
336
- error = new Error('Streaming client connection attempted received and undefined error');
338
+ errorForThrowing = new utils_1.StreamingClientError(interfaces_1.StreamingClientErrorTypes.generic, 'Streaming client connection attempted and received an undefined error');
339
+ errorForLogging = errorForThrowing;
337
340
  }
338
341
  else if (err.name === 'AxiosError') {
339
342
  const axiosError = err;
340
343
  const config = axiosError.config || { url: undefined, method: undefined };
341
344
  // sanitized error for logging
342
- error = {
345
+ errorForLogging = {
343
346
  config: {
344
347
  url: config.url,
345
348
  method: config.method
@@ -349,16 +352,26 @@ class Client extends events_1.default {
349
352
  name: axiosError.name,
350
353
  message: axiosError.message
351
354
  };
355
+ errorForThrowing = new utils_1.StreamingClientError(interfaces_1.StreamingClientErrorTypes.generic, 'Failed to connect streaming client due to network error', err);
356
+ if (this.networkErrorNeedsAuth(err)) {
357
+ errorForThrowing = new utils_1.StreamingClientError(interfaces_1.StreamingClientErrorTypes.invalid_token, 'Failed to connect streaming client due to invalid token', err);
358
+ }
352
359
  }
353
- this.logger.error('Failed to connect streaming client', { error });
354
- if (!err) {
355
- throw error;
360
+ else if (err instanceof sasl_error_1.default) {
361
+ errorForThrowing = new utils_1.StreamingClientError(interfaces_1.StreamingClientErrorTypes.invalid_token, 'Failed to connect streaming client due to invalid token', err);
362
+ if (this.saslErrorIsRetryable(err)) {
363
+ errorForThrowing = new utils_1.StreamingClientError(interfaces_1.StreamingClientErrorTypes.generic, 'Streaming client connection attempted and received a SASL error', err);
364
+ }
356
365
  }
357
- throw err;
366
+ else {
367
+ errorForThrowing = new utils_1.StreamingClientError(interfaces_1.StreamingClientErrorTypes.generic, 'Streaming client connection attempted and received an unknown error', err);
368
+ }
369
+ this.logger.error('Failed to connect streaming client', { error: errorForLogging });
370
+ throw errorForThrowing;
358
371
  }
359
372
  }
360
373
  async backoffConnectRetryHandler(connectOpts, err, connectionAttempt) {
361
- var _a, _b, _c, _d, _e;
374
+ var _a, _b, _c, _d;
362
375
  // if we exceed the `numOfAttempts` in the backoff config it still calls this retry fn and just ignores the result
363
376
  // if that's the case, we just want to bail out and ignore all the extra logging here.
364
377
  if (connectionAttempt >= connectOpts.maxConnectionAttempts) {
@@ -382,17 +395,25 @@ class Client extends events_1.default {
382
395
  message: axiosError.message
383
396
  };
384
397
  additionalErrorDetails.error = sanitizedError;
385
- if ([401, 403].includes(((_b = err.response) === null || _b === void 0 ? void 0 : _b.status) || 0)) {
398
+ if (this.networkErrorNeedsAuth(err)) {
386
399
  this.logger.error('Streaming client received an error that it can\'t recover from and will not attempt to reconnect', additionalErrorDetails);
387
400
  return false;
388
401
  }
389
402
  }
390
- // if we get a sasl error, that means we made it all the way to the point of trying to open a websocket and
391
- // it was rejected for some reason. At this point we should do a hard reconnect then try again.
403
+ // If we get a sasl error, that means we made it all the way to the point of trying to open a websocket and
404
+ // it was rejected for some reason. Some errors might resolve if we try connecting again. Others need
405
+ // re-authentication.
392
406
  if (err instanceof sasl_error_1.default) {
393
- this.logger.info('hardReconnectRequired set to true due to sasl error');
394
- this.hardReconnectRequired = true;
395
- Object.assign(additionalErrorDetails, { channelId: err.channelId, stanzaInstanceId: err.stanzaInstanceId });
407
+ if (this.saslErrorIsRetryable(err)) {
408
+ this.logger.info('hardReconnectRequired set to true due to sasl error');
409
+ this.hardReconnectRequired = true;
410
+ Object.assign(additionalErrorDetails, { channelId: err.channelId, stanzaInstanceId: err.stanzaInstanceId });
411
+ }
412
+ else {
413
+ additionalErrorDetails.error = err.condition;
414
+ this.logger.error('Streaming-client received a SASL error that it can\'t recover from and will not attempt to reconnect', additionalErrorDetails);
415
+ return false;
416
+ }
396
417
  }
397
418
  // we don't need to log the stack for a timeout message
398
419
  if (err instanceof timeout_error_1.TimeoutError) {
@@ -405,7 +426,7 @@ class Client extends events_1.default {
405
426
  if (err === null || err === void 0 ? void 0 : err.response) {
406
427
  // This *should* be an axios error according to typings, but it appears this could be an AxiosError *or* and XmlHttpRequest
407
428
  // we'll check both to be safe
408
- const retryAfter = ((_c = err.response.headers) === null || _c === void 0 ? void 0 : _c['retry-after']) || ((_e = (_d = err.response).getResponseHeader) === null || _e === void 0 ? void 0 : _e.call(_d, 'retry-after'));
429
+ const retryAfter = ((_b = err.response.headers) === null || _b === void 0 ? void 0 : _b['retry-after']) || ((_d = (_c = err.response).getResponseHeader) === null || _d === void 0 ? void 0 : _d.call(_c, 'retry-after'));
409
430
  if (retryAfter) {
410
431
  // retry after comes in seconds, we need to return milliseconds
411
432
  let retryDelay = parseInt(retryAfter, 10) * 1000;
@@ -421,6 +442,14 @@ class Client extends events_1.default {
421
442
  this.logger.debug('debug: retry info', { expectedRetryInMs: connectionData.currentDelayMs, appName: this.config.appName, clientId: this.logger.clientId });
422
443
  return true;
423
444
  }
445
+ networkErrorNeedsAuth(error) {
446
+ var _a;
447
+ return [401, 403].includes(((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) || 0);
448
+ }
449
+ saslErrorIsRetryable(error) {
450
+ const retryConditions = ['encryption-required', 'incorrect-encoding', 'invalid-mechanism', 'malformed-request', 'mechanism-too-weak'];
451
+ return retryConditions.includes(error.condition);
452
+ }
424
453
  async makeConnectionAttempt() {
425
454
  var _a, _b;
426
455
  if (!navigator.onLine) {
@@ -550,7 +579,7 @@ class Client extends events_1.default {
550
579
  return Client.version;
551
580
  }
552
581
  static get version() {
553
- return '17.2.7';
582
+ return '17.2.8';
554
583
  }
555
584
  }
556
585
  exports.Client = Client;
@@ -6,5 +6,5 @@ export * from './types/media-session';
6
6
  export * from './types/interfaces';
7
7
  export * from './messenger';
8
8
  export { HttpClient } from './http-client';
9
- export { parseJwt } from './utils';
9
+ export { StreamingClientError, parseJwt } from './utils';
10
10
  export default Client;
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseJwt = exports.HttpClient = void 0;
3
+ exports.parseJwt = exports.StreamingClientError = exports.HttpClient = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  /// <reference path="types/libs.ts" />
6
6
  const client_1 = require("./client");
@@ -12,5 +12,6 @@ tslib_1.__exportStar(require("./messenger"), exports);
12
12
  var http_client_1 = require("./http-client");
13
13
  Object.defineProperty(exports, "HttpClient", { enumerable: true, get: function () { return http_client_1.HttpClient; } });
14
14
  var utils_1 = require("./utils");
15
+ Object.defineProperty(exports, "StreamingClientError", { enumerable: true, get: function () { return utils_1.StreamingClientError; } });
15
16
  Object.defineProperty(exports, "parseJwt", { enumerable: true, get: function () { return utils_1.parseJwt; } });
16
17
  exports.default = client_1.Client;
@@ -101,6 +101,10 @@ export interface IResponseError extends IError {
101
101
  requestBody: string;
102
102
  url: string;
103
103
  }
104
+ export declare enum StreamingClientErrorTypes {
105
+ generic = "generic",
106
+ invalid_token = "invalid_token"
107
+ }
104
108
  export interface IError {
105
109
  message: string;
106
110
  name: string;
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SessionTypes = void 0;
3
+ exports.SessionTypes = exports.StreamingClientErrorTypes = void 0;
4
+ var StreamingClientErrorTypes;
5
+ (function (StreamingClientErrorTypes) {
6
+ StreamingClientErrorTypes["generic"] = "generic";
7
+ StreamingClientErrorTypes["invalid_token"] = "invalid_token";
8
+ })(StreamingClientErrorTypes = exports.StreamingClientErrorTypes || (exports.StreamingClientErrorTypes = {}));
4
9
  var SessionTypes;
5
10
  (function (SessionTypes) {
6
11
  SessionTypes["softphone"] = "softphone";
@@ -1,3 +1,9 @@
1
+ import { StreamingClientErrorTypes } from './types/interfaces';
2
+ export declare class StreamingClientError extends Error {
3
+ type: StreamingClientErrorTypes;
4
+ details?: unknown;
5
+ constructor(type: StreamingClientErrorTypes | null, messageOrError: string | Error, details?: unknown);
6
+ }
1
7
  export declare function timeoutPromise(fn: Function, timeoutMs: number, msg: string, details?: any): Promise<any>;
2
8
  export declare function delay(ms: number): Promise<void>;
3
9
  export declare function splitIntoIndividualTopics(topicString: string): string[];
package/dist/cjs/utils.js CHANGED
@@ -1,8 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.iceIsDifferent = exports.getIcePwdFromSdp = exports.getUfragFromSdp = exports.calculatePayloadSize = exports.parseJwt = exports.retryPromise = exports.isVideoJid = exports.isSoftphoneJid = exports.isScreenRecordingJid = exports.isAcdJid = exports.splitIntoIndividualTopics = exports.delay = exports.timeoutPromise = void 0;
3
+ exports.iceIsDifferent = exports.getIcePwdFromSdp = exports.getUfragFromSdp = exports.calculatePayloadSize = exports.parseJwt = exports.retryPromise = exports.isVideoJid = exports.isSoftphoneJid = exports.isScreenRecordingJid = exports.isAcdJid = exports.splitIntoIndividualTopics = exports.delay = exports.timeoutPromise = exports.StreamingClientError = void 0;
4
4
  const uuid_1 = require("uuid");
5
5
  const timeout_error_1 = require("./types/timeout-error");
6
+ const interfaces_1 = require("./types/interfaces");
7
+ class StreamingClientError extends Error {
8
+ constructor(type, messageOrError, details) {
9
+ let message;
10
+ if (messageOrError instanceof Error) {
11
+ message = messageOrError.message;
12
+ }
13
+ else {
14
+ message = messageOrError;
15
+ }
16
+ super(message);
17
+ if (messageOrError instanceof Error) {
18
+ this.name = messageOrError.name;
19
+ }
20
+ this.type = type !== null && type !== void 0 ? type : interfaces_1.StreamingClientErrorTypes.generic;
21
+ this.details = details;
22
+ }
23
+ }
24
+ exports.StreamingClientError = StreamingClientError;
6
25
  /* istanbul ignore next */
7
26
  function timeoutPromise(fn, timeoutMs, msg, details) {
8
27
  return new Promise(function (resolve, reject) {
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "developercenter-cdn/streaming-client",
3
- "version": "17.2.7",
3
+ "version": "17.2.8",
4
4
  "ecosystem": "pc",
5
5
  "team": "Client Streaming and Signaling",
6
6
  "indexFiles": [
7
7
  {
8
- "file": "v17.2.7/streaming-client.browser.ie.js"
8
+ "file": "v17.2.8/streaming-client.browser.ie.js"
9
9
  },
10
10
  {
11
- "file": "v17.2.7/streaming-client.browser.js"
11
+ "file": "v17.2.8/streaming-client.browser.js"
12
12
  },
13
13
  {
14
14
  "file": "v17/streaming-client.browser.ie.js"
@@ -17,6 +17,6 @@
17
17
  "file": "v17/streaming-client.browser.js"
18
18
  }
19
19
  ],
20
- "build": "103",
21
- "buildDate": "2024-10-10T13:18:34.046712060Z"
20
+ "build": "120",
21
+ "buildDate": "2024-11-07T09:18:50.964692533Z"
22
22
  }
@@ -56,6 +56,8 @@ export declare class Client extends EventEmitter {
56
56
  private getStartingDelay;
57
57
  connect(connectOpts?: StreamingClientConnectOptions): Promise<void>;
58
58
  private backoffConnectRetryHandler;
59
+ private networkErrorNeedsAuth;
60
+ private saslErrorIsRetryable;
59
61
  private makeConnectionAttempt;
60
62
  private setupConnectionMonitoring;
61
63
  private prepareForConnect;
package/dist/es/client.js CHANGED
@@ -7,8 +7,9 @@ import { Notifications } from './notifications';
7
7
  import { WebrtcExtension } from './webrtc';
8
8
  import { Ping } from './ping';
9
9
  import { ServerMonitor } from './server-monitor';
10
- import { delay, parseJwt, timeoutPromise } from './utils';
10
+ import { StreamingClientError, delay, parseJwt, timeoutPromise } from './utils';
11
11
  import { HttpClient } from './http-client';
12
+ import { StreamingClientErrorTypes } from './types/interfaces';
12
13
  import EventEmitter from 'events';
13
14
  import { ConnectionManager } from './connection-manager';
14
15
  import { backOff } from 'exponential-backoff';
@@ -334,15 +335,17 @@ export class Client extends EventEmitter {
334
335
  });
335
336
  }
336
337
  catch (err) {
337
- let error = err;
338
+ let errorForThrowing;
339
+ let errorForLogging = err;
338
340
  if (!err) {
339
- error = new Error('Streaming client connection attempted received and undefined error');
341
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.generic, 'Streaming client connection attempted and received an undefined error');
342
+ errorForLogging = errorForThrowing;
340
343
  }
341
344
  else if (err.name === 'AxiosError') {
342
345
  const axiosError = err;
343
346
  const config = axiosError.config || { url: undefined, method: undefined };
344
347
  // sanitized error for logging
345
- error = {
348
+ errorForLogging = {
346
349
  config: {
347
350
  url: config.url,
348
351
  method: config.method
@@ -352,17 +355,27 @@ export class Client extends EventEmitter {
352
355
  name: axiosError.name,
353
356
  message: axiosError.message
354
357
  };
358
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.generic, 'Failed to connect streaming client due to network error', err);
359
+ if (this.networkErrorNeedsAuth(err)) {
360
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.invalid_token, 'Failed to connect streaming client due to invalid token', err);
361
+ }
355
362
  }
356
- this.logger.error('Failed to connect streaming client', { error });
357
- if (!err) {
358
- throw error;
363
+ else if (err instanceof SaslError) {
364
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.invalid_token, 'Failed to connect streaming client due to invalid token', err);
365
+ if (this.saslErrorIsRetryable(err)) {
366
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.generic, 'Streaming client connection attempted and received a SASL error', err);
367
+ }
359
368
  }
360
- throw err;
369
+ else {
370
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.generic, 'Streaming client connection attempted and received an unknown error', err);
371
+ }
372
+ this.logger.error('Failed to connect streaming client', { error: errorForLogging });
373
+ throw errorForThrowing;
361
374
  }
362
375
  });
363
376
  }
364
377
  backoffConnectRetryHandler(connectOpts, err, connectionAttempt) {
365
- var _a, _b, _c, _d, _e;
378
+ var _a, _b, _c, _d;
366
379
  return __awaiter(this, void 0, void 0, function* () {
367
380
  // if we exceed the `numOfAttempts` in the backoff config it still calls this retry fn and just ignores the result
368
381
  // if that's the case, we just want to bail out and ignore all the extra logging here.
@@ -387,17 +400,25 @@ export class Client extends EventEmitter {
387
400
  message: axiosError.message
388
401
  };
389
402
  additionalErrorDetails.error = sanitizedError;
390
- if ([401, 403].includes(((_b = err.response) === null || _b === void 0 ? void 0 : _b.status) || 0)) {
403
+ if (this.networkErrorNeedsAuth(err)) {
391
404
  this.logger.error('Streaming client received an error that it can\'t recover from and will not attempt to reconnect', additionalErrorDetails);
392
405
  return false;
393
406
  }
394
407
  }
395
- // if we get a sasl error, that means we made it all the way to the point of trying to open a websocket and
396
- // it was rejected for some reason. At this point we should do a hard reconnect then try again.
408
+ // If we get a sasl error, that means we made it all the way to the point of trying to open a websocket and
409
+ // it was rejected for some reason. Some errors might resolve if we try connecting again. Others need
410
+ // re-authentication.
397
411
  if (err instanceof SaslError) {
398
- this.logger.info('hardReconnectRequired set to true due to sasl error');
399
- this.hardReconnectRequired = true;
400
- Object.assign(additionalErrorDetails, { channelId: err.channelId, stanzaInstanceId: err.stanzaInstanceId });
412
+ if (this.saslErrorIsRetryable(err)) {
413
+ this.logger.info('hardReconnectRequired set to true due to sasl error');
414
+ this.hardReconnectRequired = true;
415
+ Object.assign(additionalErrorDetails, { channelId: err.channelId, stanzaInstanceId: err.stanzaInstanceId });
416
+ }
417
+ else {
418
+ additionalErrorDetails.error = err.condition;
419
+ this.logger.error('Streaming-client received a SASL error that it can\'t recover from and will not attempt to reconnect', additionalErrorDetails);
420
+ return false;
421
+ }
401
422
  }
402
423
  // we don't need to log the stack for a timeout message
403
424
  if (err instanceof TimeoutError) {
@@ -410,7 +431,7 @@ export class Client extends EventEmitter {
410
431
  if (err === null || err === void 0 ? void 0 : err.response) {
411
432
  // This *should* be an axios error according to typings, but it appears this could be an AxiosError *or* and XmlHttpRequest
412
433
  // we'll check both to be safe
413
- const retryAfter = ((_c = err.response.headers) === null || _c === void 0 ? void 0 : _c['retry-after']) || ((_e = (_d = err.response).getResponseHeader) === null || _e === void 0 ? void 0 : _e.call(_d, 'retry-after'));
434
+ const retryAfter = ((_b = err.response.headers) === null || _b === void 0 ? void 0 : _b['retry-after']) || ((_d = (_c = err.response).getResponseHeader) === null || _d === void 0 ? void 0 : _d.call(_c, 'retry-after'));
414
435
  if (retryAfter) {
415
436
  // retry after comes in seconds, we need to return milliseconds
416
437
  let retryDelay = parseInt(retryAfter, 10) * 1000;
@@ -427,6 +448,14 @@ export class Client extends EventEmitter {
427
448
  return true;
428
449
  });
429
450
  }
451
+ networkErrorNeedsAuth(error) {
452
+ var _a;
453
+ return [401, 403].includes(((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) || 0);
454
+ }
455
+ saslErrorIsRetryable(error) {
456
+ const retryConditions = ['encryption-required', 'incorrect-encoding', 'invalid-mechanism', 'malformed-request', 'mechanism-too-weak'];
457
+ return retryConditions.includes(error.condition);
458
+ }
430
459
  makeConnectionAttempt() {
431
460
  var _a, _b;
432
461
  return __awaiter(this, void 0, void 0, function* () {
@@ -562,6 +591,6 @@ export class Client extends EventEmitter {
562
591
  return Client.version;
563
592
  }
564
593
  static get version() {
565
- return '17.2.7';
594
+ return '17.2.8';
566
595
  }
567
596
  }
@@ -8186,6 +8186,37 @@ class TimeoutError extends Error {
8186
8186
  }
8187
8187
  }
8188
8188
 
8189
+ var StreamingClientErrorTypes;
8190
+ (function (StreamingClientErrorTypes) {
8191
+ StreamingClientErrorTypes["generic"] = "generic";
8192
+ StreamingClientErrorTypes["invalid_token"] = "invalid_token";
8193
+ })(StreamingClientErrorTypes || (StreamingClientErrorTypes = {}));
8194
+ var SessionTypes;
8195
+ (function (SessionTypes) {
8196
+ SessionTypes["softphone"] = "softphone";
8197
+ SessionTypes["collaborateVideo"] = "collaborateVideo";
8198
+ SessionTypes["acdScreenShare"] = "screenShare";
8199
+ SessionTypes["screenRecording"] = "screenRecording";
8200
+ SessionTypes["unknown"] = "unknown";
8201
+ })(SessionTypes || (SessionTypes = {}));
8202
+
8203
+ class StreamingClientError extends Error {
8204
+ constructor(type, messageOrError, details) {
8205
+ let message;
8206
+ if (messageOrError instanceof Error) {
8207
+ message = messageOrError.message;
8208
+ }
8209
+ else {
8210
+ message = messageOrError;
8211
+ }
8212
+ super(message);
8213
+ if (messageOrError instanceof Error) {
8214
+ this.name = messageOrError.name;
8215
+ }
8216
+ this.type = type !== null && type !== void 0 ? type : StreamingClientErrorTypes.generic;
8217
+ this.details = details;
8218
+ }
8219
+ }
8189
8220
  /* istanbul ignore next */
8190
8221
  function timeoutPromise$1(fn, timeoutMs, msg, details) {
8191
8222
  return new Promise(function (resolve, reject) {
@@ -20675,15 +20706,6 @@ function deepFlatten(obj, prefix = '') {
20675
20706
  return flatObj;
20676
20707
  }
20677
20708
 
20678
- var SessionTypes;
20679
- (function (SessionTypes) {
20680
- SessionTypes["softphone"] = "softphone";
20681
- SessionTypes["collaborateVideo"] = "collaborateVideo";
20682
- SessionTypes["acdScreenShare"] = "screenShare";
20683
- SessionTypes["screenRecording"] = "screenRecording";
20684
- SessionTypes["unknown"] = "unknown";
20685
- })(SessionTypes || (SessionTypes = {}));
20686
-
20687
20709
  var jingle$1 = {};
20688
20710
 
20689
20711
  var FileTransferSession$1 = {};
@@ -42377,15 +42399,17 @@ class Client extends EventEmitter {
42377
42399
  });
42378
42400
  }
42379
42401
  catch (err) {
42380
- let error = err;
42402
+ let errorForThrowing;
42403
+ let errorForLogging = err;
42381
42404
  if (!err) {
42382
- error = new Error('Streaming client connection attempted received and undefined error');
42405
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.generic, 'Streaming client connection attempted and received an undefined error');
42406
+ errorForLogging = errorForThrowing;
42383
42407
  }
42384
42408
  else if (err.name === 'AxiosError') {
42385
42409
  const axiosError = err;
42386
42410
  const config = axiosError.config || { url: undefined, method: undefined };
42387
42411
  // sanitized error for logging
42388
- error = {
42412
+ errorForLogging = {
42389
42413
  config: {
42390
42414
  url: config.url,
42391
42415
  method: config.method
@@ -42395,17 +42419,27 @@ class Client extends EventEmitter {
42395
42419
  name: axiosError.name,
42396
42420
  message: axiosError.message
42397
42421
  };
42422
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.generic, 'Failed to connect streaming client due to network error', err);
42423
+ if (this.networkErrorNeedsAuth(err)) {
42424
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.invalid_token, 'Failed to connect streaming client due to invalid token', err);
42425
+ }
42398
42426
  }
42399
- this.logger.error('Failed to connect streaming client', { error });
42400
- if (!err) {
42401
- throw error;
42427
+ else if (err instanceof SaslError) {
42428
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.invalid_token, 'Failed to connect streaming client due to invalid token', err);
42429
+ if (this.saslErrorIsRetryable(err)) {
42430
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.generic, 'Streaming client connection attempted and received a SASL error', err);
42431
+ }
42402
42432
  }
42403
- throw err;
42433
+ else {
42434
+ errorForThrowing = new StreamingClientError(StreamingClientErrorTypes.generic, 'Streaming client connection attempted and received an unknown error', err);
42435
+ }
42436
+ this.logger.error('Failed to connect streaming client', { error: errorForLogging });
42437
+ throw errorForThrowing;
42404
42438
  }
42405
42439
  });
42406
42440
  }
42407
42441
  backoffConnectRetryHandler(connectOpts, err, connectionAttempt) {
42408
- var _a, _b, _c, _d, _e;
42442
+ var _a, _b, _c, _d;
42409
42443
  return __awaiter$5(this, void 0, void 0, function* () {
42410
42444
  // if we exceed the `numOfAttempts` in the backoff config it still calls this retry fn and just ignores the result
42411
42445
  // if that's the case, we just want to bail out and ignore all the extra logging here.
@@ -42430,17 +42464,25 @@ class Client extends EventEmitter {
42430
42464
  message: axiosError.message
42431
42465
  };
42432
42466
  additionalErrorDetails.error = sanitizedError;
42433
- if ([401, 403].includes(((_b = err.response) === null || _b === void 0 ? void 0 : _b.status) || 0)) {
42467
+ if (this.networkErrorNeedsAuth(err)) {
42434
42468
  this.logger.error('Streaming client received an error that it can\'t recover from and will not attempt to reconnect', additionalErrorDetails);
42435
42469
  return false;
42436
42470
  }
42437
42471
  }
42438
- // if we get a sasl error, that means we made it all the way to the point of trying to open a websocket and
42439
- // it was rejected for some reason. At this point we should do a hard reconnect then try again.
42472
+ // If we get a sasl error, that means we made it all the way to the point of trying to open a websocket and
42473
+ // it was rejected for some reason. Some errors might resolve if we try connecting again. Others need
42474
+ // re-authentication.
42440
42475
  if (err instanceof SaslError) {
42441
- this.logger.info('hardReconnectRequired set to true due to sasl error');
42442
- this.hardReconnectRequired = true;
42443
- Object.assign(additionalErrorDetails, { channelId: err.channelId, stanzaInstanceId: err.stanzaInstanceId });
42476
+ if (this.saslErrorIsRetryable(err)) {
42477
+ this.logger.info('hardReconnectRequired set to true due to sasl error');
42478
+ this.hardReconnectRequired = true;
42479
+ Object.assign(additionalErrorDetails, { channelId: err.channelId, stanzaInstanceId: err.stanzaInstanceId });
42480
+ }
42481
+ else {
42482
+ additionalErrorDetails.error = err.condition;
42483
+ this.logger.error('Streaming-client received a SASL error that it can\'t recover from and will not attempt to reconnect', additionalErrorDetails);
42484
+ return false;
42485
+ }
42444
42486
  }
42445
42487
  // we don't need to log the stack for a timeout message
42446
42488
  if (err instanceof TimeoutError) {
@@ -42453,7 +42495,7 @@ class Client extends EventEmitter {
42453
42495
  if (err === null || err === void 0 ? void 0 : err.response) {
42454
42496
  // This *should* be an axios error according to typings, but it appears this could be an AxiosError *or* and XmlHttpRequest
42455
42497
  // we'll check both to be safe
42456
- const retryAfter = ((_c = err.response.headers) === null || _c === void 0 ? void 0 : _c['retry-after']) || ((_e = (_d = err.response).getResponseHeader) === null || _e === void 0 ? void 0 : _e.call(_d, 'retry-after'));
42498
+ const retryAfter = ((_b = err.response.headers) === null || _b === void 0 ? void 0 : _b['retry-after']) || ((_d = (_c = err.response).getResponseHeader) === null || _d === void 0 ? void 0 : _d.call(_c, 'retry-after'));
42457
42499
  if (retryAfter) {
42458
42500
  // retry after comes in seconds, we need to return milliseconds
42459
42501
  let retryDelay = parseInt(retryAfter, 10) * 1000;
@@ -42470,6 +42512,14 @@ class Client extends EventEmitter {
42470
42512
  return true;
42471
42513
  });
42472
42514
  }
42515
+ networkErrorNeedsAuth(error) {
42516
+ var _a;
42517
+ return [401, 403].includes(((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) || 0);
42518
+ }
42519
+ saslErrorIsRetryable(error) {
42520
+ const retryConditions = ['encryption-required', 'incorrect-encoding', 'invalid-mechanism', 'malformed-request', 'mechanism-too-weak'];
42521
+ return retryConditions.includes(error.condition);
42522
+ }
42473
42523
  makeConnectionAttempt() {
42474
42524
  var _a, _b;
42475
42525
  return __awaiter$5(this, void 0, void 0, function* () {
@@ -42605,10 +42655,10 @@ class Client extends EventEmitter {
42605
42655
  return Client.version;
42606
42656
  }
42607
42657
  static get version() {
42608
- return '17.2.7';
42658
+ return '17.2.8';
42609
42659
  }
42610
42660
  }
42611
42661
 
42612
42662
  /// <reference path="types/libs.ts" />
42613
42663
 
42614
- export { GenesysCloudMediaSession, HttpClient, MessengerExtension, SessionTypes, StanzaMediaSession, Client as default, parseJwt };
42664
+ export { GenesysCloudMediaSession, HttpClient, MessengerExtension, SessionTypes, StanzaMediaSession, StreamingClientError, StreamingClientErrorTypes, Client as default, parseJwt };
@@ -6,5 +6,5 @@ export * from './types/media-session';
6
6
  export * from './types/interfaces';
7
7
  export * from './messenger';
8
8
  export { HttpClient } from './http-client';
9
- export { parseJwt } from './utils';
9
+ export { StreamingClientError, parseJwt } from './utils';
10
10
  export default Client;
package/dist/es/index.js CHANGED
@@ -6,5 +6,5 @@ export * from './types/media-session';
6
6
  export * from './types/interfaces';
7
7
  export * from './messenger';
8
8
  export { HttpClient } from './http-client';
9
- export { parseJwt } from './utils';
9
+ export { StreamingClientError, parseJwt } from './utils';
10
10
  export default Client;
@@ -101,6 +101,10 @@ export interface IResponseError extends IError {
101
101
  requestBody: string;
102
102
  url: string;
103
103
  }
104
+ export declare enum StreamingClientErrorTypes {
105
+ generic = "generic",
106
+ invalid_token = "invalid_token"
107
+ }
104
108
  export interface IError {
105
109
  message: string;
106
110
  name: string;
@@ -1,3 +1,8 @@
1
+ export var StreamingClientErrorTypes;
2
+ (function (StreamingClientErrorTypes) {
3
+ StreamingClientErrorTypes["generic"] = "generic";
4
+ StreamingClientErrorTypes["invalid_token"] = "invalid_token";
5
+ })(StreamingClientErrorTypes || (StreamingClientErrorTypes = {}));
1
6
  export var SessionTypes;
2
7
  (function (SessionTypes) {
3
8
  SessionTypes["softphone"] = "softphone";
@@ -1,3 +1,9 @@
1
+ import { StreamingClientErrorTypes } from './types/interfaces';
2
+ export declare class StreamingClientError extends Error {
3
+ type: StreamingClientErrorTypes;
4
+ details?: unknown;
5
+ constructor(type: StreamingClientErrorTypes | null, messageOrError: string | Error, details?: unknown);
6
+ }
1
7
  export declare function timeoutPromise(fn: Function, timeoutMs: number, msg: string, details?: any): Promise<any>;
2
8
  export declare function delay(ms: number): Promise<void>;
3
9
  export declare function splitIntoIndividualTopics(topicString: string): string[];