@dxos/edge-client 0.6.13 → 0.6.14-main.69511f5

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 (61) 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 +469 -160
  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 +125 -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 +468 -158
  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 +155 -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 +787 -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 +126 -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 +14 -13
  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/errors.d.ts +4 -1
  32. package/dist/types/src/errors.d.ts.map +1 -1
  33. package/dist/types/src/index.d.ts +4 -0
  34. package/dist/types/src/index.d.ts.map +1 -1
  35. package/dist/types/src/protocol.d.ts +2 -2
  36. package/dist/types/src/protocol.d.ts.map +1 -1
  37. package/dist/types/src/testing/index.d.ts +2 -0
  38. package/dist/types/src/testing/index.d.ts.map +1 -0
  39. package/dist/types/src/testing/test-utils.d.ts +21 -0
  40. package/dist/types/src/testing/test-utils.d.ts.map +1 -0
  41. package/dist/types/src/utils.d.ts +2 -0
  42. package/dist/types/src/utils.d.ts.map +1 -0
  43. package/package.json +27 -17
  44. package/src/auth.ts +135 -0
  45. package/src/defs.ts +2 -3
  46. package/src/edge-client.test.ts +50 -18
  47. package/src/edge-client.ts +76 -24
  48. package/src/edge-http-client.ts +210 -0
  49. package/src/edge-identity.ts +31 -0
  50. package/src/errors.ts +8 -2
  51. package/src/index.ts +4 -0
  52. package/src/persistent-lifecycle.test.ts +2 -2
  53. package/src/protocol.test.ts +1 -2
  54. package/src/protocol.ts +2 -2
  55. package/src/testing/index.ts +5 -0
  56. package/src/testing/test-utils.ts +114 -0
  57. package/src/utils.ts +10 -0
  58. package/src/websocket.test.ts +5 -4
  59. package/dist/types/src/test-utils.d.ts +0 -11
  60. package/dist/types/src/test-utils.d.ts.map +0 -1
  61. package/src/test-utils.ts +0 -49
@@ -30,129 +30,86 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  var node_exports = {};
31
31
  __export(node_exports, {
32
32
  EdgeClient: () => EdgeClient,
33
- Protocol: () => Protocol,
34
- getTypename: () => getTypename,
35
- protocol: () => protocol,
36
- toUint8Array: () => toUint8Array
33
+ EdgeConnectionClosedError: () => EdgeConnectionClosedError,
34
+ EdgeHttpClient: () => EdgeHttpClient,
35
+ EdgeIdentityChangedError: () => EdgeIdentityChangedError,
36
+ Protocol: () => import_chunk_ANV2HBEH.Protocol,
37
+ createChainEdgeIdentity: () => createChainEdgeIdentity,
38
+ createDeviceEdgeIdentity: () => createDeviceEdgeIdentity,
39
+ createEphemeralEdgeIdentity: () => createEphemeralEdgeIdentity,
40
+ createStubEdgeIdentity: () => createStubEdgeIdentity,
41
+ createTestHaloEdgeIdentity: () => createTestHaloEdgeIdentity,
42
+ getTypename: () => import_chunk_ANV2HBEH.getTypename,
43
+ handleAuthChallenge: () => handleAuthChallenge,
44
+ protocol: () => import_chunk_ANV2HBEH.protocol,
45
+ toUint8Array: () => import_chunk_ANV2HBEH.toUint8Array
37
46
  });
38
47
  module.exports = __toCommonJS(node_exports);
48
+ var import_chunk_ANV2HBEH = require("./chunk-ANV2HBEH.cjs");
39
49
  __reExport(node_exports, require("@dxos/protocols/buf/dxos/edge/messenger_pb"), module.exports);
40
50
  var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
41
51
  var import_async = require("@dxos/async");
42
52
  var import_context = require("@dxos/context");
43
- var import_invariant = require("@dxos/invariant");
44
53
  var import_log = require("@dxos/log");
45
54
  var import_buf = require("@dxos/protocols/buf");
46
55
  var import_messenger_pb = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
47
- var import_wkt = require("@bufbuild/protobuf/wkt");
48
- var import_messenger_pb2 = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
49
- var import_invariant2 = require("@dxos/invariant");
50
- var import_buf2 = require("@dxos/protocols/buf");
51
- var import_messenger_pb3 = require("@dxos/protocols/buf/dxos/edge/messenger_pb");
52
- var import_util = require("@dxos/util");
56
+ var import_invariant = require("@dxos/invariant");
57
+ var import_proto = require("@dxos/protocols/proto");
53
58
  var import_async2 = require("@dxos/async");
54
59
  var import_context2 = require("@dxos/context");
55
60
  var import_debug = require("@dxos/debug");
56
61
  var import_log2 = require("@dxos/log");
57
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/protocol.ts";
58
- var getTypename = (typeName) => `type.googleapis.com/${typeName}`;
59
- var Protocol = class {
60
- constructor(types) {
61
- this._typeRegistry = import_buf2.buf.createRegistry(...types);
62
- }
63
- get typeRegistry() {
64
- return this._typeRegistry;
65
- }
66
- toJson(message) {
67
- try {
68
- return import_buf2.buf.toJson(import_messenger_pb3.MessageSchema, message, {
69
- registry: this.typeRegistry
70
- });
71
- } catch (err) {
72
- return {
73
- type: this.getPayloadType(message)
74
- };
75
- }
76
- }
77
- /**
78
- * Return the payload with the given type.
79
- */
80
- getPayload(message, type) {
81
- (0, import_invariant2.invariant)(message.payload, void 0, {
82
- F: __dxlog_file,
83
- L: 40,
84
- S: this,
85
- A: [
86
- "message.payload",
87
- ""
88
- ]
89
- });
90
- const payloadTypename = this.getPayloadType(message);
91
- if (type && type.typeName !== payloadTypename) {
92
- throw new Error(`Unexpected payload type: ${payloadTypename}; expected ${type.typeName}`);
93
- }
94
- (0, import_invariant2.invariant)(import_buf2.bufWkt.anyIs(message.payload, type), `Unexpected payload type: ${payloadTypename}}`, {
95
- F: __dxlog_file,
96
- L: 46,
97
- S: this,
98
- A: [
99
- "bufWkt.anyIs(message.payload, type)",
100
- "`Unexpected payload type: ${payloadTypename}}`"
101
- ]
102
- });
103
- const payload = import_buf2.bufWkt.anyUnpack(message.payload, this.typeRegistry);
104
- (0, import_invariant2.invariant)(payload, `Empty payload: ${payloadTypename}}`, {
105
- F: __dxlog_file,
106
- L: 48,
107
- S: this,
108
- A: [
109
- "payload",
110
- "`Empty payload: ${payloadTypename}}`"
111
- ]
112
- });
113
- return payload;
114
- }
115
- /**
116
- * Get the payload type.
117
- */
118
- getPayloadType(message) {
119
- if (!message.payload) {
120
- return void 0;
121
- }
122
- const [, type] = message.payload.typeUrl.split("/");
123
- return type;
124
- }
125
- /**
126
- * Create a packed message.
127
- */
128
- createMessage(type, { source, target, payload, serviceId }) {
129
- return import_buf2.buf.create(import_messenger_pb3.MessageSchema, {
130
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
131
- source,
132
- target,
133
- serviceId,
134
- payload: payload ? import_buf2.bufWkt.anyPack(type, import_buf2.buf.create(type, payload)) : void 0
135
- });
136
- }
62
+ var import_credentials = require("@dxos/credentials");
63
+ var import_keyring = require("@dxos/keyring");
64
+ var import_keys = require("@dxos/keys");
65
+ var import_async3 = require("@dxos/async");
66
+ var import_context3 = require("@dxos/context");
67
+ var import_log3 = require("@dxos/log");
68
+ var import_protocols = require("@dxos/protocols");
69
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-identity.ts";
70
+ var handleAuthChallenge = async (failedResponse, identity) => {
71
+ (0, import_invariant.invariant)(failedResponse.status === 401, void 0, {
72
+ F: __dxlog_file,
73
+ L: 21,
74
+ S: void 0,
75
+ A: [
76
+ "failedResponse.status === 401",
77
+ ""
78
+ ]
79
+ });
80
+ const headerValue = failedResponse.headers.get("Www-Authenticate");
81
+ (0, import_invariant.invariant)(headerValue?.startsWith("VerifiablePresentation challenge="), void 0, {
82
+ F: __dxlog_file,
83
+ L: 24,
84
+ S: void 0,
85
+ A: [
86
+ "headerValue?.startsWith('VerifiablePresentation challenge=')",
87
+ ""
88
+ ]
89
+ });
90
+ const challenge = headerValue?.slice("VerifiablePresentation challenge=".length);
91
+ (0, import_invariant.invariant)(challenge, void 0, {
92
+ F: __dxlog_file,
93
+ L: 27,
94
+ S: void 0,
95
+ A: [
96
+ "challenge",
97
+ ""
98
+ ]
99
+ });
100
+ const presentation = await identity.presentCredentials({
101
+ challenge: Buffer.from(challenge, "base64")
102
+ });
103
+ return import_proto.schema.getCodecForType("dxos.halo.credentials.Presentation").encode(presentation);
137
104
  };
138
- var toUint8Array = async (data) => {
139
- if (data instanceof Buffer) {
140
- return (0, import_util.bufferToArray)(data);
141
- }
142
- if (data instanceof Blob) {
143
- return new Uint8Array(await data.arrayBuffer());
105
+ var EdgeConnectionClosedError = class extends Error {
106
+ constructor() {
107
+ super("Edge connection closed.");
144
108
  }
145
- throw new Error(`Unexpected datatype: ${data}`);
146
109
  };
147
- var protocol = new Protocol([
148
- import_messenger_pb2.SwarmRequestSchema,
149
- import_messenger_pb2.SwarmResponseSchema,
150
- import_messenger_pb2.TextMessageSchema,
151
- import_wkt.AnySchema
152
- ]);
153
- var WebsocketClosedError = class extends Error {
110
+ var EdgeIdentityChangedError = class extends Error {
154
111
  constructor() {
155
- super("WebSocket connection closed");
112
+ super("Edge identity changed.");
156
113
  }
157
114
  };
158
115
  function _ts_decorate(decorators, target, key, desc) {
@@ -242,16 +199,22 @@ _ts_decorate([
242
199
  _ts_decorate([
243
200
  import_async2.synchronized
244
201
  ], PersistentLifecycle.prototype, "scheduleRestart", null);
202
+ var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
203
+ const isSecure = baseUrl.startsWith("https") || baseUrl.startsWith("wss");
204
+ const url = new URL(baseUrl);
205
+ url.protocol = protocol2 + (isSecure ? "s" : "");
206
+ return url.toString();
207
+ };
245
208
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
246
209
  var DEFAULT_TIMEOUT = 1e4;
247
210
  var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
248
211
  var EdgeClient = class extends import_context.Resource {
249
- constructor(_identityKey, _peerKey, _config) {
212
+ constructor(_identity, _config) {
250
213
  super();
251
- this._identityKey = _identityKey;
252
- this._peerKey = _peerKey;
214
+ this._identity = _identity;
253
215
  this._config = _config;
254
216
  this.reconnect = new import_async.Event();
217
+ this.connected = new import_async.Event();
255
218
  this._persistentLifecycle = new PersistentLifecycle({
256
219
  start: async () => this._openWebSocket(),
257
220
  stop: async () => this._closeWebSocket(),
@@ -262,26 +225,40 @@ var EdgeClient = class extends import_context.Resource {
262
225
  this._ws = void 0;
263
226
  this._keepaliveCtx = void 0;
264
227
  this._heartBeatContext = void 0;
265
- this._protocol = this._config.protocol ?? protocol;
228
+ this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
229
+ this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
266
230
  }
267
231
  // TODO(burdon): Attach logging.
268
232
  get info() {
269
233
  return {
270
234
  open: this.isOpen,
271
- identity: this._identityKey,
272
- device: this._peerKey
235
+ identity: this._identity.identityKey,
236
+ device: this._identity.peerKey
273
237
  };
274
238
  }
239
+ get isConnected() {
240
+ return Boolean(this._ws) && this._ready.state === import_async.TriggerState.RESOLVED;
241
+ }
275
242
  get identityKey() {
276
- return this._identityKey;
243
+ return this._identity.identityKey;
277
244
  }
278
245
  get peerKey() {
279
- return this._peerKey;
246
+ return this._identity.peerKey;
280
247
  }
281
- setIdentity({ peerKey, identityKey }) {
282
- this._peerKey = peerKey;
283
- this._identityKey = identityKey;
284
- this._persistentLifecycle.scheduleRestart();
248
+ setIdentity(identity) {
249
+ if (identity.identityKey !== this._identity.identityKey || identity.peerKey !== this._identity.peerKey) {
250
+ (0, import_log.log)("Edge identity changed", {
251
+ identity,
252
+ oldIdentity: this._identity
253
+ }, {
254
+ F: __dxlog_file3,
255
+ L: 99,
256
+ S: this,
257
+ C: (f, a) => f(...a)
258
+ });
259
+ this._identity = identity;
260
+ this._persistentLifecycle.scheduleRestart();
261
+ }
285
262
  }
286
263
  addListener(listener) {
287
264
  this._listeners.add(listener);
@@ -295,7 +272,7 @@ var EdgeClient = class extends import_context.Resource {
295
272
  info: this.info
296
273
  }, {
297
274
  F: __dxlog_file3,
298
- L: 101,
275
+ L: 114,
299
276
  S: this,
300
277
  C: (f, a) => f(...a)
301
278
  });
@@ -304,7 +281,7 @@ var EdgeClient = class extends import_context.Resource {
304
281
  err
305
282
  }, {
306
283
  F: __dxlog_file3,
307
- L: 103,
284
+ L: 116,
308
285
  S: this,
309
286
  C: (f, a) => f(...a)
310
287
  });
@@ -315,31 +292,48 @@ var EdgeClient = class extends import_context.Resource {
315
292
  */
316
293
  async _close() {
317
294
  (0, import_log.log)("closing...", {
318
- peerKey: this._peerKey
295
+ peerKey: this._identity.peerKey
319
296
  }, {
320
297
  F: __dxlog_file3,
321
- L: 111,
298
+ L: 124,
322
299
  S: this,
323
300
  C: (f, a) => f(...a)
324
301
  });
325
302
  await this._persistentLifecycle.close();
326
303
  }
327
304
  async _openWebSocket() {
328
- const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);
329
- this._ws = new import_isomorphic_ws.default(url);
305
+ if (this._ctx.disposed) {
306
+ return;
307
+ }
308
+ const path = `/ws/${this._identity.identityKey}/${this._identity.peerKey}`;
309
+ const protocolHeader = this._config.disableAuth ? void 0 : await this._createAuthHeader(path);
310
+ const url = new URL(path, this._baseWsUrl);
311
+ (0, import_log.log)("Opening websocket", {
312
+ url: url.toString(),
313
+ protocolHeader
314
+ }, {
315
+ F: __dxlog_file3,
316
+ L: 136,
317
+ S: this,
318
+ C: (f, a) => f(...a)
319
+ });
320
+ this._ws = new import_isomorphic_ws.default(url, protocolHeader ? [
321
+ protocolHeader
322
+ ] : []);
330
323
  this._ws.onopen = () => {
331
324
  (0, import_log.log)("opened", this.info, {
332
325
  F: __dxlog_file3,
333
- L: 120,
326
+ L: 140,
334
327
  S: this,
335
328
  C: (f, a) => f(...a)
336
329
  });
337
330
  this._ready.wake();
331
+ this.connected.emit();
338
332
  };
339
333
  this._ws.onclose = () => {
340
334
  (0, import_log.log)("closed", this.info, {
341
335
  F: __dxlog_file3,
342
- L: 124,
336
+ L: 145,
343
337
  S: this,
344
338
  C: (f, a) => f(...a)
345
339
  });
@@ -351,7 +345,7 @@ var EdgeClient = class extends import_context.Resource {
351
345
  info: event.message
352
346
  }, {
353
347
  F: __dxlog_file3,
354
- L: 128,
348
+ L: 149,
355
349
  S: this,
356
350
  C: (f, a) => f(...a)
357
351
  });
@@ -362,14 +356,14 @@ var EdgeClient = class extends import_context.Resource {
362
356
  this._onHeartbeat();
363
357
  return;
364
358
  }
365
- const data = await toUint8Array(event.data);
359
+ const data = await (0, import_chunk_ANV2HBEH.toUint8Array)(event.data);
366
360
  const message = import_buf.buf.fromBinary(import_messenger_pb.MessageSchema, data);
367
361
  (0, import_log.log)("received", {
368
- peerKey: this._peerKey,
369
- payload: protocol.getPayloadType(message)
362
+ peerKey: this._identity.peerKey,
363
+ payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
370
364
  }, {
371
365
  F: __dxlog_file3,
372
- L: 141,
366
+ L: 162,
373
367
  S: this,
374
368
  C: (f, a) => f(...a)
375
369
  });
@@ -380,10 +374,10 @@ var EdgeClient = class extends import_context.Resource {
380
374
  } catch (err) {
381
375
  import_log.log.error("processing", {
382
376
  err,
383
- payload: protocol.getPayloadType(message)
377
+ payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
384
378
  }, {
385
379
  F: __dxlog_file3,
386
- L: 147,
380
+ L: 168,
387
381
  S: this,
388
382
  C: (f, a) => f(...a)
389
383
  });
@@ -394,9 +388,18 @@ var EdgeClient = class extends import_context.Resource {
394
388
  await this._ready.wait({
395
389
  timeout: this._config.timeout ?? DEFAULT_TIMEOUT
396
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
+ });
397
400
  this._keepaliveCtx = new import_context.Context(void 0, {
398
401
  F: __dxlog_file3,
399
- L: 154
402
+ L: 179
400
403
  });
401
404
  (0, import_async.scheduleTaskInterval)(this._keepaliveCtx, async () => {
402
405
  this._ws?.send("__ping__");
@@ -409,7 +412,7 @@ var EdgeClient = class extends import_context.Resource {
409
412
  return;
410
413
  }
411
414
  try {
412
- this._ready.throw(new WebsocketClosedError());
415
+ this._ready.throw(this.isOpen ? new EdgeIdentityChangedError() : new EdgeConnectionClosedError());
413
416
  this._ready.reset();
414
417
  void this._keepaliveCtx?.dispose();
415
418
  this._keepaliveCtx = void 0;
@@ -431,7 +434,7 @@ var EdgeClient = class extends import_context.Resource {
431
434
  err
432
435
  }, {
433
436
  F: __dxlog_file3,
434
- L: 190,
437
+ L: 215,
435
438
  S: this,
436
439
  C: (f, a) => f(...a)
437
440
  });
@@ -443,34 +446,28 @@ var EdgeClient = class extends import_context.Resource {
443
446
  */
444
447
  async send(message) {
445
448
  if (this._ready.state !== import_async.TriggerState.RESOLVED) {
449
+ (0, import_log.log)("waiting for websocket to become ready", void 0, {
450
+ F: __dxlog_file3,
451
+ L: 225,
452
+ S: this,
453
+ C: (f, a) => f(...a)
454
+ });
446
455
  await this._ready.wait({
447
456
  timeout: this._config.timeout ?? DEFAULT_TIMEOUT
448
457
  });
449
458
  }
450
- (0, import_invariant.invariant)(this._ws, void 0, {
451
- F: __dxlog_file3,
452
- L: 202,
453
- S: this,
454
- A: [
455
- "this._ws",
456
- ""
457
- ]
458
- });
459
- (0, import_invariant.invariant)(!message.source || message.source.peerKey === this._peerKey, void 0, {
460
- F: __dxlog_file3,
461
- L: 203,
462
- S: this,
463
- A: [
464
- "!message.source || message.source.peerKey === this._peerKey",
465
- ""
466
- ]
467
- });
459
+ if (!this._ws) {
460
+ throw new EdgeConnectionClosedError();
461
+ }
462
+ if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
463
+ throw new EdgeIdentityChangedError();
464
+ }
468
465
  (0, import_log.log)("sending...", {
469
- peerKey: this._peerKey,
470
- payload: protocol.getPayloadType(message)
466
+ peerKey: this._identity.peerKey,
467
+ payload: import_chunk_ANV2HBEH.protocol.getPayloadType(message)
471
468
  }, {
472
469
  F: __dxlog_file3,
473
- L: 204,
470
+ L: 238,
474
471
  S: this,
475
472
  C: (f, a) => f(...a)
476
473
  });
@@ -483,18 +480,331 @@ var EdgeClient = class extends import_context.Resource {
483
480
  void this._heartBeatContext?.dispose();
484
481
  this._heartBeatContext = new import_context.Context(void 0, {
485
482
  F: __dxlog_file3,
486
- L: 213
483
+ L: 247
487
484
  });
488
485
  (0, import_async.scheduleTask)(this._heartBeatContext, () => {
489
486
  this._persistentLifecycle.scheduleRestart();
490
487
  }, 2 * SIGNAL_KEEPALIVE_INTERVAL);
491
488
  }
489
+ async _createAuthHeader(path) {
490
+ const httpUrl = new URL(path, this._baseHttpUrl);
491
+ httpUrl.protocol = getEdgeUrlWithProtocol(this._baseWsUrl.toString(), "http");
492
+ const response = await fetch(httpUrl, {
493
+ method: "GET"
494
+ });
495
+ if (response.status === 401) {
496
+ return encodePresentationWsAuthHeader(await handleAuthChallenge(response, this._identity));
497
+ } else {
498
+ import_log.log.warn("no auth challenge from edge", {
499
+ status: response.status,
500
+ statusText: response.statusText
501
+ }, {
502
+ F: __dxlog_file3,
503
+ L: 264,
504
+ S: this,
505
+ C: (f, a) => f(...a)
506
+ });
507
+ return void 0;
508
+ }
509
+ }
510
+ };
511
+ var encodePresentationWsAuthHeader = (encodedPresentation) => {
512
+ const encodedToken = Buffer.from(encodedPresentation).toString("base64").replace(/=*$/, "").replaceAll("/", "|");
513
+ return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
514
+ };
515
+ var createDeviceEdgeIdentity = async (signer, key) => {
516
+ return {
517
+ identityKey: key.toHex(),
518
+ peerKey: key.toHex(),
519
+ presentCredentials: async ({ challenge }) => {
520
+ return (0, import_credentials.signPresentation)({
521
+ presentation: {
522
+ credentials: [
523
+ // Verifier requires at least one credential in the presentation to establish the subject.
524
+ await (0, import_credentials.createCredential)({
525
+ assertion: {
526
+ "@type": "dxos.halo.credentials.Auth"
527
+ },
528
+ issuer: key,
529
+ subject: key,
530
+ signer
531
+ })
532
+ ]
533
+ },
534
+ signer,
535
+ signerKey: key,
536
+ nonce: challenge
537
+ });
538
+ }
539
+ };
540
+ };
541
+ var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
542
+ const credentialsToSign = credentials.length > 0 ? credentials : [
543
+ await (0, import_credentials.createCredential)({
544
+ assertion: {
545
+ "@type": "dxos.halo.credentials.Auth"
546
+ },
547
+ issuer: identityKey,
548
+ subject: identityKey,
549
+ signer,
550
+ chain,
551
+ signingKey: peerKey
552
+ })
553
+ ];
554
+ return {
555
+ identityKey: identityKey.toHex(),
556
+ peerKey: peerKey.toHex(),
557
+ presentCredentials: async ({ challenge }) => {
558
+ return (0, import_credentials.signPresentation)({
559
+ presentation: {
560
+ credentials: credentialsToSign
561
+ },
562
+ signer,
563
+ nonce: challenge,
564
+ signerKey: peerKey,
565
+ chain
566
+ });
567
+ }
568
+ };
569
+ };
570
+ var createEphemeralEdgeIdentity = async () => {
571
+ const keyring = new import_keyring.Keyring();
572
+ const key = await keyring.createKey();
573
+ return createDeviceEdgeIdentity(keyring, key);
574
+ };
575
+ var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
576
+ const deviceAdmission = await (0, import_credentials.createCredential)({
577
+ assertion: {
578
+ "@type": "dxos.halo.credentials.AuthorizedDevice",
579
+ deviceKey,
580
+ identityKey
581
+ },
582
+ issuer: identityKey,
583
+ subject: deviceKey,
584
+ signer
585
+ });
586
+ return createChainEdgeIdentity(signer, identityKey, deviceKey, {
587
+ credential: deviceAdmission
588
+ }, [
589
+ await (0, import_credentials.createCredential)({
590
+ assertion: {
591
+ "@type": "dxos.halo.credentials.Auth"
592
+ },
593
+ issuer: identityKey,
594
+ subject: identityKey,
595
+ signer
596
+ })
597
+ ]);
598
+ };
599
+ var createStubEdgeIdentity = () => {
600
+ const identityKey = import_keys.PublicKey.random();
601
+ const deviceKey = import_keys.PublicKey.random();
602
+ return {
603
+ identityKey: identityKey.toHex(),
604
+ peerKey: deviceKey.toHex(),
605
+ presentCredentials: async () => {
606
+ throw new Error("Stub identity does not support authentication.");
607
+ }
608
+ };
609
+ };
610
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
611
+ var DEFAULT_RETRY_TIMEOUT = 1500;
612
+ var DEFAULT_RETRY_JITTER = 500;
613
+ var DEFAULT_MAX_RETRIES_COUNT = 3;
614
+ var EdgeHttpClient = class {
615
+ constructor(baseUrl) {
616
+ this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
617
+ (0, import_log3.log)("created", {
618
+ url: this._baseUrl
619
+ }, {
620
+ F: __dxlog_file4,
621
+ L: 42,
622
+ S: this,
623
+ C: (f, a) => f(...a)
624
+ });
625
+ }
626
+ setIdentity(identity) {
627
+ this._edgeIdentity = identity;
628
+ }
629
+ createAgent(body, args) {
630
+ return this._call("/agents/create", {
631
+ ...args,
632
+ method: "POST",
633
+ body
634
+ });
635
+ }
636
+ getAgentStatus(request, args) {
637
+ return this._call(`/users/${request.ownerIdentityKey.toHex()}/agent/status`, {
638
+ ...args,
639
+ method: "GET"
640
+ });
641
+ }
642
+ getCredentialsForNotarization(spaceId, args) {
643
+ return this._call(`/spaces/${spaceId}/notarization`, {
644
+ ...args,
645
+ method: "GET"
646
+ });
647
+ }
648
+ async notarizeCredentials(spaceId, body, args) {
649
+ await this._call(`/spaces/${spaceId}/notarization`, {
650
+ ...args,
651
+ body,
652
+ method: "POST"
653
+ });
654
+ }
655
+ async joinSpaceByInvitation(spaceId, body, args) {
656
+ return this._call(`/spaces/${spaceId}/join`, {
657
+ ...args,
658
+ body,
659
+ method: "POST"
660
+ });
661
+ }
662
+ async recoverIdentity(body, args) {
663
+ return this._call("/identity/recover", {
664
+ ...args,
665
+ body,
666
+ method: "POST"
667
+ });
668
+ }
669
+ async _call(path, args) {
670
+ const requestContext = args.context ?? new import_context3.Context(void 0, {
671
+ F: __dxlog_file4,
672
+ L: 88
673
+ });
674
+ const shouldRetry = createRetryHandler(args);
675
+ const url = `${this._baseUrl}${path.startsWith("/") ? path.slice(1) : path}`;
676
+ import_log3.log.info("call", {
677
+ method: args.method,
678
+ path,
679
+ request: args.body
680
+ }, {
681
+ F: __dxlog_file4,
682
+ L: 92,
683
+ S: this,
684
+ C: (f, a) => f(...a)
685
+ });
686
+ let handledAuth = false;
687
+ let authHeader = this._authHeader;
688
+ while (true) {
689
+ let processingError;
690
+ let retryAfterHeaderValue = Number.NaN;
691
+ try {
692
+ const request = createRequest(args, authHeader);
693
+ const response = await fetch(url, request);
694
+ retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
695
+ if (response.ok) {
696
+ const body = await response.json();
697
+ if (body.success) {
698
+ return body.data;
699
+ }
700
+ import_log3.log.info("unsuccessful edge response", {
701
+ path,
702
+ body
703
+ }, {
704
+ F: __dxlog_file4,
705
+ L: 111,
706
+ S: this,
707
+ C: (f, a) => f(...a)
708
+ });
709
+ if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
710
+ processingError = new import_protocols.EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
711
+ } else {
712
+ processingError = import_protocols.EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
713
+ }
714
+ } else if (response.status === 401 && !handledAuth) {
715
+ authHeader = await this._handleUnauthorized(response);
716
+ handledAuth = true;
717
+ continue;
718
+ } else {
719
+ processingError = import_protocols.EdgeCallFailedError.fromHttpFailure(response);
720
+ }
721
+ } catch (error) {
722
+ processingError = import_protocols.EdgeCallFailedError.fromProcessingFailureCause(error);
723
+ }
724
+ if (processingError.isRetryable && await shouldRetry(requestContext, retryAfterHeaderValue)) {
725
+ import_log3.log.info("retrying edge request", {
726
+ path,
727
+ processingError
728
+ }, {
729
+ F: __dxlog_file4,
730
+ L: 130,
731
+ S: this,
732
+ C: (f, a) => f(...a)
733
+ });
734
+ } else {
735
+ throw processingError;
736
+ }
737
+ }
738
+ }
739
+ async _handleUnauthorized(response) {
740
+ 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,
744
+ S: this,
745
+ C: (f, a) => f(...a)
746
+ });
747
+ throw import_protocols.EdgeCallFailedError.fromHttpFailure(response);
748
+ }
749
+ const challenge = await handleAuthChallenge(response, this._edgeIdentity);
750
+ this._authHeader = encodeAuthHeader(challenge);
751
+ (0, import_log3.log)("auth header updated", void 0, {
752
+ F: __dxlog_file4,
753
+ L: 144,
754
+ S: this,
755
+ C: (f, a) => f(...a)
756
+ });
757
+ return this._authHeader;
758
+ }
759
+ };
760
+ var createRetryHandler = (args) => {
761
+ if (!args.retry || args.retry.count < 1) {
762
+ return async () => false;
763
+ }
764
+ let retries = 0;
765
+ const maxRetries = args.retry.count ?? DEFAULT_MAX_RETRIES_COUNT;
766
+ const baseTimeout = args.retry.timeout ?? DEFAULT_RETRY_TIMEOUT;
767
+ const jitter = args.retry.jitter ?? DEFAULT_RETRY_JITTER;
768
+ return async (ctx, retryAfter) => {
769
+ if (++retries > maxRetries || ctx.disposed) {
770
+ return false;
771
+ }
772
+ if (retryAfter) {
773
+ await (0, import_async3.sleep)(retryAfter);
774
+ } else {
775
+ const timeout = baseTimeout + Math.random() * jitter;
776
+ await (0, import_async3.sleep)(timeout);
777
+ }
778
+ return true;
779
+ };
780
+ };
781
+ var createRequest = (args, authHeader) => {
782
+ return {
783
+ method: args.method,
784
+ body: args.body && JSON.stringify(args.body),
785
+ headers: authHeader ? {
786
+ Authorization: authHeader
787
+ } : void 0
788
+ };
789
+ };
790
+ var encodeAuthHeader = (challenge) => {
791
+ const encodedChallenge = Buffer.from(challenge).toString("base64");
792
+ return `VerifiablePresentation pb;base64,${encodedChallenge}`;
492
793
  };
493
794
  // Annotate the CommonJS export names for ESM import in node:
494
795
  0 && (module.exports = {
495
796
  EdgeClient,
797
+ EdgeConnectionClosedError,
798
+ EdgeHttpClient,
799
+ EdgeIdentityChangedError,
496
800
  Protocol,
801
+ createChainEdgeIdentity,
802
+ createDeviceEdgeIdentity,
803
+ createEphemeralEdgeIdentity,
804
+ createStubEdgeIdentity,
805
+ createTestHaloEdgeIdentity,
497
806
  getTypename,
807
+ handleAuthChallenge,
498
808
  protocol,
499
809
  toUint8Array,
500
810
  ...require("@dxos/protocols/buf/dxos/edge/messenger_pb")