@dxos/edge-client 0.6.14-staging.e15392e → 0.7.0

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 +444 -226
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/testing/index.mjs +7 -4
  5. package/dist/lib/browser/testing/index.mjs.map +3 -3
  6. package/dist/lib/node/index.cjs +441 -225
  7. package/dist/lib/node/index.cjs.map +4 -4
  8. package/dist/lib/node/meta.json +1 -1
  9. package/dist/lib/node/testing/index.cjs +7 -4
  10. package/dist/lib/node/testing/index.cjs.map +3 -3
  11. package/dist/lib/node-esm/index.mjs +444 -226
  12. package/dist/lib/node-esm/index.mjs.map +4 -4
  13. package/dist/lib/node-esm/meta.json +1 -1
  14. package/dist/lib/node-esm/testing/index.mjs +7 -4
  15. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  16. package/dist/types/src/auth.d.ts +1 -1
  17. package/dist/types/src/auth.d.ts.map +1 -1
  18. package/dist/types/src/edge-client.d.ts +21 -18
  19. package/dist/types/src/edge-client.d.ts.map +1 -1
  20. package/dist/types/src/edge-http-client.d.ts.map +1 -1
  21. package/dist/types/src/edge-ws-connection.d.ts +30 -0
  22. package/dist/types/src/edge-ws-connection.d.ts.map +1 -0
  23. package/dist/types/src/persistent-lifecycle.d.ts +7 -5
  24. package/dist/types/src/persistent-lifecycle.d.ts.map +1 -1
  25. package/dist/types/src/testing/test-utils.d.ts +1 -0
  26. package/dist/types/src/testing/test-utils.d.ts.map +1 -1
  27. package/package.json +14 -14
  28. package/src/auth.ts +4 -1
  29. package/src/edge-client.test.ts +101 -14
  30. package/src/edge-client.ts +128 -126
  31. package/src/edge-http-client.ts +4 -1
  32. package/src/edge-ws-connection.ts +148 -0
  33. package/src/persistent-lifecycle.ts +26 -11
  34. package/src/testing/test-utils.ts +3 -0
@@ -47,24 +47,29 @@ __export(node_exports, {
47
47
  module.exports = __toCommonJS(node_exports);
48
48
  var import_chunk_ANV2HBEH = require("./chunk-ANV2HBEH.cjs");
49
49
  __reExport(node_exports, require("@dxos/protocols/buf/dxos/edge/messenger_pb"), module.exports);
50
- var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
51
50
  var import_async = require("@dxos/async");
52
51
  var import_context = require("@dxos/context");
53
52
  var import_log = require("@dxos/log");
54
- var import_buf = require("@dxos/protocols/buf");
55
- var import_messenger_pb = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
56
53
  var import_invariant = require("@dxos/invariant");
57
54
  var import_proto = require("@dxos/protocols/proto");
55
+ var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
58
56
  var import_async2 = require("@dxos/async");
59
57
  var import_context2 = require("@dxos/context");
60
- var import_debug = require("@dxos/debug");
58
+ var import_invariant2 = require("@dxos/invariant");
61
59
  var import_log2 = require("@dxos/log");
62
- var import_credentials = require("@dxos/credentials");
63
- var import_keyring = require("@dxos/keyring");
64
- var import_keys = require("@dxos/keys");
60
+ var import_buf = require("@dxos/protocols/buf");
61
+ var import_messenger_pb = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
65
62
  var import_async3 = require("@dxos/async");
66
63
  var import_context3 = require("@dxos/context");
64
+ var import_debug = require("@dxos/debug");
67
65
  var import_log3 = require("@dxos/log");
66
+ var import_credentials = require("@dxos/credentials");
67
+ var import_invariant3 = require("@dxos/invariant");
68
+ var import_keyring = require("@dxos/keyring");
69
+ var import_keys = require("@dxos/keys");
70
+ var import_async4 = require("@dxos/async");
71
+ var import_context4 = require("@dxos/context");
72
+ var import_log4 = require("@dxos/log");
68
73
  var import_protocols = require("@dxos/protocols");
69
74
  var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-identity.ts";
70
75
  var handleAuthChallenge = async (failedResponse, identity) => {
@@ -102,6 +107,195 @@ var handleAuthChallenge = async (failedResponse, identity) => {
102
107
  });
103
108
  return import_proto.schema.getCodecForType("dxos.halo.credentials.Presentation").encode(presentation);
104
109
  };
110
+ function _ts_decorate(decorators, target, key, desc) {
111
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
112
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
113
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
114
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
115
+ }
116
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-ws-connection.ts";
117
+ var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
118
+ var EdgeWsConnection = class extends import_context2.Resource {
119
+ constructor(_identity, _connectionInfo, _callbacks) {
120
+ super();
121
+ this._identity = _identity;
122
+ this._connectionInfo = _connectionInfo;
123
+ this._callbacks = _callbacks;
124
+ }
125
+ get info() {
126
+ return {
127
+ open: this.isOpen,
128
+ identity: this._identity.identityKey,
129
+ device: this._identity.peerKey
130
+ };
131
+ }
132
+ send(message) {
133
+ (0, import_invariant2.invariant)(this._ws, void 0, {
134
+ F: __dxlog_file2,
135
+ L: 48,
136
+ S: this,
137
+ A: [
138
+ "this._ws",
139
+ ""
140
+ ]
141
+ });
142
+ (0, import_log2.log)("sending...", {
143
+ peerKey: this._identity.peerKey,
144
+ payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
145
+ }, {
146
+ F: __dxlog_file2,
147
+ L: 49,
148
+ S: this,
149
+ C: (f, a) => f(...a)
150
+ });
151
+ this._ws.send(import_buf.buf.toBinary(import_messenger_pb.MessageSchema, message));
152
+ }
153
+ async _open() {
154
+ this._ws = new import_isomorphic_ws.default(this._connectionInfo.url, this._connectionInfo.protocolHeader ? [
155
+ this._connectionInfo.protocolHeader
156
+ ] : []);
157
+ this._ws.onopen = () => {
158
+ if (this.isOpen) {
159
+ (0, import_log2.log)("connected", void 0, {
160
+ F: __dxlog_file2,
161
+ L: 61,
162
+ S: this,
163
+ C: (f, a) => f(...a)
164
+ });
165
+ this._callbacks.onConnected();
166
+ this._scheduleHeartbeats();
167
+ } else {
168
+ import_log2.log.verbose("connected after becoming inactive", {
169
+ currentIdentity: this._identity
170
+ }, {
171
+ F: __dxlog_file2,
172
+ L: 65,
173
+ S: this,
174
+ C: (f, a) => f(...a)
175
+ });
176
+ }
177
+ };
178
+ this._ws.onclose = () => {
179
+ if (this.isOpen) {
180
+ (0, import_log2.log)("disconnected while being open", void 0, {
181
+ F: __dxlog_file2,
182
+ L: 70,
183
+ S: this,
184
+ C: (f, a) => f(...a)
185
+ });
186
+ this._callbacks.onRestartRequired();
187
+ }
188
+ };
189
+ this._ws.onerror = (event) => {
190
+ if (this.isOpen) {
191
+ import_log2.log.warn("edge connection socket error", {
192
+ error: event.error,
193
+ info: event.message
194
+ }, {
195
+ F: __dxlog_file2,
196
+ L: 76,
197
+ S: this,
198
+ C: (f, a) => f(...a)
199
+ });
200
+ this._callbacks.onRestartRequired();
201
+ } else {
202
+ import_log2.log.verbose("error ignored on closed connection", {
203
+ error: event.error
204
+ }, {
205
+ F: __dxlog_file2,
206
+ L: 79,
207
+ S: this,
208
+ C: (f, a) => f(...a)
209
+ });
210
+ }
211
+ };
212
+ this._ws.onmessage = async (event) => {
213
+ if (!this.isOpen) {
214
+ import_log2.log.verbose("message ignored on closed connection", {
215
+ event: event.type
216
+ }, {
217
+ F: __dxlog_file2,
218
+ L: 87,
219
+ S: this,
220
+ C: (f, a) => f(...a)
221
+ });
222
+ return;
223
+ }
224
+ if (event.data === "__pong__") {
225
+ this._rescheduleHeartbeatTimeout();
226
+ return;
227
+ }
228
+ const data = await (0, import_chunk_ANV2HBEH.toUint8Array)(event.data);
229
+ if (this.isOpen) {
230
+ const message = import_buf.buf.fromBinary(import_messenger_pb.MessageSchema, data);
231
+ (0, import_log2.log)("received", {
232
+ from: message.source,
233
+ payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
234
+ }, {
235
+ F: __dxlog_file2,
236
+ L: 97,
237
+ S: this,
238
+ C: (f, a) => f(...a)
239
+ });
240
+ this._callbacks.onMessage(message);
241
+ }
242
+ };
243
+ }
244
+ async _close() {
245
+ void this._inactivityTimeoutCtx?.dispose().catch(() => {
246
+ });
247
+ try {
248
+ this._ws?.close();
249
+ this._ws = void 0;
250
+ } catch (err) {
251
+ if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
252
+ return;
253
+ }
254
+ import_log2.log.warn("Error closing websocket", {
255
+ err
256
+ }, {
257
+ F: __dxlog_file2,
258
+ L: 113,
259
+ S: this,
260
+ C: (f, a) => f(...a)
261
+ });
262
+ }
263
+ }
264
+ _scheduleHeartbeats() {
265
+ (0, import_invariant2.invariant)(this._ws, void 0, {
266
+ F: __dxlog_file2,
267
+ L: 118,
268
+ S: this,
269
+ A: [
270
+ "this._ws",
271
+ ""
272
+ ]
273
+ });
274
+ (0, import_async2.scheduleTaskInterval)(this._ctx, async () => {
275
+ this._ws?.send("__ping__");
276
+ }, SIGNAL_KEEPALIVE_INTERVAL);
277
+ this._ws.send("__ping__");
278
+ this._rescheduleHeartbeatTimeout();
279
+ }
280
+ _rescheduleHeartbeatTimeout() {
281
+ if (!this.isOpen) {
282
+ return;
283
+ }
284
+ void this._inactivityTimeoutCtx?.dispose();
285
+ this._inactivityTimeoutCtx = new import_context2.Context(void 0, {
286
+ F: __dxlog_file2,
287
+ L: 137
288
+ });
289
+ (0, import_async2.scheduleTask)(this._inactivityTimeoutCtx, () => {
290
+ if (this.isOpen) {
291
+ this._callbacks.onRestartRequired();
292
+ }
293
+ }, 2 * SIGNAL_KEEPALIVE_INTERVAL);
294
+ }
295
+ };
296
+ _ts_decorate([
297
+ import_log2.logInfo
298
+ ], EdgeWsConnection.prototype, "info", null);
105
299
  var EdgeConnectionClosedError = class extends Error {
106
300
  constructor() {
107
301
  super("Edge connection closed.");
@@ -112,18 +306,19 @@ var EdgeIdentityChangedError = class extends Error {
112
306
  super("Edge identity changed.");
113
307
  }
114
308
  };
115
- function _ts_decorate(decorators, target, key, desc) {
309
+ function _ts_decorate2(decorators, target, key, desc) {
116
310
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
117
311
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
118
312
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
119
313
  return c > 3 && r && Object.defineProperty(target, key, r), r;
120
314
  }
121
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
315
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
122
316
  var INIT_RESTART_DELAY = 100;
123
317
  var DEFAULT_MAX_RESTART_DELAY = 5e3;
124
- var PersistentLifecycle = class extends import_context2.Resource {
318
+ var PersistentLifecycle = class extends import_context3.Resource {
125
319
  constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }) {
126
320
  super();
321
+ this._currentContext = void 0;
127
322
  this._restartTask = void 0;
128
323
  this._restartAfter = 0;
129
324
  this._start = start;
@@ -132,72 +327,90 @@ var PersistentLifecycle = class extends import_context2.Resource {
132
327
  this._maxRestartDelay = maxRestartDelay;
133
328
  }
134
329
  async _open() {
135
- this._restartTask = new import_async2.DeferredTask(this._ctx, async () => {
330
+ this._restartTask = new import_async3.DeferredTask(this._ctx, async () => {
136
331
  try {
137
332
  await this._restart();
138
333
  } catch (err) {
139
- import_log2.log.warn("Restart failed", {
334
+ import_log3.log.warn("Restart failed", {
140
335
  err
141
336
  }, {
142
- F: __dxlog_file2,
143
- L: 64,
337
+ F: __dxlog_file3,
338
+ L: 65,
144
339
  S: this,
145
340
  C: (f, a) => f(...a)
146
341
  });
147
342
  this._restartTask?.schedule();
148
343
  }
149
344
  });
150
- await this._start().catch((err) => {
151
- import_log2.log.warn("Start failed", {
345
+ this._currentContext = await this._start().catch((err) => {
346
+ import_log3.log.warn("Start failed", {
152
347
  err
153
348
  }, {
154
- F: __dxlog_file2,
155
- L: 69,
349
+ F: __dxlog_file3,
350
+ L: 70,
156
351
  S: this,
157
352
  C: (f, a) => f(...a)
158
353
  });
159
354
  this._restartTask?.schedule();
355
+ return void 0;
160
356
  });
161
357
  }
162
358
  async _close() {
163
359
  await this._restartTask?.join();
164
- await this._stop();
360
+ await this._stopCurrentContext();
165
361
  this._restartTask = void 0;
166
362
  }
167
363
  async _restart() {
168
- (0, import_log2.log)(`restarting in ${this._restartAfter}ms`, {
364
+ (0, import_log3.log)(`restarting in ${this._restartAfter}ms`, {
169
365
  state: this._lifecycleState
170
366
  }, {
171
- F: __dxlog_file2,
172
- L: 81,
367
+ F: __dxlog_file3,
368
+ L: 83,
173
369
  S: this,
174
370
  C: (f, a) => f(...a)
175
371
  });
176
- await this._stop();
177
- if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
372
+ await this._stopCurrentContext();
373
+ if (this._lifecycleState !== import_context3.LifecycleState.OPEN) {
178
374
  return;
179
375
  }
180
- await (0, import_context2.cancelWithContext)(this._ctx, (0, import_async2.sleep)(this._restartAfter));
376
+ await (0, import_context3.cancelWithContext)(this._ctx, (0, import_async3.sleep)(this._restartAfter));
181
377
  this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);
182
- await (0, import_debug.warnAfterTimeout)(5e3, "Connection establishment takes too long", () => this._start());
378
+ await (0, import_debug.warnAfterTimeout)(5e3, "Connection establishment takes too long", async () => {
379
+ this._currentContext = await this._start();
380
+ });
183
381
  this._restartAfter = 0;
184
382
  await this._onRestart?.();
185
383
  }
384
+ async _stopCurrentContext() {
385
+ if (this._currentContext) {
386
+ try {
387
+ await this._stop(this._currentContext);
388
+ } catch (err) {
389
+ import_log3.log.catch(err, void 0, {
390
+ F: __dxlog_file3,
391
+ L: 105,
392
+ S: this,
393
+ C: (f, a) => f(...a)
394
+ });
395
+ }
396
+ this._currentContext = void 0;
397
+ }
398
+ }
186
399
  /**
187
400
  * Scheduling restart should be done from outside.
188
401
  */
189
402
  scheduleRestart() {
190
- if (this._lifecycleState !== import_context2.LifecycleState.OPEN) {
403
+ if (this._lifecycleState !== import_context3.LifecycleState.OPEN) {
191
404
  return;
192
405
  }
193
406
  this._restartTask.schedule();
194
407
  }
195
408
  };
196
- _ts_decorate([
197
- import_async2.synchronized
409
+ _ts_decorate2([
410
+ import_async3.synchronized
198
411
  ], PersistentLifecycle.prototype, "_open", null);
199
- _ts_decorate([
200
- import_async2.synchronized
412
+ _ts_decorate2([
413
+ import_async3.synchronized
201
414
  ], PersistentLifecycle.prototype, "scheduleRestart", null);
202
415
  var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
203
416
  const isSecure = baseUrl.startsWith("https") || baseUrl.startsWith("wss");
@@ -205,30 +418,31 @@ var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
205
418
  url.protocol = protocol2 + (isSecure ? "s" : "");
206
419
  return url.toString();
207
420
  };
208
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
421
+ function _ts_decorate3(decorators, target, key, desc) {
422
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
423
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
424
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
425
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
426
+ }
427
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
209
428
  var DEFAULT_TIMEOUT = 1e4;
210
- var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
211
429
  var EdgeClient = class extends import_context.Resource {
212
430
  constructor(_identity, _config) {
213
431
  super();
214
432
  this._identity = _identity;
215
433
  this._config = _config;
216
- this.reconnect = new import_async.Event();
217
- this.connected = new import_async.Event();
218
434
  this._persistentLifecycle = new PersistentLifecycle({
219
- start: async () => this._openWebSocket(),
220
- stop: async () => this._closeWebSocket(),
221
- onRestart: async () => this.reconnect.emit()
435
+ start: async () => this._connect(),
436
+ stop: async (state) => this._disconnect(state)
222
437
  });
223
- this._listeners = /* @__PURE__ */ new Set();
438
+ this._messageListeners = /* @__PURE__ */ new Set();
439
+ this._reconnectListeners = /* @__PURE__ */ new Set();
440
+ this._currentConnection = void 0;
224
441
  this._ready = new import_async.Trigger();
225
- this._ws = void 0;
226
- this._keepaliveCtx = void 0;
227
- this._heartBeatContext = void 0;
442
+ this._isActive = (connection) => connection === this._currentConnection;
228
443
  this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
229
444
  this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
230
445
  }
231
- // TODO(burdon): Attach logging.
232
446
  get info() {
233
447
  return {
234
448
  open: this.isOpen,
@@ -237,7 +451,7 @@ var EdgeClient = class extends import_context.Resource {
237
451
  };
238
452
  }
239
453
  get isConnected() {
240
- return Boolean(this._ws) && this._ready.state === import_async.TriggerState.RESOLVED;
454
+ return Boolean(this._currentConnection) && this._ready.state === import_async.TriggerState.RESOLVED;
241
455
  }
242
456
  get identityKey() {
243
457
  return this._identity.identityKey;
@@ -251,18 +465,39 @@ var EdgeClient = class extends import_context.Resource {
251
465
  identity,
252
466
  oldIdentity: this._identity
253
467
  }, {
254
- F: __dxlog_file3,
255
- L: 99,
468
+ F: __dxlog_file4,
469
+ L: 95,
256
470
  S: this,
257
471
  C: (f, a) => f(...a)
258
472
  });
259
473
  this._identity = identity;
474
+ this._closeCurrentConnection(new EdgeIdentityChangedError());
260
475
  this._persistentLifecycle.scheduleRestart();
261
476
  }
262
477
  }
263
- addListener(listener) {
264
- this._listeners.add(listener);
265
- return () => this._listeners.delete(listener);
478
+ onMessage(listener) {
479
+ this._messageListeners.add(listener);
480
+ return () => this._messageListeners.delete(listener);
481
+ }
482
+ onReconnected(listener) {
483
+ this._reconnectListeners.add(listener);
484
+ if (this._ready.state === import_async.TriggerState.RESOLVED) {
485
+ (0, import_async.scheduleMicroTask)(this._ctx, () => {
486
+ if (this._reconnectListeners.has(listener)) {
487
+ try {
488
+ listener();
489
+ } catch (error) {
490
+ import_log.log.catch(error, void 0, {
491
+ F: __dxlog_file4,
492
+ L: 117,
493
+ S: this,
494
+ C: (f, a) => f(...a)
495
+ });
496
+ }
497
+ }
498
+ });
499
+ }
500
+ return () => this._reconnectListeners.delete(listener);
266
501
  }
267
502
  /**
268
503
  * Open connection to messaging service.
@@ -271,8 +506,8 @@ var EdgeClient = class extends import_context.Resource {
271
506
  (0, import_log.log)("opening...", {
272
507
  info: this.info
273
508
  }, {
274
- F: __dxlog_file3,
275
- L: 114,
509
+ F: __dxlog_file4,
510
+ L: 129,
276
511
  S: this,
277
512
  C: (f, a) => f(...a)
278
513
  });
@@ -280,8 +515,8 @@ var EdgeClient = class extends import_context.Resource {
280
515
  import_log.log.warn("Error while opening connection", {
281
516
  err
282
517
  }, {
283
- F: __dxlog_file3,
284
- L: 116,
518
+ F: __dxlog_file4,
519
+ L: 131,
285
520
  S: this,
286
521
  C: (f, a) => f(...a)
287
522
  });
@@ -294,150 +529,137 @@ var EdgeClient = class extends import_context.Resource {
294
529
  (0, import_log.log)("closing...", {
295
530
  peerKey: this._identity.peerKey
296
531
  }, {
297
- F: __dxlog_file3,
298
- L: 124,
532
+ F: __dxlog_file4,
533
+ L: 139,
299
534
  S: this,
300
535
  C: (f, a) => f(...a)
301
536
  });
537
+ this._closeCurrentConnection();
302
538
  await this._persistentLifecycle.close();
303
539
  }
304
- async _openWebSocket() {
540
+ async _connect() {
305
541
  if (this._ctx.disposed) {
306
- return;
542
+ return void 0;
307
543
  }
308
- const path = `/ws/${this._identity.identityKey}/${this._identity.peerKey}`;
544
+ const identity = this._identity;
545
+ const path = `/ws/${identity.identityKey}/${identity.peerKey}`;
309
546
  const protocolHeader = this._config.disableAuth ? void 0 : await this._createAuthHeader(path);
547
+ if (this._identity !== identity) {
548
+ (0, import_log.log)("identity changed during auth header request", void 0, {
549
+ F: __dxlog_file4,
550
+ L: 153,
551
+ S: this,
552
+ C: (f, a) => f(...a)
553
+ });
554
+ return void 0;
555
+ }
556
+ const restartRequired = new import_async.Trigger();
310
557
  const url = new URL(path, this._baseWsUrl);
311
558
  (0, import_log.log)("Opening websocket", {
312
559
  url: url.toString(),
313
560
  protocolHeader
314
561
  }, {
315
- F: __dxlog_file3,
316
- L: 136,
562
+ F: __dxlog_file4,
563
+ L: 159,
317
564
  S: this,
318
565
  C: (f, a) => f(...a)
319
566
  });
320
- this._ws = new import_isomorphic_ws.default(url, protocolHeader ? [
567
+ const connection = new EdgeWsConnection(identity, {
568
+ url,
321
569
  protocolHeader
322
- ] : []);
323
- this._ws.onopen = () => {
324
- (0, import_log.log)("opened", this.info, {
325
- F: __dxlog_file3,
326
- L: 140,
327
- S: this,
328
- C: (f, a) => f(...a)
329
- });
330
- this._ready.wake();
331
- this.connected.emit();
332
- };
333
- this._ws.onclose = () => {
334
- (0, import_log.log)("closed", this.info, {
335
- F: __dxlog_file3,
336
- L: 145,
337
- S: this,
338
- C: (f, a) => f(...a)
339
- });
340
- this._persistentLifecycle.scheduleRestart();
341
- };
342
- this._ws.onerror = (event) => {
343
- import_log.log.warn("EdgeClient socket error", {
344
- error: event.error,
345
- info: event.message
346
- }, {
347
- F: __dxlog_file3,
348
- L: 149,
349
- S: this,
350
- C: (f, a) => f(...a)
351
- });
352
- this._persistentLifecycle.scheduleRestart();
353
- };
354
- this._ws.onmessage = async (event) => {
355
- if (event.data === "__pong__") {
356
- this._onHeartbeat();
357
- return;
358
- }
359
- const data = await (0, import_chunk_ANV2HBEH.toUint8Array)(event.data);
360
- const message = import_buf.buf.fromBinary(import_messenger_pb.MessageSchema, data);
361
- (0, import_log.log)("received", {
362
- peerKey: this._identity.peerKey,
363
- payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
364
- }, {
365
- F: __dxlog_file3,
366
- L: 162,
367
- S: this,
368
- C: (f, a) => f(...a)
369
- });
370
- if (message) {
371
- for (const listener of this._listeners) {
372
- try {
373
- await listener(message);
374
- } catch (err) {
375
- import_log.log.error("processing", {
376
- err,
377
- payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
378
- }, {
379
- F: __dxlog_file3,
380
- L: 168,
381
- S: this,
382
- C: (f, a) => f(...a)
383
- });
384
- }
570
+ }, {
571
+ onConnected: () => {
572
+ if (this._isActive(connection)) {
573
+ this._ready.wake();
574
+ this._notifyReconnected();
575
+ } else {
576
+ import_log.log.verbose("connected callback ignored, because connection is not active", void 0, {
577
+ F: __dxlog_file4,
578
+ L: 169,
579
+ S: this,
580
+ C: (f, a) => f(...a)
581
+ });
582
+ }
583
+ },
584
+ onRestartRequired: () => {
585
+ if (this._isActive(connection)) {
586
+ this._closeCurrentConnection();
587
+ this._persistentLifecycle.scheduleRestart();
588
+ } else {
589
+ import_log.log.verbose("restart requested by inactive connection", void 0, {
590
+ F: __dxlog_file4,
591
+ L: 177,
592
+ S: this,
593
+ C: (f, a) => f(...a)
594
+ });
595
+ }
596
+ restartRequired.wake();
597
+ },
598
+ onMessage: (message) => {
599
+ if (this._isActive(connection)) {
600
+ this._notifyMessageReceived(message);
601
+ } else {
602
+ import_log.log.verbose("ignored a message on inactive connection", {
603
+ from: message.source,
604
+ type: message.payload?.typeUrl
605
+ }, {
606
+ F: __dxlog_file4,
607
+ L: 185,
608
+ S: this,
609
+ C: (f, a) => f(...a)
610
+ });
385
611
  }
386
612
  }
387
- };
388
- await this._ready.wait({
389
- timeout: this._config.timeout ?? DEFAULT_TIMEOUT
390
- });
391
- (0, import_log.log)("Websocket is ready", {
392
- identity: this._identity.identityKey,
393
- peer: this._identity.peerKey
394
- }, {
395
- F: __dxlog_file3,
396
- L: 176,
397
- S: this,
398
- C: (f, a) => f(...a)
399
- });
400
- this._keepaliveCtx = new import_context.Context(void 0, {
401
- F: __dxlog_file3,
402
- L: 179
403
613
  });
404
- (0, import_async.scheduleTaskInterval)(this._keepaliveCtx, async () => {
405
- this._ws?.send("__ping__");
406
- }, SIGNAL_KEEPALIVE_INTERVAL);
407
- this._ws.send("__ping__");
408
- this._onHeartbeat();
614
+ this._currentConnection = connection;
615
+ await connection.open();
616
+ await Promise.race([
617
+ this._ready.wait({
618
+ timeout: this._config.timeout ?? DEFAULT_TIMEOUT
619
+ }),
620
+ restartRequired
621
+ ]);
622
+ return connection;
409
623
  }
410
- async _closeWebSocket() {
411
- if (!this._ws) {
412
- return;
624
+ async _disconnect(state) {
625
+ await state.close();
626
+ }
627
+ _closeCurrentConnection(error = new EdgeConnectionClosedError()) {
628
+ this._currentConnection = void 0;
629
+ this._ready.throw(error);
630
+ this._ready.reset();
631
+ }
632
+ _notifyReconnected() {
633
+ for (const listener of this._reconnectListeners) {
634
+ try {
635
+ listener();
636
+ } catch (err) {
637
+ import_log.log.error("ws reconnect listener failed", {
638
+ err
639
+ }, {
640
+ F: __dxlog_file4,
641
+ L: 218,
642
+ S: this,
643
+ C: (f, a) => f(...a)
644
+ });
645
+ }
413
646
  }
414
- try {
415
- this._ready.throw(this.isOpen ? new EdgeIdentityChangedError() : new EdgeConnectionClosedError());
416
- this._ready.reset();
417
- void this._keepaliveCtx?.dispose();
418
- this._keepaliveCtx = void 0;
419
- void this._heartBeatContext?.dispose();
420
- this._heartBeatContext = void 0;
421
- this._ws.onopen = () => {
422
- };
423
- this._ws.onclose = () => {
424
- };
425
- this._ws.onerror = () => {
426
- };
427
- this._ws.close();
428
- this._ws = void 0;
429
- } catch (err) {
430
- if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
431
- return;
647
+ }
648
+ _notifyMessageReceived(message) {
649
+ for (const listener of this._messageListeners) {
650
+ try {
651
+ listener(message);
652
+ } catch (err) {
653
+ import_log.log.error("ws incoming message processing failed", {
654
+ err,
655
+ payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
656
+ }, {
657
+ F: __dxlog_file4,
658
+ L: 228,
659
+ S: this,
660
+ C: (f, a) => f(...a)
661
+ });
432
662
  }
433
- import_log.log.warn("Error closing websocket", {
434
- err
435
- }, {
436
- F: __dxlog_file3,
437
- L: 215,
438
- S: this,
439
- C: (f, a) => f(...a)
440
- });
441
663
  }
442
664
  }
443
665
  /**
@@ -447,8 +669,8 @@ var EdgeClient = class extends import_context.Resource {
447
669
  async send(message) {
448
670
  if (this._ready.state !== import_async.TriggerState.RESOLVED) {
449
671
  (0, import_log.log)("waiting for websocket to become ready", void 0, {
450
- F: __dxlog_file3,
451
- L: 225,
672
+ F: __dxlog_file4,
673
+ L: 239,
452
674
  S: this,
453
675
  C: (f, a) => f(...a)
454
676
  });
@@ -456,35 +678,13 @@ var EdgeClient = class extends import_context.Resource {
456
678
  timeout: this._config.timeout ?? DEFAULT_TIMEOUT
457
679
  });
458
680
  }
459
- if (!this._ws) {
681
+ if (!this._currentConnection) {
460
682
  throw new EdgeConnectionClosedError();
461
683
  }
462
684
  if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
463
685
  throw new EdgeIdentityChangedError();
464
686
  }
465
- (0, import_log.log)("sending...", {
466
- peerKey: this._identity.peerKey,
467
- payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
468
- }, {
469
- F: __dxlog_file3,
470
- L: 238,
471
- S: this,
472
- C: (f, a) => f(...a)
473
- });
474
- this._ws.send(import_buf.buf.toBinary(import_messenger_pb.MessageSchema, message));
475
- }
476
- _onHeartbeat() {
477
- if (this._lifecycleState !== import_context.LifecycleState.OPEN) {
478
- return;
479
- }
480
- void this._heartBeatContext?.dispose();
481
- this._heartBeatContext = new import_context.Context(void 0, {
482
- F: __dxlog_file3,
483
- L: 247
484
- });
485
- (0, import_async.scheduleTask)(this._heartBeatContext, () => {
486
- this._persistentLifecycle.scheduleRestart();
487
- }, 2 * SIGNAL_KEEPALIVE_INTERVAL);
687
+ this._currentConnection.send(message);
488
688
  }
489
689
  async _createAuthHeader(path) {
490
690
  const httpUrl = new URL(path, this._baseHttpUrl);
@@ -499,7 +699,7 @@ var EdgeClient = class extends import_context.Resource {
499
699
  status: response.status,
500
700
  statusText: response.statusText
501
701
  }, {
502
- F: __dxlog_file3,
702
+ F: __dxlog_file4,
503
703
  L: 264,
504
704
  S: this,
505
705
  C: (f, a) => f(...a)
@@ -508,10 +708,14 @@ var EdgeClient = class extends import_context.Resource {
508
708
  }
509
709
  }
510
710
  };
711
+ _ts_decorate3([
712
+ import_log.logInfo
713
+ ], EdgeClient.prototype, "info", null);
511
714
  var encodePresentationWsAuthHeader = (encodedPresentation) => {
512
715
  const encodedToken = Buffer.from(encodedPresentation).toString("base64").replace(/=*$/, "").replaceAll("/", "|");
513
716
  return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
514
717
  };
718
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/auth.ts";
515
719
  var createDeviceEdgeIdentity = async (signer, key) => {
516
720
  return {
517
721
  identityKey: key.toHex(),
@@ -555,6 +759,15 @@ var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, creden
555
759
  identityKey: identityKey.toHex(),
556
760
  peerKey: peerKey.toHex(),
557
761
  presentCredentials: async ({ challenge }) => {
762
+ (0, import_invariant3.invariant)(chain, void 0, {
763
+ F: __dxlog_file5,
764
+ L: 75,
765
+ S: void 0,
766
+ A: [
767
+ "chain",
768
+ ""
769
+ ]
770
+ });
558
771
  return (0, import_credentials.signPresentation)({
559
772
  presentation: {
560
773
  credentials: credentialsToSign
@@ -607,24 +820,27 @@ var createStubEdgeIdentity = () => {
607
820
  }
608
821
  };
609
822
  };
610
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
823
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
611
824
  var DEFAULT_RETRY_TIMEOUT = 1500;
612
825
  var DEFAULT_RETRY_JITTER = 500;
613
826
  var DEFAULT_MAX_RETRIES_COUNT = 3;
614
827
  var EdgeHttpClient = class {
615
828
  constructor(baseUrl) {
616
829
  this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
617
- (0, import_log3.log)("created", {
830
+ (0, import_log4.log)("created", {
618
831
  url: this._baseUrl
619
832
  }, {
620
- F: __dxlog_file4,
833
+ F: __dxlog_file6,
621
834
  L: 42,
622
835
  S: this,
623
836
  C: (f, a) => f(...a)
624
837
  });
625
838
  }
626
839
  setIdentity(identity) {
627
- this._edgeIdentity = identity;
840
+ if (this._edgeIdentity?.identityKey !== identity.identityKey || this._edgeIdentity?.peerKey !== identity.peerKey) {
841
+ this._edgeIdentity = identity;
842
+ this._authHeader = void 0;
843
+ }
628
844
  }
629
845
  createAgent(body, args) {
630
846
  return this._call("/agents/create", {
@@ -667,19 +883,19 @@ var EdgeHttpClient = class {
667
883
  });
668
884
  }
669
885
  async _call(path, args) {
670
- const requestContext = args.context ?? new import_context3.Context(void 0, {
671
- F: __dxlog_file4,
672
- L: 88
886
+ const requestContext = args.context ?? new import_context4.Context(void 0, {
887
+ F: __dxlog_file6,
888
+ L: 91
673
889
  });
674
890
  const shouldRetry = createRetryHandler(args);
675
891
  const url = `${this._baseUrl}${path.startsWith("/") ? path.slice(1) : path}`;
676
- import_log3.log.info("call", {
892
+ import_log4.log.info("call", {
677
893
  method: args.method,
678
894
  path,
679
895
  request: args.body
680
896
  }, {
681
- F: __dxlog_file4,
682
- L: 92,
897
+ F: __dxlog_file6,
898
+ L: 95,
683
899
  S: this,
684
900
  C: (f, a) => f(...a)
685
901
  });
@@ -697,12 +913,12 @@ var EdgeHttpClient = class {
697
913
  if (body.success) {
698
914
  return body.data;
699
915
  }
700
- import_log3.log.info("unsuccessful edge response", {
916
+ import_log4.log.info("unsuccessful edge response", {
701
917
  path,
702
918
  body
703
919
  }, {
704
- F: __dxlog_file4,
705
- L: 111,
920
+ F: __dxlog_file6,
921
+ L: 114,
706
922
  S: this,
707
923
  C: (f, a) => f(...a)
708
924
  });
@@ -722,12 +938,12 @@ var EdgeHttpClient = class {
722
938
  processingError = import_protocols.EdgeCallFailedError.fromProcessingFailureCause(error);
723
939
  }
724
940
  if (processingError.isRetryable && await shouldRetry(requestContext, retryAfterHeaderValue)) {
725
- import_log3.log.info("retrying edge request", {
941
+ import_log4.log.info("retrying edge request", {
726
942
  path,
727
943
  processingError
728
944
  }, {
729
- F: __dxlog_file4,
730
- L: 130,
945
+ F: __dxlog_file6,
946
+ L: 133,
731
947
  S: this,
732
948
  C: (f, a) => f(...a)
733
949
  });
@@ -738,9 +954,9 @@ var EdgeHttpClient = class {
738
954
  }
739
955
  async _handleUnauthorized(response) {
740
956
  if (!this._edgeIdentity) {
741
- import_log3.log.warn("edge unauthorized response received before identity was set", void 0, {
742
- F: __dxlog_file4,
743
- L: 139,
957
+ import_log4.log.warn("edge unauthorized response received before identity was set", void 0, {
958
+ F: __dxlog_file6,
959
+ L: 142,
744
960
  S: this,
745
961
  C: (f, a) => f(...a)
746
962
  });
@@ -748,9 +964,9 @@ var EdgeHttpClient = class {
748
964
  }
749
965
  const challenge = await handleAuthChallenge(response, this._edgeIdentity);
750
966
  this._authHeader = encodeAuthHeader(challenge);
751
- (0, import_log3.log)("auth header updated", void 0, {
752
- F: __dxlog_file4,
753
- L: 144,
967
+ (0, import_log4.log)("auth header updated", void 0, {
968
+ F: __dxlog_file6,
969
+ L: 147,
754
970
  S: this,
755
971
  C: (f, a) => f(...a)
756
972
  });
@@ -770,10 +986,10 @@ var createRetryHandler = (args) => {
770
986
  return false;
771
987
  }
772
988
  if (retryAfter) {
773
- await (0, import_async3.sleep)(retryAfter);
989
+ await (0, import_async4.sleep)(retryAfter);
774
990
  } else {
775
991
  const timeout = baseTimeout + Math.random() * jitter;
776
- await (0, import_async3.sleep)(timeout);
992
+ await (0, import_async4.sleep)(timeout);
777
993
  }
778
994
  return true;
779
995
  };