genesys-cloud-streaming-client 19.3.1 → 19.4.0-release.2

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 (38) hide show
  1. package/README.md +3 -0
  2. package/dist/cjs/client.js +1 -1
  3. package/dist/cjs/index.d.ts +1 -1
  4. package/dist/cjs/index.js +2 -1
  5. package/dist/cjs/notifications.d.ts +26 -7
  6. package/dist/cjs/notifications.js +60 -9
  7. package/dist/cjs/types/genesys-cloud-media-session.js +2 -1
  8. package/dist/cjs/types/interfaces.d.ts +2 -0
  9. package/dist/cjs/utils.d.ts +6 -0
  10. package/dist/cjs/utils.js +10 -1
  11. package/dist/deploy-info.json +3 -3
  12. package/dist/es/client.js +1 -1
  13. package/dist/es/index.bundle.js +87 -28
  14. package/dist/es/index.d.ts +1 -1
  15. package/dist/es/index.js +1 -1
  16. package/dist/es/notifications.d.ts +26 -7
  17. package/dist/es/notifications.js +76 -24
  18. package/dist/es/types/genesys-cloud-media-session.js +2 -1
  19. package/dist/es/types/interfaces.d.ts +2 -0
  20. package/dist/es/utils.d.ts +6 -0
  21. package/dist/es/utils.js +8 -0
  22. package/dist/manifest.json +3 -3
  23. package/dist/npm/CHANGELOG.md +9 -1
  24. package/dist/npm/client.js +1 -1
  25. package/dist/npm/index.d.ts +1 -1
  26. package/dist/npm/index.js +2 -1
  27. package/dist/npm/module.js +1 -1
  28. package/dist/npm/notifications.d.ts +26 -7
  29. package/dist/npm/notifications.js +60 -9
  30. package/dist/npm/types/genesys-cloud-media-session.js +2 -1
  31. package/dist/npm/types/interfaces.d.ts +2 -0
  32. package/dist/npm/utils.d.ts +6 -0
  33. package/dist/npm/utils.js +10 -1
  34. package/dist/streaming-client.browser.js +6 -6
  35. package/dist/v19/streaming-client.browser.js +6 -6
  36. package/dist/v19.4.0/streaming-client.browser.js +19 -0
  37. package/package.json +3 -1
  38. package/dist/v19.3.1/streaming-client.browser.js +0 -19
package/README.md CHANGED
@@ -2,6 +2,9 @@
2
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
4
 
5
+ ### Playbook
6
+ See [docs/playbook.md](docs/playbook.md).
7
+
5
8
  ### What is this repository for?
6
9
 
7
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.
@@ -610,7 +610,7 @@ class Client extends events_1.default {
610
610
  return Client.version;
611
611
  }
612
612
  static get version() {
613
- return '19.3.1';
613
+ return '19.4.0';
614
614
  }
615
615
  }
616
616
  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 { StreamingClientError, parseJwt } from './utils';
9
+ export { StreamingClientError, StreamingSubscriptionError, 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.StreamingClientError = exports.HttpClient = void 0;
3
+ exports.parseJwt = exports.StreamingSubscriptionError = 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");
@@ -13,5 +13,6 @@ 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
15
  Object.defineProperty(exports, "StreamingClientError", { enumerable: true, get: function () { return utils_1.StreamingClientError; } });
16
+ Object.defineProperty(exports, "StreamingSubscriptionError", { enumerable: true, get: function () { return utils_1.StreamingSubscriptionError; } });
16
17
  Object.defineProperty(exports, "parseJwt", { enumerable: true, get: function () { return utils_1.parseJwt; } });
17
18
  exports.default = client_1.Client;
@@ -1,15 +1,17 @@
1
1
  import { PubsubEvent, PubsubSubscription, PubsubSubscriptionWithOptions } from 'stanza/protocol';
2
2
  import { Client } from './client';
3
- import { StreamingClientExtension } from './types/interfaces';
3
+ import { IClientOptions, StreamingClientExtension } from './types/interfaces';
4
4
  import { NamedAgent } from './types/named-agent';
5
+ import { AxiosResponse } from 'axios';
5
6
  export declare class Notifications implements StreamingClientExtension {
6
7
  client: Client;
7
8
  stanzaInstance?: NamedAgent;
8
9
  subscriptions: any;
9
10
  bulkSubscriptions: any;
10
11
  topicPriorities: any;
11
- debouncedResubscribe: any;
12
- constructor(client: any);
12
+ debouncedResubscribe: () => Promise<BulkSubscribeResult>;
13
+ enablePartialBulkResubscribe: boolean;
14
+ constructor(client: any, options?: IClientOptions);
13
15
  get pubsubHost(): string;
14
16
  handleStanzaInstanceChange(stanza: NamedAgent): void;
15
17
  topicHandlers(topic: string): Array<(obj?: any) => void>;
@@ -32,23 +34,23 @@ export declare class Notifications implements StreamingClientExtension {
32
34
  }>): Array<{
33
35
  id: string;
34
36
  }>;
35
- makeBulkSubscribeRequest(topics: string[], options: any): Promise<any>;
37
+ makeBulkSubscribeRequest(topics: string[], options: any): Promise<AxiosResponse<ChannelTopicsEntityListing>>;
36
38
  createSubscription(topic: string, handler: (obj?: any) => void): void;
37
39
  removeSubscription(topic: string, handler: (obj?: any) => void): void;
38
40
  removeTopicPriority(topic: string): void;
39
41
  getActiveIndividualTopics(): string[];
40
- resubscribe(): Promise<any>;
42
+ resubscribe(): Promise<BulkSubscribeResult>;
41
43
  subscriptionsKeepAlive(): void;
42
44
  getTopicParts(topic: string): {
43
45
  prefix: string;
44
46
  postfixes: string[];
45
47
  };
46
48
  setTopicPriorities(priorities?: {}): void;
47
- subscribe(topic: string, handler?: (..._: any[]) => void, immediate?: boolean, priority?: number): Promise<any>;
49
+ subscribe(topic: string, handler?: (..._: any[]) => void, immediate?: boolean, priority?: number): Promise<TopicSubscribeResult>;
48
50
  unsubscribe(topic: string, handler?: (..._: any[]) => void, immediate?: boolean): Promise<any>;
49
51
  bulkSubscribe(topics: string[], options?: BulkSubscribeOpts, priorities?: {
50
52
  [topicName: string]: number;
51
- }): Promise<any>;
53
+ }): Promise<BulkSubscribeResult>;
52
54
  get expose(): NotificationsAPI;
53
55
  }
54
56
  export interface NotificationsAPI {
@@ -62,3 +64,20 @@ export interface BulkSubscribeOpts {
62
64
  replace?: boolean;
63
65
  force?: boolean;
64
66
  }
67
+ export interface BulkSubscribeResult {
68
+ [topic: string]: TopicSubscribeResult;
69
+ }
70
+ export interface TopicSubscribeResult {
71
+ topic: string;
72
+ state: 'Permitted' | 'Rejected' | 'Unknown';
73
+ rejectionReason?: string;
74
+ }
75
+ export interface ChannelTopicResponseEntity {
76
+ id: string;
77
+ state: 'Permitted' | 'Rejected';
78
+ rejectionReason?: string;
79
+ selfUri?: string;
80
+ }
81
+ export interface ChannelTopicsEntityListing {
82
+ entities: ChannelTopicResponseEntity[];
83
+ }
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Notifications = void 0;
4
- const debounce = require('debounce-promise');
4
+ const tslib_1 = require("tslib");
5
+ const debounce_promise_1 = tslib_1.__importDefault(require("debounce-promise"));
5
6
  const utils_1 = require("./utils");
7
+ const _1 = require("./");
6
8
  const PUBSUB_HOST_DEFAULT = 'notifications.mypurecloud.com';
7
9
  const MAX_SUBSCRIBABLE_TOPICS = 1000;
8
10
  const DROPPED_TOPICS_DISPLAY_COUNT = 20;
@@ -11,14 +13,16 @@ function mergeAndDedup(arr1, arr2) {
11
13
  return [...arr1, ...arr2].filter((t, i, arr) => arr.indexOf(t) === i);
12
14
  }
13
15
  class Notifications {
14
- constructor(client) {
16
+ constructor(client, options) {
17
+ var _a;
15
18
  this.subscriptions = {};
16
19
  this.bulkSubscriptions = {};
17
20
  this.topicPriorities = {};
18
21
  this.client = client;
22
+ this.enablePartialBulkResubscribe = (_a = options === null || options === void 0 ? void 0 : options.enablePartialBulkResubscribe) !== null && _a !== void 0 ? _a : false;
19
23
  client.on('pubsub:event', this.pubsubEvent.bind(this));
20
24
  client.on('connected', this.subscriptionsKeepAlive.bind(this));
21
- this.debouncedResubscribe = debounce(this.resubscribe.bind(this), 100);
25
+ this.debouncedResubscribe = debounce_promise_1.default(this.resubscribe.bind(this), 100);
22
26
  }
23
27
  get pubsubHost() {
24
28
  try {
@@ -37,7 +41,7 @@ class Notifications {
37
41
  this.stanzaInstance = stanza;
38
42
  if (needsToResub) {
39
43
  this.client.logger.info('resubscribing due to hard reconnect');
40
- this.debouncedResubscribe();
44
+ void this.debouncedResubscribe();
41
45
  }
42
46
  }
43
47
  topicHandlers(topic) {
@@ -178,7 +182,11 @@ class Notifications {
178
182
  logger: this.client.logger
179
183
  };
180
184
  const channelId = this.stanzaInstance.channelId;
181
- return this.client.http.requestApi(`notifications/channels/${channelId}/subscriptions`, requestOptions);
185
+ let path = `notifications/channels/${channelId}/subscriptions`;
186
+ if (this.enablePartialBulkResubscribe) {
187
+ path += '?ignoreErrors=true';
188
+ }
189
+ return this.client.http.requestApi(path, requestOptions);
182
190
  }
183
191
  createSubscription(topic, handler) {
184
192
  const topics = utils_1.splitIntoIndividualTopics(topic);
@@ -234,7 +242,7 @@ class Notifications {
234
242
  /* if we don't have bulk or individual subs, we don't need to resubscribe */
235
243
  const noTopics = bulkSubs.length + this.getActiveIndividualTopics().length === 0;
236
244
  if (noTopics) {
237
- return Promise.resolve();
245
+ return Promise.resolve({});
238
246
  }
239
247
  /* only pass in bulk subs with the replace flag – bulkSubscribe() will handle merging our individual topics (see PCM-1846) */
240
248
  return this.bulkSubscribe(bulkSubs, { replace: true });
@@ -289,7 +297,7 @@ class Notifications {
289
297
  }
290
298
  });
291
299
  }
292
- subscribe(topic, handler, immediate, priority) {
300
+ async subscribe(topic, handler, immediate, priority) {
293
301
  if (priority) {
294
302
  this.setTopicPriorities({ [topic]: priority });
295
303
  }
@@ -307,7 +315,19 @@ class Notifications {
307
315
  else {
308
316
  this.bulkSubscriptions[topic] = true;
309
317
  }
310
- return promise;
318
+ const result = await promise;
319
+ // Assume topic subscription succeeded if promise is resolved...
320
+ let topicResult = { topic, state: 'Permitted' };
321
+ // ... but if partial bulk resubscribe is enabled, use topic's individual result from the API response.
322
+ if (this.enablePartialBulkResubscribe && result && typeof result === 'object' && isTopicSubscribeResult(result[topic])) {
323
+ topicResult = result[topic];
324
+ }
325
+ // Topic result other than state=Permitted becomes a StreamingSubscriptionError promise rejection.
326
+ if (topicResult.state !== 'Permitted') {
327
+ const message = topicResult.rejectionReason || `Failed to subscribe topic ${topic}`;
328
+ throw new _1.StreamingSubscriptionError(message, topic, 'subscribe');
329
+ }
330
+ return topicResult;
311
331
  }
312
332
  unsubscribe(topic, handler, immediate) {
313
333
  if (handler) {
@@ -335,13 +355,35 @@ class Notifications {
335
355
  // if it's a forcible bulk subscribe, wipe out individual subscriptions
336
356
  this.subscriptions = {};
337
357
  }
338
- await this.makeBulkSubscribeRequest(toSubscribe, options);
358
+ const response = await this.makeBulkSubscribeRequest(toSubscribe, options);
359
+ let topicResponseEntities = [];
360
+ if (response && response.data && 'entities' in response.data && Array.isArray(response.data.entities)) {
361
+ topicResponseEntities = response.data.entities;
362
+ }
363
+ const topicResponsesById = {};
364
+ for (const topicEntity of topicResponseEntities) {
365
+ topicResponsesById[topicEntity.id] = topicEntity;
366
+ }
367
+ const result = {};
339
368
  if (options.replace) {
340
369
  this.bulkSubscriptions = {};
341
370
  }
342
371
  topics.forEach(topic => {
343
372
  this.bulkSubscriptions[topic] = true;
373
+ if (this.enablePartialBulkResubscribe) {
374
+ if (topic in topicResponsesById) {
375
+ const { state, rejectionReason } = topicResponsesById[topic];
376
+ result[topic] = { topic, state, rejectionReason };
377
+ }
378
+ else {
379
+ result[topic] = { topic, state: 'Unknown' };
380
+ }
381
+ }
382
+ else {
383
+ result[topic] = { topic, state: 'Permitted' };
384
+ }
344
385
  });
386
+ return result;
345
387
  }
346
388
  get expose() {
347
389
  return {
@@ -352,3 +394,12 @@ class Notifications {
352
394
  }
353
395
  }
354
396
  exports.Notifications = Notifications;
397
+ function isTopicSubscribeResult(value) {
398
+ let hasTopic = false;
399
+ let hasValidState = false;
400
+ if (value && typeof value === 'object') {
401
+ hasTopic = 'topic' in value && typeof value.topic === 'string';
402
+ hasValidState = 'state' in value && ['Permitted', 'Rejected', 'Unknown'].includes(value.state);
403
+ }
404
+ return hasTopic && hasValidState;
405
+ }
@@ -295,7 +295,8 @@ class GenesysCloudMediaSession {
295
295
  sdp: answer.sdp,
296
296
  sessionId: this.id
297
297
  };
298
- this.logger.info('sending sdp answer', params);
298
+ // Do not log the SDP payload to avoid logging sensitive information.
299
+ this.logger.info('sending sdp answer', { sessionId: this.id, conversationId: this.conversationId });
299
300
  return this.sendGenesysWebrtc({
300
301
  jsonrpc: '2.0',
301
302
  method: 'answer',
@@ -22,6 +22,8 @@ export interface IClientOptions {
22
22
  appVersion?: string;
23
23
  appId?: string;
24
24
  customHeaders?: ICustomHeader;
25
+ /** Allow bulk topic resubscribe to succeed or fail per-topic rather than all or nothing */
26
+ enablePartialBulkResubscribe?: boolean;
25
27
  }
26
28
  export interface ICustomHeader {
27
29
  [header: string]: string;
@@ -4,6 +4,12 @@ export declare class StreamingClientError extends Error {
4
4
  details?: unknown;
5
5
  constructor(type: StreamingClientErrorTypes | null, messageOrError: string | Error, details?: unknown);
6
6
  }
7
+ export declare class StreamingSubscriptionError extends Error {
8
+ readonly topic?: string | undefined;
9
+ readonly operation?: "subscribe" | "unsubscribe" | undefined;
10
+ name: string;
11
+ constructor(message: string, topic?: string | undefined, operation?: "subscribe" | "unsubscribe" | undefined);
12
+ }
7
13
  export declare function timeoutPromise(fn: Function, timeoutMs: number, msg: string, details?: any): Promise<any>;
8
14
  export declare function delay(ms: number): Promise<void>;
9
15
  export declare function splitIntoIndividualTopics(topicString: string): string[];
package/dist/cjs/utils.js CHANGED
@@ -1,6 +1,6 @@
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 = exports.StreamingClientError = 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.StreamingSubscriptionError = exports.StreamingClientError = void 0;
4
4
  const uuid_1 = require("uuid");
5
5
  const timeout_error_1 = require("./types/timeout-error");
6
6
  const interfaces_1 = require("./types/interfaces");
@@ -22,6 +22,15 @@ class StreamingClientError extends Error {
22
22
  }
23
23
  }
24
24
  exports.StreamingClientError = StreamingClientError;
25
+ class StreamingSubscriptionError extends Error {
26
+ constructor(message, topic, operation) {
27
+ super(message);
28
+ this.topic = topic;
29
+ this.operation = operation;
30
+ this.name = 'StreamingSubscriptionError';
31
+ }
32
+ }
33
+ exports.StreamingSubscriptionError = StreamingSubscriptionError;
25
34
  /* istanbul ignore next */
26
35
  function timeoutPromise(fn, timeoutMs, msg, details) {
27
36
  return new Promise(function (resolve, reject) {
@@ -1,10 +1,10 @@
1
1
  {
2
- "version": "19.3.1",
2
+ "version": "release/v19.4.0",
3
3
  "build": "2",
4
- "buildDate": "2025-07-24T14:11:50.599Z",
4
+ "buildDate": "2025-09-19T03:18:00.531Z",
5
5
  "indexFiles": [
6
6
  {
7
- "file": "v19.3.1/streaming-client.browser.js"
7
+ "file": "v19.4.0/streaming-client.browser.js"
8
8
  },
9
9
  {
10
10
  "file": "v19/streaming-client.browser.js"
package/dist/es/client.js CHANGED
@@ -622,6 +622,6 @@ export class Client extends EventEmitter {
622
622
  return Client.version;
623
623
  }
624
624
  static get version() {
625
- return '19.3.1';
625
+ return '19.4.0';
626
626
  }
627
627
  }
@@ -8234,6 +8234,14 @@ class StreamingClientError extends Error {
8234
8234
  this.details = details;
8235
8235
  }
8236
8236
  }
8237
+ class StreamingSubscriptionError extends Error {
8238
+ constructor(message, topic, operation) {
8239
+ super(message);
8240
+ this.topic = topic;
8241
+ this.operation = operation;
8242
+ this.name = 'StreamingSubscriptionError';
8243
+ }
8244
+ }
8237
8245
  /* istanbul ignore next */
8238
8246
  function timeoutPromise$1(fn, timeoutMs, msg, details) {
8239
8247
  return new Promise(function (resolve, reject) {
@@ -8387,7 +8395,6 @@ function iceIsDifferent(sdp1, sdp2) {
8387
8395
  // return destination;
8388
8396
  // }
8389
8397
 
8390
- const debounce$1 = dist$1;
8391
8398
  const PUBSUB_HOST_DEFAULT = 'notifications.mypurecloud.com';
8392
8399
  const MAX_SUBSCRIBABLE_TOPICS = 1000;
8393
8400
  const DROPPED_TOPICS_DISPLAY_COUNT = 20;
@@ -8396,14 +8403,16 @@ function mergeAndDedup(arr1, arr2) {
8396
8403
  return [...arr1, ...arr2].filter((t, i, arr) => arr.indexOf(t) === i);
8397
8404
  }
8398
8405
  class Notifications {
8399
- constructor(client) {
8406
+ constructor(client, options) {
8407
+ var _a;
8400
8408
  this.subscriptions = {};
8401
8409
  this.bulkSubscriptions = {};
8402
8410
  this.topicPriorities = {};
8403
8411
  this.client = client;
8412
+ this.enablePartialBulkResubscribe = (_a = options === null || options === void 0 ? void 0 : options.enablePartialBulkResubscribe) !== null && _a !== void 0 ? _a : false;
8404
8413
  client.on('pubsub:event', this.pubsubEvent.bind(this));
8405
8414
  client.on('connected', this.subscriptionsKeepAlive.bind(this));
8406
- this.debouncedResubscribe = debounce$1(this.resubscribe.bind(this), 100);
8415
+ this.debouncedResubscribe = dist$1(this.resubscribe.bind(this), 100);
8407
8416
  }
8408
8417
  get pubsubHost() {
8409
8418
  try {
@@ -8422,7 +8431,7 @@ class Notifications {
8422
8431
  this.stanzaInstance = stanza;
8423
8432
  if (needsToResub) {
8424
8433
  this.client.logger.info('resubscribing due to hard reconnect');
8425
- this.debouncedResubscribe();
8434
+ void this.debouncedResubscribe();
8426
8435
  }
8427
8436
  }
8428
8437
  topicHandlers(topic) {
@@ -8565,7 +8574,11 @@ class Notifications {
8565
8574
  logger: this.client.logger
8566
8575
  };
8567
8576
  const channelId = this.stanzaInstance.channelId;
8568
- return this.client.http.requestApi(`notifications/channels/${channelId}/subscriptions`, requestOptions);
8577
+ let path = `notifications/channels/${channelId}/subscriptions`;
8578
+ if (this.enablePartialBulkResubscribe) {
8579
+ path += '?ignoreErrors=true';
8580
+ }
8581
+ return this.client.http.requestApi(path, requestOptions);
8569
8582
  }
8570
8583
  createSubscription(topic, handler) {
8571
8584
  const topics = splitIntoIndividualTopics(topic);
@@ -8621,7 +8634,7 @@ class Notifications {
8621
8634
  /* if we don't have bulk or individual subs, we don't need to resubscribe */
8622
8635
  const noTopics = bulkSubs.length + this.getActiveIndividualTopics().length === 0;
8623
8636
  if (noTopics) {
8624
- return Promise.resolve();
8637
+ return Promise.resolve({});
8625
8638
  }
8626
8639
  /* only pass in bulk subs with the replace flag – bulkSubscribe() will handle merging our individual topics (see PCM-1846) */
8627
8640
  return this.bulkSubscribe(bulkSubs, { replace: true });
@@ -8677,24 +8690,38 @@ class Notifications {
8677
8690
  });
8678
8691
  }
8679
8692
  subscribe(topic, handler, immediate, priority) {
8680
- if (priority) {
8681
- this.setTopicPriorities({ [topic]: priority });
8682
- }
8683
- let promise;
8684
- if (!immediate) {
8685
- // let this and any other subscribe/unsubscribe calls roll in, then trigger a whole resubscribe
8686
- promise = this.debouncedResubscribe();
8687
- }
8688
- else {
8689
- promise = this.xmppSubscribe(topic);
8690
- }
8691
- if (handler) {
8692
- this.createSubscription(topic, handler);
8693
- }
8694
- else {
8695
- this.bulkSubscriptions[topic] = true;
8696
- }
8697
- return promise;
8693
+ return __awaiter$5(this, void 0, void 0, function* () {
8694
+ if (priority) {
8695
+ this.setTopicPriorities({ [topic]: priority });
8696
+ }
8697
+ let promise;
8698
+ if (!immediate) {
8699
+ // let this and any other subscribe/unsubscribe calls roll in, then trigger a whole resubscribe
8700
+ promise = this.debouncedResubscribe();
8701
+ }
8702
+ else {
8703
+ promise = this.xmppSubscribe(topic);
8704
+ }
8705
+ if (handler) {
8706
+ this.createSubscription(topic, handler);
8707
+ }
8708
+ else {
8709
+ this.bulkSubscriptions[topic] = true;
8710
+ }
8711
+ const result = yield promise;
8712
+ // Assume topic subscription succeeded if promise is resolved...
8713
+ let topicResult = { topic, state: 'Permitted' };
8714
+ // ... but if partial bulk resubscribe is enabled, use topic's individual result from the API response.
8715
+ if (this.enablePartialBulkResubscribe && result && typeof result === 'object' && isTopicSubscribeResult(result[topic])) {
8716
+ topicResult = result[topic];
8717
+ }
8718
+ // Topic result other than state=Permitted becomes a StreamingSubscriptionError promise rejection.
8719
+ if (topicResult.state !== 'Permitted') {
8720
+ const message = topicResult.rejectionReason || `Failed to subscribe topic ${topic}`;
8721
+ throw new StreamingSubscriptionError(message, topic, 'subscribe');
8722
+ }
8723
+ return topicResult;
8724
+ });
8698
8725
  }
8699
8726
  unsubscribe(topic, handler, immediate) {
8700
8727
  if (handler) {
@@ -8723,13 +8750,35 @@ class Notifications {
8723
8750
  // if it's a forcible bulk subscribe, wipe out individual subscriptions
8724
8751
  this.subscriptions = {};
8725
8752
  }
8726
- yield this.makeBulkSubscribeRequest(toSubscribe, options);
8753
+ const response = yield this.makeBulkSubscribeRequest(toSubscribe, options);
8754
+ let topicResponseEntities = [];
8755
+ if (response && response.data && 'entities' in response.data && Array.isArray(response.data.entities)) {
8756
+ topicResponseEntities = response.data.entities;
8757
+ }
8758
+ const topicResponsesById = {};
8759
+ for (const topicEntity of topicResponseEntities) {
8760
+ topicResponsesById[topicEntity.id] = topicEntity;
8761
+ }
8762
+ const result = {};
8727
8763
  if (options.replace) {
8728
8764
  this.bulkSubscriptions = {};
8729
8765
  }
8730
8766
  topics.forEach(topic => {
8731
8767
  this.bulkSubscriptions[topic] = true;
8768
+ if (this.enablePartialBulkResubscribe) {
8769
+ if (topic in topicResponsesById) {
8770
+ const { state, rejectionReason } = topicResponsesById[topic];
8771
+ result[topic] = { topic, state, rejectionReason };
8772
+ }
8773
+ else {
8774
+ result[topic] = { topic, state: 'Unknown' };
8775
+ }
8776
+ }
8777
+ else {
8778
+ result[topic] = { topic, state: 'Permitted' };
8779
+ }
8732
8780
  });
8781
+ return result;
8733
8782
  });
8734
8783
  }
8735
8784
  get expose() {
@@ -8740,6 +8789,15 @@ class Notifications {
8740
8789
  };
8741
8790
  }
8742
8791
  }
8792
+ function isTopicSubscribeResult(value) {
8793
+ let hasTopic = false;
8794
+ let hasValidState = false;
8795
+ if (value && typeof value === 'object') {
8796
+ hasTopic = 'topic' in value && typeof value.topic === 'string';
8797
+ hasValidState = 'state' in value && ['Permitted', 'Rejected', 'Unknown'].includes(value.state);
8798
+ }
8799
+ return hasTopic && hasValidState;
8800
+ }
8743
8801
 
8744
8802
  var JID$8 = {};
8745
8803
 
@@ -31737,7 +31795,8 @@ class GenesysCloudMediaSession {
31737
31795
  sdp: answer.sdp,
31738
31796
  sessionId: this.id
31739
31797
  };
31740
- this.logger.info('sending sdp answer', params);
31798
+ // Do not log the SDP payload to avoid logging sensitive information.
31799
+ this.logger.info('sending sdp answer', { sessionId: this.id, conversationId: this.conversationId });
31741
31800
  return this.sendGenesysWebrtc({
31742
31801
  jsonrpc: '2.0',
31743
31802
  method: 'answer',
@@ -43584,10 +43643,10 @@ class Client extends EventEmitter {
43584
43643
  return Client.version;
43585
43644
  }
43586
43645
  static get version() {
43587
- return '19.3.1';
43646
+ return '19.4.0';
43588
43647
  }
43589
43648
  }
43590
43649
 
43591
43650
  /// <reference path="types/libs.ts" />
43592
43651
 
43593
- export { GenesysCloudMediaSession, HttpClient, MessengerExtension, SessionTypes, StanzaMediaSession, StreamingClientError, StreamingClientErrorTypes, Client as default, parseJwt };
43652
+ export { GenesysCloudMediaSession, HttpClient, MessengerExtension, SessionTypes, StanzaMediaSession, StreamingClientError, StreamingClientErrorTypes, StreamingSubscriptionError, 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 { StreamingClientError, parseJwt } from './utils';
9
+ export { StreamingClientError, StreamingSubscriptionError, 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 { StreamingClientError, parseJwt } from './utils';
9
+ export { StreamingClientError, StreamingSubscriptionError, parseJwt } from './utils';
10
10
  export default Client;
@@ -1,15 +1,17 @@
1
1
  import { PubsubEvent, PubsubSubscription, PubsubSubscriptionWithOptions } from 'stanza/protocol';
2
2
  import { Client } from './client';
3
- import { StreamingClientExtension } from './types/interfaces';
3
+ import { IClientOptions, StreamingClientExtension } from './types/interfaces';
4
4
  import { NamedAgent } from './types/named-agent';
5
+ import { AxiosResponse } from 'axios';
5
6
  export declare class Notifications implements StreamingClientExtension {
6
7
  client: Client;
7
8
  stanzaInstance?: NamedAgent;
8
9
  subscriptions: any;
9
10
  bulkSubscriptions: any;
10
11
  topicPriorities: any;
11
- debouncedResubscribe: any;
12
- constructor(client: any);
12
+ debouncedResubscribe: () => Promise<BulkSubscribeResult>;
13
+ enablePartialBulkResubscribe: boolean;
14
+ constructor(client: any, options?: IClientOptions);
13
15
  get pubsubHost(): string;
14
16
  handleStanzaInstanceChange(stanza: NamedAgent): void;
15
17
  topicHandlers(topic: string): Array<(obj?: any) => void>;
@@ -32,23 +34,23 @@ export declare class Notifications implements StreamingClientExtension {
32
34
  }>): Array<{
33
35
  id: string;
34
36
  }>;
35
- makeBulkSubscribeRequest(topics: string[], options: any): Promise<any>;
37
+ makeBulkSubscribeRequest(topics: string[], options: any): Promise<AxiosResponse<ChannelTopicsEntityListing>>;
36
38
  createSubscription(topic: string, handler: (obj?: any) => void): void;
37
39
  removeSubscription(topic: string, handler: (obj?: any) => void): void;
38
40
  removeTopicPriority(topic: string): void;
39
41
  getActiveIndividualTopics(): string[];
40
- resubscribe(): Promise<any>;
42
+ resubscribe(): Promise<BulkSubscribeResult>;
41
43
  subscriptionsKeepAlive(): void;
42
44
  getTopicParts(topic: string): {
43
45
  prefix: string;
44
46
  postfixes: string[];
45
47
  };
46
48
  setTopicPriorities(priorities?: {}): void;
47
- subscribe(topic: string, handler?: (..._: any[]) => void, immediate?: boolean, priority?: number): Promise<any>;
49
+ subscribe(topic: string, handler?: (..._: any[]) => void, immediate?: boolean, priority?: number): Promise<TopicSubscribeResult>;
48
50
  unsubscribe(topic: string, handler?: (..._: any[]) => void, immediate?: boolean): Promise<any>;
49
51
  bulkSubscribe(topics: string[], options?: BulkSubscribeOpts, priorities?: {
50
52
  [topicName: string]: number;
51
- }): Promise<any>;
53
+ }): Promise<BulkSubscribeResult>;
52
54
  get expose(): NotificationsAPI;
53
55
  }
54
56
  export interface NotificationsAPI {
@@ -62,3 +64,20 @@ export interface BulkSubscribeOpts {
62
64
  replace?: boolean;
63
65
  force?: boolean;
64
66
  }
67
+ export interface BulkSubscribeResult {
68
+ [topic: string]: TopicSubscribeResult;
69
+ }
70
+ export interface TopicSubscribeResult {
71
+ topic: string;
72
+ state: 'Permitted' | 'Rejected' | 'Unknown';
73
+ rejectionReason?: string;
74
+ }
75
+ export interface ChannelTopicResponseEntity {
76
+ id: string;
77
+ state: 'Permitted' | 'Rejected';
78
+ rejectionReason?: string;
79
+ selfUri?: string;
80
+ }
81
+ export interface ChannelTopicsEntityListing {
82
+ entities: ChannelTopicResponseEntity[];
83
+ }