@dxos/edge-client 0.6.9 → 0.6.10-main.3cfcc89

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 (34) hide show
  1. package/dist/lib/browser/index.mjs +276 -138
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +263 -129
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/types/src/{client.d.ts → edge-client.d.ts} +21 -16
  8. package/dist/types/src/edge-client.d.ts.map +1 -0
  9. package/dist/types/src/edge-client.test.d.ts +2 -0
  10. package/dist/types/src/edge-client.test.d.ts.map +1 -0
  11. package/dist/types/src/errors.d.ts +4 -0
  12. package/dist/types/src/errors.d.ts.map +1 -0
  13. package/dist/types/src/index.d.ts +1 -1
  14. package/dist/types/src/index.d.ts.map +1 -1
  15. package/dist/types/src/persistent-lifecycle.d.ts +42 -0
  16. package/dist/types/src/persistent-lifecycle.d.ts.map +1 -0
  17. package/dist/types/src/persistent-lifecycle.test.d.ts +2 -0
  18. package/dist/types/src/persistent-lifecycle.test.d.ts.map +1 -0
  19. package/dist/types/src/test-utils.d.ts +11 -0
  20. package/dist/types/src/test-utils.d.ts.map +1 -0
  21. package/dist/types/src/websocket.test.d.ts +2 -0
  22. package/dist/types/src/websocket.test.d.ts.map +1 -0
  23. package/package.json +13 -9
  24. package/src/edge-client.test.ts +50 -0
  25. package/src/edge-client.ts +226 -0
  26. package/src/errors.ts +9 -0
  27. package/src/index.ts +1 -1
  28. package/src/persistent-lifecycle.test.ts +71 -0
  29. package/src/persistent-lifecycle.ts +106 -0
  30. package/src/protocol.test.ts +1 -1
  31. package/src/test-utils.ts +49 -0
  32. package/src/websocket.test.ts +35 -0
  33. package/dist/types/src/client.d.ts.map +0 -1
  34. package/src/client.ts +0 -179
@@ -1,12 +1,12 @@
1
1
  // packages/core/mesh/edge-client/src/index.ts
2
2
  export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
3
3
 
4
- // packages/core/mesh/edge-client/src/client.ts
4
+ // packages/core/mesh/edge-client/src/edge-client.ts
5
5
  import WebSocket from "isomorphic-ws";
6
- import { Trigger } from "@dxos/async";
7
- import { LifecycleState, Resource } from "@dxos/context";
6
+ import { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from "@dxos/async";
7
+ import { Context, LifecycleState as LifecycleState2, Resource as Resource2 } from "@dxos/context";
8
8
  import { invariant as invariant2 } from "@dxos/invariant";
9
- import { log } from "@dxos/log";
9
+ import { log as log2 } from "@dxos/log";
10
10
  import { buf as buf2 } from "@dxos/protocols/buf";
11
11
  import { MessageSchema as MessageSchema2 } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
12
12
 
@@ -118,19 +118,131 @@ var protocol = new Protocol([
118
118
  AnySchema
119
119
  ]);
120
120
 
121
- // packages/core/mesh/edge-client/src/client.ts
122
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/client.ts";
123
- var DEFAULT_TIMEOUT = 5e3;
124
- var EdgeClient = class extends Resource {
125
- constructor(_identityKey, _deviceKey, _config) {
121
+ // packages/core/mesh/edge-client/src/errors.ts
122
+ var WebsocketClosedError = class extends Error {
123
+ constructor() {
124
+ super("WebSocket connection closed");
125
+ }
126
+ };
127
+
128
+ // packages/core/mesh/edge-client/src/persistent-lifecycle.ts
129
+ import { DeferredTask, sleep, synchronized } from "@dxos/async";
130
+ import { cancelWithContext, LifecycleState, Resource } from "@dxos/context";
131
+ import { warnAfterTimeout } from "@dxos/debug";
132
+ import { log } from "@dxos/log";
133
+ function _ts_decorate(decorators, target, key, desc) {
134
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
135
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
136
+ r = Reflect.decorate(decorators, target, key, desc);
137
+ else
138
+ for (var i = decorators.length - 1; i >= 0; i--)
139
+ if (d = decorators[i])
140
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
141
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
142
+ }
143
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
144
+ var INIT_RESTART_DELAY = 100;
145
+ var DEFAULT_MAX_RESTART_DELAY = 5e3;
146
+ var PersistentLifecycle = class extends Resource {
147
+ constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }) {
148
+ super();
149
+ this._restartTask = void 0;
150
+ this._restartAfter = 0;
151
+ this._start = start;
152
+ this._stop = stop;
153
+ this._onRestart = onRestart;
154
+ this._maxRestartDelay = maxRestartDelay;
155
+ }
156
+ async _open() {
157
+ this._restartTask = new DeferredTask(this._ctx, async () => {
158
+ try {
159
+ await this._restart();
160
+ } catch (err) {
161
+ log.warn("Restart failed", {
162
+ err
163
+ }, {
164
+ F: __dxlog_file2,
165
+ L: 64,
166
+ S: this,
167
+ C: (f, a) => f(...a)
168
+ });
169
+ this._restartTask?.schedule();
170
+ }
171
+ });
172
+ await this._start().catch((err) => {
173
+ log.warn("Start failed", {
174
+ err
175
+ }, {
176
+ F: __dxlog_file2,
177
+ L: 69,
178
+ S: this,
179
+ C: (f, a) => f(...a)
180
+ });
181
+ this._restartTask?.schedule();
182
+ });
183
+ }
184
+ async _close() {
185
+ await this._restartTask?.join();
186
+ await this._stop();
187
+ this._restartTask = void 0;
188
+ }
189
+ async _restart() {
190
+ log(`restarting in ${this._restartAfter}ms`, {
191
+ state: this._lifecycleState
192
+ }, {
193
+ F: __dxlog_file2,
194
+ L: 81,
195
+ S: this,
196
+ C: (f, a) => f(...a)
197
+ });
198
+ await this._stop();
199
+ if (this._lifecycleState !== LifecycleState.OPEN) {
200
+ return;
201
+ }
202
+ await cancelWithContext(this._ctx, sleep(this._restartAfter));
203
+ this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);
204
+ await warnAfterTimeout(5e3, "Connection establishment takes too long", () => this._start());
205
+ this._restartAfter = 0;
206
+ await this._onRestart?.();
207
+ }
208
+ /**
209
+ * Scheduling restart should be done from outside.
210
+ */
211
+ scheduleRestart() {
212
+ if (this._lifecycleState !== LifecycleState.OPEN) {
213
+ return;
214
+ }
215
+ this._restartTask.schedule();
216
+ }
217
+ };
218
+ _ts_decorate([
219
+ synchronized
220
+ ], PersistentLifecycle.prototype, "_open", null);
221
+ _ts_decorate([
222
+ synchronized
223
+ ], PersistentLifecycle.prototype, "scheduleRestart", null);
224
+
225
+ // packages/core/mesh/edge-client/src/edge-client.ts
226
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
227
+ var DEFAULT_TIMEOUT = 1e4;
228
+ var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
229
+ var EdgeClient = class extends Resource2 {
230
+ constructor(_identityKey, _peerKey, _config) {
126
231
  super();
127
232
  this._identityKey = _identityKey;
128
- this._deviceKey = _deviceKey;
233
+ this._peerKey = _peerKey;
129
234
  this._config = _config;
235
+ this.reconnect = new Event();
236
+ this._persistentLifecycle = new PersistentLifecycle({
237
+ start: async () => this._openWebSocket(),
238
+ stop: async () => this._closeWebSocket(),
239
+ onRestart: async () => this.reconnect.emit()
240
+ });
130
241
  this._listeners = /* @__PURE__ */ new Set();
131
- this._reconnect = void 0;
132
242
  this._ready = new Trigger();
133
243
  this._ws = void 0;
244
+ this._keepaliveCtx = void 0;
245
+ this._heartBeatContext = void 0;
134
246
  this._protocol = this._config.protocol ?? protocol;
135
247
  }
136
248
  // TODO(burdon): Attach logging.
@@ -138,29 +250,22 @@ var EdgeClient = class extends Resource {
138
250
  return {
139
251
  open: this.isOpen,
140
252
  identity: this._identityKey,
141
- device: this._deviceKey
253
+ device: this._peerKey
142
254
  };
143
255
  }
144
256
  get identityKey() {
145
257
  return this._identityKey;
146
258
  }
147
- get deviceKey() {
148
- return this._deviceKey;
259
+ get peerKey() {
260
+ return this._peerKey;
149
261
  }
150
262
  get isOpen() {
151
- return this._lifecycleState === LifecycleState.OPEN;
263
+ return this._lifecycleState === LifecycleState2.OPEN;
152
264
  }
153
- setIdentity({ deviceKey, identityKey }) {
154
- this._deviceKey = deviceKey;
265
+ setIdentity({ peerKey, identityKey }) {
266
+ this._peerKey = peerKey;
155
267
  this._identityKey = identityKey;
156
- this._reconnect = this._closeWebSocket().then(async () => {
157
- await this._openWebSocket();
158
- }).catch((err) => log.catch(err, void 0, {
159
- F: __dxlog_file2,
160
- L: 87,
161
- S: this,
162
- C: (f, a) => f(...a)
163
- }));
268
+ this._persistentLifecycle.scheduleRestart();
164
269
  }
165
270
  addListener(listener) {
166
271
  this._listeners.add(listener);
@@ -170,171 +275,204 @@ var EdgeClient = class extends Resource {
170
275
  * Open connection to messaging service.
171
276
  */
172
277
  async _open() {
173
- await this._reconnect;
174
- if (this._ws) {
175
- return;
176
- }
177
- invariant2(this._deviceKey && this._identityKey, void 0, {
178
- F: __dxlog_file2,
179
- L: 103,
180
- S: this,
181
- A: [
182
- "this._deviceKey && this._identityKey",
183
- ""
184
- ]
185
- });
186
- log.info("opening...", {
278
+ log2("opening...", {
187
279
  info: this.info
188
280
  }, {
189
- F: __dxlog_file2,
190
- L: 104,
281
+ F: __dxlog_file3,
282
+ L: 105,
191
283
  S: this,
192
284
  C: (f, a) => f(...a)
193
285
  });
194
- await this._openWebSocket();
195
- log.info("opened", {
196
- info: this.info
197
- }, {
198
- F: __dxlog_file2,
199
- L: 108,
200
- S: this,
201
- C: (f, a) => f(...a)
286
+ this._persistentLifecycle.open().catch((err) => {
287
+ log2.warn("Error while opening connection", {
288
+ err
289
+ }, {
290
+ F: __dxlog_file3,
291
+ L: 107,
292
+ S: this,
293
+ C: (f, a) => f(...a)
294
+ });
202
295
  });
203
296
  }
204
297
  /**
205
298
  * Close connection and free resources.
206
299
  */
207
300
  async _close() {
208
- log("closing...", {
209
- deviceKey: this._deviceKey
301
+ log2("closing...", {
302
+ peerKey: this._peerKey
210
303
  }, {
211
- F: __dxlog_file2,
304
+ F: __dxlog_file3,
212
305
  L: 115,
213
306
  S: this,
214
307
  C: (f, a) => f(...a)
215
308
  });
216
- await this._reconnect;
217
- await this._closeWebSocket();
218
- log("closed", {
219
- deviceKey: this._deviceKey
220
- }, {
221
- F: __dxlog_file2,
222
- L: 118,
223
- S: this,
224
- C: (f, a) => f(...a)
225
- });
309
+ await this._persistentLifecycle.close();
226
310
  }
227
311
  async _openWebSocket() {
228
- const url = new URL(`/ws/${this._identityKey.toHex()}/${this._deviceKey.toHex()}`, this._config.socketEndpoint);
312
+ const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);
229
313
  this._ws = new WebSocket(url);
230
- Object.assign(this._ws, {
231
- onopen: () => {
232
- log("opened", this.info, {
233
- F: __dxlog_file2,
234
- L: 126,
235
- S: this,
236
- C: (f, a) => f(...a)
237
- });
238
- this._ready.wake();
239
- },
240
- onclose: () => {
241
- log("closed", this.info, {
242
- F: __dxlog_file2,
243
- L: 131,
244
- S: this,
245
- C: (f, a) => f(...a)
246
- });
247
- },
248
- onerror: (event) => {
249
- log.catch(event.error, this.info, {
250
- F: __dxlog_file2,
251
- L: 135,
252
- S: this,
253
- C: (f, a) => f(...a)
254
- });
255
- this._ready.throw(event.error);
256
- },
257
- /**
258
- * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data
259
- */
260
- onmessage: async (event) => {
261
- const data = await toUint8Array(event.data);
262
- const message = buf2.fromBinary(MessageSchema2, data);
263
- log("received", {
264
- deviceKey: this._deviceKey,
265
- payload: protocol.getPayloadType(message)
266
- }, {
267
- F: __dxlog_file2,
268
- L: 145,
269
- S: this,
270
- C: (f, a) => f(...a)
271
- });
272
- if (message) {
273
- for (const listener of this._listeners) {
274
- try {
275
- await listener(message);
276
- } catch (err) {
277
- log.error("processing", {
278
- err,
279
- payload: protocol.getPayloadType(message)
280
- }, {
281
- F: __dxlog_file2,
282
- L: 151,
283
- S: this,
284
- C: (f, a) => f(...a)
285
- });
286
- }
314
+ this._ws.onopen = () => {
315
+ log2("opened", this.info, {
316
+ F: __dxlog_file3,
317
+ L: 124,
318
+ S: this,
319
+ C: (f, a) => f(...a)
320
+ });
321
+ this._ready.wake();
322
+ };
323
+ this._ws.onclose = () => {
324
+ log2("closed", this.info, {
325
+ F: __dxlog_file3,
326
+ L: 128,
327
+ S: this,
328
+ C: (f, a) => f(...a)
329
+ });
330
+ this._persistentLifecycle.scheduleRestart();
331
+ };
332
+ this._ws.onerror = (event) => {
333
+ log2.warn("EdgeClient socket error", {
334
+ error: event.error,
335
+ info: event.message
336
+ }, {
337
+ F: __dxlog_file3,
338
+ L: 132,
339
+ S: this,
340
+ C: (f, a) => f(...a)
341
+ });
342
+ this._persistentLifecycle.scheduleRestart();
343
+ };
344
+ this._ws.onmessage = async (event) => {
345
+ if (event.data === "__pong__") {
346
+ this._onHeartbeat();
347
+ return;
348
+ }
349
+ const data = await toUint8Array(event.data);
350
+ const message = buf2.fromBinary(MessageSchema2, data);
351
+ log2("received", {
352
+ peerKey: this._peerKey,
353
+ payload: protocol.getPayloadType(message)
354
+ }, {
355
+ F: __dxlog_file3,
356
+ L: 145,
357
+ S: this,
358
+ C: (f, a) => f(...a)
359
+ });
360
+ if (message) {
361
+ for (const listener of this._listeners) {
362
+ try {
363
+ await listener(message);
364
+ } catch (err) {
365
+ log2.error("processing", {
366
+ err,
367
+ payload: protocol.getPayloadType(message)
368
+ }, {
369
+ F: __dxlog_file3,
370
+ L: 151,
371
+ S: this,
372
+ C: (f, a) => f(...a)
373
+ });
287
374
  }
288
375
  }
289
376
  }
290
- });
377
+ };
291
378
  await this._ready.wait({
292
379
  timeout: this._config.timeout ?? DEFAULT_TIMEOUT
293
380
  });
381
+ this._keepaliveCtx = new Context(void 0, {
382
+ F: __dxlog_file3,
383
+ L: 158
384
+ });
385
+ scheduleTaskInterval(this._keepaliveCtx, async () => {
386
+ this._ws?.send("__ping__");
387
+ }, SIGNAL_KEEPALIVE_INTERVAL);
388
+ this._ws.send("__ping__");
389
+ this._onHeartbeat();
294
390
  }
295
391
  async _closeWebSocket() {
296
- this._ready.reset();
297
- this._ws.close();
298
- this._ws = void 0;
392
+ if (!this._ws) {
393
+ return;
394
+ }
395
+ try {
396
+ this._ready.throw(new WebsocketClosedError());
397
+ this._ready.reset();
398
+ void this._keepaliveCtx?.dispose();
399
+ this._keepaliveCtx = void 0;
400
+ void this._heartBeatContext?.dispose();
401
+ this._heartBeatContext = void 0;
402
+ this._ws.onopen = () => {
403
+ };
404
+ this._ws.onclose = () => {
405
+ };
406
+ this._ws.onerror = () => {
407
+ };
408
+ this._ws.close();
409
+ this._ws = void 0;
410
+ } catch (err) {
411
+ if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
412
+ return;
413
+ }
414
+ log2.warn("Error closing websocket", {
415
+ err
416
+ }, {
417
+ F: __dxlog_file3,
418
+ L: 194,
419
+ S: this,
420
+ C: (f, a) => f(...a)
421
+ });
422
+ }
299
423
  }
300
424
  /**
301
425
  * Send message.
302
426
  * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.
303
427
  */
304
- // TODO(burdon): Implement ACK?
305
428
  async send(message) {
306
- await this._ready.wait({
307
- timeout: this._config.timeout ?? DEFAULT_TIMEOUT
308
- });
429
+ if (this._ready.state !== TriggerState.RESOLVED) {
430
+ await this._ready.wait({
431
+ timeout: this._config.timeout ?? DEFAULT_TIMEOUT
432
+ });
433
+ }
309
434
  invariant2(this._ws, void 0, {
310
- F: __dxlog_file2,
311
- L: 174,
435
+ F: __dxlog_file3,
436
+ L: 206,
312
437
  S: this,
313
438
  A: [
314
439
  "this._ws",
315
440
  ""
316
441
  ]
317
442
  });
318
- invariant2(!message.source || message.source.peerKey === this._deviceKey.toHex(), void 0, {
319
- F: __dxlog_file2,
320
- L: 175,
443
+ invariant2(!message.source || message.source.peerKey === this._peerKey, void 0, {
444
+ F: __dxlog_file3,
445
+ L: 207,
321
446
  S: this,
322
447
  A: [
323
- "!message.source || message.source.peerKey === this._deviceKey.toHex()",
448
+ "!message.source || message.source.peerKey === this._peerKey",
324
449
  ""
325
450
  ]
326
451
  });
327
- log("sending...", {
328
- deviceKey: this._deviceKey,
452
+ log2("sending...", {
453
+ peerKey: this._peerKey,
329
454
  payload: protocol.getPayloadType(message)
330
455
  }, {
331
- F: __dxlog_file2,
332
- L: 176,
456
+ F: __dxlog_file3,
457
+ L: 208,
333
458
  S: this,
334
459
  C: (f, a) => f(...a)
335
460
  });
336
461
  this._ws.send(buf2.toBinary(MessageSchema2, message));
337
462
  }
463
+ _onHeartbeat() {
464
+ if (this._lifecycleState !== LifecycleState2.OPEN) {
465
+ return;
466
+ }
467
+ void this._heartBeatContext?.dispose();
468
+ this._heartBeatContext = new Context(void 0, {
469
+ F: __dxlog_file3,
470
+ L: 217
471
+ });
472
+ scheduleTask(this._heartBeatContext, () => {
473
+ this._persistentLifecycle.scheduleRestart();
474
+ }, 2 * SIGNAL_KEEPALIVE_INTERVAL);
475
+ }
338
476
  };
339
477
  export {
340
478
  EdgeClient,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../src/index.ts", "../../../src/client.ts", "../../../src/defs.ts", "../../../src/protocol.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './client';\nexport * from './defs';\nexport * from './protocol';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger } from '@dxos/async';\nimport { LifecycleState, Resource, type Lifecycle } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { buf } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { protocol } from './defs';\nimport { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\nexport interface EdgeConnection extends Required<Lifecycle> {\n get info(): any;\n get identityKey(): PublicKey;\n get deviceKey(): PublicKey;\n get isOpen(): boolean;\n setIdentity(params: { deviceKey: PublicKey; identityKey: PublicKey }): void;\n addListener(listener: MessageListener): () => void;\n send(message: Message): Promise<void>;\n}\n\nexport type MessengerConfig = {\n socketEndpoint: string;\n timeout?: number;\n protocol?: Protocol;\n};\n\n/**\n * Messenger client.\n */\n// TODO(dmaretskyi): Rename EdgeClient.\n// TODO(mykola): Handle reconnections.\nexport class EdgeClient extends Resource implements EdgeConnection {\n private readonly _listeners = new Set<MessageListener>();\n private _reconnect?: Promise<void> = undefined;\n private readonly _protocol: Protocol;\n private _ready = new Trigger();\n private _ws?: WebSocket = undefined;\n\n constructor(\n private _identityKey: PublicKey,\n private _deviceKey: PublicKey,\n private readonly _config: MessengerConfig,\n ) {\n super();\n this._protocol = this._config.protocol ?? protocol;\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identityKey,\n device: this._deviceKey,\n };\n }\n\n get identityKey() {\n return this._identityKey;\n }\n\n get deviceKey() {\n return this._deviceKey;\n }\n\n public get isOpen() {\n return this._lifecycleState === LifecycleState.OPEN;\n }\n\n setIdentity({ deviceKey, identityKey }: { deviceKey: PublicKey; identityKey: PublicKey }) {\n this._deviceKey = deviceKey;\n this._identityKey = identityKey;\n this._reconnect = this._closeWebSocket()\n .then(async () => {\n await this._openWebSocket();\n })\n .catch((err) => log.catch(err));\n }\n\n public addListener(listener: MessageListener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /**\n * Open connection to messaging service.\n */\n protected override async _open() {\n await this._reconnect;\n if (this._ws) {\n return;\n }\n invariant(this._deviceKey && this._identityKey);\n log.info('opening...', { info: this.info });\n\n // TODO: handle reconnects\n await this._openWebSocket();\n log.info('opened', { info: this.info });\n }\n\n /**\n * Close connection and free resources.\n */\n protected override async _close() {\n log('closing...', { deviceKey: this._deviceKey });\n await this._reconnect;\n await this._closeWebSocket();\n log('closed', { deviceKey: this._deviceKey });\n }\n\n private async _openWebSocket() {\n const url = new URL(`/ws/${this._identityKey.toHex()}/${this._deviceKey.toHex()}`, this._config.socketEndpoint);\n this._ws = new WebSocket(url);\n Object.assign<WebSocket, Partial<WebSocket>>(this._ws, {\n onopen: () => {\n log('opened', this.info);\n this._ready.wake();\n },\n\n onclose: () => {\n log('closed', this.info);\n },\n\n onerror: (event) => {\n log.catch(event.error, this.info);\n this._ready.throw(event.error);\n },\n\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n onmessage: async (event) => {\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { deviceKey: this._deviceKey, payload: protocol.getPayloadType(message) });\n if (message) {\n for (const listener of this._listeners) {\n try {\n await listener(message);\n } catch (err) {\n log.error('processing', { err, payload: protocol.getPayloadType(message) });\n }\n }\n }\n },\n });\n\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n }\n\n private async _closeWebSocket() {\n this._ready.reset();\n this._ws!.close();\n this._ws = undefined;\n }\n\n /**\n * Send message.\n * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.\n */\n // TODO(burdon): Implement ACK?\n public async send(message: Message): Promise<void> {\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n invariant(this._ws);\n invariant(!message.source || message.source.peerKey === this._deviceKey.toHex());\n log('sending...', { deviceKey: this._deviceKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AnySchema } from '@bufbuild/protobuf/wkt';\n\nimport { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { Protocol } from './protocol';\n\nexport const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema, AnySchema]);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf, bufWkt } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema, type Peer as PeerProto } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { bufferToArray } from '@dxos/util';\n\nexport type PeerData = Partial<PeerProto>;\n\nexport const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;\n\n/**\n * NOTE: The type registry should be extended with all message types.\n */\nexport class Protocol {\n private readonly _typeRegistry: buf.Registry;\n\n constructor(types: buf.DescMessage[]) {\n this._typeRegistry = buf.createRegistry(...types);\n }\n\n get typeRegistry(): buf.Registry {\n return this._typeRegistry;\n }\n\n toJson(message: Message): any {\n try {\n return buf.toJson(MessageSchema, message, { registry: this.typeRegistry });\n } catch (err) {\n return { type: this.getPayloadType(message) };\n }\n }\n\n /**\n * Return the payload with the given type.\n */\n getPayload<Desc extends buf.DescMessage>(message: Message, type: Desc): buf.MessageShape<Desc> {\n invariant(message.payload);\n const payloadTypename = this.getPayloadType(message);\n if (type && type.typeName !== payloadTypename) {\n throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);\n }\n\n invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`);\n const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry) as buf.MessageShape<Desc>;\n invariant(payload, `Empty payload: ${payloadTypename}}`);\n return payload;\n }\n\n /**\n * Get the payload type.\n */\n getPayloadType(message: Message): string | undefined {\n if (!message.payload) {\n return undefined;\n }\n\n const [, type] = message.payload.typeUrl.split('/');\n return type;\n }\n\n /**\n * Create a packed message.\n */\n createMessage<Desc extends buf.DescMessage>(\n type: Desc,\n {\n source,\n target,\n payload,\n serviceId,\n }: {\n source?: PeerData;\n target?: PeerData[];\n payload?: buf.MessageInitShape<Desc>;\n serviceId?: string;\n },\n ) {\n return buf.create(MessageSchema, {\n timestamp: new Date().toISOString(),\n source,\n target,\n serviceId,\n payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : undefined,\n });\n }\n}\n\n/**\n * Convert websocket data to Uint8Array.\n */\nexport const toUint8Array = async (data: any): Promise<Uint8Array> => {\n // Node.\n if (data instanceof Buffer) {\n return bufferToArray(data);\n }\n\n // Browser.\n if (data instanceof Blob) {\n return new Uint8Array(await (data as Blob).arrayBuffer());\n }\n\n throw new Error(`Unexpected datatype: ${data}`);\n};\n"],
5
- "mappings": "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",
6
- "names": ["WebSocket", "Trigger", "LifecycleState", "Resource", "invariant", "log", "buf", "MessageSchema", "AnySchema", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "invariant", "buf", "bufWkt", "MessageSchema", "bufferToArray", "getTypename", "typeName", "Protocol", "constructor", "types", "_typeRegistry", "createRegistry", "typeRegistry", "toJson", "message", "registry", "err", "type", "getPayloadType", "getPayload", "payload", "payloadTypename", "Error", "anyIs", "anyUnpack", "undefined", "typeUrl", "split", "createMessage", "source", "target", "serviceId", "create", "timestamp", "Date", "toISOString", "anyPack", "toUint8Array", "data", "Buffer", "Blob", "Uint8Array", "arrayBuffer", "protocol", "Protocol", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "AnySchema", "DEFAULT_TIMEOUT", "EdgeClient", "Resource", "constructor", "_identityKey", "_deviceKey", "_config", "_listeners", "Set", "_reconnect", "undefined", "_ready", "Trigger", "_ws", "_protocol", "protocol", "info", "open", "isOpen", "identity", "device", "identityKey", "deviceKey", "_lifecycleState", "LifecycleState", "OPEN", "setIdentity", "_closeWebSocket", "then", "_openWebSocket", "catch", "err", "log", "addListener", "listener", "add", "delete", "_open", "invariant", "_close", "url", "URL", "toHex", "socketEndpoint", "WebSocket", "Object", "assign", "onopen", "wake", "onclose", "onerror", "event", "error", "throw", "onmessage", "data", "toUint8Array", "message", "buf", "fromBinary", "MessageSchema", "payload", "getPayloadType", "wait", "timeout", "reset", "close", "send", "source", "peerKey", "toBinary"]
3
+ "sources": ["../../../src/index.ts", "../../../src/edge-client.ts", "../../../src/defs.ts", "../../../src/protocol.ts", "../../../src/errors.ts", "../../../src/persistent-lifecycle.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nexport * from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nexport * from './edge-client';\nexport * from './defs';\nexport * from './protocol';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport WebSocket from 'isomorphic-ws';\n\nimport { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from '@dxos/async';\nimport { Context, LifecycleState, Resource, type Lifecycle } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport { buf } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { protocol } from './defs';\nimport { WebsocketClosedError } from './errors';\nimport { PersistentLifecycle } from './persistent-lifecycle';\nimport { type Protocol, toUint8Array } from './protocol';\n\nconst DEFAULT_TIMEOUT = 10_000;\nconst SIGNAL_KEEPALIVE_INTERVAL = 5_000;\n\nexport type MessageListener = (message: Message) => void | Promise<void>;\n\nexport interface EdgeConnection extends Required<Lifecycle> {\n reconnect: Event;\n\n get info(): any;\n get identityKey(): string;\n get peerKey(): string;\n get isOpen(): boolean;\n setIdentity(params: { peerKey: string; identityKey: string }): void;\n addListener(listener: MessageListener): () => void;\n send(message: Message): Promise<void>;\n}\n\nexport type MessengerConfig = {\n socketEndpoint: string;\n timeout?: number;\n protocol?: Protocol;\n};\n\n/**\n * Messenger client.\n */\nexport class EdgeClient extends Resource implements EdgeConnection {\n public reconnect = new Event();\n private readonly _persistentLifecycle = new PersistentLifecycle({\n start: async () => this._openWebSocket(),\n stop: async () => this._closeWebSocket(),\n onRestart: async () => this.reconnect.emit(),\n });\n\n private readonly _listeners = new Set<MessageListener>();\n private readonly _protocol: Protocol;\n private _ready = new Trigger();\n private _ws?: WebSocket = undefined;\n private _keepaliveCtx?: Context = undefined;\n private _heartBeatContext?: Context = undefined;\n\n constructor(\n private _identityKey: string,\n private _peerKey: string,\n private readonly _config: MessengerConfig,\n ) {\n super();\n this._protocol = this._config.protocol ?? protocol;\n }\n\n // TODO(burdon): Attach logging.\n public get info() {\n return {\n open: this.isOpen,\n identity: this._identityKey,\n device: this._peerKey,\n };\n }\n\n get identityKey() {\n return this._identityKey;\n }\n\n get peerKey() {\n return this._peerKey;\n }\n\n public get isOpen() {\n return this._lifecycleState === LifecycleState.OPEN;\n }\n\n setIdentity({ peerKey, identityKey }: { peerKey: string; identityKey: string }) {\n this._peerKey = peerKey;\n this._identityKey = identityKey;\n this._persistentLifecycle.scheduleRestart();\n }\n\n public addListener(listener: MessageListener): () => void {\n this._listeners.add(listener);\n return () => this._listeners.delete(listener);\n }\n\n /**\n * Open connection to messaging service.\n */\n protected override async _open() {\n log('opening...', { info: this.info });\n this._persistentLifecycle.open().catch((err) => {\n log.warn('Error while opening connection', { err });\n });\n }\n\n /**\n * Close connection and free resources.\n */\n protected override async _close() {\n log('closing...', { peerKey: this._peerKey });\n await this._persistentLifecycle.close();\n }\n\n private async _openWebSocket() {\n const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);\n this._ws = new WebSocket(url);\n\n this._ws.onopen = () => {\n log('opened', this.info);\n this._ready.wake();\n };\n this._ws.onclose = () => {\n log('closed', this.info);\n this._persistentLifecycle.scheduleRestart();\n };\n this._ws.onerror = (event) => {\n log.warn('EdgeClient socket error', { error: event.error, info: event.message });\n this._persistentLifecycle.scheduleRestart();\n };\n /**\n * https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/data\n */\n this._ws.onmessage = async (event) => {\n if (event.data === '__pong__') {\n this._onHeartbeat();\n return;\n }\n const data = await toUint8Array(event.data);\n const message = buf.fromBinary(MessageSchema, data);\n log('received', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });\n if (message) {\n for (const listener of this._listeners) {\n try {\n await listener(message);\n } catch (err) {\n log.error('processing', { err, payload: protocol.getPayloadType(message) });\n }\n }\n }\n };\n\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n this._keepaliveCtx = new Context();\n scheduleTaskInterval(\n this._keepaliveCtx,\n async () => {\n // TODO(mykola): use RFC6455 ping/pong once implemented in the browser?\n // Cloudflare's worker responds to this `without interrupting hibernation`. https://developers.cloudflare.com/durable-objects/api/websockets/#setwebsocketautoresponse\n this._ws?.send('__ping__');\n },\n SIGNAL_KEEPALIVE_INTERVAL,\n );\n this._ws.send('__ping__');\n this._onHeartbeat();\n }\n\n private async _closeWebSocket() {\n if (!this._ws) {\n return;\n }\n try {\n this._ready.throw(new WebsocketClosedError());\n this._ready.reset();\n void this._keepaliveCtx?.dispose();\n this._keepaliveCtx = undefined;\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = undefined;\n\n // NOTE: Remove event handlers to avoid scheduling restart.\n this._ws.onopen = () => {};\n this._ws.onclose = () => {};\n this._ws.onerror = () => {};\n this._ws.close();\n this._ws = undefined;\n } catch (err) {\n if (err instanceof Error && err.message.includes('WebSocket is closed before the connection is established.')) {\n return;\n }\n log.warn('Error closing websocket', { err });\n }\n }\n\n /**\n * Send message.\n * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.\n */\n public async send(message: Message): Promise<void> {\n if (this._ready.state !== TriggerState.RESOLVED) {\n await this._ready.wait({ timeout: this._config.timeout ?? DEFAULT_TIMEOUT });\n }\n invariant(this._ws);\n invariant(!message.source || message.source.peerKey === this._peerKey);\n log('sending...', { peerKey: this._peerKey, payload: protocol.getPayloadType(message) });\n this._ws.send(buf.toBinary(MessageSchema, message));\n }\n\n private _onHeartbeat() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n void this._heartBeatContext?.dispose();\n this._heartBeatContext = new Context();\n scheduleTask(\n this._heartBeatContext,\n () => {\n this._persistentLifecycle.scheduleRestart();\n },\n 2 * SIGNAL_KEEPALIVE_INTERVAL,\n );\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { AnySchema } from '@bufbuild/protobuf/wkt';\n\nimport { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\n\nimport { Protocol } from './protocol';\n\nexport const protocol = new Protocol([SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema, AnySchema]);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\nimport { buf, bufWkt } from '@dxos/protocols/buf';\nimport { type Message, MessageSchema, type Peer as PeerProto } from '@dxos/protocols/buf/dxos/edge/messenger_pb';\nimport { bufferToArray } from '@dxos/util';\n\nexport type PeerData = Partial<PeerProto>;\n\nexport const getTypename = (typeName: string) => `type.googleapis.com/${typeName}`;\n\n/**\n * NOTE: The type registry should be extended with all message types.\n */\nexport class Protocol {\n private readonly _typeRegistry: buf.Registry;\n\n constructor(types: buf.DescMessage[]) {\n this._typeRegistry = buf.createRegistry(...types);\n }\n\n get typeRegistry(): buf.Registry {\n return this._typeRegistry;\n }\n\n toJson(message: Message): any {\n try {\n return buf.toJson(MessageSchema, message, { registry: this.typeRegistry });\n } catch (err) {\n return { type: this.getPayloadType(message) };\n }\n }\n\n /**\n * Return the payload with the given type.\n */\n getPayload<Desc extends buf.DescMessage>(message: Message, type: Desc): buf.MessageShape<Desc> {\n invariant(message.payload);\n const payloadTypename = this.getPayloadType(message);\n if (type && type.typeName !== payloadTypename) {\n throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);\n }\n\n invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`);\n const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry) as buf.MessageShape<Desc>;\n invariant(payload, `Empty payload: ${payloadTypename}}`);\n return payload;\n }\n\n /**\n * Get the payload type.\n */\n getPayloadType(message: Message): string | undefined {\n if (!message.payload) {\n return undefined;\n }\n\n const [, type] = message.payload.typeUrl.split('/');\n return type;\n }\n\n /**\n * Create a packed message.\n */\n createMessage<Desc extends buf.DescMessage>(\n type: Desc,\n {\n source,\n target,\n payload,\n serviceId,\n }: {\n source?: PeerData;\n target?: PeerData[];\n payload?: buf.MessageInitShape<Desc>;\n serviceId?: string;\n },\n ) {\n return buf.create(MessageSchema, {\n timestamp: new Date().toISOString(),\n source,\n target,\n serviceId,\n payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : undefined,\n });\n }\n}\n\n/**\n * Convert websocket data to Uint8Array.\n */\nexport const toUint8Array = async (data: any): Promise<Uint8Array> => {\n // Node.\n if (data instanceof Buffer) {\n return bufferToArray(data);\n }\n\n // Browser.\n if (data instanceof Blob) {\n return new Uint8Array(await (data as Blob).arrayBuffer());\n }\n\n throw new Error(`Unexpected datatype: ${data}`);\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nexport class WebsocketClosedError extends Error {\n constructor() {\n super('WebSocket connection closed');\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { DeferredTask, sleep, synchronized } from '@dxos/async';\nimport { cancelWithContext, LifecycleState, Resource } from '@dxos/context';\nimport { warnAfterTimeout } from '@dxos/debug';\nimport { log } from '@dxos/log';\n\nconst INIT_RESTART_DELAY = 100;\nconst DEFAULT_MAX_RESTART_DELAY = 5000;\n\nexport type PersistentLifecycleParams = {\n /**\n * Create connection.\n * If promise resolves successfully, connection is considered established.\n */\n start: () => Promise<void>;\n\n /**\n * Reset connection to initial state.\n */\n stop: () => Promise<void>;\n\n /**\n * Called after successful start.\n */\n onRestart?: () => Promise<void>;\n\n /**\n * Maximum delay between restartion attempts.\n * Default: 5000ms\n */\n maxRestartDelay?: number;\n};\n\n/**\n * Handles restarts (e.g. persists connection).\n * Restarts are scheduled with exponential backoff.\n */\nexport class PersistentLifecycle extends Resource {\n private readonly _start: () => Promise<void>;\n private readonly _stop: () => Promise<void>;\n private readonly _onRestart?: () => Promise<void>;\n private readonly _maxRestartDelay: number;\n\n private _restartTask?: DeferredTask = undefined;\n private _restartAfter = 0;\n\n constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }: PersistentLifecycleParams) {\n super();\n this._start = start;\n this._stop = stop;\n this._onRestart = onRestart;\n this._maxRestartDelay = maxRestartDelay;\n }\n\n @synchronized\n protected override async _open() {\n this._restartTask = new DeferredTask(this._ctx, async () => {\n try {\n await this._restart();\n } catch (err) {\n log.warn('Restart failed', { err });\n this._restartTask?.schedule();\n }\n });\n await this._start().catch((err) => {\n log.warn('Start failed', { err });\n this._restartTask?.schedule();\n });\n }\n\n protected override async _close() {\n await this._restartTask?.join();\n await this._stop();\n this._restartTask = undefined;\n }\n\n private async _restart() {\n log(`restarting in ${this._restartAfter}ms`, { state: this._lifecycleState });\n await this._stop();\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n await cancelWithContext(this._ctx!, sleep(this._restartAfter));\n this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);\n\n // May fail if the connection is not established.\n await warnAfterTimeout(5_000, 'Connection establishment takes too long', () => this._start());\n\n this._restartAfter = 0;\n await this._onRestart?.();\n }\n\n /**\n * Scheduling restart should be done from outside.\n */\n @synchronized\n scheduleRestart() {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return;\n }\n this._restartTask!.schedule();\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["WebSocket", "Trigger", "Event", "scheduleTaskInterval", "scheduleTask", "TriggerState", "Context", "LifecycleState", "Resource", "invariant", "log", "buf", "MessageSchema", "AnySchema", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "invariant", "buf", "bufWkt", "MessageSchema", "bufferToArray", "getTypename", "typeName", "Protocol", "constructor", "types", "_typeRegistry", "createRegistry", "typeRegistry", "toJson", "message", "registry", "err", "type", "getPayloadType", "getPayload", "payload", "payloadTypename", "Error", "anyIs", "anyUnpack", "undefined", "typeUrl", "split", "createMessage", "source", "target", "serviceId", "create", "timestamp", "Date", "toISOString", "anyPack", "toUint8Array", "data", "Buffer", "Blob", "Uint8Array", "arrayBuffer", "protocol", "Protocol", "SwarmRequestSchema", "SwarmResponseSchema", "TextMessageSchema", "AnySchema", "WebsocketClosedError", "Error", "constructor", "DeferredTask", "sleep", "synchronized", "cancelWithContext", "LifecycleState", "Resource", "warnAfterTimeout", "log", "INIT_RESTART_DELAY", "DEFAULT_MAX_RESTART_DELAY", "PersistentLifecycle", "constructor", "start", "stop", "onRestart", "maxRestartDelay", "_restartTask", "undefined", "_restartAfter", "_start", "_stop", "_onRestart", "_maxRestartDelay", "_open", "_ctx", "_restart", "err", "warn", "schedule", "catch", "_close", "join", "state", "_lifecycleState", "OPEN", "Math", "min", "max", "scheduleRestart", "DEFAULT_TIMEOUT", "SIGNAL_KEEPALIVE_INTERVAL", "EdgeClient", "Resource", "constructor", "_identityKey", "_peerKey", "_config", "reconnect", "Event", "_persistentLifecycle", "PersistentLifecycle", "start", "_openWebSocket", "stop", "_closeWebSocket", "onRestart", "emit", "_listeners", "Set", "_ready", "Trigger", "_ws", "undefined", "_keepaliveCtx", "_heartBeatContext", "_protocol", "protocol", "info", "open", "isOpen", "identity", "device", "identityKey", "peerKey", "_lifecycleState", "LifecycleState", "OPEN", "setIdentity", "scheduleRestart", "addListener", "listener", "add", "delete", "_open", "log", "catch", "err", "warn", "_close", "close", "url", "URL", "socketEndpoint", "WebSocket", "onopen", "wake", "onclose", "onerror", "event", "error", "message", "onmessage", "data", "_onHeartbeat", "toUint8Array", "buf", "fromBinary", "MessageSchema", "payload", "getPayloadType", "wait", "timeout", "Context", "scheduleTaskInterval", "send", "throw", "WebsocketClosedError", "reset", "dispose", "Error", "includes", "state", "TriggerState", "RESOLVED", "invariant", "source", "toBinary", "scheduleTask"]
7
7
  }