genesys-cloud-streaming-client 15.1.1 → 15.1.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.
- package/dist/cjs/client.d.ts +1 -0
- package/dist/cjs/client.js +64 -20
- package/dist/cjs/http-client.js +7 -3
- package/dist/cjs/ping.js +2 -1
- package/dist/deploy-info.json +5 -5
- package/dist/es/client.d.ts +1 -0
- package/dist/es/client.js +107 -61
- package/dist/es/http-client.js +7 -3
- package/dist/es/index.bundle.js +116 -65
- package/dist/es/ping.js +2 -1
- package/dist/npm/CHANGELOG.md +6 -2
- package/dist/npm/client.d.ts +1 -0
- package/dist/npm/client.js +64 -20
- package/dist/npm/http-client.js +7 -3
- package/dist/npm/ping.js +2 -1
- package/dist/streaming-client.browser.ie.js +2 -2
- package/dist/streaming-client.browser.js +5 -5
- package/dist/v15/streaming-client.browser.ie.js +2 -2
- package/dist/v15/streaming-client.browser.js +5 -5
- package/dist/v15.1.2/streaming-client.browser.ie.js +11 -0
- package/dist/v15.1.2/streaming-client.browser.js +40 -0
- package/package.json +1 -1
- package/dist/v15.1.1/streaming-client.browser.ie.js +0 -11
- package/dist/v15.1.1/streaming-client.browser.js +0 -40
package/dist/cjs/client.d.ts
CHANGED
package/dist/cjs/client.js
CHANGED
|
@@ -22,6 +22,7 @@ let extensions = {
|
|
|
22
22
|
};
|
|
23
23
|
const STANZA_DISCONNECTED = 'stanzaDisconnected';
|
|
24
24
|
const NO_LONGER_SUBSCRIBED = 'notify:no_longer_subscribed';
|
|
25
|
+
const MAX_CHANNEL_REUSES = 10;
|
|
25
26
|
class Client extends events_1.default {
|
|
26
27
|
constructor(options) {
|
|
27
28
|
super();
|
|
@@ -32,6 +33,7 @@ class Client extends events_1.default {
|
|
|
32
33
|
this.backgroundAssistantMode = false;
|
|
33
34
|
this.autoReconnect = true;
|
|
34
35
|
this.extensions = [];
|
|
36
|
+
this.channelReuses = 0;
|
|
35
37
|
this.http = new http_client_1.HttpClient();
|
|
36
38
|
this.reconnectOnNoLongerSubscribed = options.reconnectOnNoLongerSubscribed !== false;
|
|
37
39
|
this.config = {
|
|
@@ -186,7 +188,7 @@ class Client extends events_1.default {
|
|
|
186
188
|
return this.logger.warn(error);
|
|
187
189
|
}
|
|
188
190
|
this.connecting = true;
|
|
189
|
-
const maxDelay = (connectOpts === null || connectOpts === void 0 ? void 0 : connectOpts.maxDelayBetweenConnectionAttempts) ||
|
|
191
|
+
const maxDelay = (connectOpts === null || connectOpts === void 0 ? void 0 : connectOpts.maxDelayBetweenConnectionAttempts) || 90000;
|
|
190
192
|
let maxAttempts = (connectOpts === null || connectOpts === void 0 ? void 0 : connectOpts.maxConnectionAttempts) || 1;
|
|
191
193
|
// tslint:disable-next-line
|
|
192
194
|
if (connectOpts === null || connectOpts === void 0 ? void 0 : connectOpts.keepTryingOnFailure) {
|
|
@@ -229,8 +231,8 @@ class Client extends events_1.default {
|
|
|
229
231
|
throw err;
|
|
230
232
|
}
|
|
231
233
|
}
|
|
232
|
-
backoffConnectRetryHandler(connectOpts, err, connectionAttempt) {
|
|
233
|
-
var _a, _b;
|
|
234
|
+
async backoffConnectRetryHandler(connectOpts, err, connectionAttempt) {
|
|
235
|
+
var _a, _b, _c, _d, _e;
|
|
234
236
|
// if we exceed the `numOfAttempts` in the backoff config it still calls this retry fn and just ignores the result
|
|
235
237
|
// if that's the case, we just want to bail out and ignore all the extra logging here.
|
|
236
238
|
if (connectionAttempt >= connectOpts.maxConnectionAttempts) {
|
|
@@ -274,6 +276,22 @@ class Client extends events_1.default {
|
|
|
274
276
|
additionalErrorDetails.details = details;
|
|
275
277
|
}
|
|
276
278
|
}
|
|
279
|
+
if (err === null || err === void 0 ? void 0 : err.response) {
|
|
280
|
+
// This *should* be an axios error according to typings, but it appears this could be an AxiosError *or* and XmlHttpRequest
|
|
281
|
+
// we'll check both to be safe
|
|
282
|
+
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'));
|
|
283
|
+
if (retryAfter) {
|
|
284
|
+
// retry after comes in seconds, we need to return milliseconds
|
|
285
|
+
let retryDelay = parseInt(retryAfter, 10) * 1000;
|
|
286
|
+
additionalErrorDetails.retryDelay = retryDelay;
|
|
287
|
+
this.logger.error('Failed streaming client connection attempt, respecting retry-after header and will retry afterwards.', additionalErrorDetails, { skipServer: err instanceof offline_error_1.default });
|
|
288
|
+
await new Promise((resolve) => {
|
|
289
|
+
setTimeout(resolve, retryDelay);
|
|
290
|
+
});
|
|
291
|
+
this.logger.debug('finished waiting for retry-after');
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
277
295
|
this.logger.error('Failed streaming client connection attempt, retrying', additionalErrorDetails, { skipServer: err instanceof offline_error_1.default });
|
|
278
296
|
return true;
|
|
279
297
|
}
|
|
@@ -281,28 +299,54 @@ class Client extends events_1.default {
|
|
|
281
299
|
if (!navigator.onLine) {
|
|
282
300
|
throw new offline_error_1.default('Browser is offline, skipping connection attempt');
|
|
283
301
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
302
|
+
let stanzaInstance;
|
|
303
|
+
let previousConnectingState = this.connecting;
|
|
304
|
+
try {
|
|
305
|
+
await this.prepareForConnect();
|
|
306
|
+
stanzaInstance = await this.connectionManager.getNewStanzaConnection();
|
|
307
|
+
this.connected = true;
|
|
308
|
+
this.connecting = false;
|
|
309
|
+
this.addInateEventHandlers(stanzaInstance);
|
|
310
|
+
this.proxyStanzaEvents(stanzaInstance);
|
|
311
|
+
stanzaInstance.pinger = new ping_1.Ping(this, stanzaInstance);
|
|
312
|
+
// handle any extension configuration
|
|
313
|
+
for (const extension of this.extensions) {
|
|
314
|
+
if (extension.configureNewStanzaInstance) {
|
|
315
|
+
await extension.configureNewStanzaInstance(stanzaInstance);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
for (const extension of this.extensions) {
|
|
319
|
+
extension.handleStanzaInstanceChange(stanzaInstance);
|
|
295
320
|
}
|
|
321
|
+
this.activeStanzaInstance = stanzaInstance;
|
|
322
|
+
this.emit('connected');
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
if (stanzaInstance) {
|
|
326
|
+
this.logger.error('Error occurred in connection attempt, but after websocket connected. Cleaning up connection so backoff is respected', { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
|
|
327
|
+
// unproxy stanza events so we don't try and reconnect
|
|
328
|
+
stanzaInstance.emit = stanzaInstance.originalEmitter;
|
|
329
|
+
stanzaInstance.pinger.stop();
|
|
330
|
+
stanzaInstance.disconnect();
|
|
331
|
+
this.connected = false;
|
|
332
|
+
this.connecting = previousConnectingState;
|
|
333
|
+
}
|
|
334
|
+
throw err;
|
|
296
335
|
}
|
|
297
|
-
this.extensions.forEach(extension => extension.handleStanzaInstanceChange(stanzaInstance));
|
|
298
|
-
this.activeStanzaInstance = stanzaInstance;
|
|
299
|
-
this.emit('connected');
|
|
300
336
|
}
|
|
301
337
|
async prepareForConnect() {
|
|
302
338
|
if (this.config.jwt) {
|
|
303
339
|
this.hardReconnectRequired = false;
|
|
304
340
|
return this.connectionManager.setConfig(this.config);
|
|
305
341
|
}
|
|
342
|
+
if (!this.hardReconnectRequired) {
|
|
343
|
+
this.channelReuses++;
|
|
344
|
+
if (this.channelReuses > MAX_CHANNEL_REUSES) {
|
|
345
|
+
this.logger.warn('Forcing a hard reconnect due to max channel reuses', { channelId: this.config.channelId, channelReuses: this.channelReuses });
|
|
346
|
+
this.channelReuses = 0;
|
|
347
|
+
this.hardReconnectRequired = true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
306
350
|
if (this.hardReconnectRequired) {
|
|
307
351
|
let jidPromise;
|
|
308
352
|
if (this.config.jid) {
|
|
@@ -315,7 +359,7 @@ class Client extends events_1.default {
|
|
|
315
359
|
authToken: this.config.authToken,
|
|
316
360
|
logger: this.logger
|
|
317
361
|
};
|
|
318
|
-
jidPromise = this.http.
|
|
362
|
+
jidPromise = this.http.requestApi('users/me', jidRequestOpts)
|
|
319
363
|
.then(res => res.data.chat.jabberId);
|
|
320
364
|
}
|
|
321
365
|
const channelRequestOpts = {
|
|
@@ -324,7 +368,7 @@ class Client extends events_1.default {
|
|
|
324
368
|
authToken: this.config.authToken,
|
|
325
369
|
logger: this.logger
|
|
326
370
|
};
|
|
327
|
-
const channelPromise = this.http.
|
|
371
|
+
const channelPromise = this.http.requestApi('notifications/channels?connectionType=streaming', channelRequestOpts)
|
|
328
372
|
.then(res => res.data.id);
|
|
329
373
|
const [jid, channelId] = await Promise.all([jidPromise, channelPromise]);
|
|
330
374
|
this.config.jid = jid;
|
|
@@ -358,7 +402,7 @@ class Client extends events_1.default {
|
|
|
358
402
|
return Client.version;
|
|
359
403
|
}
|
|
360
404
|
static get version() {
|
|
361
|
-
return '15.1.
|
|
405
|
+
return '15.1.2';
|
|
362
406
|
}
|
|
363
407
|
}
|
|
364
408
|
exports.Client = Client;
|
package/dist/cjs/http-client.js
CHANGED
|
@@ -11,12 +11,15 @@ class HttpClient {
|
|
|
11
11
|
}
|
|
12
12
|
requestApiWithRetry(path, opts, retryInterval) {
|
|
13
13
|
const retry = utils_1.retryPromise(this.requestApi.bind(this, path, opts), (error) => {
|
|
14
|
-
var _a;
|
|
14
|
+
var _a, _b, _c;
|
|
15
15
|
let retryValue = false;
|
|
16
16
|
if (error === null || error === void 0 ? void 0 : error.response) {
|
|
17
17
|
retryValue = HttpClient.retryStatusCodes.has(error.response.status || 0);
|
|
18
|
-
|
|
18
|
+
// This *should* be an axios error according to typings, but it appears this could be an AxiosError *or* and XmlHttpRequest
|
|
19
|
+
// we'll check both to be safe
|
|
20
|
+
const retryAfter = ((_a = error.response.headers) === null || _a === void 0 ? void 0 : _a['retry-after']) || ((_c = (_b = error.response).getResponseHeader) === null || _c === void 0 ? void 0 : _c.call(_b, 'retry-after'));
|
|
19
21
|
if (retryAfter) {
|
|
22
|
+
(opts.logger || console).debug('retry-after header found on response. setting retry delay', { retryAfter });
|
|
20
23
|
// retry after comes in seconds, we need to return milliseconds
|
|
21
24
|
retryValue = parseInt(retryAfter, 10) * 1000;
|
|
22
25
|
}
|
|
@@ -51,6 +54,7 @@ class HttpClient {
|
|
|
51
54
|
.then(boundHandler, boundHandler);
|
|
52
55
|
}
|
|
53
56
|
handleResponse(logger, start, params, res) {
|
|
57
|
+
var _a;
|
|
54
58
|
let now = new Date().getTime();
|
|
55
59
|
let elapsed = (now - start) + 'ms';
|
|
56
60
|
if (res instanceof axios_1.AxiosError) {
|
|
@@ -70,7 +74,7 @@ class HttpClient {
|
|
|
70
74
|
let body = response.data;
|
|
71
75
|
let error = {
|
|
72
76
|
...res,
|
|
73
|
-
text: response.request.response
|
|
77
|
+
text: (_a = response.request) === null || _a === void 0 ? void 0 : _a.response
|
|
74
78
|
};
|
|
75
79
|
logger.debug(`request error: ${params.url}`, {
|
|
76
80
|
message: res.message,
|
package/dist/cjs/ping.js
CHANGED
|
@@ -33,7 +33,8 @@ class Ping {
|
|
|
33
33
|
catch (err) {
|
|
34
34
|
const info = {
|
|
35
35
|
channelId: this.client.config.channelId,
|
|
36
|
-
jid: this.stanzaInstance.jid
|
|
36
|
+
jid: this.stanzaInstance.jid,
|
|
37
|
+
stanzaInstanceId: this.stanzaInstance.id
|
|
37
38
|
};
|
|
38
39
|
this.client.logger.warn('Missed a ping.', Object.assign({ error: err }, info));
|
|
39
40
|
/* if we have reached max number of missed pings, disconnect */
|
package/dist/deploy-info.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "developercenter-cdn/streaming-client",
|
|
3
|
-
"version": "15.1.
|
|
3
|
+
"version": "15.1.2",
|
|
4
4
|
"ecosystem": "pc",
|
|
5
5
|
"team": "Genesys Client Media (WebRTC)",
|
|
6
6
|
"indexFiles": [
|
|
7
7
|
{
|
|
8
|
-
"file": "/v15.1.
|
|
8
|
+
"file": "/v15.1.2/streaming-client.browser.ie.js"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
|
-
"file": "/v15.1.
|
|
11
|
+
"file": "/v15.1.2/streaming-client.browser.js"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"file": "/v15/streaming-client.browser.ie.js"
|
|
@@ -17,6 +17,6 @@
|
|
|
17
17
|
"file": "/v15/streaming-client.browser.js"
|
|
18
18
|
}
|
|
19
19
|
],
|
|
20
|
-
"build": "
|
|
21
|
-
"buildDate": "2023-
|
|
20
|
+
"build": "57",
|
|
21
|
+
"buildDate": "2023-03-02T21:43:00.982202Z"
|
|
22
22
|
}
|
package/dist/es/client.d.ts
CHANGED
package/dist/es/client.js
CHANGED
|
@@ -20,6 +20,7 @@ let extensions = {
|
|
|
20
20
|
};
|
|
21
21
|
const STANZA_DISCONNECTED = 'stanzaDisconnected';
|
|
22
22
|
const NO_LONGER_SUBSCRIBED = 'notify:no_longer_subscribed';
|
|
23
|
+
const MAX_CHANNEL_REUSES = 10;
|
|
23
24
|
export class Client extends EventEmitter {
|
|
24
25
|
constructor(options) {
|
|
25
26
|
super();
|
|
@@ -30,6 +31,7 @@ export class Client extends EventEmitter {
|
|
|
30
31
|
this.backgroundAssistantMode = false;
|
|
31
32
|
this.autoReconnect = true;
|
|
32
33
|
this.extensions = [];
|
|
34
|
+
this.channelReuses = 0;
|
|
33
35
|
this.http = new HttpClient();
|
|
34
36
|
this.reconnectOnNoLongerSubscribed = options.reconnectOnNoLongerSubscribed !== false;
|
|
35
37
|
this.config = {
|
|
@@ -189,7 +191,7 @@ export class Client extends EventEmitter {
|
|
|
189
191
|
return this.logger.warn(error);
|
|
190
192
|
}
|
|
191
193
|
this.connecting = true;
|
|
192
|
-
const maxDelay = (connectOpts === null || connectOpts === void 0 ? void 0 : connectOpts.maxDelayBetweenConnectionAttempts) ||
|
|
194
|
+
const maxDelay = (connectOpts === null || connectOpts === void 0 ? void 0 : connectOpts.maxDelayBetweenConnectionAttempts) || 90000;
|
|
193
195
|
let maxAttempts = (connectOpts === null || connectOpts === void 0 ? void 0 : connectOpts.maxConnectionAttempts) || 1;
|
|
194
196
|
// tslint:disable-next-line
|
|
195
197
|
if (connectOpts === null || connectOpts === void 0 ? void 0 : connectOpts.keepTryingOnFailure) {
|
|
@@ -234,74 +236,110 @@ export class Client extends EventEmitter {
|
|
|
234
236
|
});
|
|
235
237
|
}
|
|
236
238
|
backoffConnectRetryHandler(connectOpts, err, connectionAttempt) {
|
|
237
|
-
var _a, _b;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
const additionalErrorDetails = { connectionAttempt, error: err };
|
|
244
|
-
if (!err) {
|
|
245
|
-
additionalErrorDetails.error = new Error('streaming client backoff handler received undefined error');
|
|
246
|
-
}
|
|
247
|
-
else if (err.name === 'AxiosError') {
|
|
248
|
-
const axiosError = err;
|
|
249
|
-
const config = axiosError.config;
|
|
250
|
-
let sanitizedError = {
|
|
251
|
-
config: {
|
|
252
|
-
url: config.url,
|
|
253
|
-
method: config.method
|
|
254
|
-
},
|
|
255
|
-
status: (_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.status,
|
|
256
|
-
code: axiosError.code,
|
|
257
|
-
name: axiosError.name,
|
|
258
|
-
message: axiosError.message
|
|
259
|
-
};
|
|
260
|
-
additionalErrorDetails.error = sanitizedError;
|
|
261
|
-
if ([401, 403].includes(((_b = err.response) === null || _b === void 0 ? void 0 : _b.status) || 0)) {
|
|
262
|
-
this.logger.error('Streaming client received an error that it can\'t recover from and will not attempt to reconnect', additionalErrorDetails);
|
|
239
|
+
var _a, _b, _c, _d, _e;
|
|
240
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
241
|
+
// if we exceed the `numOfAttempts` in the backoff config it still calls this retry fn and just ignores the result
|
|
242
|
+
// if that's the case, we just want to bail out and ignore all the extra logging here.
|
|
243
|
+
if (connectionAttempt >= connectOpts.maxConnectionAttempts) {
|
|
263
244
|
return false;
|
|
264
245
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (err instanceof SaslError) {
|
|
269
|
-
this.logger.info('hardReconnectRequired set to true due to sasl error');
|
|
270
|
-
this.hardReconnectRequired = true;
|
|
271
|
-
Object.assign(additionalErrorDetails, { channelId: err.channelId, stanzaInstanceId: err.stanzaInstanceId });
|
|
272
|
-
}
|
|
273
|
-
// we don't need to log the stack for a timeout message
|
|
274
|
-
if (err instanceof TimeoutError) {
|
|
275
|
-
additionalErrorDetails.error = err.message;
|
|
276
|
-
const details = err.details;
|
|
277
|
-
if (details) {
|
|
278
|
-
additionalErrorDetails.details = details;
|
|
246
|
+
const additionalErrorDetails = { connectionAttempt, error: err };
|
|
247
|
+
if (!err) {
|
|
248
|
+
additionalErrorDetails.error = new Error('streaming client backoff handler received undefined error');
|
|
279
249
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
250
|
+
else if (err.name === 'AxiosError') {
|
|
251
|
+
const axiosError = err;
|
|
252
|
+
const config = axiosError.config;
|
|
253
|
+
let sanitizedError = {
|
|
254
|
+
config: {
|
|
255
|
+
url: config.url,
|
|
256
|
+
method: config.method
|
|
257
|
+
},
|
|
258
|
+
status: (_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.status,
|
|
259
|
+
code: axiosError.code,
|
|
260
|
+
name: axiosError.name,
|
|
261
|
+
message: axiosError.message
|
|
262
|
+
};
|
|
263
|
+
additionalErrorDetails.error = sanitizedError;
|
|
264
|
+
if ([401, 403].includes(((_b = err.response) === null || _b === void 0 ? void 0 : _b.status) || 0)) {
|
|
265
|
+
this.logger.error('Streaming client received an error that it can\'t recover from and will not attempt to reconnect', additionalErrorDetails);
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// if we get a sasl error, that means we made it all the way to the point of trying to open a websocket and
|
|
270
|
+
// it was rejected for some reason. At this point we should do a hard reconnect then try again.
|
|
271
|
+
if (err instanceof SaslError) {
|
|
272
|
+
this.logger.info('hardReconnectRequired set to true due to sasl error');
|
|
273
|
+
this.hardReconnectRequired = true;
|
|
274
|
+
Object.assign(additionalErrorDetails, { channelId: err.channelId, stanzaInstanceId: err.stanzaInstanceId });
|
|
275
|
+
}
|
|
276
|
+
// we don't need to log the stack for a timeout message
|
|
277
|
+
if (err instanceof TimeoutError) {
|
|
278
|
+
additionalErrorDetails.error = err.message;
|
|
279
|
+
const details = err.details;
|
|
280
|
+
if (details) {
|
|
281
|
+
additionalErrorDetails.details = details;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (err === null || err === void 0 ? void 0 : err.response) {
|
|
285
|
+
// This *should* be an axios error according to typings, but it appears this could be an AxiosError *or* and XmlHttpRequest
|
|
286
|
+
// we'll check both to be safe
|
|
287
|
+
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'));
|
|
288
|
+
if (retryAfter) {
|
|
289
|
+
// retry after comes in seconds, we need to return milliseconds
|
|
290
|
+
let retryDelay = parseInt(retryAfter, 10) * 1000;
|
|
291
|
+
additionalErrorDetails.retryDelay = retryDelay;
|
|
292
|
+
this.logger.error('Failed streaming client connection attempt, respecting retry-after header and will retry afterwards.', additionalErrorDetails, { skipServer: err instanceof OfflineError });
|
|
293
|
+
yield new Promise((resolve) => {
|
|
294
|
+
setTimeout(resolve, retryDelay);
|
|
295
|
+
});
|
|
296
|
+
this.logger.debug('finished waiting for retry-after');
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
this.logger.error('Failed streaming client connection attempt, retrying', additionalErrorDetails, { skipServer: err instanceof OfflineError });
|
|
301
|
+
return true;
|
|
302
|
+
});
|
|
283
303
|
}
|
|
284
304
|
makeConnectionAttempt() {
|
|
285
305
|
return __awaiter(this, void 0, void 0, function* () {
|
|
286
306
|
if (!navigator.onLine) {
|
|
287
307
|
throw new OfflineError('Browser is offline, skipping connection attempt');
|
|
288
308
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
309
|
+
let stanzaInstance;
|
|
310
|
+
let previousConnectingState = this.connecting;
|
|
311
|
+
try {
|
|
312
|
+
yield this.prepareForConnect();
|
|
313
|
+
stanzaInstance = yield this.connectionManager.getNewStanzaConnection();
|
|
314
|
+
this.connected = true;
|
|
315
|
+
this.connecting = false;
|
|
316
|
+
this.addInateEventHandlers(stanzaInstance);
|
|
317
|
+
this.proxyStanzaEvents(stanzaInstance);
|
|
318
|
+
stanzaInstance.pinger = new Ping(this, stanzaInstance);
|
|
319
|
+
// handle any extension configuration
|
|
320
|
+
for (const extension of this.extensions) {
|
|
321
|
+
if (extension.configureNewStanzaInstance) {
|
|
322
|
+
yield extension.configureNewStanzaInstance(stanzaInstance);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
for (const extension of this.extensions) {
|
|
326
|
+
extension.handleStanzaInstanceChange(stanzaInstance);
|
|
300
327
|
}
|
|
328
|
+
this.activeStanzaInstance = stanzaInstance;
|
|
329
|
+
this.emit('connected');
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
if (stanzaInstance) {
|
|
333
|
+
this.logger.error('Error occurred in connection attempt, but after websocket connected. Cleaning up connection so backoff is respected', { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
|
|
334
|
+
// unproxy stanza events so we don't try and reconnect
|
|
335
|
+
stanzaInstance.emit = stanzaInstance.originalEmitter;
|
|
336
|
+
stanzaInstance.pinger.stop();
|
|
337
|
+
stanzaInstance.disconnect();
|
|
338
|
+
this.connected = false;
|
|
339
|
+
this.connecting = previousConnectingState;
|
|
340
|
+
}
|
|
341
|
+
throw err;
|
|
301
342
|
}
|
|
302
|
-
this.extensions.forEach(extension => extension.handleStanzaInstanceChange(stanzaInstance));
|
|
303
|
-
this.activeStanzaInstance = stanzaInstance;
|
|
304
|
-
this.emit('connected');
|
|
305
343
|
});
|
|
306
344
|
}
|
|
307
345
|
prepareForConnect() {
|
|
@@ -310,6 +348,14 @@ export class Client extends EventEmitter {
|
|
|
310
348
|
this.hardReconnectRequired = false;
|
|
311
349
|
return this.connectionManager.setConfig(this.config);
|
|
312
350
|
}
|
|
351
|
+
if (!this.hardReconnectRequired) {
|
|
352
|
+
this.channelReuses++;
|
|
353
|
+
if (this.channelReuses > MAX_CHANNEL_REUSES) {
|
|
354
|
+
this.logger.warn('Forcing a hard reconnect due to max channel reuses', { channelId: this.config.channelId, channelReuses: this.channelReuses });
|
|
355
|
+
this.channelReuses = 0;
|
|
356
|
+
this.hardReconnectRequired = true;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
313
359
|
if (this.hardReconnectRequired) {
|
|
314
360
|
let jidPromise;
|
|
315
361
|
if (this.config.jid) {
|
|
@@ -322,7 +368,7 @@ export class Client extends EventEmitter {
|
|
|
322
368
|
authToken: this.config.authToken,
|
|
323
369
|
logger: this.logger
|
|
324
370
|
};
|
|
325
|
-
jidPromise = this.http.
|
|
371
|
+
jidPromise = this.http.requestApi('users/me', jidRequestOpts)
|
|
326
372
|
.then(res => res.data.chat.jabberId);
|
|
327
373
|
}
|
|
328
374
|
const channelRequestOpts = {
|
|
@@ -331,7 +377,7 @@ export class Client extends EventEmitter {
|
|
|
331
377
|
authToken: this.config.authToken,
|
|
332
378
|
logger: this.logger
|
|
333
379
|
};
|
|
334
|
-
const channelPromise = this.http.
|
|
380
|
+
const channelPromise = this.http.requestApi('notifications/channels?connectionType=streaming', channelRequestOpts)
|
|
335
381
|
.then(res => res.data.id);
|
|
336
382
|
const [jid, channelId] = yield Promise.all([jidPromise, channelPromise]);
|
|
337
383
|
this.config.jid = jid;
|
|
@@ -366,6 +412,6 @@ export class Client extends EventEmitter {
|
|
|
366
412
|
return Client.version;
|
|
367
413
|
}
|
|
368
414
|
static get version() {
|
|
369
|
-
return '15.1.
|
|
415
|
+
return '15.1.2';
|
|
370
416
|
}
|
|
371
417
|
}
|
package/dist/es/http-client.js
CHANGED
|
@@ -7,12 +7,15 @@ export class HttpClient {
|
|
|
7
7
|
}
|
|
8
8
|
requestApiWithRetry(path, opts, retryInterval) {
|
|
9
9
|
const retry = retryPromise(this.requestApi.bind(this, path, opts), (error) => {
|
|
10
|
-
var _a;
|
|
10
|
+
var _a, _b, _c;
|
|
11
11
|
let retryValue = false;
|
|
12
12
|
if (error === null || error === void 0 ? void 0 : error.response) {
|
|
13
13
|
retryValue = HttpClient.retryStatusCodes.has(error.response.status || 0);
|
|
14
|
-
|
|
14
|
+
// This *should* be an axios error according to typings, but it appears this could be an AxiosError *or* and XmlHttpRequest
|
|
15
|
+
// we'll check both to be safe
|
|
16
|
+
const retryAfter = ((_a = error.response.headers) === null || _a === void 0 ? void 0 : _a['retry-after']) || ((_c = (_b = error.response).getResponseHeader) === null || _c === void 0 ? void 0 : _c.call(_b, 'retry-after'));
|
|
15
17
|
if (retryAfter) {
|
|
18
|
+
(opts.logger || console).debug('retry-after header found on response. setting retry delay', { retryAfter });
|
|
16
19
|
// retry after comes in seconds, we need to return milliseconds
|
|
17
20
|
retryValue = parseInt(retryAfter, 10) * 1000;
|
|
18
21
|
}
|
|
@@ -47,6 +50,7 @@ export class HttpClient {
|
|
|
47
50
|
.then(boundHandler, boundHandler);
|
|
48
51
|
}
|
|
49
52
|
handleResponse(logger, start, params, res) {
|
|
53
|
+
var _a;
|
|
50
54
|
let now = new Date().getTime();
|
|
51
55
|
let elapsed = (now - start) + 'ms';
|
|
52
56
|
if (res instanceof AxiosError) {
|
|
@@ -64,7 +68,7 @@ export class HttpClient {
|
|
|
64
68
|
let status = response.status;
|
|
65
69
|
let correlationId = response.headers && response.headers[correlationIdHeaderName];
|
|
66
70
|
let body = response.data;
|
|
67
|
-
let error = Object.assign(Object.assign({}, res), { text: response.request.response });
|
|
71
|
+
let error = Object.assign(Object.assign({}, res), { text: (_a = response.request) === null || _a === void 0 ? void 0 : _a.response });
|
|
68
72
|
logger.debug(`request error: ${params.url}`, {
|
|
69
73
|
message: res.message,
|
|
70
74
|
now,
|