@rc-ex/ws 1.3.12 → 1.3.14

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/esm/index.js CHANGED
@@ -1,68 +1,23 @@
1
- var __extends = (this && this.__extends) || (function () {
2
- var extendStatics = function (d, b) {
3
- extendStatics = Object.setPrototypeOf ||
4
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5
- function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
6
- return extendStatics(d, b);
7
- };
8
- return function (d, b) {
9
- if (typeof b !== "function" && b !== null)
10
- throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
11
- extendStatics(d, b);
12
- function __() { this.constructor = d; }
13
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
14
- };
15
- })();
16
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
17
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
18
- return new (P || (P = Promise))(function (resolve, reject) {
19
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
22
- step((generator = generator.apply(thisArg, _arguments || [])).next());
23
- });
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
24
4
  };
25
- var __generator = (this && this.__generator) || function (thisArg, body) {
26
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
27
- return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
28
- function verb(n) { return function (v) { return step([n, v]); }; }
29
- function step(op) {
30
- if (f) throw new TypeError("Generator is already executing.");
31
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
32
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
33
- if (y = 0, t) op = [op[0] & 2, t.value];
34
- switch (op[0]) {
35
- case 0: case 1: t = op; break;
36
- case 4: _.label++; return { value: op[1], done: false };
37
- case 5: _.label++; y = op[1]; op = [0]; continue;
38
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
39
- default:
40
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
41
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
42
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
43
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
44
- if (t[2]) _.ops.pop();
45
- _.trys.pop(); continue;
46
- }
47
- op = body.call(thisArg, _);
48
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
49
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
50
- }
51
- };
52
- import SdkExtension from "@rc-ex/core/SdkExtension";
53
- import WS from "isomorphic-ws";
54
- import hyperid from "hyperid";
55
- import { EventEmitter } from "events";
56
- import waitFor from "wait-for-async";
57
- import RestException from "@rc-ex/core/RestException";
58
- import { request } from "./rest.js";
59
- import Subscription from "./subscription.js";
60
- import ConnectionException from "./exceptions/ConnectionException.js";
61
- import Utils from "./utils.js";
62
- var CONNECTING = 0;
63
- var OPEN = 1;
64
- var uuid = hyperid();
65
- export var Events;
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Events = void 0;
7
+ const SdkExtension_1 = __importDefault(require("@rc-ex/core/SdkExtension"));
8
+ const isomorphic_ws_1 = __importDefault(require("isomorphic-ws"));
9
+ const hyperid_1 = __importDefault(require("hyperid"));
10
+ const events_1 = require("events");
11
+ const wait_for_async_1 = __importDefault(require("wait-for-async"));
12
+ const RestException_1 = __importDefault(require("@rc-ex/core/RestException"));
13
+ const rest_js_1 = require("./rest.js");
14
+ const subscription_js_1 = __importDefault(require("./subscription.js"));
15
+ const ConnectionException_js_1 = __importDefault(require("./exceptions/ConnectionException.js"));
16
+ const utils_js_1 = __importDefault(require("./utils.js"));
17
+ const CONNECTING = 0;
18
+ const OPEN = 1;
19
+ const uuid = (0, hyperid_1.default)();
20
+ var Events;
66
21
  (function (Events) {
67
22
  Events["autoRecoverSuccess"] = "autoRecoverSuccess";
68
23
  Events["autoRecoverFailed"] = "autoRecoverFailed";
@@ -70,439 +25,309 @@ export var Events;
70
25
  Events["newWebSocketObject"] = "newWebSocketObject";
71
26
  Events["newWsc"] = "newWsc";
72
27
  Events["connectionReady"] = "connectionReady";
73
- })(Events || (Events = {}));
74
- var WebSocketExtension = /** @class */ (function (_super) {
75
- __extends(WebSocketExtension, _super);
76
- function WebSocketExtension(options) {
77
- if (options === void 0) { options = {}; }
78
- var _a, _b, _c, _d, _e;
79
- var _f, _g, _h, _j, _k;
80
- var _this = _super.call(this) || this;
81
- _this.eventEmitter = new EventEmitter();
82
- _this.wsTokenExpiresAt = 0;
83
- _this.request = request; // request method was moved to another file to keep this file short
84
- _this.options = options;
85
- (_a = (_f = _this.options).restOverWebSocket) !== null && _a !== void 0 ? _a : (_f.restOverWebSocket = false);
86
- (_b = (_g = _this.options).debugMode) !== null && _b !== void 0 ? _b : (_g.debugMode = false);
87
- (_c = (_h = _this.options).autoRecover) !== null && _c !== void 0 ? _c : (_h.autoRecover = {
28
+ })(Events || (exports.Events = Events = {}));
29
+ class WebSocketExtension extends SdkExtension_1.default {
30
+ eventEmitter = new events_1.EventEmitter();
31
+ options;
32
+ rc;
33
+ wsToken;
34
+ wsTokenExpiresAt = 0;
35
+ ws;
36
+ connectionDetails;
37
+ wsc;
38
+ subscription;
39
+ // for auto recover
40
+ intervalHandle;
41
+ recoverTimestamp;
42
+ pingServerHandle;
43
+ _recoverPromise;
44
+ _connectPromise;
45
+ request = rest_js_1.request; // request method was moved to another file to keep this file short
46
+ constructor(options = {}) {
47
+ super();
48
+ this.options = options;
49
+ this.options.restOverWebSocket ??= false;
50
+ this.options.debugMode ??= false;
51
+ this.options.autoRecover ??= {
88
52
  enabled: true,
89
- });
90
- (_d = (_j = _this.options.autoRecover).checkInterval) !== null && _d !== void 0 ? _d : (_j.checkInterval = function (retriesAttempted) {
91
- var interval = 2000 + 2000 * retriesAttempted;
53
+ };
54
+ this.options.autoRecover.checkInterval ??= (retriesAttempted) => {
55
+ const interval = 2000 + 2000 * retriesAttempted;
92
56
  return Math.min(8000, interval);
93
- });
94
- (_e = (_k = _this.options.autoRecover).pingServerInterval) !== null && _e !== void 0 ? _e : (_k.pingServerInterval = 60000);
95
- return _this;
57
+ };
58
+ this.options.autoRecover.pingServerInterval ??= 60000;
96
59
  }
97
- WebSocketExtension.prototype.disable = function () {
98
- _super.prototype.disable.call(this);
60
+ disable() {
61
+ super.disable();
99
62
  if (this.subscription) {
100
63
  this.subscription.enabled = false;
101
64
  }
102
- };
103
- WebSocketExtension.prototype.install = function (rc) {
104
- return __awaiter(this, void 0, void 0, function () {
105
- var request_1, connectMethod, e_1, retriesAttempted, checking, check;
106
- var _this = this;
107
- return __generator(this, function (_a) {
108
- switch (_a.label) {
109
- case 0:
110
- this.rc = rc;
111
- if (this.options.restOverWebSocket) {
112
- request_1 = rc.request.bind(rc);
113
- rc.request = function (method, endpoint, content, queryParams, config) { return __awaiter(_this, void 0, void 0, function () {
114
- var _a, _b, _c;
115
- return __generator(this, function (_d) {
116
- if (!this.enabled || !this.options.restOverWebSocket) {
117
- return [2 /*return*/, request_1(method, endpoint, content, queryParams, config)];
118
- }
119
- if (
120
- // the following cannot be done with WebSocket
121
- ((_c = (_b = (_a = config === null || config === void 0 ? void 0 : config.headers) === null || _a === void 0 ? void 0 : _a.getContentType) === null || _b === void 0 ? void 0 : _b.toString()) === null || _c === void 0 ? void 0 : _c.includes("multipart/form-data")) ||
122
- (config === null || config === void 0 ? void 0 : config.responseType) === "arraybuffer" ||
123
- endpoint.startsWith("/restapi/oauth/") // token, revoke, wstoken
124
- ) {
125
- return [2 /*return*/, request_1(method, endpoint, content, queryParams, config)];
126
- }
127
- return [2 /*return*/, this.request(method, endpoint, content, queryParams, config)];
128
- });
129
- }); };
130
- }
131
- connectMethod = this.connect.bind(this);
132
- if (this.options.wscToken) {
133
- this.wsc = {
134
- token: this.options.wscToken,
135
- sequence: 0,
136
- };
137
- connectMethod = this.recover.bind(this);
138
- }
139
- if (!!this.options.autoRecover.enabled) return [3 /*break*/, 2];
140
- return [4 /*yield*/, connectMethod()];
141
- case 1:
142
- _a.sent();
143
- return [2 /*return*/];
144
- case 2:
145
- _a.trys.push([2, 4, , 5]);
146
- return [4 /*yield*/, connectMethod()];
147
- case 3:
148
- _a.sent();
149
- return [3 /*break*/, 5];
150
- case 4:
151
- e_1 = _a.sent();
152
- if (e_1 instanceof RestException) {
153
- throw e_1; // such as InsufficientPermissions
154
- }
155
- if (this.options.debugMode) {
156
- console.debug("Initial connect failed:", e_1);
157
- }
158
- return [3 /*break*/, 5];
159
- case 5:
160
- retriesAttempted = 0;
161
- checking = false;
162
- check = function () { return __awaiter(_this, void 0, void 0, function () {
163
- var e_2;
164
- var _a, _b, _c;
165
- return __generator(this, function (_d) {
166
- switch (_d.label) {
167
- case 0:
168
- if (!this.enabled) {
169
- return [2 /*return*/];
170
- }
171
- if (((_a = this.options.autoRecover) === null || _a === void 0 ? void 0 : _a.enabled) !== true) {
172
- return [2 /*return*/];
173
- }
174
- if (checking) {
175
- return [2 /*return*/];
176
- }
177
- checking = true;
178
- if (!(((_b = this.ws) === null || _b === void 0 ? void 0 : _b.readyState) !== OPEN && ((_c = this.ws) === null || _c === void 0 ? void 0 : _c.readyState) !== CONNECTING)) return [3 /*break*/, 5];
179
- clearInterval(this.intervalHandle);
180
- _d.label = 1;
181
- case 1:
182
- _d.trys.push([1, 3, , 4]);
183
- return [4 /*yield*/, this.recover()];
184
- case 2:
185
- _d.sent();
186
- retriesAttempted = 0;
187
- if (this.options.debugMode) {
188
- console.debug("Auto recover done, recoveryState: ".concat(this.connectionDetails.recoveryState));
189
- }
190
- this.eventEmitter.emit(this.connectionDetails.recoveryState === "Successful"
191
- ? Events.autoRecoverSuccess
192
- : Events.autoRecoverFailed, this.ws);
193
- return [3 /*break*/, 4];
194
- case 3:
195
- e_2 = _d.sent();
196
- if (e_2 instanceof RestException) {
197
- throw e_2; // such as InsufficientPermissions
198
- }
199
- retriesAttempted += 1;
200
- if (this.options.debugMode) {
201
- console.debug("Auto recover error:", e_2);
202
- }
203
- this.eventEmitter.emit(Events.autoRecoverError, e_2);
204
- return [3 /*break*/, 4];
205
- case 4:
206
- this.intervalHandle = setInterval(check, this.options.autoRecover.checkInterval(retriesAttempted));
207
- _d.label = 5;
208
- case 5:
209
- checking = false;
210
- return [2 /*return*/];
211
- }
212
- });
213
- }); };
214
- this.intervalHandle = setInterval(check, this.options.autoRecover.checkInterval(retriesAttempted));
215
- // browser only code start
216
- if (typeof globalThis.window !== "undefined" &&
217
- globalThis.window.addEventListener) {
218
- globalThis.window.addEventListener("offline", function () {
219
- var _a;
220
- if (_this.pingServerHandle) {
221
- clearTimeout(_this.pingServerHandle);
222
- }
223
- (_a = _this.ws) === null || _a === void 0 ? void 0 : _a.close();
224
- });
225
- globalThis.window.addEventListener("online", function () {
226
- check();
227
- });
228
- }
229
- return [2 /*return*/];
230
- }
231
- });
232
- });
233
- };
234
- WebSocketExtension.prototype.recover = function () {
235
- return __awaiter(this, void 0, void 0, function () {
236
- return __generator(this, function (_a) {
237
- switch (_a.label) {
238
- case 0:
239
- if (this._recoverPromise) {
240
- return [2 /*return*/, this._recoverPromise];
241
- }
242
- this._recoverPromise = this._recover();
243
- _a.label = 1;
244
- case 1:
245
- _a.trys.push([1, , 3, 4]);
246
- return [4 /*yield*/, this._recoverPromise];
247
- case 2:
248
- _a.sent();
249
- return [3 /*break*/, 4];
250
- case 3:
251
- this._recoverPromise = undefined;
252
- return [7 /*endfinally*/];
253
- case 4: return [2 /*return*/, undefined];
65
+ }
66
+ async install(rc) {
67
+ this.rc = rc;
68
+ if (this.options.restOverWebSocket) {
69
+ const request = rc.request.bind(rc);
70
+ rc.request = async (method, endpoint, content, queryParams, config) => {
71
+ if (!this.enabled || !this.options.restOverWebSocket) {
72
+ return request(method, endpoint, content, queryParams, config);
254
73
  }
255
- });
256
- });
257
- };
258
- WebSocketExtension.prototype._recover = function () {
259
- return __awaiter(this, void 0, void 0, function () {
260
- var _a, _b;
261
- return __generator(this, function (_c) {
262
- switch (_c.label) {
263
- case 0:
264
- if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === OPEN || ((_b = this.ws) === null || _b === void 0 ? void 0 : _b.readyState) === CONNECTING) {
265
- return [2 /*return*/];
266
- }
267
- if (!(!this.wsc || !this.wsc.token)) return [3 /*break*/, 2];
268
- return [4 /*yield*/, this.connect(false)];
269
- case 1:
270
- _c.sent(); // connect to WSG but do not recover
271
- return [2 /*return*/];
272
- case 2:
273
- if (this.recoverTimestamp === undefined) {
274
- this.recoverTimestamp = Date.now();
275
- }
276
- if (!(this.connectionDetails !== undefined &&
277
- Date.now() - this.recoverTimestamp >
278
- this.connectionDetails.recoveryTimeout * 1000)) return [3 /*break*/, 4];
279
- if (this.options.debugMode) {
280
- console.debug("connect to WSG but do not recover");
281
- }
282
- return [4 /*yield*/, this.connect(false)];
283
- case 3:
284
- _c.sent(); // connect to WSG but do not recover
285
- return [3 /*break*/, 6];
286
- case 4:
287
- if (this.options.debugMode) {
288
- console.debug("connect to WSG and recover");
289
- }
290
- return [4 /*yield*/, this.connect(true)];
291
- case 5:
292
- _c.sent(); // connect to WSG and recover
293
- _c.label = 6;
294
- case 6:
295
- this.recoverTimestamp = undefined;
296
- this.enable();
297
- return [2 /*return*/];
74
+ if (
75
+ // the following cannot be done with WebSocket
76
+ config?.headers?.getContentType?.toString()?.includes("multipart/form-data") ||
77
+ config?.responseType === "arraybuffer" ||
78
+ endpoint.startsWith("/restapi/oauth/") // token, revoke, wstoken
79
+ ) {
80
+ return request(method, endpoint, content, queryParams, config);
298
81
  }
299
- });
300
- });
301
- };
302
- WebSocketExtension.prototype.pingServer = function () {
303
- return __awaiter(this, void 0, void 0, function () {
304
- var e_3;
305
- var _a, _b;
306
- return __generator(this, function (_c) {
307
- switch (_c.label) {
308
- case 0:
309
- if (((_a = this.options.autoRecover) === null || _a === void 0 ? void 0 : _a.enabled) !== true) {
310
- return [2 /*return*/];
311
- }
312
- if (((_b = this.ws) === null || _b === void 0 ? void 0 : _b.readyState) !== OPEN) {
313
- return [2 /*return*/];
314
- }
315
- _c.label = 1;
316
- case 1:
317
- _c.trys.push([1, 3, , 4]);
318
- return [4 /*yield*/, this.ws.send(JSON.stringify([
319
- {
320
- type: "Heartbeat",
321
- messageId: uuid(),
322
- },
323
- ]))];
324
- case 2:
325
- _c.sent();
326
- return [3 /*break*/, 4];
327
- case 3:
328
- e_3 = _c.sent();
329
- this.ws.close(); // Explicitly mark WS as closed
330
- return [3 /*break*/, 4];
331
- case 4: return [2 /*return*/];
82
+ return this.request(method, endpoint, content, queryParams, config);
83
+ };
84
+ }
85
+ // should recover if this.options.wscToken
86
+ let connectMethod = this.connect.bind(this);
87
+ if (this.options.wscToken) {
88
+ this.wsc = {
89
+ token: this.options.wscToken,
90
+ sequence: 0,
91
+ };
92
+ connectMethod = this.recover.bind(this);
93
+ }
94
+ if (!this.options.autoRecover.enabled) {
95
+ await connectMethod();
96
+ return;
97
+ }
98
+ // code after is for auto recover
99
+ try {
100
+ await connectMethod();
101
+ }
102
+ catch (e) {
103
+ if (e instanceof RestException_1.default) {
104
+ throw e; // such as InsufficientPermissions
105
+ }
106
+ if (this.options.debugMode) {
107
+ console.debug("Initial connect failed:", e);
108
+ }
109
+ }
110
+ let retriesAttempted = 0;
111
+ let checking = false;
112
+ const check = async () => {
113
+ if (!this.enabled) {
114
+ return;
115
+ }
116
+ if (this.options.autoRecover?.enabled !== true) {
117
+ return;
118
+ }
119
+ if (checking) {
120
+ return;
121
+ }
122
+ checking = true;
123
+ if (this.ws?.readyState !== OPEN && this.ws?.readyState !== CONNECTING) {
124
+ clearInterval(this.intervalHandle);
125
+ try {
126
+ await this.recover();
127
+ retriesAttempted = 0;
128
+ if (this.options.debugMode) {
129
+ console.debug(`Auto recover done, recoveryState: ${this.connectionDetails.recoveryState}`);
130
+ }
131
+ this.eventEmitter.emit(this.connectionDetails.recoveryState === "Successful"
132
+ ? Events.autoRecoverSuccess
133
+ : Events.autoRecoverFailed, this.ws);
332
134
  }
333
- });
334
- });
335
- };
336
- WebSocketExtension.prototype.connect = function (recoverSession) {
337
- return __awaiter(this, void 0, void 0, function () {
338
- return __generator(this, function (_a) {
339
- switch (_a.label) {
340
- case 0:
341
- if (this._connectPromise) {
342
- return [2 /*return*/, this._connectPromise];
343
- }
344
- this._connectPromise = this._connect(recoverSession);
345
- _a.label = 1;
346
- case 1:
347
- _a.trys.push([1, , 3, 4]);
348
- return [4 /*yield*/, this._connectPromise];
349
- case 2:
350
- _a.sent();
351
- return [3 /*break*/, 4];
352
- case 3:
353
- this._connectPromise = undefined;
354
- return [7 /*endfinally*/];
355
- case 4: return [2 /*return*/, undefined];
135
+ catch (e) {
136
+ if (e instanceof RestException_1.default) {
137
+ throw e; // such as InsufficientPermissions
138
+ }
139
+ retriesAttempted += 1;
140
+ if (this.options.debugMode) {
141
+ console.debug("Auto recover error:", e);
142
+ }
143
+ this.eventEmitter.emit(Events.autoRecoverError, e);
356
144
  }
357
- });
358
- });
359
- };
360
- WebSocketExtension.prototype._connect = function () {
361
- return __awaiter(this, arguments, void 0, function (recoverSession) {
362
- var r, wsUri, send, _a, meta, body, event;
363
- var _this = this;
364
- var _b;
365
- if (recoverSession === void 0) { recoverSession = false; }
366
- return __generator(this, function (_c) {
367
- switch (_c.label) {
368
- case 0:
369
- if (!(!this.wsToken || Date.now() > this.wsTokenExpiresAt)) return [3 /*break*/, 2];
370
- return [4 /*yield*/, this.rc.post("/restapi/oauth/wstoken")];
371
- case 1:
372
- r = _c.sent();
373
- this.wsToken = r.data;
374
- // `expires_in` default value is 600 seconds. That's why we `* 0.8`
375
- this.wsTokenExpiresAt = Date.now() + this.wsToken.expires_in * 0.8 * 1000;
376
- _c.label = 2;
377
- case 2:
378
- wsUri = "".concat(this.wsToken.uri, "?access_token=").concat(this.wsToken.ws_access_token);
379
- if (recoverSession && this.wsc) {
380
- wsUri += "&wsc=".concat(this.wsc.token);
381
- }
382
- this.ws = new WS(wsUri);
383
- this.eventEmitter.emit(Events.newWebSocketObject, this.ws);
384
- send = this.ws.send.bind(this.ws);
385
- this.ws.send = function (s) { return __awaiter(_this, void 0, void 0, function () {
386
- var _this = this;
387
- return __generator(this, function (_a) {
388
- switch (_a.label) {
389
- case 0:
390
- if (!(this.ws.readyState === CONNECTING)) return [3 /*break*/, 2];
391
- return [4 /*yield*/, waitFor({
392
- interval: 100,
393
- condition: function () { return _this.ws.readyState !== CONNECTING; },
394
- })];
395
- case 1:
396
- _a.sent();
397
- _a.label = 2;
398
- case 2: return [4 /*yield*/, send(s)];
399
- case 3:
400
- _a.sent();
401
- return [2 /*return*/];
402
- }
403
- });
404
- }); };
405
- if ((_b = this.options.autoRecover) === null || _b === void 0 ? void 0 : _b.enabled) {
406
- this.ws.addEventListener("message", function () {
407
- if (_this.pingServerHandle) {
408
- clearTimeout(_this.pingServerHandle);
409
- }
410
- _this.pingServerHandle = setTimeout(function () { return _this.pingServer(); }, _this.options.autoRecover.pingServerInterval);
411
- });
412
- }
413
- // debug mode to print all WebSocket traffic
414
- if (this.options.debugMode) {
415
- Utils.debugWebSocket(this.ws);
416
- }
417
- // listen for new wsc data
418
- this.ws.addEventListener("message", function (mEvent) {
419
- var event = mEvent;
420
- var _a = Utils.splitWsgData(event.data), meta = _a[0], body = _a[1];
421
- if (meta.wsc &&
422
- (!_this.wsc ||
423
- (meta.type === "ConnectionDetails" && body.recoveryState) ||
424
- _this.wsc.sequence < meta.wsc.sequence)) {
425
- _this.wsc = meta.wsc;
426
- _this.eventEmitter.emit(Events.newWsc, _this.wsc);
427
- }
428
- });
429
- return [4 /*yield*/, Utils.waitForWebSocketMessage(this.ws, function (meta) { return meta.type === "ConnectionDetails" || meta.type === "Error"; })];
430
- case 3:
431
- _a = _c.sent(), meta = _a[0], body = _a[1], event = _a[2];
432
- if (meta.type === "Error") {
433
- throw new ConnectionException(event);
434
- }
435
- this.connectionDetails = body;
436
- // fired when ws connection is ready for creating subscription
437
- this.eventEmitter.emit(Events.connectionReady, this.ws);
438
- if (!(this.subscription && this.subscription.enabled)) return [3 /*break*/, 5];
439
- // because we have a new ws object
440
- this.subscription.setupWsEventListener();
441
- if (!(!recoverSession || this.connectionDetails.recoveryState === "Failed")) return [3 /*break*/, 5];
442
- // create new subscription if don't recover existing one
443
- return [4 /*yield*/, this.subscription.subscribe()];
444
- case 4:
445
- // create new subscription if don't recover existing one
446
- _c.sent();
447
- _c.label = 5;
448
- case 5: return [2 /*return*/];
145
+ this.intervalHandle = setInterval(check, this.options.autoRecover.checkInterval(retriesAttempted));
146
+ }
147
+ checking = false;
148
+ };
149
+ this.intervalHandle = setInterval(check, this.options.autoRecover.checkInterval(retriesAttempted));
150
+ // browser only code start
151
+ if (typeof globalThis.window !== "undefined" &&
152
+ globalThis.window.addEventListener) {
153
+ globalThis.window.addEventListener("offline", () => {
154
+ if (this.pingServerHandle) {
155
+ clearTimeout(this.pingServerHandle);
449
156
  }
157
+ this.ws?.close();
450
158
  });
451
- });
452
- };
453
- // keepInterval means we do not clear the interval
454
- WebSocketExtension.prototype.revoke = function () {
455
- return __awaiter(this, arguments, void 0, function (keepInterval) {
456
- var _a, _b;
457
- if (keepInterval === void 0) { keepInterval = false; }
458
- return __generator(this, function (_c) {
459
- switch (_c.label) {
460
- case 0: return [4 /*yield*/, ((_a = this.subscription) === null || _a === void 0 ? void 0 : _a.revoke())];
461
- case 1:
462
- _c.sent();
463
- this.subscription = undefined;
464
- if (!keepInterval && this.intervalHandle) {
465
- clearInterval(this.intervalHandle);
466
- }
467
- if (this.pingServerHandle) {
468
- clearTimeout(this.pingServerHandle);
469
- }
470
- (_b = this.ws) === null || _b === void 0 ? void 0 : _b.close();
471
- this.wsc = undefined;
472
- this.wsToken = undefined;
473
- this.wsTokenExpiresAt = 0;
474
- this.disable();
475
- return [2 /*return*/];
476
- }
159
+ globalThis.window.addEventListener("online", () => {
160
+ check();
477
161
  });
478
- });
479
- };
480
- WebSocketExtension.prototype.subscribe = function (eventFilters_1, callback_1) {
481
- return __awaiter(this, arguments, void 0, function (eventFilters, callback, cache) {
482
- var subscription;
483
- if (cache === void 0) { cache = undefined; }
484
- return __generator(this, function (_a) {
485
- switch (_a.label) {
486
- case 0:
487
- subscription = new Subscription(this, eventFilters, callback);
488
- if (!(cache === undefined || cache === null)) return [3 /*break*/, 2];
489
- return [4 /*yield*/, subscription.subscribe()];
490
- case 1:
491
- _a.sent();
492
- return [3 /*break*/, 4];
493
- case 2:
494
- subscription.subscriptionInfo = cache;
495
- return [4 /*yield*/, subscription.refresh()];
496
- case 3:
497
- _a.sent();
498
- _a.label = 4;
499
- case 4:
500
- this.subscription = subscription;
501
- return [2 /*return*/, subscription];
162
+ }
163
+ // browser only code end
164
+ }
165
+ async recover() {
166
+ if (this._recoverPromise) {
167
+ return this._recoverPromise;
168
+ }
169
+ this._recoverPromise = this._recover();
170
+ try {
171
+ await this._recoverPromise;
172
+ }
173
+ finally {
174
+ this._recoverPromise = undefined;
175
+ }
176
+ return undefined;
177
+ }
178
+ async _recover() {
179
+ if (this.ws?.readyState === OPEN || this.ws?.readyState === CONNECTING) {
180
+ return;
181
+ }
182
+ if (!this.wsc || !this.wsc.token) {
183
+ await this.connect(false); // connect to WSG but do not recover
184
+ return;
185
+ }
186
+ if (this.recoverTimestamp === undefined) {
187
+ this.recoverTimestamp = Date.now();
188
+ }
189
+ if (this.connectionDetails !== undefined &&
190
+ Date.now() - this.recoverTimestamp >
191
+ this.connectionDetails.recoveryTimeout * 1000) {
192
+ if (this.options.debugMode) {
193
+ console.debug("connect to WSG but do not recover");
194
+ }
195
+ await this.connect(false); // connect to WSG but do not recover
196
+ }
197
+ else {
198
+ if (this.options.debugMode) {
199
+ console.debug("connect to WSG and recover");
200
+ }
201
+ await this.connect(true); // connect to WSG and recover
202
+ }
203
+ this.recoverTimestamp = undefined;
204
+ this.enable();
205
+ }
206
+ async pingServer() {
207
+ if (this.options.autoRecover?.enabled !== true) {
208
+ return;
209
+ }
210
+ if (this.ws?.readyState !== OPEN) {
211
+ return;
212
+ }
213
+ try {
214
+ await this.ws.send(JSON.stringify([
215
+ {
216
+ type: "Heartbeat",
217
+ messageId: uuid(),
218
+ },
219
+ ]));
220
+ }
221
+ catch (e) {
222
+ this.ws.close(); // Explicitly mark WS as closed
223
+ }
224
+ }
225
+ async connect(recoverSession) {
226
+ if (this._connectPromise) {
227
+ return this._connectPromise;
228
+ }
229
+ this._connectPromise = this._connect(recoverSession);
230
+ try {
231
+ await this._connectPromise;
232
+ }
233
+ finally {
234
+ this._connectPromise = undefined;
235
+ }
236
+ return undefined;
237
+ }
238
+ async _connect(recoverSession = false) {
239
+ if (!this.wsToken || Date.now() > this.wsTokenExpiresAt) {
240
+ const r = await this.rc.post("/restapi/oauth/wstoken");
241
+ this.wsToken = r.data;
242
+ // `expires_in` default value is 600 seconds. That's why we `* 0.8`
243
+ this.wsTokenExpiresAt = Date.now() + this.wsToken.expires_in * 0.8 * 1000;
244
+ }
245
+ let wsUri = `${this.wsToken.uri}?access_token=${this.wsToken.ws_access_token}`;
246
+ if (recoverSession && this.wsc) {
247
+ wsUri += `&wsc=${this.wsc.token}`;
248
+ }
249
+ this.ws = new isomorphic_ws_1.default(wsUri);
250
+ this.eventEmitter.emit(Events.newWebSocketObject, this.ws);
251
+ // override send method to wait for connecting
252
+ const send = this.ws.send.bind(this.ws);
253
+ this.ws.send = async (s) => {
254
+ if (this.ws.readyState === CONNECTING) {
255
+ await (0, wait_for_async_1.default)({
256
+ interval: 100,
257
+ condition: () => this.ws.readyState !== CONNECTING,
258
+ });
259
+ }
260
+ await send(s);
261
+ };
262
+ if (this.options.autoRecover?.enabled) {
263
+ this.ws.addEventListener("message", () => {
264
+ if (this.pingServerHandle) {
265
+ clearTimeout(this.pingServerHandle);
502
266
  }
267
+ this.pingServerHandle = setTimeout(() => this.pingServer(), this.options.autoRecover.pingServerInterval);
503
268
  });
269
+ }
270
+ // debug mode to print all WebSocket traffic
271
+ if (this.options.debugMode) {
272
+ utils_js_1.default.debugWebSocket(this.ws);
273
+ }
274
+ // listen for new wsc data
275
+ this.ws.addEventListener("message", (mEvent) => {
276
+ const event = mEvent;
277
+ const [meta, body] = utils_js_1.default.splitWsgData(event.data);
278
+ if (meta.wsc &&
279
+ (!this.wsc ||
280
+ (meta.type === "ConnectionDetails" && body.recoveryState) ||
281
+ this.wsc.sequence < meta.wsc.sequence)) {
282
+ this.wsc = meta.wsc;
283
+ this.eventEmitter.emit(Events.newWsc, this.wsc);
284
+ }
504
285
  });
505
- };
506
- return WebSocketExtension;
507
- }(SdkExtension));
508
- export default WebSocketExtension;
286
+ // get initial ConnectionDetails data
287
+ const [meta, body, event] = await utils_js_1.default.waitForWebSocketMessage(this.ws, (meta) => meta.type === "ConnectionDetails" || meta.type === "Error");
288
+ if (meta.type === "Error") {
289
+ throw new ConnectionException_js_1.default(event);
290
+ }
291
+ this.connectionDetails = body;
292
+ // fired when ws connection is ready for creating subscription
293
+ this.eventEmitter.emit(Events.connectionReady, this.ws);
294
+ // recover the subscription, if it exists and enabled
295
+ if (this.subscription && this.subscription.enabled) {
296
+ // because we have a new ws object
297
+ this.subscription.setupWsEventListener();
298
+ if (!recoverSession || this.connectionDetails.recoveryState === "Failed") {
299
+ // create new subscription if don't recover existing one
300
+ await this.subscription.subscribe();
301
+ }
302
+ }
303
+ }
304
+ // keepInterval means we do not clear the interval
305
+ async revoke(keepInterval = false) {
306
+ await this.subscription?.revoke();
307
+ this.subscription = undefined;
308
+ if (!keepInterval && this.intervalHandle) {
309
+ clearInterval(this.intervalHandle);
310
+ }
311
+ if (this.pingServerHandle) {
312
+ clearTimeout(this.pingServerHandle);
313
+ }
314
+ this.ws?.close();
315
+ this.wsc = undefined;
316
+ this.wsToken = undefined;
317
+ this.wsTokenExpiresAt = 0;
318
+ this.disable();
319
+ }
320
+ async subscribe(eventFilters, callback, cache = undefined) {
321
+ const subscription = new subscription_js_1.default(this, eventFilters, callback);
322
+ if (cache === undefined || cache === null) {
323
+ await subscription.subscribe();
324
+ }
325
+ else {
326
+ subscription.subscriptionInfo = cache;
327
+ await subscription.refresh();
328
+ }
329
+ this.subscription = subscription;
330
+ return subscription;
331
+ }
332
+ }
333
+ exports.default = WebSocketExtension;