genesys-cloud-streaming-client 19.1.0-develop.137 → 19.1.0-double-feature.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 (37) hide show
  1. package/dist/cjs/client.js +2 -0
  2. package/dist/cjs/connection-transfer.d.ts +7 -0
  3. package/dist/cjs/connection-transfer.js +19 -0
  4. package/dist/cjs/stanza-definitions/webrtc-signaling.d.ts +2 -0
  5. package/dist/cjs/stanza-definitions/xep0051.d.ts +19 -0
  6. package/dist/cjs/stanza-definitions/xep0051.js +28 -0
  7. package/dist/cjs/types/genesys-cloud-media-session.js +1 -2
  8. package/dist/cjs/types/named-agent.d.ts +2 -0
  9. package/dist/cjs/webrtc.d.ts +1 -1
  10. package/dist/cjs/webrtc.js +10 -3
  11. package/dist/deploy-info.json +3 -3
  12. package/dist/es/client.js +2 -0
  13. package/dist/es/connection-transfer.d.ts +7 -0
  14. package/dist/es/connection-transfer.js +15 -0
  15. package/dist/es/index.bundle.js +52 -5
  16. package/dist/es/stanza-definitions/webrtc-signaling.d.ts +2 -0
  17. package/dist/es/stanza-definitions/xep0051.d.ts +19 -0
  18. package/dist/es/stanza-definitions/xep0051.js +25 -0
  19. package/dist/es/types/genesys-cloud-media-session.js +1 -2
  20. package/dist/es/types/named-agent.d.ts +2 -0
  21. package/dist/es/webrtc.d.ts +1 -1
  22. package/dist/es/webrtc.js +10 -3
  23. package/dist/npm/CHANGELOG.md +4 -0
  24. package/dist/npm/client.js +2 -0
  25. package/dist/npm/connection-transfer.d.ts +7 -0
  26. package/dist/npm/connection-transfer.js +19 -0
  27. package/dist/npm/stanza-definitions/webrtc-signaling.d.ts +2 -0
  28. package/dist/npm/stanza-definitions/xep0051.d.ts +19 -0
  29. package/dist/npm/stanza-definitions/xep0051.js +28 -0
  30. package/dist/npm/types/genesys-cloud-media-session.js +1 -2
  31. package/dist/npm/types/named-agent.d.ts +2 -0
  32. package/dist/npm/webrtc.d.ts +1 -1
  33. package/dist/npm/webrtc.js +10 -3
  34. package/dist/streaming-client.browser.js +4 -4
  35. package/dist/v19/streaming-client.browser.js +4 -4
  36. package/dist/v19.1.0/streaming-client.browser.js +4 -4
  37. package/package.json +1 -1
@@ -20,6 +20,7 @@ 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");
22
22
  const uuid_1 = require("uuid");
23
+ const connection_transfer_1 = require("./connection-transfer");
23
24
  let extensions = {
24
25
  notifications: notifications_1.Notifications,
25
26
  webrtcSessions: webrtc_1.WebrtcExtension,
@@ -495,6 +496,7 @@ class Client extends events_1.default {
495
496
  }
496
497
  }
497
498
  async setupConnectionMonitoring(stanzaInstance) {
499
+ stanzaInstance.connectionTransfer = new connection_transfer_1.ConnectionTransfer(this, stanzaInstance);
498
500
  const setupClientPinger = (message) => {
499
501
  const logMessage = `${message}, falling back to client-side pinging`;
500
502
  this.logger.warn(logMessage, { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
@@ -0,0 +1,7 @@
1
+ import { Client } from './client';
2
+ import { NamedAgent } from './types/named-agent';
3
+ export declare class ConnectionTransfer {
4
+ private client;
5
+ private stanzaInstance;
6
+ constructor(client: Client, stanzaInstance: NamedAgent);
7
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConnectionTransfer = void 0;
4
+ const xep0051_1 = require("./stanza-definitions/xep0051");
5
+ class ConnectionTransfer {
6
+ constructor(client, stanzaInstance) {
7
+ this.client = client;
8
+ this.stanzaInstance = stanzaInstance;
9
+ stanzaInstance.stanzas.define(xep0051_1.connectionTransfer);
10
+ // Hawk maps `v2.system.socket_closing` to XEP-0051 Connection Transfer
11
+ // The docs says we have up to one minute to disconnect and connect a new WebSocket, so we should be proactive in reconnecting.
12
+ stanzaInstance.on('iq:set:connectionTransfer', (iq) => {
13
+ client.logger.warn('connection transfer (socket_closing) event received', { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
14
+ void client.disconnect();
15
+ void client.connect({ keepTryingOnFailure: true });
16
+ });
17
+ }
18
+ }
19
+ exports.ConnectionTransfer = ConnectionTransfer;
@@ -18,6 +18,8 @@ declare module 'stanza/protocol' {
18
18
  interface ReceivedMessage {
19
19
  mediaMessage?: GenesysMediaMessage;
20
20
  }
21
+ }
22
+ declare module 'stanza' {
21
23
  interface AgentEvents {
22
24
  'iq:set:genesysWebrtc': Stanzas.ReceivedIQ & {
23
25
  genesysWebrtc: GenesysWebrtcJsonRpcMessage;
@@ -0,0 +1,19 @@
1
+ import { Stanzas } from 'stanza';
2
+ import { DefinitionOptions } from 'stanza/jxt';
3
+ declare module 'stanza' {
4
+ interface AgentEvents {
5
+ 'iq:set:connectionTransfer': Stanzas.ReceivedIQ & {
6
+ query: ConnectionTransfer;
7
+ };
8
+ }
9
+ }
10
+ declare module 'stanza/protocol' {
11
+ interface IQPayload {
12
+ query?: ConnectionTransfer;
13
+ }
14
+ }
15
+ export interface ConnectionTransfer {
16
+ domain?: string;
17
+ server?: string;
18
+ }
19
+ export declare const connectionTransfer: DefinitionOptions;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectionTransfer = void 0;
4
+ const jxt_1 = require("stanza/jxt");
5
+ // XEP-0051: Connection Transfer
6
+ // Source: https://xmpp.org/extensions/xep-0051.html
7
+ // Version: 0.2.1 (2022-03-08)
8
+ // ---------------------------
9
+ // We don't currently use domain or server
10
+ const NS_CONNECTION_TRANSFER = 'urn:xmpp:cxfr';
11
+ /*
12
+ <iq xmlns="jabber:client" id="<someId>" to="<toJID>" type="set">
13
+ <query xmlns="urn:xmpp:cxfr">
14
+ <domain>jabber.org</domain>
15
+ <server>123.123.123.122</server>
16
+ </query>
17
+ </iq>
18
+ */
19
+ exports.connectionTransfer = {
20
+ path: 'iq.query',
21
+ aliases: ['iq.connectionTransfer'],
22
+ namespace: NS_CONNECTION_TRANSFER,
23
+ element: 'query',
24
+ fields: {
25
+ domain: jxt_1.childText(null, 'domain'),
26
+ server: jxt_1.childText(null, 'server')
27
+ }
28
+ };
@@ -66,7 +66,6 @@ class GenesysCloudMediaSession {
66
66
  // if we have a state mismatch
67
67
  if (this.state !== 'ended' && ['failed', 'closed'].includes(this.peerConnection.connectionState)) {
68
68
  this.log('warn', 'state mismatch between session.state and peerConnection.connectionState, manually terminating the session', { sessionId: this.id, conversationId: this.conversationId, sessionType: this.sessionType });
69
- this.state = 'ended';
70
69
  this.onSessionTerminate();
71
70
  }
72
71
  }
@@ -171,7 +170,6 @@ class GenesysCloudMediaSession {
171
170
  }
172
171
  else if (connectionState === 'failed') {
173
172
  this.log('info', 'Connection was interrupted and failed to recover, cleaning up', { sessionId, conversationId, sessionType });
174
- this.state = 'ended';
175
173
  this.onSessionTerminate();
176
174
  }
177
175
  }
@@ -241,6 +239,7 @@ class GenesysCloudMediaSession {
241
239
  });
242
240
  }
243
241
  onSessionTerminate(reason) {
242
+ this.state = 'ended';
244
243
  if (this.peerConnection) {
245
244
  this.peerConnection.close();
246
245
  }
@@ -1,11 +1,13 @@
1
1
  import { Agent } from 'stanza';
2
2
  import { Ping } from '../ping';
3
3
  import { ServerMonitor } from '../server-monitor';
4
+ import { ConnectionTransfer } from '../connection-transfer';
4
5
  export interface NamedAgent extends Omit<Agent, 'disconnect'> {
5
6
  id: string;
6
7
  channelId?: string;
7
8
  originalEmitter?: Function;
8
9
  pinger?: Ping;
9
10
  serverMonitor?: ServerMonitor;
11
+ connectionTransfer?: ConnectionTransfer;
10
12
  disconnect: () => Promise<void>;
11
13
  }
@@ -43,7 +43,7 @@ export declare class WebrtcExtension extends EventEmitter implements StreamingCl
43
43
  private stanzaInstance?;
44
44
  private webrtcSessions;
45
45
  private reinviteCache;
46
- private sdpOverXmpp;
46
+ private sessionsMap;
47
47
  get jid(): string | undefined;
48
48
  constructor(client: Client, clientOptions: IClientOptions);
49
49
  private onOnlineStatusChange;
@@ -63,7 +63,8 @@ class WebrtcExtension extends events_1.EventEmitter {
63
63
  max: 5,
64
64
  ttl: 1000 * 60 * 3
65
65
  });
66
- this.sdpOverXmpp = false;
66
+ // private sdpOverXmpp = false;
67
+ this.sessionsMap = {};
67
68
  this.client = client;
68
69
  this.config = {
69
70
  allowIPv6: clientOptions.allowIPv6 === true,
@@ -219,6 +220,7 @@ class WebrtcExtension extends events_1.EventEmitter {
219
220
  this.webrtcSessions = this.webrtcSessions.filter(s => s.id !== session.id);
220
221
  });
221
222
  this.webrtcSessions.push(session);
223
+ // delete this.sessionsMap[session.id];
222
224
  this.logger.info('emitting sdp media-session (offer');
223
225
  this.applyEarlyIceCandidates(session);
224
226
  return this.emit(events.INCOMING_RTCSESSION, session);
@@ -301,13 +303,14 @@ class WebrtcExtension extends events_1.EventEmitter {
301
303
  }
302
304
  }
303
305
  prepareSession(options) {
304
- if (this.sdpOverXmpp) {
306
+ if (options.sid && this.sessionsMap[options.sid]) {
305
307
  this.logger.debug('skipping creation of jingle webrtc session due to sdpOverXmpp');
306
308
  return;
307
309
  }
308
310
  const pendingSession = this.pendingSessions[options.sid];
309
311
  if (pendingSession) {
310
312
  delete this.pendingSessions[pendingSession.sessionId];
313
+ // delete this.sessionsMap[pendingSession.sessionId];
311
314
  }
312
315
  const ignoreHostCandidatesForForceTurnFF = this.getIceTransportPolicy() === 'relay' && browserama_1.isFirefox;
313
316
  const gcSessionOpts = {
@@ -524,7 +527,8 @@ class WebrtcExtension extends events_1.EventEmitter {
524
527
  sdpOverXmpp: msg.propose.sdpOverXmpp,
525
528
  privAnswerMode: msg.propose.privAnswerMode
526
529
  };
527
- this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
530
+ // this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
531
+ this.sessionsMap[sessionInfo.id] = !!sessionInfo.sdpOverXmpp;
528
532
  this.pendingSessions[sessionId] = sessionInfo;
529
533
  }
530
534
  if (sessionInfo.accepted) {
@@ -536,6 +540,7 @@ class WebrtcExtension extends events_1.EventEmitter {
536
540
  }
537
541
  handleRetract(sessionId) {
538
542
  this.logger.info('retract received', this.getLogDetailsForPendingSessionId(sessionId));
543
+ // delete this.sessionsMap[sessionId];
539
544
  delete this.pendingSessions[sessionId];
540
545
  return this.emit(events.CANCEL_INCOMING_RTCSESSION, sessionId);
541
546
  }
@@ -633,6 +638,7 @@ class WebrtcExtension extends events_1.EventEmitter {
633
638
  this.emit(events.RTCSESSION_ERROR, 'Cannot reject session because it is not pending or does not exist');
634
639
  return;
635
640
  }
641
+ // delete this.sessionsMap[sessionId];
636
642
  delete this.pendingSessions[sessionId];
637
643
  if (ignore) {
638
644
  this.ignoredSessions.set(sessionId, true);
@@ -708,6 +714,7 @@ class WebrtcExtension extends events_1.EventEmitter {
708
714
  }
709
715
  };
710
716
  delete this.pendingSessions[sessionId];
717
+ // delete this.sessionsMap[sessionId];
711
718
  this.logger.info('sending jingle retract', logDetails);
712
719
  await this.stanzaInstance.send('message', retract); // send as Message
713
720
  this.logger.info('sent jingle retract', logDetails);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "developercenter-cdn/streaming-client",
3
- "version": "19.1.0",
3
+ "version": "double-feature",
4
4
  "ecosystem": "pc",
5
5
  "team": "Client Streaming and Signaling",
6
6
  "indexFiles": [
@@ -11,8 +11,8 @@
11
11
  "file": "v19/streaming-client.browser.js"
12
12
  }
13
13
  ],
14
- "build": "137",
15
- "buildDate": "2025-05-06T14:28:33.034825406Z",
14
+ "build": "2",
15
+ "buildDate": "2025-05-30T16:57:36.877672642Z",
16
16
  "appName": "developercenter-cdn/streaming-client",
17
17
  "gcServiceName": "developercenter-cdn--streaming-client-webui"
18
18
  }
package/dist/es/client.js CHANGED
@@ -18,6 +18,7 @@ import SaslError from './types/sasl-error';
18
18
  import { TimeoutError } from './types/timeout-error';
19
19
  import { MessengerExtension } from './messenger';
20
20
  import { v4 } from 'uuid';
21
+ import { ConnectionTransfer } from './connection-transfer';
21
22
  let extensions = {
22
23
  notifications: Notifications,
23
24
  webrtcSessions: WebrtcExtension,
@@ -504,6 +505,7 @@ export class Client extends EventEmitter {
504
505
  }
505
506
  setupConnectionMonitoring(stanzaInstance) {
506
507
  return __awaiter(this, void 0, void 0, function* () {
508
+ stanzaInstance.connectionTransfer = new ConnectionTransfer(this, stanzaInstance);
507
509
  const setupClientPinger = (message) => {
508
510
  const logMessage = `${message}, falling back to client-side pinging`;
509
511
  this.logger.warn(logMessage, { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
@@ -0,0 +1,7 @@
1
+ import { Client } from './client';
2
+ import { NamedAgent } from './types/named-agent';
3
+ export declare class ConnectionTransfer {
4
+ private client;
5
+ private stanzaInstance;
6
+ constructor(client: Client, stanzaInstance: NamedAgent);
7
+ }
@@ -0,0 +1,15 @@
1
+ import { connectionTransfer } from './stanza-definitions/xep0051';
2
+ export class ConnectionTransfer {
3
+ constructor(client, stanzaInstance) {
4
+ this.client = client;
5
+ this.stanzaInstance = stanzaInstance;
6
+ stanzaInstance.stanzas.define(connectionTransfer);
7
+ // Hawk maps `v2.system.socket_closing` to XEP-0051 Connection Transfer
8
+ // The docs says we have up to one minute to disconnect and connect a new WebSocket, so we should be proactive in reconnecting.
9
+ stanzaInstance.on('iq:set:connectionTransfer', (iq) => {
10
+ client.logger.warn('connection transfer (socket_closing) event received', { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
11
+ void client.disconnect();
12
+ void client.connect({ keepTryingOnFailure: true });
13
+ });
14
+ }
15
+ }
@@ -31477,7 +31477,6 @@ class GenesysCloudMediaSession {
31477
31477
  // if we have a state mismatch
31478
31478
  if (this.state !== 'ended' && ['failed', 'closed'].includes(this.peerConnection.connectionState)) {
31479
31479
  this.log('warn', 'state mismatch between session.state and peerConnection.connectionState, manually terminating the session', { sessionId: this.id, conversationId: this.conversationId, sessionType: this.sessionType });
31480
- this.state = 'ended';
31481
31480
  this.onSessionTerminate();
31482
31481
  }
31483
31482
  }
@@ -31590,7 +31589,6 @@ class GenesysCloudMediaSession {
31590
31589
  }
31591
31590
  else if (connectionState === 'failed') {
31592
31591
  this.log('info', 'Connection was interrupted and failed to recover, cleaning up', { sessionId, conversationId, sessionType });
31593
- this.state = 'ended';
31594
31592
  this.onSessionTerminate();
31595
31593
  }
31596
31594
  }
@@ -31662,6 +31660,7 @@ class GenesysCloudMediaSession {
31662
31660
  });
31663
31661
  }
31664
31662
  onSessionTerminate(reason) {
31663
+ this.state = 'ended';
31665
31664
  if (this.peerConnection) {
31666
31665
  this.peerConnection.close();
31667
31666
  }
@@ -32001,7 +32000,8 @@ class WebrtcExtension extends EventEmitter {
32001
32000
  max: 5,
32002
32001
  ttl: 1000 * 60 * 3
32003
32002
  });
32004
- this.sdpOverXmpp = false;
32003
+ // private sdpOverXmpp = false;
32004
+ this.sessionsMap = {};
32005
32005
  this.client = client;
32006
32006
  this.config = {
32007
32007
  allowIPv6: clientOptions.allowIPv6 === true,
@@ -32156,6 +32156,7 @@ class WebrtcExtension extends EventEmitter {
32156
32156
  this.webrtcSessions = this.webrtcSessions.filter(s => s.id !== session.id);
32157
32157
  });
32158
32158
  this.webrtcSessions.push(session);
32159
+ // delete this.sessionsMap[session.id];
32159
32160
  this.logger.info('emitting sdp media-session (offer');
32160
32161
  this.applyEarlyIceCandidates(session);
32161
32162
  return this.emit(events.INCOMING_RTCSESSION, session);
@@ -32251,13 +32252,14 @@ class WebrtcExtension extends EventEmitter {
32251
32252
  });
32252
32253
  }
32253
32254
  prepareSession(options) {
32254
- if (this.sdpOverXmpp) {
32255
+ if (options.sid && this.sessionsMap[options.sid]) {
32255
32256
  this.logger.debug('skipping creation of jingle webrtc session due to sdpOverXmpp');
32256
32257
  return;
32257
32258
  }
32258
32259
  const pendingSession = this.pendingSessions[options.sid];
32259
32260
  if (pendingSession) {
32260
32261
  delete this.pendingSessions[pendingSession.sessionId];
32262
+ // delete this.sessionsMap[pendingSession.sessionId];
32261
32263
  }
32262
32264
  const ignoreHostCandidatesForForceTurnFF = this.getIceTransportPolicy() === 'relay' && browserama_min.exports.isFirefox;
32263
32265
  const gcSessionOpts = {
@@ -32467,7 +32469,8 @@ class WebrtcExtension extends EventEmitter {
32467
32469
  sessionInfo = Object.assign(Object.assign({}, msg.propose), { toJid: msg.to, fromJid,
32468
32470
  sessionType,
32469
32471
  roomJid, id: sessionId, sdpOverXmpp: msg.propose.sdpOverXmpp, privAnswerMode: msg.propose.privAnswerMode });
32470
- this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
32472
+ // this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
32473
+ this.sessionsMap[sessionInfo.id] = !!sessionInfo.sdpOverXmpp;
32471
32474
  this.pendingSessions[sessionId] = sessionInfo;
32472
32475
  }
32473
32476
  if (sessionInfo.accepted) {
@@ -32480,6 +32483,7 @@ class WebrtcExtension extends EventEmitter {
32480
32483
  }
32481
32484
  handleRetract(sessionId) {
32482
32485
  this.logger.info('retract received', this.getLogDetailsForPendingSessionId(sessionId));
32486
+ // delete this.sessionsMap[sessionId];
32483
32487
  delete this.pendingSessions[sessionId];
32484
32488
  return this.emit(events.CANCEL_INCOMING_RTCSESSION, sessionId);
32485
32489
  }
@@ -32582,6 +32586,7 @@ class WebrtcExtension extends EventEmitter {
32582
32586
  this.emit(events.RTCSESSION_ERROR, 'Cannot reject session because it is not pending or does not exist');
32583
32587
  return;
32584
32588
  }
32589
+ // delete this.sessionsMap[sessionId];
32585
32590
  delete this.pendingSessions[sessionId];
32586
32591
  if (ignore) {
32587
32592
  this.ignoredSessions.set(sessionId, true);
@@ -32665,6 +32670,7 @@ class WebrtcExtension extends EventEmitter {
32665
32670
  }
32666
32671
  };
32667
32672
  delete this.pendingSessions[sessionId];
32673
+ // delete this.sessionsMap[sessionId];
32668
32674
  this.logger.info('sending jingle retract', logDetails);
32669
32675
  yield this.stanzaInstance.send('message', retract); // send as Message
32670
32676
  this.logger.info('sent jingle retract', logDetails);
@@ -42892,6 +42898,46 @@ class MessengerExtension extends Emitter {
42892
42898
  }
42893
42899
  }
42894
42900
 
42901
+ // XEP-0051: Connection Transfer
42902
+ // Source: https://xmpp.org/extensions/xep-0051.html
42903
+ // Version: 0.2.1 (2022-03-08)
42904
+ // ---------------------------
42905
+ // We don't currently use domain or server
42906
+ const NS_CONNECTION_TRANSFER = 'urn:xmpp:cxfr';
42907
+ /*
42908
+ <iq xmlns="jabber:client" id="<someId>" to="<toJID>" type="set">
42909
+ <query xmlns="urn:xmpp:cxfr">
42910
+ <domain>jabber.org</domain>
42911
+ <server>123.123.123.122</server>
42912
+ </query>
42913
+ </iq>
42914
+ */
42915
+ const connectionTransfer = {
42916
+ path: 'iq.query',
42917
+ aliases: ['iq.connectionTransfer'],
42918
+ namespace: NS_CONNECTION_TRANSFER,
42919
+ element: 'query',
42920
+ fields: {
42921
+ domain: jxt.childText(null, 'domain'),
42922
+ server: jxt.childText(null, 'server')
42923
+ }
42924
+ };
42925
+
42926
+ class ConnectionTransfer {
42927
+ constructor(client, stanzaInstance) {
42928
+ this.client = client;
42929
+ this.stanzaInstance = stanzaInstance;
42930
+ stanzaInstance.stanzas.define(connectionTransfer);
42931
+ // Hawk maps `v2.system.socket_closing` to XEP-0051 Connection Transfer
42932
+ // The docs says we have up to one minute to disconnect and connect a new WebSocket, so we should be proactive in reconnecting.
42933
+ stanzaInstance.on('iq:set:connectionTransfer', (iq) => {
42934
+ client.logger.warn('connection transfer (socket_closing) event received', { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
42935
+ void client.disconnect();
42936
+ void client.connect({ keepTryingOnFailure: true });
42937
+ });
42938
+ }
42939
+ }
42940
+
42895
42941
  let extensions = {
42896
42942
  notifications: Notifications,
42897
42943
  webrtcSessions: WebrtcExtension,
@@ -43378,6 +43424,7 @@ class Client extends EventEmitter {
43378
43424
  }
43379
43425
  setupConnectionMonitoring(stanzaInstance) {
43380
43426
  return __awaiter$5(this, void 0, void 0, function* () {
43427
+ stanzaInstance.connectionTransfer = new ConnectionTransfer(this, stanzaInstance);
43381
43428
  const setupClientPinger = (message) => {
43382
43429
  const logMessage = `${message}, falling back to client-side pinging`;
43383
43430
  this.logger.warn(logMessage, { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
@@ -18,6 +18,8 @@ declare module 'stanza/protocol' {
18
18
  interface ReceivedMessage {
19
19
  mediaMessage?: GenesysMediaMessage;
20
20
  }
21
+ }
22
+ declare module 'stanza' {
21
23
  interface AgentEvents {
22
24
  'iq:set:genesysWebrtc': Stanzas.ReceivedIQ & {
23
25
  genesysWebrtc: GenesysWebrtcJsonRpcMessage;
@@ -0,0 +1,19 @@
1
+ import { Stanzas } from 'stanza';
2
+ import { DefinitionOptions } from 'stanza/jxt';
3
+ declare module 'stanza' {
4
+ interface AgentEvents {
5
+ 'iq:set:connectionTransfer': Stanzas.ReceivedIQ & {
6
+ query: ConnectionTransfer;
7
+ };
8
+ }
9
+ }
10
+ declare module 'stanza/protocol' {
11
+ interface IQPayload {
12
+ query?: ConnectionTransfer;
13
+ }
14
+ }
15
+ export interface ConnectionTransfer {
16
+ domain?: string;
17
+ server?: string;
18
+ }
19
+ export declare const connectionTransfer: DefinitionOptions;
@@ -0,0 +1,25 @@
1
+ import { childText } from 'stanza/jxt';
2
+ // XEP-0051: Connection Transfer
3
+ // Source: https://xmpp.org/extensions/xep-0051.html
4
+ // Version: 0.2.1 (2022-03-08)
5
+ // ---------------------------
6
+ // We don't currently use domain or server
7
+ const NS_CONNECTION_TRANSFER = 'urn:xmpp:cxfr';
8
+ /*
9
+ <iq xmlns="jabber:client" id="<someId>" to="<toJID>" type="set">
10
+ <query xmlns="urn:xmpp:cxfr">
11
+ <domain>jabber.org</domain>
12
+ <server>123.123.123.122</server>
13
+ </query>
14
+ </iq>
15
+ */
16
+ export const connectionTransfer = {
17
+ path: 'iq.query',
18
+ aliases: ['iq.connectionTransfer'],
19
+ namespace: NS_CONNECTION_TRANSFER,
20
+ element: 'query',
21
+ fields: {
22
+ domain: childText(null, 'domain'),
23
+ server: childText(null, 'server')
24
+ }
25
+ };
@@ -63,7 +63,6 @@ export class GenesysCloudMediaSession {
63
63
  // if we have a state mismatch
64
64
  if (this.state !== 'ended' && ['failed', 'closed'].includes(this.peerConnection.connectionState)) {
65
65
  this.log('warn', 'state mismatch between session.state and peerConnection.connectionState, manually terminating the session', { sessionId: this.id, conversationId: this.conversationId, sessionType: this.sessionType });
66
- this.state = 'ended';
67
66
  this.onSessionTerminate();
68
67
  }
69
68
  }
@@ -176,7 +175,6 @@ export class GenesysCloudMediaSession {
176
175
  }
177
176
  else if (connectionState === 'failed') {
178
177
  this.log('info', 'Connection was interrupted and failed to recover, cleaning up', { sessionId, conversationId, sessionType });
179
- this.state = 'ended';
180
178
  this.onSessionTerminate();
181
179
  }
182
180
  }
@@ -248,6 +246,7 @@ export class GenesysCloudMediaSession {
248
246
  });
249
247
  }
250
248
  onSessionTerminate(reason) {
249
+ this.state = 'ended';
251
250
  if (this.peerConnection) {
252
251
  this.peerConnection.close();
253
252
  }
@@ -1,11 +1,13 @@
1
1
  import { Agent } from 'stanza';
2
2
  import { Ping } from '../ping';
3
3
  import { ServerMonitor } from '../server-monitor';
4
+ import { ConnectionTransfer } from '../connection-transfer';
4
5
  export interface NamedAgent extends Omit<Agent, 'disconnect'> {
5
6
  id: string;
6
7
  channelId?: string;
7
8
  originalEmitter?: Function;
8
9
  pinger?: Ping;
9
10
  serverMonitor?: ServerMonitor;
11
+ connectionTransfer?: ConnectionTransfer;
10
12
  disconnect: () => Promise<void>;
11
13
  }
@@ -43,7 +43,7 @@ export declare class WebrtcExtension extends EventEmitter implements StreamingCl
43
43
  private stanzaInstance?;
44
44
  private webrtcSessions;
45
45
  private reinviteCache;
46
- private sdpOverXmpp;
46
+ private sessionsMap;
47
47
  get jid(): string | undefined;
48
48
  constructor(client: Client, clientOptions: IClientOptions);
49
49
  private onOnlineStatusChange;
package/dist/es/webrtc.js CHANGED
@@ -60,7 +60,8 @@ export class WebrtcExtension extends EventEmitter {
60
60
  max: 5,
61
61
  ttl: 1000 * 60 * 3
62
62
  });
63
- this.sdpOverXmpp = false;
63
+ // private sdpOverXmpp = false;
64
+ this.sessionsMap = {};
64
65
  this.client = client;
65
66
  this.config = {
66
67
  allowIPv6: clientOptions.allowIPv6 === true,
@@ -215,6 +216,7 @@ export class WebrtcExtension extends EventEmitter {
215
216
  this.webrtcSessions = this.webrtcSessions.filter(s => s.id !== session.id);
216
217
  });
217
218
  this.webrtcSessions.push(session);
219
+ // delete this.sessionsMap[session.id];
218
220
  this.logger.info('emitting sdp media-session (offer');
219
221
  this.applyEarlyIceCandidates(session);
220
222
  return this.emit(events.INCOMING_RTCSESSION, session);
@@ -310,13 +312,14 @@ export class WebrtcExtension extends EventEmitter {
310
312
  });
311
313
  }
312
314
  prepareSession(options) {
313
- if (this.sdpOverXmpp) {
315
+ if (options.sid && this.sessionsMap[options.sid]) {
314
316
  this.logger.debug('skipping creation of jingle webrtc session due to sdpOverXmpp');
315
317
  return;
316
318
  }
317
319
  const pendingSession = this.pendingSessions[options.sid];
318
320
  if (pendingSession) {
319
321
  delete this.pendingSessions[pendingSession.sessionId];
322
+ // delete this.sessionsMap[pendingSession.sessionId];
320
323
  }
321
324
  const ignoreHostCandidatesForForceTurnFF = this.getIceTransportPolicy() === 'relay' && isFirefox;
322
325
  const gcSessionOpts = {
@@ -526,7 +529,8 @@ export class WebrtcExtension extends EventEmitter {
526
529
  sessionInfo = Object.assign(Object.assign({}, msg.propose), { toJid: msg.to, fromJid,
527
530
  sessionType,
528
531
  roomJid, id: sessionId, sdpOverXmpp: msg.propose.sdpOverXmpp, privAnswerMode: msg.propose.privAnswerMode });
529
- this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
532
+ // this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
533
+ this.sessionsMap[sessionInfo.id] = !!sessionInfo.sdpOverXmpp;
530
534
  this.pendingSessions[sessionId] = sessionInfo;
531
535
  }
532
536
  if (sessionInfo.accepted) {
@@ -539,6 +543,7 @@ export class WebrtcExtension extends EventEmitter {
539
543
  }
540
544
  handleRetract(sessionId) {
541
545
  this.logger.info('retract received', this.getLogDetailsForPendingSessionId(sessionId));
546
+ // delete this.sessionsMap[sessionId];
542
547
  delete this.pendingSessions[sessionId];
543
548
  return this.emit(events.CANCEL_INCOMING_RTCSESSION, sessionId);
544
549
  }
@@ -641,6 +646,7 @@ export class WebrtcExtension extends EventEmitter {
641
646
  this.emit(events.RTCSESSION_ERROR, 'Cannot reject session because it is not pending or does not exist');
642
647
  return;
643
648
  }
649
+ // delete this.sessionsMap[sessionId];
644
650
  delete this.pendingSessions[sessionId];
645
651
  if (ignore) {
646
652
  this.ignoredSessions.set(sessionId, true);
@@ -724,6 +730,7 @@ export class WebrtcExtension extends EventEmitter {
724
730
  }
725
731
  };
726
732
  delete this.pendingSessions[sessionId];
733
+ // delete this.sessionsMap[sessionId];
727
734
  this.logger.info('sending jingle retract', logDetails);
728
735
  yield this.stanzaInstance.send('message', retract); // send as Message
729
736
  this.logger.info('sent jingle retract', logDetails);
@@ -9,9 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
  * [STREAM-462](https://inindca.atlassian.net/browse/STREAM-462) - Update Stanza timeout timer to 35 seconds to align with the updated server timeout.
10
10
  * [STREAM-461](https://inindca.atlassian.net/browse/STREAM-461) - Remove support for conferenceId in JWT auth (not breaking change, never released).
11
11
 
12
+ ### Fixed
13
+ * [STREAM-262](https://inindca.atlassian.net/browse/STREAM-262) - Set the state of a GenesysCloudMediaSession to `ended` when a `terminate` is received (or we determine a hard closure of the PeerConnection is needed)
14
+
12
15
  ### Added
13
16
  * [STREAM-461](https://inindca.atlassian.net/browse/STREAM-461) - Allow for conferenceId or JID to be used in JWT auth.
14
17
  * [STREAM-523](https://inindca.atlassian.net/browse/STREAM-523) - Properly emit `connectionState` event while using SDP over XMPP
18
+ * [STREAM-85](https://inindca.atlassian.net/browse/STREAM-85) - Handle connection transfer (socket closing) message from Hawk signaling a reconnect is necessary
15
19
 
16
20
  # [v19.1.0](https://github.com/purecloudlabs/genesys-cloud-streaming-client/compare/v19.0.1...v19.1.0)
17
21
  * [STREAM-357](https://inindca.atlassian.net/browse/STREAM-357) - Maintain the same JID resource across hard reconnects/websockets/stanza instances so that reinvites can be sent to the new WS/stanza instance.
@@ -20,6 +20,7 @@ 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");
22
22
  const uuid_1 = require("uuid");
23
+ const connection_transfer_1 = require("./connection-transfer");
23
24
  let extensions = {
24
25
  notifications: notifications_1.Notifications,
25
26
  webrtcSessions: webrtc_1.WebrtcExtension,
@@ -495,6 +496,7 @@ class Client extends events_1.default {
495
496
  }
496
497
  }
497
498
  async setupConnectionMonitoring(stanzaInstance) {
499
+ stanzaInstance.connectionTransfer = new connection_transfer_1.ConnectionTransfer(this, stanzaInstance);
498
500
  const setupClientPinger = (message) => {
499
501
  const logMessage = `${message}, falling back to client-side pinging`;
500
502
  this.logger.warn(logMessage, { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
@@ -0,0 +1,7 @@
1
+ import { Client } from './client';
2
+ import { NamedAgent } from './types/named-agent';
3
+ export declare class ConnectionTransfer {
4
+ private client;
5
+ private stanzaInstance;
6
+ constructor(client: Client, stanzaInstance: NamedAgent);
7
+ }