@dxos/edge-client 0.6.12 → 0.6.13-main.041e8aa

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 (58) 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 +368 -179
  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 +367 -176
  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 +667 -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 +24 -13
  26. package/dist/types/src/edge-client.d.ts.map +1 -1
  27. package/dist/types/src/edge-http-client.d.ts +35 -0
  28. package/dist/types/src/edge-http-client.d.ts.map +1 -0
  29. package/dist/types/src/errors.d.ts +4 -1
  30. package/dist/types/src/errors.d.ts.map +1 -1
  31. package/dist/types/src/index.d.ts +3 -0
  32. package/dist/types/src/index.d.ts.map +1 -1
  33. package/dist/types/src/protocol.d.ts +2 -2
  34. package/dist/types/src/protocol.d.ts.map +1 -1
  35. package/dist/types/src/testing/index.d.ts +2 -0
  36. package/dist/types/src/testing/index.d.ts.map +1 -0
  37. package/dist/types/src/testing/test-utils.d.ts +21 -0
  38. package/dist/types/src/testing/test-utils.d.ts.map +1 -0
  39. package/dist/types/src/utils.d.ts +2 -0
  40. package/dist/types/src/utils.d.ts.map +1 -0
  41. package/package.json +29 -14
  42. package/src/auth.ts +135 -0
  43. package/src/defs.ts +2 -3
  44. package/src/edge-client.test.ts +50 -18
  45. package/src/edge-client.ts +84 -24
  46. package/src/edge-http-client.ts +151 -0
  47. package/src/errors.ts +8 -2
  48. package/src/index.ts +3 -0
  49. package/src/persistent-lifecycle.test.ts +2 -2
  50. package/src/protocol.test.ts +1 -2
  51. package/src/protocol.ts +2 -2
  52. package/src/testing/index.ts +5 -0
  53. package/src/testing/test-utils.ts +114 -0
  54. package/src/utils.ts +10 -0
  55. package/src/websocket.test.ts +5 -4
  56. package/dist/types/src/test-utils.d.ts +0 -11
  57. package/dist/types/src/test-utils.d.ts.map +0 -1
  58. package/src/test-utils.ts +0 -49
@@ -1,3 +1,10 @@
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
 
@@ -5,123 +12,21 @@ export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
5
12
  import WebSocket from "isomorphic-ws";
6
13
  import { Trigger, Event, scheduleTaskInterval, scheduleTask, TriggerState } from "@dxos/async";
7
14
  import { Context, LifecycleState as LifecycleState2, Resource as Resource2 } from "@dxos/context";
8
- import { invariant as invariant2 } from "@dxos/invariant";
15
+ import { randomBytes } from "@dxos/crypto";
9
16
  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";
16
-
17
- // packages/core/mesh/edge-client/src/protocol.ts
18
- import { invariant } from "@dxos/invariant";
19
- import { buf, bufWkt } from "@dxos/protocols/buf";
17
+ import { buf } from "@dxos/protocols/buf";
20
18
  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;
30
- }
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
- }
41
- }
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,
49
- S: this,
50
- A: [
51
- "message.payload",
52
- ""
53
- ]
54
- });
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,
62
- S: this,
63
- A: [
64
- "bufWkt.anyIs(message.payload, type)",
65
- "`Unexpected payload type: ${payloadTypename}}`"
66
- ]
67
- });
68
- const payload = bufWkt.anyUnpack(message.payload, this.typeRegistry);
69
- invariant(payload, `Empty payload: ${payloadTypename}}`, {
70
- F: __dxlog_file,
71
- L: 48,
72
- S: this,
73
- A: [
74
- "payload",
75
- "`Empty payload: ${payloadTypename}}`"
76
- ]
77
- });
78
- return payload;
79
- }
80
- /**
81
- * Get the payload type.
82
- */
83
- getPayloadType(message) {
84
- if (!message.payload) {
85
- return void 0;
86
- }
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
100
- });
101
- }
102
- };
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
- ]);
19
+ import { schema } from "@dxos/protocols/proto";
120
20
 
121
21
  // packages/core/mesh/edge-client/src/errors.ts
122
- var WebsocketClosedError = class extends Error {
22
+ var EdgeConnectionClosedError = class extends Error {
23
+ constructor() {
24
+ super("Edge connection closed.");
25
+ }
26
+ };
27
+ var EdgeIdentityChangedError = class extends Error {
123
28
  constructor() {
124
- super("WebSocket connection closed");
29
+ super("Edge identity changed.");
125
30
  }
126
31
  };
127
32
 
@@ -136,7 +41,7 @@ function _ts_decorate(decorators, target, key, desc) {
136
41
  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
42
  return c > 3 && r && Object.defineProperty(target, key, r), r;
138
43
  }
139
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
44
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/persistent-lifecycle.ts";
140
45
  var INIT_RESTART_DELAY = 100;
141
46
  var DEFAULT_MAX_RESTART_DELAY = 5e3;
142
47
  var PersistentLifecycle = class extends Resource {
@@ -157,7 +62,7 @@ var PersistentLifecycle = class extends Resource {
157
62
  log.warn("Restart failed", {
158
63
  err
159
64
  }, {
160
- F: __dxlog_file2,
65
+ F: __dxlog_file,
161
66
  L: 64,
162
67
  S: this,
163
68
  C: (f, a) => f(...a)
@@ -169,7 +74,7 @@ var PersistentLifecycle = class extends Resource {
169
74
  log.warn("Start failed", {
170
75
  err
171
76
  }, {
172
- F: __dxlog_file2,
77
+ F: __dxlog_file,
173
78
  L: 69,
174
79
  S: this,
175
80
  C: (f, a) => f(...a)
@@ -186,7 +91,7 @@ var PersistentLifecycle = class extends Resource {
186
91
  log(`restarting in ${this._restartAfter}ms`, {
187
92
  state: this._lifecycleState
188
93
  }, {
189
- F: __dxlog_file2,
94
+ F: __dxlog_file,
190
95
  L: 81,
191
96
  S: this,
192
97
  C: (f, a) => f(...a)
@@ -218,17 +123,25 @@ _ts_decorate([
218
123
  synchronized
219
124
  ], PersistentLifecycle.prototype, "scheduleRestart", null);
220
125
 
126
+ // packages/core/mesh/edge-client/src/utils.ts
127
+ var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
128
+ const isSecure = baseUrl.startsWith("https") || baseUrl.startsWith("wss");
129
+ const url = new URL(baseUrl);
130
+ url.protocol = protocol2 + (isSecure ? "s" : "");
131
+ return url.toString();
132
+ };
133
+
221
134
  // 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";
135
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
223
136
  var DEFAULT_TIMEOUT = 1e4;
224
137
  var SIGNAL_KEEPALIVE_INTERVAL = 5e3;
225
138
  var EdgeClient = class extends Resource2 {
226
- constructor(_identityKey, _peerKey, _config) {
139
+ constructor(_identity, _config) {
227
140
  super();
228
- this._identityKey = _identityKey;
229
- this._peerKey = _peerKey;
141
+ this._identity = _identity;
230
142
  this._config = _config;
231
143
  this.reconnect = new Event();
144
+ this.connected = new Event();
232
145
  this._persistentLifecycle = new PersistentLifecycle({
233
146
  start: async () => this._openWebSocket(),
234
147
  stop: async () => this._closeWebSocket(),
@@ -239,26 +152,39 @@ var EdgeClient = class extends Resource2 {
239
152
  this._ws = void 0;
240
153
  this._keepaliveCtx = void 0;
241
154
  this._heartBeatContext = void 0;
242
- this._protocol = this._config.protocol ?? protocol;
155
+ this._baseUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
243
156
  }
244
157
  // TODO(burdon): Attach logging.
245
158
  get info() {
246
159
  return {
247
160
  open: this.isOpen,
248
- identity: this._identityKey,
249
- device: this._peerKey
161
+ identity: this._identity.identityKey,
162
+ device: this._identity.peerKey
250
163
  };
251
164
  }
165
+ get isConnected() {
166
+ return Boolean(this._ws) && this._ready.state === TriggerState.RESOLVED;
167
+ }
252
168
  get identityKey() {
253
- return this._identityKey;
169
+ return this._identity.identityKey;
254
170
  }
255
171
  get peerKey() {
256
- return this._peerKey;
172
+ return this._identity.peerKey;
257
173
  }
258
- setIdentity({ peerKey, identityKey }) {
259
- this._peerKey = peerKey;
260
- this._identityKey = identityKey;
261
- this._persistentLifecycle.scheduleRestart();
174
+ setIdentity(identity) {
175
+ if (identity.identityKey !== this._identity.identityKey || identity.peerKey !== this._identity.peerKey) {
176
+ log2("Edge identity changed", {
177
+ identity,
178
+ oldIdentity: this._identity
179
+ }, {
180
+ F: __dxlog_file2,
181
+ L: 110,
182
+ S: this,
183
+ C: (f, a) => f(...a)
184
+ });
185
+ this._identity = identity;
186
+ this._persistentLifecycle.scheduleRestart();
187
+ }
262
188
  }
263
189
  addListener(listener) {
264
190
  this._listeners.add(listener);
@@ -271,8 +197,8 @@ var EdgeClient = class extends Resource2 {
271
197
  log2("opening...", {
272
198
  info: this.info
273
199
  }, {
274
- F: __dxlog_file3,
275
- L: 101,
200
+ F: __dxlog_file2,
201
+ L: 125,
276
202
  S: this,
277
203
  C: (f, a) => f(...a)
278
204
  });
@@ -280,8 +206,8 @@ var EdgeClient = class extends Resource2 {
280
206
  log2.warn("Error while opening connection", {
281
207
  err
282
208
  }, {
283
- F: __dxlog_file3,
284
- L: 103,
209
+ F: __dxlog_file2,
210
+ L: 127,
285
211
  S: this,
286
212
  C: (f, a) => f(...a)
287
213
  });
@@ -292,31 +218,54 @@ var EdgeClient = class extends Resource2 {
292
218
  */
293
219
  async _close() {
294
220
  log2("closing...", {
295
- peerKey: this._peerKey
221
+ peerKey: this._identity.peerKey
296
222
  }, {
297
- F: __dxlog_file3,
298
- L: 111,
223
+ F: __dxlog_file2,
224
+ L: 135,
299
225
  S: this,
300
226
  C: (f, a) => f(...a)
301
227
  });
302
228
  await this._persistentLifecycle.close();
303
229
  }
304
230
  async _openWebSocket() {
305
- const url = new URL(`/ws/${this._identityKey}/${this._peerKey}`, this._config.socketEndpoint);
306
- this._ws = new WebSocket(url);
231
+ let protocolHeader;
232
+ if (!this._config.disableAuth) {
233
+ const challenge = randomBytes(32);
234
+ const credential = await this._identity.presentCredentials({
235
+ challenge
236
+ });
237
+ protocolHeader = encodePresentationIntoAuthHeader(credential);
238
+ }
239
+ if (this._ctx.disposed) {
240
+ return;
241
+ }
242
+ const url = new URL(`/ws/${this._identity.identityKey}/${this._identity.peerKey}`, this._baseUrl);
243
+ log2("Opening websocket", {
244
+ url: url.toString(),
245
+ protocolHeader
246
+ }, {
247
+ F: __dxlog_file2,
248
+ L: 154,
249
+ S: this,
250
+ C: (f, a) => f(...a)
251
+ });
252
+ this._ws = new WebSocket(url, protocolHeader ? [
253
+ protocolHeader
254
+ ] : []);
307
255
  this._ws.onopen = () => {
308
256
  log2("opened", this.info, {
309
- F: __dxlog_file3,
310
- L: 120,
257
+ F: __dxlog_file2,
258
+ L: 158,
311
259
  S: this,
312
260
  C: (f, a) => f(...a)
313
261
  });
314
262
  this._ready.wake();
263
+ this.connected.emit();
315
264
  };
316
265
  this._ws.onclose = () => {
317
266
  log2("closed", this.info, {
318
- F: __dxlog_file3,
319
- L: 124,
267
+ F: __dxlog_file2,
268
+ L: 163,
320
269
  S: this,
321
270
  C: (f, a) => f(...a)
322
271
  });
@@ -327,8 +276,8 @@ var EdgeClient = class extends Resource2 {
327
276
  error: event.error,
328
277
  info: event.message
329
278
  }, {
330
- F: __dxlog_file3,
331
- L: 128,
279
+ F: __dxlog_file2,
280
+ L: 167,
332
281
  S: this,
333
282
  C: (f, a) => f(...a)
334
283
  });
@@ -340,13 +289,13 @@ var EdgeClient = class extends Resource2 {
340
289
  return;
341
290
  }
342
291
  const data = await toUint8Array(event.data);
343
- const message = buf2.fromBinary(MessageSchema2, data);
292
+ const message = buf.fromBinary(MessageSchema, data);
344
293
  log2("received", {
345
- peerKey: this._peerKey,
294
+ peerKey: this._identity.peerKey,
346
295
  payload: protocol.getPayloadType(message)
347
296
  }, {
348
- F: __dxlog_file3,
349
- L: 141,
297
+ F: __dxlog_file2,
298
+ L: 180,
350
299
  S: this,
351
300
  C: (f, a) => f(...a)
352
301
  });
@@ -359,8 +308,8 @@ var EdgeClient = class extends Resource2 {
359
308
  err,
360
309
  payload: protocol.getPayloadType(message)
361
310
  }, {
362
- F: __dxlog_file3,
363
- L: 147,
311
+ F: __dxlog_file2,
312
+ L: 186,
364
313
  S: this,
365
314
  C: (f, a) => f(...a)
366
315
  });
@@ -371,9 +320,18 @@ var EdgeClient = class extends Resource2 {
371
320
  await this._ready.wait({
372
321
  timeout: this._config.timeout ?? DEFAULT_TIMEOUT
373
322
  });
323
+ log2("Websocket is ready", {
324
+ identity: this._identity.identityKey,
325
+ peer: this._identity.peerKey
326
+ }, {
327
+ F: __dxlog_file2,
328
+ L: 194,
329
+ S: this,
330
+ C: (f, a) => f(...a)
331
+ });
374
332
  this._keepaliveCtx = new Context(void 0, {
375
- F: __dxlog_file3,
376
- L: 154
333
+ F: __dxlog_file2,
334
+ L: 197
377
335
  });
378
336
  scheduleTaskInterval(this._keepaliveCtx, async () => {
379
337
  this._ws?.send("__ping__");
@@ -386,7 +344,7 @@ var EdgeClient = class extends Resource2 {
386
344
  return;
387
345
  }
388
346
  try {
389
- this._ready.throw(new WebsocketClosedError());
347
+ this._ready.throw(this.isOpen ? new EdgeIdentityChangedError() : new EdgeConnectionClosedError());
390
348
  this._ready.reset();
391
349
  void this._keepaliveCtx?.dispose();
392
350
  this._keepaliveCtx = void 0;
@@ -407,8 +365,8 @@ var EdgeClient = class extends Resource2 {
407
365
  log2.warn("Error closing websocket", {
408
366
  err
409
367
  }, {
410
- F: __dxlog_file3,
411
- L: 190,
368
+ F: __dxlog_file2,
369
+ L: 233,
412
370
  S: this,
413
371
  C: (f, a) => f(...a)
414
372
  });
@@ -420,38 +378,32 @@ var EdgeClient = class extends Resource2 {
420
378
  */
421
379
  async send(message) {
422
380
  if (this._ready.state !== TriggerState.RESOLVED) {
381
+ log2("waiting for websocket to become ready", void 0, {
382
+ F: __dxlog_file2,
383
+ L: 243,
384
+ S: this,
385
+ C: (f, a) => f(...a)
386
+ });
423
387
  await this._ready.wait({
424
388
  timeout: this._config.timeout ?? DEFAULT_TIMEOUT
425
389
  });
426
390
  }
427
- invariant2(this._ws, void 0, {
428
- F: __dxlog_file3,
429
- L: 202,
430
- S: this,
431
- A: [
432
- "this._ws",
433
- ""
434
- ]
435
- });
436
- invariant2(!message.source || message.source.peerKey === this._peerKey, void 0, {
437
- F: __dxlog_file3,
438
- L: 203,
439
- S: this,
440
- A: [
441
- "!message.source || message.source.peerKey === this._peerKey",
442
- ""
443
- ]
444
- });
391
+ if (!this._ws) {
392
+ throw new EdgeConnectionClosedError();
393
+ }
394
+ if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
395
+ throw new EdgeIdentityChangedError();
396
+ }
445
397
  log2("sending...", {
446
- peerKey: this._peerKey,
398
+ peerKey: this._identity.peerKey,
447
399
  payload: protocol.getPayloadType(message)
448
400
  }, {
449
- F: __dxlog_file3,
450
- L: 204,
401
+ F: __dxlog_file2,
402
+ L: 256,
451
403
  S: this,
452
404
  C: (f, a) => f(...a)
453
405
  });
454
- this._ws.send(buf2.toBinary(MessageSchema2, message));
406
+ this._ws.send(buf.toBinary(MessageSchema, message));
455
407
  }
456
408
  _onHeartbeat() {
457
409
  if (this._lifecycleState !== LifecycleState2.OPEN) {
@@ -459,17 +411,254 @@ var EdgeClient = class extends Resource2 {
459
411
  }
460
412
  void this._heartBeatContext?.dispose();
461
413
  this._heartBeatContext = new Context(void 0, {
462
- F: __dxlog_file3,
463
- L: 213
414
+ F: __dxlog_file2,
415
+ L: 265
464
416
  });
465
417
  scheduleTask(this._heartBeatContext, () => {
466
418
  this._persistentLifecycle.scheduleRestart();
467
419
  }, 2 * SIGNAL_KEEPALIVE_INTERVAL);
468
420
  }
469
421
  };
422
+ var encodePresentationIntoAuthHeader = (presentation) => {
423
+ const encoded = schema.getCodecForType("dxos.halo.credentials.Presentation").encode(presentation);
424
+ const encodedToken = Buffer.from(encoded).toString("base64").replace(/=*$/, "").replaceAll("/", "|");
425
+ return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
426
+ };
427
+
428
+ // packages/core/mesh/edge-client/src/auth.ts
429
+ import { createCredential, signPresentation } from "@dxos/credentials";
430
+ import { Keyring } from "@dxos/keyring";
431
+ import { PublicKey } from "@dxos/keys";
432
+ var createDeviceEdgeIdentity = async (signer, key) => {
433
+ return {
434
+ identityKey: key.toHex(),
435
+ peerKey: key.toHex(),
436
+ presentCredentials: async ({ challenge }) => {
437
+ return signPresentation({
438
+ presentation: {
439
+ credentials: [
440
+ // Verifier requires at least one credential in the presentation to establish the subject.
441
+ await createCredential({
442
+ assertion: {
443
+ "@type": "dxos.halo.credentials.Auth"
444
+ },
445
+ issuer: key,
446
+ subject: key,
447
+ signer
448
+ })
449
+ ]
450
+ },
451
+ signer,
452
+ signerKey: key,
453
+ nonce: challenge
454
+ });
455
+ }
456
+ };
457
+ };
458
+ var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
459
+ const credentialsToSign = credentials.length > 0 ? credentials : [
460
+ await createCredential({
461
+ assertion: {
462
+ "@type": "dxos.halo.credentials.Auth"
463
+ },
464
+ issuer: identityKey,
465
+ subject: identityKey,
466
+ signer,
467
+ chain,
468
+ signingKey: peerKey
469
+ })
470
+ ];
471
+ return {
472
+ identityKey: identityKey.toHex(),
473
+ peerKey: peerKey.toHex(),
474
+ presentCredentials: async ({ challenge }) => {
475
+ return signPresentation({
476
+ presentation: {
477
+ credentials: credentialsToSign
478
+ },
479
+ signer,
480
+ nonce: challenge,
481
+ signerKey: peerKey,
482
+ chain
483
+ });
484
+ }
485
+ };
486
+ };
487
+ var createEphemeralEdgeIdentity = async () => {
488
+ const keyring = new Keyring();
489
+ const key = await keyring.createKey();
490
+ return createDeviceEdgeIdentity(keyring, key);
491
+ };
492
+ var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
493
+ const deviceAdmission = await createCredential({
494
+ assertion: {
495
+ "@type": "dxos.halo.credentials.AuthorizedDevice",
496
+ deviceKey,
497
+ identityKey
498
+ },
499
+ issuer: identityKey,
500
+ subject: deviceKey,
501
+ signer
502
+ });
503
+ return createChainEdgeIdentity(signer, identityKey, deviceKey, {
504
+ credential: deviceAdmission
505
+ }, [
506
+ await createCredential({
507
+ assertion: {
508
+ "@type": "dxos.halo.credentials.Auth"
509
+ },
510
+ issuer: identityKey,
511
+ subject: identityKey,
512
+ signer
513
+ })
514
+ ]);
515
+ };
516
+ var createStubEdgeIdentity = () => {
517
+ const identityKey = PublicKey.random();
518
+ const deviceKey = PublicKey.random();
519
+ return {
520
+ identityKey: identityKey.toHex(),
521
+ peerKey: deviceKey.toHex(),
522
+ presentCredentials: async () => {
523
+ throw new Error("Stub identity does not support authentication.");
524
+ }
525
+ };
526
+ };
527
+
528
+ // packages/core/mesh/edge-client/src/edge-http-client.ts
529
+ import { sleep as sleep2 } from "@dxos/async";
530
+ import { Context as Context2 } from "@dxos/context";
531
+ import { log as log3 } from "@dxos/log";
532
+ import { EdgeCallFailedError, EdgeAuthChallengeError } from "@dxos/protocols";
533
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
534
+ var DEFAULT_RETRY_TIMEOUT = 1500;
535
+ var DEFAULT_RETRY_JITTER = 500;
536
+ var DEFAULT_MAX_RETRIES_COUNT = 3;
537
+ var EdgeHttpClient = class {
538
+ constructor(baseUrl) {
539
+ this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
540
+ log3("created", {
541
+ url: this._baseUrl
542
+ }, {
543
+ F: __dxlog_file3,
544
+ L: 30,
545
+ S: this,
546
+ C: (f, a) => f(...a)
547
+ });
548
+ }
549
+ getCredentialsForNotarization(spaceId, args) {
550
+ return this._call(`/spaces/${spaceId}/notarization`, {
551
+ ...args,
552
+ method: "GET"
553
+ });
554
+ }
555
+ async notarizeCredentials(spaceId, body, args) {
556
+ await this._call(`/spaces/${spaceId}/notarization`, {
557
+ ...args,
558
+ body,
559
+ method: "POST"
560
+ });
561
+ }
562
+ async joinSpaceByInvitation(spaceId, body, args) {
563
+ return this._call(`/spaces/${spaceId}/join`, {
564
+ ...args,
565
+ body,
566
+ method: "POST"
567
+ });
568
+ }
569
+ async _call(path, args) {
570
+ const requestContext = args.context ?? new Context2(void 0, {
571
+ F: __dxlog_file3,
572
+ L: 54
573
+ });
574
+ const shouldRetry = createRetryHandler(args);
575
+ const request = createRequest(args);
576
+ const url = `${this._baseUrl}${path.startsWith("/") ? path.slice(1) : path}`;
577
+ log3.info("call", {
578
+ method: args.method,
579
+ path
580
+ }, {
581
+ F: __dxlog_file3,
582
+ L: 59,
583
+ S: this,
584
+ C: (f, a) => f(...a)
585
+ });
586
+ while (true) {
587
+ let processingError;
588
+ let retryAfterHeaderValue = Number.NaN;
589
+ try {
590
+ const response = await fetch(url, request);
591
+ retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
592
+ if (response.ok) {
593
+ const body = await response.json();
594
+ if (body.success) {
595
+ return body.data;
596
+ }
597
+ if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
598
+ processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
599
+ } else {
600
+ processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
601
+ }
602
+ } else {
603
+ processingError = EdgeCallFailedError.fromHttpFailure(response);
604
+ }
605
+ } catch (error) {
606
+ processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
607
+ }
608
+ if (processingError.isRetryable && await shouldRetry(requestContext, retryAfterHeaderValue)) {
609
+ log3.info("retrying edge request", {
610
+ path,
611
+ processingError
612
+ }, {
613
+ F: __dxlog_file3,
614
+ L: 88,
615
+ S: this,
616
+ C: (f, a) => f(...a)
617
+ });
618
+ } else {
619
+ throw processingError;
620
+ }
621
+ }
622
+ }
623
+ };
624
+ var createRequest = (args) => {
625
+ return {
626
+ method: args.method,
627
+ body: args.body && JSON.stringify(args.body)
628
+ };
629
+ };
630
+ var createRetryHandler = (args) => {
631
+ if (!args.retry || args.retry.count < 1) {
632
+ return async () => false;
633
+ }
634
+ let retries = 0;
635
+ const maxRetries = args.retry.count ?? DEFAULT_MAX_RETRIES_COUNT;
636
+ const baseTimeout = args.retry.timeout ?? DEFAULT_RETRY_TIMEOUT;
637
+ const jitter = args.retry.jitter ?? DEFAULT_RETRY_JITTER;
638
+ return async (ctx, retryAfter) => {
639
+ if (++retries > maxRetries || ctx.disposed) {
640
+ return false;
641
+ }
642
+ if (retryAfter) {
643
+ await sleep2(retryAfter);
644
+ } else {
645
+ const timeout = baseTimeout + Math.random() * jitter;
646
+ await sleep2(timeout);
647
+ }
648
+ return true;
649
+ };
650
+ };
470
651
  export {
471
652
  EdgeClient,
653
+ EdgeConnectionClosedError,
654
+ EdgeHttpClient,
655
+ EdgeIdentityChangedError,
472
656
  Protocol,
657
+ createChainEdgeIdentity,
658
+ createDeviceEdgeIdentity,
659
+ createEphemeralEdgeIdentity,
660
+ createStubEdgeIdentity,
661
+ createTestHaloEdgeIdentity,
473
662
  getTypename,
474
663
  protocol,
475
664
  toUint8Array