@dxos/edge-client 0.6.13 → 0.6.14-main.1366248

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 (67) hide show
  1. package/dist/lib/browser/chunk-ZWJXA37R.mjs +113 -0
  2. package/dist/lib/browser/chunk-ZWJXA37R.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +802 -286
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +128 -0
  7. package/dist/lib/browser/testing/index.mjs.map +7 -0
  8. package/dist/lib/node/chunk-ANV2HBEH.cjs +136 -0
  9. package/dist/lib/node/chunk-ANV2HBEH.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +798 -283
  11. package/dist/lib/node/index.cjs.map +4 -4
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +158 -0
  14. package/dist/lib/node/testing/index.cjs.map +7 -0
  15. package/dist/lib/node-esm/chunk-HNVT57AU.mjs +115 -0
  16. package/dist/lib/node-esm/chunk-HNVT57AU.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +994 -0
  18. package/dist/lib/node-esm/index.mjs.map +7 -0
  19. package/dist/lib/node-esm/meta.json +1 -0
  20. package/dist/lib/node-esm/testing/index.mjs +129 -0
  21. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  22. package/dist/types/src/auth.d.ts +22 -0
  23. package/dist/types/src/auth.d.ts.map +1 -0
  24. package/dist/types/src/defs.d.ts.map +1 -1
  25. package/dist/types/src/edge-client.d.ts +30 -26
  26. package/dist/types/src/edge-client.d.ts.map +1 -1
  27. package/dist/types/src/edge-http-client.d.ts +48 -0
  28. package/dist/types/src/edge-http-client.d.ts.map +1 -0
  29. package/dist/types/src/edge-identity.d.ts +15 -0
  30. package/dist/types/src/edge-identity.d.ts.map +1 -0
  31. package/dist/types/src/edge-ws-connection.d.ts +30 -0
  32. package/dist/types/src/edge-ws-connection.d.ts.map +1 -0
  33. package/dist/types/src/errors.d.ts +4 -1
  34. package/dist/types/src/errors.d.ts.map +1 -1
  35. package/dist/types/src/index.d.ts +4 -0
  36. package/dist/types/src/index.d.ts.map +1 -1
  37. package/dist/types/src/persistent-lifecycle.d.ts +7 -5
  38. package/dist/types/src/persistent-lifecycle.d.ts.map +1 -1
  39. package/dist/types/src/protocol.d.ts +2 -2
  40. package/dist/types/src/protocol.d.ts.map +1 -1
  41. package/dist/types/src/testing/index.d.ts +2 -0
  42. package/dist/types/src/testing/index.d.ts.map +1 -0
  43. package/dist/types/src/testing/test-utils.d.ts +22 -0
  44. package/dist/types/src/testing/test-utils.d.ts.map +1 -0
  45. package/dist/types/src/utils.d.ts +2 -0
  46. package/dist/types/src/utils.d.ts.map +1 -0
  47. package/package.json +27 -17
  48. package/src/auth.ts +135 -0
  49. package/src/defs.ts +2 -3
  50. package/src/edge-client.test.ts +144 -25
  51. package/src/edge-client.ts +181 -127
  52. package/src/edge-http-client.ts +213 -0
  53. package/src/edge-identity.ts +31 -0
  54. package/src/edge-ws-connection.ts +148 -0
  55. package/src/errors.ts +8 -2
  56. package/src/index.ts +4 -0
  57. package/src/persistent-lifecycle.test.ts +2 -2
  58. package/src/persistent-lifecycle.ts +26 -11
  59. package/src/protocol.test.ts +1 -2
  60. package/src/protocol.ts +2 -2
  61. package/src/testing/index.ts +5 -0
  62. package/src/testing/test-utils.ts +117 -0
  63. package/src/utils.ts +10 -0
  64. package/src/websocket.test.ts +5 -4
  65. package/dist/types/src/test-utils.d.ts +0 -11
  66. package/dist/types/src/test-utils.d.ts.map +0 -1
  67. package/src/test-utils.ts +0 -49
@@ -1,147 +1,286 @@
1
+ import {
2
+ Protocol,
3
+ getTypename,
4
+ protocol,
5
+ toUint8Array
6
+ } from "./chunk-ZWJXA37R.mjs";
7
+
1
8
  // packages/core/mesh/edge-client/src/index.ts
2
9
  export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
3
10
 
4
11
  // packages/core/mesh/edge-client/src/edge-client.ts
5
- import WebSocket from "isomorphic-ws";
6
- import { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from "@dxos/async";
7
- import { Context, LifecycleState as LifecycleState2, Resource as Resource2 } from "@dxos/context";
8
- import { invariant as invariant2 } from "@dxos/invariant";
9
- import { log as log2 } from "@dxos/log";
10
- import { buf as buf2 } from "@dxos/protocols/buf";
11
- import { MessageSchema as MessageSchema2 } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
12
-
13
- // packages/core/mesh/edge-client/src/defs.ts
14
- import { AnySchema } from "@bufbuild/protobuf/wkt";
15
- import { SwarmRequestSchema, SwarmResponseSchema, TextMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
12
+ import { Trigger, scheduleMicroTask, TriggerState } from "@dxos/async";
13
+ import { Resource as Resource3 } from "@dxos/context";
14
+ import { log as log3, logInfo as logInfo2 } from "@dxos/log";
16
15
 
17
- // packages/core/mesh/edge-client/src/protocol.ts
16
+ // packages/core/mesh/edge-client/src/edge-identity.ts
18
17
  import { invariant } from "@dxos/invariant";
19
- import { buf, bufWkt } from "@dxos/protocols/buf";
18
+ import { schema } from "@dxos/protocols/proto";
19
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-identity.ts";
20
+ var handleAuthChallenge = async (failedResponse, identity) => {
21
+ invariant(failedResponse.status === 401, void 0, {
22
+ F: __dxlog_file,
23
+ L: 21,
24
+ S: void 0,
25
+ A: [
26
+ "failedResponse.status === 401",
27
+ ""
28
+ ]
29
+ });
30
+ const headerValue = failedResponse.headers.get("Www-Authenticate");
31
+ invariant(headerValue?.startsWith("VerifiablePresentation challenge="), void 0, {
32
+ F: __dxlog_file,
33
+ L: 24,
34
+ S: void 0,
35
+ A: [
36
+ "headerValue?.startsWith('VerifiablePresentation challenge=')",
37
+ ""
38
+ ]
39
+ });
40
+ const challenge = headerValue?.slice("VerifiablePresentation challenge=".length);
41
+ invariant(challenge, void 0, {
42
+ F: __dxlog_file,
43
+ L: 27,
44
+ S: void 0,
45
+ A: [
46
+ "challenge",
47
+ ""
48
+ ]
49
+ });
50
+ const presentation = await identity.presentCredentials({
51
+ challenge: Buffer.from(challenge, "base64")
52
+ });
53
+ return schema.getCodecForType("dxos.halo.credentials.Presentation").encode(presentation);
54
+ };
55
+
56
+ // packages/core/mesh/edge-client/src/edge-ws-connection.ts
57
+ import WebSocket from "isomorphic-ws";
58
+ import { scheduleTask, scheduleTaskInterval } from "@dxos/async";
59
+ import { Context, Resource } from "@dxos/context";
60
+ import { invariant as invariant2 } from "@dxos/invariant";
61
+ import { log, logInfo } from "@dxos/log";
62
+ import { buf } from "@dxos/protocols/buf";
20
63
  import { MessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
21
- import { bufferToArray } from "@dxos/util";
22
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/protocol.ts";
23
- var getTypename = (typeName) => `type.googleapis.com/${typeName}`;
24
- var Protocol = class {
25
- constructor(types) {
26
- this._typeRegistry = buf.createRegistry(...types);
27
- }
28
- get typeRegistry() {
29
- return this._typeRegistry;
64
+ function _ts_decorate(decorators, target, key, desc) {
65
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
66
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
67
+ 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;
68
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
69
+ }
70
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-ws-connection.ts";
71
+ var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
72
+ var EdgeWsConnection = class extends Resource {
73
+ constructor(_identity, _connectionInfo, _callbacks) {
74
+ super();
75
+ this._identity = _identity;
76
+ this._connectionInfo = _connectionInfo;
77
+ this._callbacks = _callbacks;
30
78
  }
31
- toJson(message) {
32
- try {
33
- return buf.toJson(MessageSchema, message, {
34
- registry: this.typeRegistry
35
- });
36
- } catch (err) {
37
- return {
38
- type: this.getPayloadType(message)
39
- };
40
- }
79
+ get info() {
80
+ return {
81
+ open: this.isOpen,
82
+ identity: this._identity.identityKey,
83
+ device: this._identity.peerKey
84
+ };
41
85
  }
42
- /**
43
- * Return the payload with the given type.
44
- */
45
- getPayload(message, type) {
46
- invariant(message.payload, void 0, {
47
- F: __dxlog_file,
48
- L: 40,
86
+ send(message) {
87
+ invariant2(this._ws, void 0, {
88
+ F: __dxlog_file2,
89
+ L: 48,
49
90
  S: this,
50
91
  A: [
51
- "message.payload",
92
+ "this._ws",
52
93
  ""
53
94
  ]
54
95
  });
55
- const payloadTypename = this.getPayloadType(message);
56
- if (type && type.typeName !== payloadTypename) {
57
- throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);
58
- }
59
- invariant(bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`, {
60
- F: __dxlog_file,
61
- L: 46,
96
+ log("sending...", {
97
+ peerKey: this._identity.peerKey,
98
+ payload: protocol.getPayloadType(message)
99
+ }, {
100
+ F: __dxlog_file2,
101
+ L: 49,
62
102
  S: this,
63
- A: [
64
- "bufWkt.anyIs(message.payload, type)",
65
- "`Unexpected payload type: ${payloadTypename}}`"
66
- ]
103
+ C: (f, a) => f(...a)
67
104
  });
68
- const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry);
69
- invariant(payload, `Empty payload: ${payloadTypename}}`, {
70
- F: __dxlog_file,
71
- L: 48,
105
+ this._ws.send(buf.toBinary(MessageSchema, message));
106
+ }
107
+ async _open() {
108
+ this._ws = new WebSocket(this._connectionInfo.url, this._connectionInfo.protocolHeader ? [
109
+ this._connectionInfo.protocolHeader
110
+ ] : []);
111
+ this._ws.onopen = () => {
112
+ if (this.isOpen) {
113
+ log("connected", void 0, {
114
+ F: __dxlog_file2,
115
+ L: 61,
116
+ S: this,
117
+ C: (f, a) => f(...a)
118
+ });
119
+ this._callbacks.onConnected();
120
+ this._scheduleHeartbeats();
121
+ } else {
122
+ log.verbose("connected after becoming inactive", {
123
+ currentIdentity: this._identity
124
+ }, {
125
+ F: __dxlog_file2,
126
+ L: 65,
127
+ S: this,
128
+ C: (f, a) => f(...a)
129
+ });
130
+ }
131
+ };
132
+ this._ws.onclose = () => {
133
+ if (this.isOpen) {
134
+ log("disconnected while being open", void 0, {
135
+ F: __dxlog_file2,
136
+ L: 70,
137
+ S: this,
138
+ C: (f, a) => f(...a)
139
+ });
140
+ this._callbacks.onRestartRequired();
141
+ }
142
+ };
143
+ this._ws.onerror = (event) => {
144
+ if (this.isOpen) {
145
+ log.warn("edge connection socket error", {
146
+ error: event.error,
147
+ info: event.message
148
+ }, {
149
+ F: __dxlog_file2,
150
+ L: 76,
151
+ S: this,
152
+ C: (f, a) => f(...a)
153
+ });
154
+ this._callbacks.onRestartRequired();
155
+ } else {
156
+ log.verbose("error ignored on closed connection", {
157
+ error: event.error
158
+ }, {
159
+ F: __dxlog_file2,
160
+ L: 79,
161
+ S: this,
162
+ C: (f, a) => f(...a)
163
+ });
164
+ }
165
+ };
166
+ this._ws.onmessage = async (event) => {
167
+ if (!this.isOpen) {
168
+ log.verbose("message ignored on closed connection", {
169
+ event: event.type
170
+ }, {
171
+ F: __dxlog_file2,
172
+ L: 87,
173
+ S: this,
174
+ C: (f, a) => f(...a)
175
+ });
176
+ return;
177
+ }
178
+ if (event.data === "__pong__") {
179
+ this._rescheduleHeartbeatTimeout();
180
+ return;
181
+ }
182
+ const data = await toUint8Array(event.data);
183
+ if (this.isOpen) {
184
+ const message = buf.fromBinary(MessageSchema, data);
185
+ log("received", {
186
+ from: message.source,
187
+ payload: protocol.getPayloadType(message)
188
+ }, {
189
+ F: __dxlog_file2,
190
+ L: 97,
191
+ S: this,
192
+ C: (f, a) => f(...a)
193
+ });
194
+ this._callbacks.onMessage(message);
195
+ }
196
+ };
197
+ }
198
+ async _close() {
199
+ void this._inactivityTimeoutCtx?.dispose().catch(() => {
200
+ });
201
+ try {
202
+ this._ws?.close();
203
+ this._ws = void 0;
204
+ } catch (err) {
205
+ if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
206
+ return;
207
+ }
208
+ log.warn("Error closing websocket", {
209
+ err
210
+ }, {
211
+ F: __dxlog_file2,
212
+ L: 113,
213
+ S: this,
214
+ C: (f, a) => f(...a)
215
+ });
216
+ }
217
+ }
218
+ _scheduleHeartbeats() {
219
+ invariant2(this._ws, void 0, {
220
+ F: __dxlog_file2,
221
+ L: 118,
72
222
  S: this,
73
223
  A: [
74
- "payload",
75
- "`Empty payload: ${payloadTypename}}`"
224
+ "this._ws",
225
+ ""
76
226
  ]
77
227
  });
78
- return payload;
228
+ scheduleTaskInterval(this._ctx, async () => {
229
+ this._ws?.send("__ping__");
230
+ }, SIGNAL_KEEPALIVE_INTERVAL);
231
+ this._ws.send("__ping__");
232
+ this._rescheduleHeartbeatTimeout();
79
233
  }
80
- /**
81
- * Get the payload type.
82
- */
83
- getPayloadType(message) {
84
- if (!message.payload) {
85
- return void 0;
234
+ _rescheduleHeartbeatTimeout() {
235
+ if (!this.isOpen) {
236
+ return;
86
237
  }
87
- const [, type] = message.payload.typeUrl.split("/");
88
- return type;
89
- }
90
- /**
91
- * Create a packed message.
92
- */
93
- createMessage(type, { source, target, payload, serviceId }) {
94
- return buf.create(MessageSchema, {
95
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
96
- source,
97
- target,
98
- serviceId,
99
- payload: payload ? bufWkt.anyPack(type, buf.create(type, payload)) : void 0
238
+ void this._inactivityTimeoutCtx?.dispose();
239
+ this._inactivityTimeoutCtx = new Context(void 0, {
240
+ F: __dxlog_file2,
241
+ L: 137
100
242
  });
243
+ scheduleTask(this._inactivityTimeoutCtx, () => {
244
+ if (this.isOpen) {
245
+ this._callbacks.onRestartRequired();
246
+ }
247
+ }, 2 * SIGNAL_KEEPALIVE_INTERVAL);
101
248
  }
102
249
  };
103
- var toUint8Array = async (data) => {
104
- if (data instanceof Buffer) {
105
- return bufferToArray(data);
106
- }
107
- if (data instanceof Blob) {
108
- return new Uint8Array(await data.arrayBuffer());
109
- }
110
- throw new Error(`Unexpected datatype: ${data}`);
111
- };
112
-
113
- // packages/core/mesh/edge-client/src/defs.ts
114
- var protocol = new Protocol([
115
- SwarmRequestSchema,
116
- SwarmResponseSchema,
117
- TextMessageSchema,
118
- AnySchema
119
- ]);
250
+ _ts_decorate([
251
+ logInfo
252
+ ], EdgeWsConnection.prototype, "info", null);
120
253
 
121
254
  // packages/core/mesh/edge-client/src/errors.ts
122
- var WebsocketClosedError = class extends Error {
255
+ var EdgeConnectionClosedError = class extends Error {
123
256
  constructor() {
124
- super("WebSocket connection closed");
257
+ super("Edge connection closed.");
258
+ }
259
+ };
260
+ var EdgeIdentityChangedError = class extends Error {
261
+ constructor() {
262
+ super("Edge identity changed.");
125
263
  }
126
264
  };
127
265
 
128
266
  // packages/core/mesh/edge-client/src/persistent-lifecycle.ts
129
267
  import { DeferredTask, sleep, synchronized } from "@dxos/async";
130
- import { cancelWithContext, LifecycleState, Resource } from "@dxos/context";
268
+ import { cancelWithContext, LifecycleState, Resource as Resource2 } from "@dxos/context";
131
269
  import { warnAfterTimeout } from "@dxos/debug";
132
- import { log } from "@dxos/log";
133
- function _ts_decorate(decorators, target, key, desc) {
270
+ import { log as log2 } from "@dxos/log";
271
+ function _ts_decorate2(decorators, target, key, desc) {
134
272
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
135
273
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
136
274
  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;
137
275
  return c > 3 && r && Object.defineProperty(target, key, r), r;
138
276
  }
139
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
277
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
140
278
  var INIT_RESTART_DELAY = 100;
141
279
  var DEFAULT_MAX_RESTART_DELAY = 5e3;
142
- var PersistentLifecycle = class extends Resource {
280
+ var PersistentLifecycle = class extends Resource2 {
143
281
  constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }) {
144
282
  super();
283
+ this._currentContext = void 0;
145
284
  this._restartTask = void 0;
146
285
  this._restartAfter = 0;
147
286
  this._start = start;
@@ -154,53 +293,71 @@ var PersistentLifecycle = class extends Resource {
154
293
  try {
155
294
  await this._restart();
156
295
  } catch (err) {
157
- log.warn("Restart failed", {
296
+ log2.warn("Restart failed", {
158
297
  err
159
298
  }, {
160
- F: __dxlog_file2,
161
- L: 64,
299
+ F: __dxlog_file3,
300
+ L: 65,
162
301
  S: this,
163
302
  C: (f, a) => f(...a)
164
303
  });
165
304
  this._restartTask?.schedule();
166
305
  }
167
306
  });
168
- await this._start().catch((err) => {
169
- log.warn("Start failed", {
307
+ this._currentContext = await this._start().catch((err) => {
308
+ log2.warn("Start failed", {
170
309
  err
171
310
  }, {
172
- F: __dxlog_file2,
173
- L: 69,
311
+ F: __dxlog_file3,
312
+ L: 70,
174
313
  S: this,
175
314
  C: (f, a) => f(...a)
176
315
  });
177
316
  this._restartTask?.schedule();
317
+ return void 0;
178
318
  });
179
319
  }
180
320
  async _close() {
181
321
  await this._restartTask?.join();
182
- await this._stop();
322
+ await this._stopCurrentContext();
183
323
  this._restartTask = void 0;
184
324
  }
185
325
  async _restart() {
186
- log(`restarting in ${this._restartAfter}ms`, {
326
+ log2(`restarting in ${this._restartAfter}ms`, {
187
327
  state: this._lifecycleState
188
328
  }, {
189
- F: __dxlog_file2,
190
- L: 81,
329
+ F: __dxlog_file3,
330
+ L: 83,
191
331
  S: this,
192
332
  C: (f, a) => f(...a)
193
333
  });
194
- await this._stop();
334
+ await this._stopCurrentContext();
195
335
  if (this._lifecycleState !== LifecycleState.OPEN) {
196
336
  return;
197
337
  }
198
338
  await cancelWithContext(this._ctx, sleep(this._restartAfter));
199
339
  this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);
200
- await warnAfterTimeout(5e3, "Connection establishment takes too long", () => this._start());
340
+ await warnAfterTimeout(5e3, "Connection establishment takes too long", async () => {
341
+ this._currentContext = await this._start();
342
+ });
201
343
  this._restartAfter = 0;
202
344
  await this._onRestart?.();
203
345
  }
346
+ async _stopCurrentContext() {
347
+ if (this._currentContext) {
348
+ try {
349
+ await this._stop(this._currentContext);
350
+ } catch (err) {
351
+ log2.catch(err, void 0, {
352
+ F: __dxlog_file3,
353
+ L: 105,
354
+ S: this,
355
+ C: (f, a) => f(...a)
356
+ });
357
+ }
358
+ this._currentContext = void 0;
359
+ }
360
+ }
204
361
  /**
205
362
  * Scheduling restart should be done from outside.
206
363
  */
@@ -211,77 +368,121 @@ var PersistentLifecycle = class extends Resource {
211
368
  this._restartTask.schedule();
212
369
  }
213
370
  };
214
- _ts_decorate([
371
+ _ts_decorate2([
215
372
  synchronized
216
373
  ], PersistentLifecycle.prototype, "_open", null);
217
- _ts_decorate([
374
+ _ts_decorate2([
218
375
  synchronized
219
376
  ], PersistentLifecycle.prototype, "scheduleRestart", null);
220
377
 
378
+ // packages/core/mesh/edge-client/src/utils.ts
379
+ var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
380
+ const isSecure = baseUrl.startsWith("https") || baseUrl.startsWith("wss");
381
+ const url = new URL(baseUrl);
382
+ url.protocol = protocol2 + (isSecure ? "s" : "");
383
+ return url.toString();
384
+ };
385
+
221
386
  // packages/core/mesh/edge-client/src/edge-client.ts
222
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
387
+ function _ts_decorate3(decorators, target, key, desc) {
388
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
389
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
390
+ 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;
391
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
392
+ }
393
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
223
394
  var DEFAULT_TIMEOUT = 1e4;
224
- var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
225
- var EdgeClient = class extends Resource2 {
226
- constructor(_identityKey, _peerKey, _config) {
395
+ var EdgeClient = class extends Resource3 {
396
+ constructor(_identity, _config) {
227
397
  super();
228
- this._identityKey = _identityKey;
229
- this._peerKey = _peerKey;
398
+ this._identity = _identity;
230
399
  this._config = _config;
231
- this.reconnect = new Event();
232
400
  this._persistentLifecycle = new PersistentLifecycle({
233
- start: async () => this._openWebSocket(),
234
- stop: async () => this._closeWebSocket(),
235
- onRestart: async () => this.reconnect.emit()
401
+ start: async () => this._connect(),
402
+ stop: async (state) => this._disconnect(state)
236
403
  });
237
- this._listeners = /* @__PURE__ */ new Set();
404
+ this._messageListeners = /* @__PURE__ */ new Set();
405
+ this._reconnectListeners = /* @__PURE__ */ new Set();
406
+ this._currentConnection = void 0;
238
407
  this._ready = new Trigger();
239
- this._ws = void 0;
240
- this._keepaliveCtx = void 0;
241
- this._heartBeatContext = void 0;
242
- this._protocol = this._config.protocol ?? protocol;
408
+ this._isActive = (connection) => connection === this._currentConnection;
409
+ this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
410
+ this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
243
411
  }
244
- // TODO(burdon): Attach logging.
245
412
  get info() {
246
413
  return {
247
414
  open: this.isOpen,
248
- identity: this._identityKey,
249
- device: this._peerKey
415
+ identity: this._identity.identityKey,
416
+ device: this._identity.peerKey
250
417
  };
251
418
  }
419
+ get isConnected() {
420
+ return Boolean(this._currentConnection) && this._ready.state === TriggerState.RESOLVED;
421
+ }
252
422
  get identityKey() {
253
- return this._identityKey;
423
+ return this._identity.identityKey;
254
424
  }
255
425
  get peerKey() {
256
- return this._peerKey;
426
+ return this._identity.peerKey;
257
427
  }
258
- setIdentity({ peerKey, identityKey }) {
259
- this._peerKey = peerKey;
260
- this._identityKey = identityKey;
261
- this._persistentLifecycle.scheduleRestart();
428
+ setIdentity(identity) {
429
+ if (identity.identityKey !== this._identity.identityKey || identity.peerKey !== this._identity.peerKey) {
430
+ log3("Edge identity changed", {
431
+ identity,
432
+ oldIdentity: this._identity
433
+ }, {
434
+ F: __dxlog_file4,
435
+ L: 95,
436
+ S: this,
437
+ C: (f, a) => f(...a)
438
+ });
439
+ this._identity = identity;
440
+ this._closeCurrentConnection(new EdgeIdentityChangedError());
441
+ this._persistentLifecycle.scheduleRestart();
442
+ }
262
443
  }
263
- addListener(listener) {
264
- this._listeners.add(listener);
265
- return () => this._listeners.delete(listener);
444
+ onMessage(listener) {
445
+ this._messageListeners.add(listener);
446
+ return () => this._messageListeners.delete(listener);
447
+ }
448
+ onReconnected(listener) {
449
+ this._reconnectListeners.add(listener);
450
+ if (this._ready.state === TriggerState.RESOLVED) {
451
+ scheduleMicroTask(this._ctx, () => {
452
+ if (this._reconnectListeners.has(listener)) {
453
+ try {
454
+ listener();
455
+ } catch (error) {
456
+ log3.catch(error, void 0, {
457
+ F: __dxlog_file4,
458
+ L: 117,
459
+ S: this,
460
+ C: (f, a) => f(...a)
461
+ });
462
+ }
463
+ }
464
+ });
465
+ }
466
+ return () => this._reconnectListeners.delete(listener);
266
467
  }
267
468
  /**
268
469
  * Open connection to messaging service.
269
470
  */
270
471
  async _open() {
271
- log2("opening...", {
472
+ log3("opening...", {
272
473
  info: this.info
273
474
  }, {
274
- F: __dxlog_file3,
275
- L: 101,
475
+ F: __dxlog_file4,
476
+ L: 129,
276
477
  S: this,
277
478
  C: (f, a) => f(...a)
278
479
  });
279
480
  this._persistentLifecycle.open().catch((err) => {
280
- log2.warn("Error while opening connection", {
481
+ log3.warn("Error while opening connection", {
281
482
  err
282
483
  }, {
283
- F: __dxlog_file3,
284
- L: 103,
484
+ F: __dxlog_file4,
485
+ L: 131,
285
486
  S: this,
286
487
  C: (f, a) => f(...a)
287
488
  });
@@ -291,127 +492,140 @@ var EdgeClient = class extends Resource2 {
291
492
  * Close connection and free resources.
292
493
  */
293
494
  async _close() {
294
- log2("closing...", {
295
- peerKey: this._peerKey
495
+ log3("closing...", {
496
+ peerKey: this._identity.peerKey
296
497
  }, {
297
- F: __dxlog_file3,
298
- L: 111,
498
+ F: __dxlog_file4,
499
+ L: 139,
299
500
  S: this,
300
501
  C: (f, a) => f(...a)
301
502
  });
503
+ this._closeCurrentConnection();
302
504
  await this._persistentLifecycle.close();
303
505
  }
304
- async _openWebSocket() {
305
- const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);
306
- this._ws = new WebSocket(url);
307
- this._ws.onopen = () => {
308
- log2("opened", this.info, {
309
- F: __dxlog_file3,
310
- L: 120,
311
- S: this,
312
- C: (f, a) => f(...a)
313
- });
314
- this._ready.wake();
315
- };
316
- this._ws.onclose = () => {
317
- log2("closed", this.info, {
318
- F: __dxlog_file3,
319
- L: 124,
320
- S: this,
321
- C: (f, a) => f(...a)
322
- });
323
- this._persistentLifecycle.scheduleRestart();
324
- };
325
- this._ws.onerror = (event) => {
326
- log2.warn("EdgeClient socket error", {
327
- error: event.error,
328
- info: event.message
329
- }, {
330
- F: __dxlog_file3,
331
- L: 128,
332
- S: this,
333
- C: (f, a) => f(...a)
334
- });
335
- this._persistentLifecycle.scheduleRestart();
336
- };
337
- this._ws.onmessage = async (event) => {
338
- if (event.data === "__pong__") {
339
- this._onHeartbeat();
340
- return;
341
- }
342
- const data = await toUint8Array(event.data);
343
- const message = buf2.fromBinary(MessageSchema2, data);
344
- log2("received", {
345
- peerKey: this._peerKey,
346
- payload: protocol.getPayloadType(message)
347
- }, {
348
- F: __dxlog_file3,
349
- L: 141,
506
+ async _connect() {
507
+ if (this._ctx.disposed) {
508
+ return void 0;
509
+ }
510
+ const identity = this._identity;
511
+ const path = `/ws/${identity.identityKey}/${identity.peerKey}`;
512
+ const protocolHeader = this._config.disableAuth ? void 0 : await this._createAuthHeader(path);
513
+ if (this._identity !== identity) {
514
+ log3("identity changed during auth header request", void 0, {
515
+ F: __dxlog_file4,
516
+ L: 153,
350
517
  S: this,
351
518
  C: (f, a) => f(...a)
352
519
  });
353
- if (message) {
354
- for (const listener of this._listeners) {
355
- try {
356
- await listener(message);
357
- } catch (err) {
358
- log2.error("processing", {
359
- err,
360
- payload: protocol.getPayloadType(message)
361
- }, {
362
- F: __dxlog_file3,
363
- L: 147,
364
- S: this,
365
- C: (f, a) => f(...a)
366
- });
367
- }
520
+ return void 0;
521
+ }
522
+ const restartRequired = new Trigger();
523
+ const url = new URL(path, this._baseWsUrl);
524
+ log3("Opening websocket", {
525
+ url: url.toString(),
526
+ protocolHeader
527
+ }, {
528
+ F: __dxlog_file4,
529
+ L: 159,
530
+ S: this,
531
+ C: (f, a) => f(...a)
532
+ });
533
+ const connection = new EdgeWsConnection(identity, {
534
+ url,
535
+ protocolHeader
536
+ }, {
537
+ onConnected: () => {
538
+ if (this._isActive(connection)) {
539
+ this._ready.wake();
540
+ this._notifyReconnected();
541
+ } else {
542
+ log3.verbose("connected callback ignored, because connection is not active", void 0, {
543
+ F: __dxlog_file4,
544
+ L: 169,
545
+ S: this,
546
+ C: (f, a) => f(...a)
547
+ });
548
+ }
549
+ },
550
+ onRestartRequired: () => {
551
+ if (this._isActive(connection)) {
552
+ this._closeCurrentConnection();
553
+ this._persistentLifecycle.scheduleRestart();
554
+ } else {
555
+ log3.verbose("restart requested by inactive connection", void 0, {
556
+ F: __dxlog_file4,
557
+ L: 177,
558
+ S: this,
559
+ C: (f, a) => f(...a)
560
+ });
561
+ }
562
+ restartRequired.wake();
563
+ },
564
+ onMessage: (message) => {
565
+ if (this._isActive(connection)) {
566
+ this._notifyMessageReceived(message);
567
+ } else {
568
+ log3.verbose("ignored a message on inactive connection", {
569
+ from: message.source,
570
+ type: message.payload?.typeUrl
571
+ }, {
572
+ F: __dxlog_file4,
573
+ L: 185,
574
+ S: this,
575
+ C: (f, a) => f(...a)
576
+ });
368
577
  }
369
578
  }
370
- };
371
- await this._ready.wait({
372
- timeout: this._config.timeout ?? DEFAULT_TIMEOUT
373
579
  });
374
- this._keepaliveCtx = new Context(void 0, {
375
- F: __dxlog_file3,
376
- L: 154
377
- });
378
- scheduleTaskInterval(this._keepaliveCtx, async () => {
379
- this._ws?.send("__ping__");
380
- }, SIGNAL_KEEPALIVE_INTERVAL);
381
- this._ws.send("__ping__");
382
- this._onHeartbeat();
580
+ this._currentConnection = connection;
581
+ await connection.open();
582
+ await Promise.race([
583
+ this._ready.wait({
584
+ timeout: this._config.timeout ?? DEFAULT_TIMEOUT
585
+ }),
586
+ restartRequired
587
+ ]);
588
+ return connection;
383
589
  }
384
- async _closeWebSocket() {
385
- if (!this._ws) {
386
- return;
590
+ async _disconnect(state) {
591
+ await state.close();
592
+ }
593
+ _closeCurrentConnection(error = new EdgeConnectionClosedError()) {
594
+ this._currentConnection = void 0;
595
+ this._ready.throw(error);
596
+ this._ready.reset();
597
+ }
598
+ _notifyReconnected() {
599
+ for (const listener of this._reconnectListeners) {
600
+ try {
601
+ listener();
602
+ } catch (err) {
603
+ log3.error("ws reconnect listener failed", {
604
+ err
605
+ }, {
606
+ F: __dxlog_file4,
607
+ L: 218,
608
+ S: this,
609
+ C: (f, a) => f(...a)
610
+ });
611
+ }
387
612
  }
388
- try {
389
- this._ready.throw(new WebsocketClosedError());
390
- this._ready.reset();
391
- void this._keepaliveCtx?.dispose();
392
- this._keepaliveCtx = void 0;
393
- void this._heartBeatContext?.dispose();
394
- this._heartBeatContext = void 0;
395
- this._ws.onopen = () => {
396
- };
397
- this._ws.onclose = () => {
398
- };
399
- this._ws.onerror = () => {
400
- };
401
- this._ws.close();
402
- this._ws = void 0;
403
- } catch (err) {
404
- if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
405
- return;
613
+ }
614
+ _notifyMessageReceived(message) {
615
+ for (const listener of this._messageListeners) {
616
+ try {
617
+ listener(message);
618
+ } catch (err) {
619
+ log3.error("ws incoming message processing failed", {
620
+ err,
621
+ payload: protocol.getPayloadType(message)
622
+ }, {
623
+ F: __dxlog_file4,
624
+ L: 228,
625
+ S: this,
626
+ C: (f, a) => f(...a)
627
+ });
406
628
  }
407
- log2.warn("Error closing websocket", {
408
- err
409
- }, {
410
- F: __dxlog_file3,
411
- L: 190,
412
- S: this,
413
- C: (f, a) => f(...a)
414
- });
415
629
  }
416
630
  }
417
631
  /**
@@ -420,57 +634,359 @@ var EdgeClient = class extends Resource2 {
420
634
  */
421
635
  async send(message) {
422
636
  if (this._ready.state !== TriggerState.RESOLVED) {
637
+ log3("waiting for websocket to become ready", void 0, {
638
+ F: __dxlog_file4,
639
+ L: 239,
640
+ S: this,
641
+ C: (f, a) => f(...a)
642
+ });
423
643
  await this._ready.wait({
424
644
  timeout: this._config.timeout ?? DEFAULT_TIMEOUT
425
645
  });
426
646
  }
427
- invariant2(this._ws, void 0, {
428
- F: __dxlog_file3,
429
- L: 202,
430
- S: this,
431
- A: [
432
- "this._ws",
433
- ""
434
- ]
647
+ if (!this._currentConnection) {
648
+ throw new EdgeConnectionClosedError();
649
+ }
650
+ if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
651
+ throw new EdgeIdentityChangedError();
652
+ }
653
+ this._currentConnection.send(message);
654
+ }
655
+ async _createAuthHeader(path) {
656
+ const httpUrl = new URL(path, this._baseHttpUrl);
657
+ httpUrl.protocol = getEdgeUrlWithProtocol(this._baseWsUrl.toString(), "http");
658
+ const response = await fetch(httpUrl, {
659
+ method: "GET"
435
660
  });
436
- invariant2(!message.source || message.source.peerKey === this._peerKey, void 0, {
437
- F: __dxlog_file3,
438
- L: 203,
661
+ if (response.status === 401) {
662
+ return encodePresentationWsAuthHeader(await handleAuthChallenge(response, this._identity));
663
+ } else {
664
+ log3.warn("no auth challenge from edge", {
665
+ status: response.status,
666
+ statusText: response.statusText
667
+ }, {
668
+ F: __dxlog_file4,
669
+ L: 264,
670
+ S: this,
671
+ C: (f, a) => f(...a)
672
+ });
673
+ return void 0;
674
+ }
675
+ }
676
+ };
677
+ _ts_decorate3([
678
+ logInfo2
679
+ ], EdgeClient.prototype, "info", null);
680
+ var encodePresentationWsAuthHeader = (encodedPresentation) => {
681
+ const encodedToken = Buffer.from(encodedPresentation).toString("base64").replace(/=*$/, "").replaceAll("/", "|");
682
+ return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
683
+ };
684
+
685
+ // packages/core/mesh/edge-client/src/auth.ts
686
+ import { createCredential, signPresentation } from "@dxos/credentials";
687
+ import { Keyring } from "@dxos/keyring";
688
+ import { PublicKey } from "@dxos/keys";
689
+ var createDeviceEdgeIdentity = async (signer, key) => {
690
+ return {
691
+ identityKey: key.toHex(),
692
+ peerKey: key.toHex(),
693
+ presentCredentials: async ({ challenge }) => {
694
+ return signPresentation({
695
+ presentation: {
696
+ credentials: [
697
+ // Verifier requires at least one credential in the presentation to establish the subject.
698
+ await createCredential({
699
+ assertion: {
700
+ "@type": "dxos.halo.credentials.Auth"
701
+ },
702
+ issuer: key,
703
+ subject: key,
704
+ signer
705
+ })
706
+ ]
707
+ },
708
+ signer,
709
+ signerKey: key,
710
+ nonce: challenge
711
+ });
712
+ }
713
+ };
714
+ };
715
+ var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
716
+ const credentialsToSign = credentials.length > 0 ? credentials : [
717
+ await createCredential({
718
+ assertion: {
719
+ "@type": "dxos.halo.credentials.Auth"
720
+ },
721
+ issuer: identityKey,
722
+ subject: identityKey,
723
+ signer,
724
+ chain,
725
+ signingKey: peerKey
726
+ })
727
+ ];
728
+ return {
729
+ identityKey: identityKey.toHex(),
730
+ peerKey: peerKey.toHex(),
731
+ presentCredentials: async ({ challenge }) => {
732
+ return signPresentation({
733
+ presentation: {
734
+ credentials: credentialsToSign
735
+ },
736
+ signer,
737
+ nonce: challenge,
738
+ signerKey: peerKey,
739
+ chain
740
+ });
741
+ }
742
+ };
743
+ };
744
+ var createEphemeralEdgeIdentity = async () => {
745
+ const keyring = new Keyring();
746
+ const key = await keyring.createKey();
747
+ return createDeviceEdgeIdentity(keyring, key);
748
+ };
749
+ var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
750
+ const deviceAdmission = await createCredential({
751
+ assertion: {
752
+ "@type": "dxos.halo.credentials.AuthorizedDevice",
753
+ deviceKey,
754
+ identityKey
755
+ },
756
+ issuer: identityKey,
757
+ subject: deviceKey,
758
+ signer
759
+ });
760
+ return createChainEdgeIdentity(signer, identityKey, deviceKey, {
761
+ credential: deviceAdmission
762
+ }, [
763
+ await createCredential({
764
+ assertion: {
765
+ "@type": "dxos.halo.credentials.Auth"
766
+ },
767
+ issuer: identityKey,
768
+ subject: identityKey,
769
+ signer
770
+ })
771
+ ]);
772
+ };
773
+ var createStubEdgeIdentity = () => {
774
+ const identityKey = PublicKey.random();
775
+ const deviceKey = PublicKey.random();
776
+ return {
777
+ identityKey: identityKey.toHex(),
778
+ peerKey: deviceKey.toHex(),
779
+ presentCredentials: async () => {
780
+ throw new Error("Stub identity does not support authentication.");
781
+ }
782
+ };
783
+ };
784
+
785
+ // packages/core/mesh/edge-client/src/edge-http-client.ts
786
+ import { sleep as sleep2 } from "@dxos/async";
787
+ import { Context as Context2 } from "@dxos/context";
788
+ import { log as log4 } from "@dxos/log";
789
+ import { EdgeCallFailedError, EdgeAuthChallengeError } from "@dxos/protocols";
790
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
791
+ var DEFAULT_RETRY_TIMEOUT = 1500;
792
+ var DEFAULT_RETRY_JITTER = 500;
793
+ var DEFAULT_MAX_RETRIES_COUNT = 3;
794
+ var EdgeHttpClient = class {
795
+ constructor(baseUrl) {
796
+ this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
797
+ log4("created", {
798
+ url: this._baseUrl
799
+ }, {
800
+ F: __dxlog_file5,
801
+ L: 42,
439
802
  S: this,
440
- A: [
441
- "!message.source || message.source.peerKey === this._peerKey",
442
- ""
443
- ]
803
+ C: (f, a) => f(...a)
444
804
  });
445
- log2("sending...", {
446
- peerKey: this._peerKey,
447
- payload: protocol.getPayloadType(message)
805
+ }
806
+ setIdentity(identity) {
807
+ if (this._edgeIdentity?.identityKey !== identity.identityKey || this._edgeIdentity?.peerKey !== identity.peerKey) {
808
+ this._edgeIdentity = identity;
809
+ this._authHeader = void 0;
810
+ }
811
+ }
812
+ createAgent(body, args) {
813
+ return this._call("/agents/create", {
814
+ ...args,
815
+ method: "POST",
816
+ body
817
+ });
818
+ }
819
+ getAgentStatus(request, args) {
820
+ return this._call(`/users/${request.ownerIdentityKey.toHex()}/agent/status`, {
821
+ ...args,
822
+ method: "GET"
823
+ });
824
+ }
825
+ getCredentialsForNotarization(spaceId, args) {
826
+ return this._call(`/spaces/${spaceId}/notarization`, {
827
+ ...args,
828
+ method: "GET"
829
+ });
830
+ }
831
+ async notarizeCredentials(spaceId, body, args) {
832
+ await this._call(`/spaces/${spaceId}/notarization`, {
833
+ ...args,
834
+ body,
835
+ method: "POST"
836
+ });
837
+ }
838
+ async joinSpaceByInvitation(spaceId, body, args) {
839
+ return this._call(`/spaces/${spaceId}/join`, {
840
+ ...args,
841
+ body,
842
+ method: "POST"
843
+ });
844
+ }
845
+ async recoverIdentity(body, args) {
846
+ return this._call("/identity/recover", {
847
+ ...args,
848
+ body,
849
+ method: "POST"
850
+ });
851
+ }
852
+ async _call(path, args) {
853
+ const requestContext = args.context ?? new Context2(void 0, {
854
+ F: __dxlog_file5,
855
+ L: 91
856
+ });
857
+ const shouldRetry = createRetryHandler(args);
858
+ const url = `${this._baseUrl}${path.startsWith("/") ? path.slice(1) : path}`;
859
+ log4.info("call", {
860
+ method: args.method,
861
+ path,
862
+ request: args.body
448
863
  }, {
449
- F: __dxlog_file3,
450
- L: 204,
864
+ F: __dxlog_file5,
865
+ L: 95,
451
866
  S: this,
452
867
  C: (f, a) => f(...a)
453
868
  });
454
- this._ws.send(buf2.toBinary(MessageSchema2, message));
869
+ let handledAuth = false;
870
+ let authHeader = this._authHeader;
871
+ while (true) {
872
+ let processingError;
873
+ let retryAfterHeaderValue = Number.NaN;
874
+ try {
875
+ const request = createRequest(args, authHeader);
876
+ const response = await fetch(url, request);
877
+ retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
878
+ if (response.ok) {
879
+ const body = await response.json();
880
+ if (body.success) {
881
+ return body.data;
882
+ }
883
+ log4.info("unsuccessful edge response", {
884
+ path,
885
+ body
886
+ }, {
887
+ F: __dxlog_file5,
888
+ L: 114,
889
+ S: this,
890
+ C: (f, a) => f(...a)
891
+ });
892
+ if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
893
+ processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
894
+ } else {
895
+ processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
896
+ }
897
+ } else if (response.status === 401 && !handledAuth) {
898
+ authHeader = await this._handleUnauthorized(response);
899
+ handledAuth = true;
900
+ continue;
901
+ } else {
902
+ processingError = EdgeCallFailedError.fromHttpFailure(response);
903
+ }
904
+ } catch (error) {
905
+ processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
906
+ }
907
+ if (processingError.isRetryable && await shouldRetry(requestContext, retryAfterHeaderValue)) {
908
+ log4.info("retrying edge request", {
909
+ path,
910
+ processingError
911
+ }, {
912
+ F: __dxlog_file5,
913
+ L: 133,
914
+ S: this,
915
+ C: (f, a) => f(...a)
916
+ });
917
+ } else {
918
+ throw processingError;
919
+ }
920
+ }
455
921
  }
456
- _onHeartbeat() {
457
- if (this._lifecycleState !== LifecycleState2.OPEN) {
458
- return;
922
+ async _handleUnauthorized(response) {
923
+ if (!this._edgeIdentity) {
924
+ log4.warn("edge unauthorized response received before identity was set", void 0, {
925
+ F: __dxlog_file5,
926
+ L: 142,
927
+ S: this,
928
+ C: (f, a) => f(...a)
929
+ });
930
+ throw EdgeCallFailedError.fromHttpFailure(response);
459
931
  }
460
- void this._heartBeatContext?.dispose();
461
- this._heartBeatContext = new Context(void 0, {
462
- F: __dxlog_file3,
463
- L: 213
932
+ const challenge = await handleAuthChallenge(response, this._edgeIdentity);
933
+ this._authHeader = encodeAuthHeader(challenge);
934
+ log4("auth header updated", void 0, {
935
+ F: __dxlog_file5,
936
+ L: 147,
937
+ S: this,
938
+ C: (f, a) => f(...a)
464
939
  });
465
- scheduleTask(this._heartBeatContext, () => {
466
- this._persistentLifecycle.scheduleRestart();
467
- }, 2 * SIGNAL_KEEPALIVE_INTERVAL);
940
+ return this._authHeader;
941
+ }
942
+ };
943
+ var createRetryHandler = (args) => {
944
+ if (!args.retry || args.retry.count < 1) {
945
+ return async () => false;
468
946
  }
947
+ let retries = 0;
948
+ const maxRetries = args.retry.count ?? DEFAULT_MAX_RETRIES_COUNT;
949
+ const baseTimeout = args.retry.timeout ?? DEFAULT_RETRY_TIMEOUT;
950
+ const jitter = args.retry.jitter ?? DEFAULT_RETRY_JITTER;
951
+ return async (ctx, retryAfter) => {
952
+ if (++retries > maxRetries || ctx.disposed) {
953
+ return false;
954
+ }
955
+ if (retryAfter) {
956
+ await sleep2(retryAfter);
957
+ } else {
958
+ const timeout = baseTimeout + Math.random() * jitter;
959
+ await sleep2(timeout);
960
+ }
961
+ return true;
962
+ };
963
+ };
964
+ var createRequest = (args, authHeader) => {
965
+ return {
966
+ method: args.method,
967
+ body: args.body && JSON.stringify(args.body),
968
+ headers: authHeader ? {
969
+ Authorization: authHeader
970
+ } : void 0
971
+ };
972
+ };
973
+ var encodeAuthHeader = (challenge) => {
974
+ const encodedChallenge = Buffer.from(challenge).toString("base64");
975
+ return `VerifiablePresentation pb;base64,${encodedChallenge}`;
469
976
  };
470
977
  export {
471
978
  EdgeClient,
979
+ EdgeConnectionClosedError,
980
+ EdgeHttpClient,
981
+ EdgeIdentityChangedError,
472
982
  Protocol,
983
+ createChainEdgeIdentity,
984
+ createDeviceEdgeIdentity,
985
+ createEphemeralEdgeIdentity,
986
+ createStubEdgeIdentity,
987
+ createTestHaloEdgeIdentity,
473
988
  getTypename,
989
+ handleAuthChallenge,
474
990
  protocol,
475
991
  toUint8Array
476
992
  };