genesys-cloud-streaming-client 19.5.1-develop.15 → 19.6.0-release.1

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/README.md +15 -12
  2. package/dist/cjs/alerting-leader.d.ts +14 -0
  3. package/dist/cjs/alerting-leader.js +51 -0
  4. package/dist/cjs/client.d.ts +12 -0
  5. package/dist/cjs/client.js +76 -15
  6. package/dist/cjs/notifications.d.ts +7 -0
  7. package/dist/cjs/notifications.js +25 -2
  8. package/dist/cjs/types/interfaces.d.ts +6 -0
  9. package/dist/cjs/types/interfaces.js +5 -1
  10. package/dist/deploy-info.json +5 -5
  11. package/dist/es/alerting-leader.d.ts +14 -0
  12. package/dist/es/alerting-leader.js +50 -0
  13. package/dist/es/client.d.ts +12 -0
  14. package/dist/es/client.js +78 -15
  15. package/dist/es/index.bundle.js +1504 -919
  16. package/dist/es/notifications.d.ts +7 -0
  17. package/dist/es/notifications.js +27 -2
  18. package/dist/es/types/interfaces.d.ts +6 -0
  19. package/dist/es/types/interfaces.js +4 -0
  20. package/dist/manifest.json +5 -5
  21. package/dist/npm/CHANGELOG.md +15 -1
  22. package/dist/npm/alerting-leader.d.ts +14 -0
  23. package/dist/npm/alerting-leader.js +51 -0
  24. package/dist/npm/client.d.ts +12 -0
  25. package/dist/npm/client.js +76 -15
  26. package/dist/npm/notifications.d.ts +7 -0
  27. package/dist/npm/notifications.js +25 -2
  28. package/dist/npm/types/interfaces.d.ts +6 -0
  29. package/dist/npm/types/interfaces.js +5 -1
  30. package/dist/streaming-client.browser.js +1 -1
  31. package/dist/streaming-client.browser.js.LICENSE.txt +1 -1
  32. package/dist/v19/streaming-client.browser.js +1 -1
  33. package/dist/v19/streaming-client.browser.js.LICENSE.txt +1 -1
  34. package/dist/v19.6.0/streaming-client.browser.js +2 -0
  35. package/dist/{v19.5.1 → v19.6.0}/streaming-client.browser.js.LICENSE.txt +1 -1
  36. package/package.json +3 -3
  37. package/dist/v19.5.1/streaming-client.browser.js +0 -2
package/README.md CHANGED
@@ -1,20 +1,23 @@
1
- # Genesys Cloud Streaming Client #
1
+ ## Streaming Client
2
+ [![Test Matrix](https://github.com/purecloudlabs/genesys-cloud-streaming-client/actions/workflows/matrix.yml/badge.svg)](https://github.com/purecloudlabs/genesys-cloud-streaming-client/actions/workflows/matrix.yml)
2
3
 
3
- This project is a Bitbucket repository that contains the pipeline infrastructure for the open source [Genesys Cloud Streaming Client](https://github.com/purecloudlabs/genesys-cloud-streaming-client) hosted on GitHub.
4
+ ### Overview
5
+ Client library for streaming-service
4
6
 
5
- ### Playbook
6
- See [docs/playbook.md](docs/playbook.md).
7
+ ### Installation
8
+ Run `npm install` in order to install all the dependencies
7
9
 
8
- ### What is this repository for?
10
+ ### Testing
11
+ Run the tests using `npm test` in the command line
9
12
 
10
- Current guidance from security and the CI/CD teams is to not have the pipeline infrastructure available in open source repositories. This repository is used to host the pipeline infrastructure for the Genesys Cloud Streaming Client so that we may retain access to the CDN and ability to publish to NPM.
13
+ **In order to see code coverage run `npm run test:coverage`**
11
14
 
12
- ### Contributions
15
+ ### Build for Local Use
16
+ Run the script `npm run build`
13
17
 
14
- * Leave all source code in the GitHub repository.
15
- * Only pipeline infrastructure should be in this repository.
18
+ ### Linting and Style
19
+ semistandard has been added and you can run linting through the command line via `npm run lint` script
16
20
 
17
- ### Who do I talk to?
21
+ To fix minor styling errors, run `npm run lint:fix`
18
22
 
19
- * gcmediastreamsignal@genesys.com
20
- * Client Signaling and Streaming Team (STREAM).
23
+ **If you can configure you editor to run linting while typing or on save this is preferrable**
@@ -0,0 +1,14 @@
1
+ import { IClientOptions, StreamingClientExtension } from './types/interfaces';
2
+ import { Client } from './client';
3
+ import { NamedAgent } from './types/named-agent';
4
+ export declare class AlertingLeaderExtension implements StreamingClientExtension {
5
+ private client;
6
+ private connectionId?;
7
+ private alertableInteractionTypes;
8
+ constructor(client: Client, options: IClientOptions);
9
+ handleStanzaInstanceChange(stanzaInstance: NamedAgent): void;
10
+ private markAsAlertable;
11
+ get expose(): AlertingLeaderApi;
12
+ }
13
+ export interface AlertingLeaderApi {
14
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AlertingLeaderExtension = void 0;
4
+ const utils_1 = require("./utils");
5
+ class AlertingLeaderExtension {
6
+ constructor(client, options) {
7
+ var _a;
8
+ this.client = client;
9
+ this.alertableInteractionTypes = (_a = options.alertableInteractionTypes) !== null && _a !== void 0 ? _a : [];
10
+ }
11
+ handleStanzaInstanceChange(stanzaInstance) {
12
+ var _a, _b;
13
+ this.connectionId = (_b = (_a = stanzaInstance.transport) === null || _a === void 0 ? void 0 : _a.stream) === null || _b === void 0 ? void 0 : _b.id;
14
+ if (this.alertableInteractionTypes.length !== 0) {
15
+ this.markAsAlertable();
16
+ }
17
+ }
18
+ async markAsAlertable() {
19
+ const userId = this.client.config.userId;
20
+ const connectionsRequestOptions = {
21
+ method: 'patch',
22
+ host: this.client.config.apiHost,
23
+ authToken: this.client.config.authToken,
24
+ logger: this.client.logger,
25
+ data: {
26
+ alertable: true
27
+ }
28
+ };
29
+ // STREAM-1204
30
+ // There's a race condition between the backend service knowing about the connection
31
+ // and us marking the connection as alertable. For now, we'll just retry with some delay.
32
+ const maxRetries = 16;
33
+ let retryCount = 0;
34
+ const retry = (0, utils_1.retryPromise)(() => this.client.http.requestApi(`apps/users/${userId}/connections/${this.connectionId}`, connectionsRequestOptions), () => {
35
+ retryCount++;
36
+ if (retryCount >= maxRetries) {
37
+ this.client.logger.info('Max retries reached for marking connection as alertable');
38
+ return false;
39
+ }
40
+ return true;
41
+ }, 500, this.client.logger);
42
+ return retry.promise
43
+ .catch(() => {
44
+ this.client.logger.warn('Could not mark this connection as alertable; this client may not alert for incoming interactions');
45
+ });
46
+ }
47
+ get expose() {
48
+ return {};
49
+ }
50
+ }
51
+ exports.AlertingLeaderExtension = AlertingLeaderExtension;
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { Logger } from 'genesys-cloud-client-logger';
3
3
  import './polyfills';
4
+ import { AlertingLeaderExtension, AlertingLeaderApi } from './alerting-leader';
4
5
  import { Notifications, NotificationsAPI } from './notifications';
5
6
  import { WebrtcExtension, WebrtcExtensionAPI } from './webrtc';
6
7
  import { Ping } from './ping';
@@ -39,6 +40,8 @@ export declare class Client extends EventEmitter {
39
40
  _webrtcSessions: WebrtcExtension;
40
41
  messenger: MessengerExtension;
41
42
  _messenger: MessengerExtensionApi;
43
+ alertingLeader: AlertingLeaderApi;
44
+ _alertingLeader: AlertingLeaderExtension;
42
45
  _ping: Ping;
43
46
  constructor(options: IClientOptions);
44
47
  private handleSendEventFromExtension;
@@ -60,6 +63,15 @@ export declare class Client extends EventEmitter {
60
63
  private backoffConnectRetryHandler;
61
64
  private networkErrorNeedsAuth;
62
65
  private saslErrorIsRetryable;
66
+ /**
67
+ * Performs an active network connectivity check by querying the API.
68
+ * navigator.onLine is unreliable (VPNs, virtual adapters, etc.), so we
69
+ * actually reach out to verify we can talk to the server.
70
+ *
71
+ * Returns true if connectivity is confirmed, false otherwise.
72
+ * This is advisory only — it does not gate connection attempts.
73
+ */
74
+ checkNetworkConnectivity(): Promise<boolean>;
63
75
  private makeConnectionAttempt;
64
76
  private setupConnectionMonitoring;
65
77
  private prepareForConnect;
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const limiter_1 = require("limiter");
6
6
  const genesys_cloud_client_logger_1 = require("genesys-cloud-client-logger");
7
7
  require("./polyfills");
8
+ const alerting_leader_1 = require("./alerting-leader");
8
9
  const notifications_1 = require("./notifications");
9
10
  const webrtc_1 = require("./webrtc");
10
11
  const ping_1 = require("./ping");
@@ -15,7 +16,6 @@ const interfaces_1 = require("./types/interfaces");
15
16
  const events_1 = tslib_1.__importDefault(require("events"));
16
17
  const connection_manager_1 = require("./connection-manager");
17
18
  const exponential_backoff_1 = require("exponential-backoff");
18
- const offline_error_1 = tslib_1.__importDefault(require("./types/offline-error"));
19
19
  const sasl_error_1 = tslib_1.__importDefault(require("./types/sasl-error"));
20
20
  const timeout_error_1 = require("./types/timeout-error");
21
21
  const messenger_1 = require("./messenger");
@@ -25,7 +25,8 @@ const user_cancelled_error_1 = tslib_1.__importDefault(require("./types/user-can
25
25
  const extensions = {
26
26
  notifications: notifications_1.Notifications,
27
27
  webrtcSessions: webrtc_1.WebrtcExtension,
28
- messenger: messenger_1.MessengerExtension
28
+ messenger: messenger_1.MessengerExtension,
29
+ alertingLeader: alerting_leader_1.AlertingLeaderExtension
29
30
  };
30
31
  const STANZA_DISCONNECTED = 'stanzaDisconnected';
31
32
  const NO_LONGER_SUBSCRIBED = 'notify:no_longer_subscribed';
@@ -198,7 +199,18 @@ class Client extends events_1.default {
198
199
  this.activeStanzaInstance = undefined;
199
200
  this.emit('disconnected', { reconnecting: this.autoReconnect });
200
201
  if (this.autoReconnect) {
201
- return this.connect({ keepTryingOnFailure: true });
202
+ return this.connect({ keepTryingOnFailure: true })
203
+ .catch(error => {
204
+ this.logger.error('Failed to auto reconnect', {
205
+ keepTryingOnFailure: true,
206
+ stanzaInstanceId: disconnectedInstance.id,
207
+ channelId: disconnectedInstance.channelId
208
+ });
209
+ this.emit('disconnected', {
210
+ error,
211
+ reconnecting: false
212
+ });
213
+ });
202
214
  }
203
215
  }
204
216
  handleNoLongerSubscribed(stanzaInstance) {
@@ -453,14 +465,14 @@ class Client extends events_1.default {
453
465
  // retry after comes in seconds, we need to return milliseconds
454
466
  const retryDelay = parseInt(retryAfter, 10) * 1000;
455
467
  additionalErrorDetails.retryDelay = retryDelay;
456
- this.logger.error('Failed streaming client connection attempt, respecting retry-after header and will retry afterwards.', additionalErrorDetails, { skipServer: err instanceof offline_error_1.default });
468
+ this.logger.error('Failed streaming client connection attempt, respecting retry-after header and will retry afterwards.', additionalErrorDetails);
457
469
  await (0, utils_1.delay)(retryDelay);
458
470
  this.logger.debug('finished waiting for retry-after');
459
471
  return true;
460
472
  }
461
473
  }
462
474
  const connectionData = this.increaseBackoff();
463
- this.logger.error('Failed streaming client connection attempt, retrying', additionalErrorDetails, { skipServer: err instanceof offline_error_1.default });
475
+ this.logger.error('Failed streaming client connection attempt, retrying', additionalErrorDetails);
464
476
  this.logger.debug('debug: retry info', { expectedRetryInMs: connectionData.currentDelayMs, appName: this.config.appName, clientId: this.logger.clientId });
465
477
  return true;
466
478
  }
@@ -472,14 +484,57 @@ class Client extends events_1.default {
472
484
  const retryConditions = ['encryption-required', 'incorrect-encoding', 'invalid-mechanism', 'malformed-request', 'mechanism-too-weak'];
473
485
  return retryConditions.includes(error.condition);
474
486
  }
487
+ /**
488
+ * Performs an active network connectivity check by querying the API.
489
+ * navigator.onLine is unreliable (VPNs, virtual adapters, etc.), so we
490
+ * actually reach out to verify we can talk to the server.
491
+ *
492
+ * Returns true if connectivity is confirmed, false otherwise.
493
+ * This is advisory only — it does not gate connection attempts.
494
+ */
495
+ async checkNetworkConnectivity() {
496
+ // Quick hint check first — if the browser says offline, that's a strong signal
497
+ if (!navigator.onLine) {
498
+ this.logger.warn('navigator.onLine reports offline — connectivity may be unavailable');
499
+ this.emit('networkConnectivityWarning', { reason: 'navigator.onLine is false' });
500
+ return false;
501
+ }
502
+ // JWT-based connections (e.g. background assistants) don't have an auth token
503
+ // that works with the users/me endpoint, so we can only rely on navigator.onLine
504
+ if (this.config.jwt && !this.config.authToken) {
505
+ this.logger.debug('Skipping active connectivity check in JWT mode, relying on navigator.onLine');
506
+ return true;
507
+ }
508
+ try {
509
+ const opts = {
510
+ method: 'get',
511
+ host: this.config.apiHost,
512
+ authToken: this.config.authToken,
513
+ logger: this.logger,
514
+ requestTimeout: 10000
515
+ };
516
+ await this.http.requestApi('users/me', opts);
517
+ return true;
518
+ }
519
+ catch (err) {
520
+ this.logger.warn('Active network connectivity check failed — connectivity may be unavailable', { error: err });
521
+ this.emit('networkConnectivityWarning', { reason: 'active connectivity check failed', error: err });
522
+ return false;
523
+ }
524
+ }
475
525
  async makeConnectionAttempt() {
476
526
  var _a, _b;
477
527
  if (this.cancelConnectionAttempt) {
478
528
  throw new user_cancelled_error_1.default('Connection attempt cancelled');
479
529
  }
480
- if (!navigator.onLine) {
481
- throw new offline_error_1.default('Browser is offline, skipping connection attempt');
482
- }
530
+ // navigator.onLine is unreliable — use it as a hint, not a gate.
531
+ // Fire off an active connectivity check in the background. It will
532
+ // log and emit warnings if there's an issue, but we don't wait for it.
533
+ this.checkNetworkConnectivity().then(isConnected => {
534
+ if (!isConnected) {
535
+ this.logger.warn('Network connectivity check failed, but proceeding with connection attempt anyway');
536
+ }
537
+ });
483
538
  let stanzaInstance;
484
539
  const previousConnectingState = this.connecting;
485
540
  try {
@@ -553,9 +608,9 @@ class Client extends events_1.default {
553
608
  }
554
609
  }
555
610
  if (this.hardReconnectRequired) {
556
- let jidPromise;
557
- if (this.config.jid) {
558
- jidPromise = Promise.resolve(this.config.jid);
611
+ let userPromise;
612
+ if (this.config.userId && this.config.jid) {
613
+ userPromise = Promise.resolve({ userId: this.config.userId, jid: this.config.jid });
559
614
  }
560
615
  else {
561
616
  const jidRequestOpts = {
@@ -564,8 +619,13 @@ class Client extends events_1.default {
564
619
  authToken: this.config.authToken,
565
620
  logger: this.logger
566
621
  };
567
- jidPromise = await this.http.requestApi('users/me', jidRequestOpts)
568
- .then(res => res.data.chat.jabberId);
622
+ userPromise = this.http.requestApi('users/me', jidRequestOpts)
623
+ .then(res => {
624
+ return {
625
+ userId: res.data.id,
626
+ jid: res.data.chat.jabberId
627
+ };
628
+ });
569
629
  }
570
630
  // If no jidResource is provided, generate a random one to maintain ourselves.
571
631
  this.jidResource = this.config.jidResource || (0, uuid_1.v4)();
@@ -577,7 +637,8 @@ class Client extends events_1.default {
577
637
  };
578
638
  const channelPromise = await this.http.requestApi('notifications/channels?connectionType=streaming', channelRequestOpts)
579
639
  .then(res => res.data.id);
580
- const [jid, channelId] = await Promise.all([jidPromise, channelPromise]);
640
+ const [{ userId, jid }, channelId] = await Promise.all([userPromise, channelPromise]);
641
+ this.config.userId = userId;
581
642
  this.config.jid = jid;
582
643
  this.config.jidResource = this.jidResource;
583
644
  this.config.channelId = channelId;
@@ -609,7 +670,7 @@ class Client extends events_1.default {
609
670
  return Client.version;
610
671
  }
611
672
  static get version() {
612
- return '19.5.1';
673
+ return '19.6.0';
613
674
  }
614
675
  }
615
676
  exports.Client = Client;
@@ -11,6 +11,7 @@ export declare class Notifications implements StreamingClientExtension {
11
11
  topicPriorities: any;
12
12
  debouncedResubscribe: () => Promise<BulkSubscribeResult>;
13
13
  enablePartialBulkResubscribe: boolean;
14
+ private internalSubscriptions;
14
15
  constructor(client: any, options?: IClientOptions);
15
16
  get pubsubHost(): string;
16
17
  handleStanzaInstanceChange(stanza: NamedAgent): void;
@@ -47,6 +48,12 @@ export declare class Notifications implements StreamingClientExtension {
47
48
  };
48
49
  setTopicPriorities(priorities?: {}): void;
49
50
  subscribe(topic: string, handler?: (..._: any[]) => void, immediate?: boolean, priority?: number): Promise<TopicSubscribeResult>;
51
+ /**
52
+ * Use `_subscribeInternal` when subscribing to a topic from within streaming-client itself.
53
+ * Internal subscriptions won't be overwritten by subscriptions from consumers and will be prioritized
54
+ * over subscriptions from consumers.
55
+ */
56
+ _subscribeInternal(topic: string): Promise<PubsubSubscriptionWithOptions | void>;
50
57
  unsubscribe(topic: string, handler?: (..._: any[]) => void, immediate?: boolean): Promise<any>;
51
58
  bulkSubscribe(topics: string[], options?: BulkSubscribeOpts, priorities?: {
52
59
  [topicName: string]: number;
@@ -18,6 +18,7 @@ class Notifications {
18
18
  this.subscriptions = {};
19
19
  this.bulkSubscriptions = {};
20
20
  this.topicPriorities = {};
21
+ this.internalSubscriptions = [];
21
22
  this.client = client;
22
23
  this.enablePartialBulkResubscribe = (_a = options === null || options === void 0 ? void 0 : options.enablePartialBulkResubscribe) !== null && _a !== void 0 ? _a : false;
23
24
  client.on('pubsub:event', this.pubsubEvent.bind(this));
@@ -41,7 +42,11 @@ class Notifications {
41
42
  this.stanzaInstance = stanza;
42
43
  if (needsToResub) {
43
44
  this.client.logger.info('resubscribing due to hard reconnect');
44
- void this.debouncedResubscribe();
45
+ this.debouncedResubscribe().catch((err) => {
46
+ const msg = 'Error resubscribing to topics';
47
+ this.client.logger.error(msg, err);
48
+ this.client.emit('pubsub:error', { msg, err });
49
+ });
45
50
  }
46
51
  }
47
52
  topicHandlers(topic) {
@@ -330,6 +335,21 @@ class Notifications {
330
335
  }
331
336
  return topicResult;
332
337
  }
338
+ /**
339
+ * Use `_subscribeInternal` when subscribing to a topic from within streaming-client itself.
340
+ * Internal subscriptions won't be overwritten by subscriptions from consumers and will be prioritized
341
+ * over subscriptions from consumers.
342
+ */
343
+ async _subscribeInternal(topic) {
344
+ if (this.internalSubscriptions.includes(topic)) {
345
+ return Promise.resolve();
346
+ }
347
+ this.setTopicPriorities({ [topic]: Number.MAX_VALUE });
348
+ const promise = this.xmppSubscribe(topic);
349
+ this.internalSubscriptions.push(topic);
350
+ this.bulkSubscriptions[topic] = true;
351
+ return promise;
352
+ }
333
353
  unsubscribe(topic, handler, immediate) {
334
354
  if (handler) {
335
355
  this.removeSubscription(topic, handler);
@@ -348,7 +368,7 @@ class Notifications {
348
368
  async bulkSubscribe(topics, options = { replace: false, force: false }, priorities = {}) {
349
369
  var _a;
350
370
  this.setTopicPriorities(priorities);
351
- let toSubscribe = mergeAndDedup(topics, []);
371
+ let toSubscribe = mergeAndDedup(topics, this.internalSubscriptions);
352
372
  if (options.replace && !options.force) {
353
373
  // if this is a bulk subscription, but not a forcible one, keep all individual subscriptions
354
374
  toSubscribe = mergeAndDedup(toSubscribe, this.getActiveIndividualTopics());
@@ -388,6 +408,9 @@ class Notifications {
388
408
  topics.forEach(topic => {
389
409
  this.bulkSubscriptions[topic] = true;
390
410
  });
411
+ this.internalSubscriptions.forEach(topic => {
412
+ this.bulkSubscriptions[topic] = true;
413
+ });
391
414
  // Add a fallback result for any topic in the toSubscribe list that isn't already in result.
392
415
  // With partial bulk resubscribe enabled missing result means "Unknown" state but when not
393
416
  // enabled the fallback is "Permitted" for backward compatibility (success response means OK).
@@ -24,15 +24,21 @@ export interface IClientOptions {
24
24
  customHeaders?: ICustomHeader;
25
25
  /** Allow bulk topic resubscribe to succeed or fail per-topic rather than all or nothing */
26
26
  enablePartialBulkResubscribe?: boolean;
27
+ /** Genesys internal use only - non-Genesys apps that pass in `alertableInteractionTypes` may experience unexpected behavior */
28
+ alertableInteractionTypes?: AlertableInteractionTypes[];
27
29
  }
28
30
  export interface ICustomHeader {
29
31
  [header: string]: string;
30
32
  }
33
+ export declare enum AlertableInteractionTypes {
34
+ voice = "voice"
35
+ }
31
36
  export interface IClientConfig {
32
37
  host: string;
33
38
  apiHost: string;
34
39
  authToken?: string;
35
40
  jwt?: string;
41
+ userId?: string;
36
42
  jid?: string;
37
43
  jidResource?: string;
38
44
  channelId: string;
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SessionTypes = exports.StreamingClientErrorTypes = void 0;
3
+ exports.SessionTypes = exports.StreamingClientErrorTypes = exports.AlertableInteractionTypes = void 0;
4
+ var AlertableInteractionTypes;
5
+ (function (AlertableInteractionTypes) {
6
+ AlertableInteractionTypes["voice"] = "voice";
7
+ })(AlertableInteractionTypes = exports.AlertableInteractionTypes || (exports.AlertableInteractionTypes = {}));
4
8
  var StreamingClientErrorTypes;
5
9
  (function (StreamingClientErrorTypes) {
6
10
  StreamingClientErrorTypes["generic"] = "generic";
@@ -1,13 +1,13 @@
1
1
  {
2
- "version": "19.5.1-develop",
3
- "build": "15",
4
- "buildDate": "2026-01-09T18:09:01.125Z",
2
+ "version": "release/v19.6.0",
3
+ "build": "1",
4
+ "buildDate": "2026-04-14T21:56:54.192Z",
5
5
  "indexFiles": [
6
6
  {
7
- "file": "v19.5.1/streaming-client.browser.js"
7
+ "file": "v19.6.0/streaming-client.browser.js"
8
8
  },
9
9
  {
10
- "file": "v19.5.1/streaming-client.browser.js.LICENSE.txt"
10
+ "file": "v19.6.0/streaming-client.browser.js.LICENSE.txt"
11
11
  },
12
12
  {
13
13
  "file": "v19/streaming-client.browser.js"
@@ -0,0 +1,14 @@
1
+ import { IClientOptions, StreamingClientExtension } from './types/interfaces';
2
+ import { Client } from './client';
3
+ import { NamedAgent } from './types/named-agent';
4
+ export declare class AlertingLeaderExtension implements StreamingClientExtension {
5
+ private client;
6
+ private connectionId?;
7
+ private alertableInteractionTypes;
8
+ constructor(client: Client, options: IClientOptions);
9
+ handleStanzaInstanceChange(stanzaInstance: NamedAgent): void;
10
+ private markAsAlertable;
11
+ get expose(): AlertingLeaderApi;
12
+ }
13
+ export interface AlertingLeaderApi {
14
+ }
@@ -0,0 +1,50 @@
1
+ import { __awaiter } from "tslib";
2
+ import { retryPromise } from './utils';
3
+ export class AlertingLeaderExtension {
4
+ constructor(client, options) {
5
+ var _a;
6
+ this.client = client;
7
+ this.alertableInteractionTypes = (_a = options.alertableInteractionTypes) !== null && _a !== void 0 ? _a : [];
8
+ }
9
+ handleStanzaInstanceChange(stanzaInstance) {
10
+ var _a, _b;
11
+ this.connectionId = (_b = (_a = stanzaInstance.transport) === null || _a === void 0 ? void 0 : _a.stream) === null || _b === void 0 ? void 0 : _b.id;
12
+ if (this.alertableInteractionTypes.length !== 0) {
13
+ this.markAsAlertable();
14
+ }
15
+ }
16
+ markAsAlertable() {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ const userId = this.client.config.userId;
19
+ const connectionsRequestOptions = {
20
+ method: 'patch',
21
+ host: this.client.config.apiHost,
22
+ authToken: this.client.config.authToken,
23
+ logger: this.client.logger,
24
+ data: {
25
+ alertable: true
26
+ }
27
+ };
28
+ // STREAM-1204
29
+ // There's a race condition between the backend service knowing about the connection
30
+ // and us marking the connection as alertable. For now, we'll just retry with some delay.
31
+ const maxRetries = 16;
32
+ let retryCount = 0;
33
+ const retry = retryPromise(() => this.client.http.requestApi(`apps/users/${userId}/connections/${this.connectionId}`, connectionsRequestOptions), () => {
34
+ retryCount++;
35
+ if (retryCount >= maxRetries) {
36
+ this.client.logger.info('Max retries reached for marking connection as alertable');
37
+ return false;
38
+ }
39
+ return true;
40
+ }, 500, this.client.logger);
41
+ return retry.promise
42
+ .catch(() => {
43
+ this.client.logger.warn('Could not mark this connection as alertable; this client may not alert for incoming interactions');
44
+ });
45
+ });
46
+ }
47
+ get expose() {
48
+ return {};
49
+ }
50
+ }
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import { Logger } from 'genesys-cloud-client-logger';
3
3
  import './polyfills';
4
+ import { AlertingLeaderExtension, AlertingLeaderApi } from './alerting-leader';
4
5
  import { Notifications, NotificationsAPI } from './notifications';
5
6
  import { WebrtcExtension, WebrtcExtensionAPI } from './webrtc';
6
7
  import { Ping } from './ping';
@@ -39,6 +40,8 @@ export declare class Client extends EventEmitter {
39
40
  _webrtcSessions: WebrtcExtension;
40
41
  messenger: MessengerExtension;
41
42
  _messenger: MessengerExtensionApi;
43
+ alertingLeader: AlertingLeaderApi;
44
+ _alertingLeader: AlertingLeaderExtension;
42
45
  _ping: Ping;
43
46
  constructor(options: IClientOptions);
44
47
  private handleSendEventFromExtension;
@@ -60,6 +63,15 @@ export declare class Client extends EventEmitter {
60
63
  private backoffConnectRetryHandler;
61
64
  private networkErrorNeedsAuth;
62
65
  private saslErrorIsRetryable;
66
+ /**
67
+ * Performs an active network connectivity check by querying the API.
68
+ * navigator.onLine is unreliable (VPNs, virtual adapters, etc.), so we
69
+ * actually reach out to verify we can talk to the server.
70
+ *
71
+ * Returns true if connectivity is confirmed, false otherwise.
72
+ * This is advisory only — it does not gate connection attempts.
73
+ */
74
+ checkNetworkConnectivity(): Promise<boolean>;
63
75
  private makeConnectionAttempt;
64
76
  private setupConnectionMonitoring;
65
77
  private prepareForConnect;