@dxos/edge-client 0.6.11 → 0.6.12-main.2d19bf1

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