@dxos/edge-client 0.8.4-main.b97322e → 0.8.4-main.bc674ce

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 (42) hide show
  1. package/dist/lib/browser/{chunk-LMP5TVOP.mjs → chunk-VESGVCLQ.mjs} +8 -4
  2. package/dist/lib/browser/{chunk-LMP5TVOP.mjs.map → chunk-VESGVCLQ.mjs.map} +3 -3
  3. package/dist/lib/browser/edge-ws-muxer.mjs +1 -1
  4. package/dist/lib/browser/index.mjs +561 -289
  5. package/dist/lib/browser/index.mjs.map +4 -4
  6. package/dist/lib/browser/meta.json +1 -1
  7. package/dist/lib/browser/testing/index.mjs +1 -1
  8. package/dist/lib/browser/testing/index.mjs.map +2 -2
  9. package/dist/lib/node-esm/{chunk-X7J46ISZ.mjs → chunk-JTBFRYNM.mjs} +8 -4
  10. package/dist/lib/node-esm/{chunk-X7J46ISZ.mjs.map → chunk-JTBFRYNM.mjs.map} +3 -3
  11. package/dist/lib/node-esm/edge-ws-muxer.mjs +1 -1
  12. package/dist/lib/node-esm/index.mjs +561 -289
  13. package/dist/lib/node-esm/index.mjs.map +4 -4
  14. package/dist/lib/node-esm/meta.json +1 -1
  15. package/dist/lib/node-esm/testing/index.mjs +1 -1
  16. package/dist/lib/node-esm/testing/index.mjs.map +2 -2
  17. package/dist/types/src/edge-client.d.ts +15 -15
  18. package/dist/types/src/edge-client.d.ts.map +1 -1
  19. package/dist/types/src/edge-http-client.d.ts +29 -4
  20. package/dist/types/src/edge-http-client.d.ts.map +1 -1
  21. package/dist/types/src/edge-ws-connection.d.ts +19 -0
  22. package/dist/types/src/edge-ws-connection.d.ts.map +1 -1
  23. package/dist/types/src/edge-ws-muxer.d.ts.map +1 -1
  24. package/dist/types/src/http-client.d.ts +10 -7
  25. package/dist/types/src/http-client.d.ts.map +1 -1
  26. package/dist/types/src/index.d.ts +4 -3
  27. package/dist/types/src/index.d.ts.map +1 -1
  28. package/dist/types/src/testing/test-utils.d.ts +3 -3
  29. package/dist/types/src/testing/test-utils.d.ts.map +1 -1
  30. package/dist/types/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +25 -17
  32. package/src/edge-client.test.ts +4 -4
  33. package/src/edge-client.ts +73 -42
  34. package/src/edge-http-client.test.ts +1 -1
  35. package/src/edge-http-client.ts +202 -42
  36. package/src/edge-ws-connection.ts +119 -6
  37. package/src/edge-ws-muxer.ts +1 -1
  38. package/src/http-client.test.ts +11 -7
  39. package/src/http-client.ts +18 -8
  40. package/src/index.ts +4 -3
  41. package/src/testing/test-utils.ts +8 -8
  42. package/src/websocket.test.ts +1 -1
@@ -6,24 +6,135 @@ import {
6
6
  getTypename,
7
7
  protocol,
8
8
  toUint8Array
9
- } from "./chunk-LMP5TVOP.mjs";
9
+ } from "./chunk-VESGVCLQ.mjs";
10
10
 
11
11
  // src/index.ts
12
12
  export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
13
13
 
14
+ // src/auth.ts
15
+ import { createCredential, signPresentation } from "@dxos/credentials";
16
+ import { invariant } from "@dxos/invariant";
17
+ import { Keyring } from "@dxos/keyring";
18
+ import { PublicKey } from "@dxos/keys";
19
+ var __dxlog_file = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/auth.ts";
20
+ var createDeviceEdgeIdentity = async (signer, key) => {
21
+ return {
22
+ identityKey: key.toHex(),
23
+ peerKey: key.toHex(),
24
+ presentCredentials: async ({ challenge }) => {
25
+ return signPresentation({
26
+ presentation: {
27
+ credentials: [
28
+ // Verifier requires at least one credential in the presentation to establish the subject.
29
+ await createCredential({
30
+ assertion: {
31
+ "@type": "dxos.halo.credentials.Auth"
32
+ },
33
+ issuer: key,
34
+ subject: key,
35
+ signer
36
+ })
37
+ ]
38
+ },
39
+ signer,
40
+ signerKey: key,
41
+ nonce: challenge
42
+ });
43
+ }
44
+ };
45
+ };
46
+ var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
47
+ const credentialsToSign = credentials.length > 0 ? credentials : [
48
+ await createCredential({
49
+ assertion: {
50
+ "@type": "dxos.halo.credentials.Auth"
51
+ },
52
+ issuer: identityKey,
53
+ subject: identityKey,
54
+ signer,
55
+ chain,
56
+ signingKey: peerKey
57
+ })
58
+ ];
59
+ return {
60
+ identityKey: identityKey.toHex(),
61
+ peerKey: peerKey.toHex(),
62
+ presentCredentials: async ({ challenge }) => {
63
+ invariant(chain, void 0, {
64
+ F: __dxlog_file,
65
+ L: 75,
66
+ S: void 0,
67
+ A: [
68
+ "chain",
69
+ ""
70
+ ]
71
+ });
72
+ return signPresentation({
73
+ presentation: {
74
+ credentials: credentialsToSign
75
+ },
76
+ signer,
77
+ nonce: challenge,
78
+ signerKey: peerKey,
79
+ chain
80
+ });
81
+ }
82
+ };
83
+ };
84
+ var createEphemeralEdgeIdentity = async () => {
85
+ const keyring = new Keyring();
86
+ const key = await keyring.createKey();
87
+ return createDeviceEdgeIdentity(keyring, key);
88
+ };
89
+ var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
90
+ const deviceAdmission = await createCredential({
91
+ assertion: {
92
+ "@type": "dxos.halo.credentials.AuthorizedDevice",
93
+ deviceKey,
94
+ identityKey
95
+ },
96
+ issuer: identityKey,
97
+ subject: deviceKey,
98
+ signer
99
+ });
100
+ return createChainEdgeIdentity(signer, identityKey, deviceKey, {
101
+ credential: deviceAdmission
102
+ }, [
103
+ await createCredential({
104
+ assertion: {
105
+ "@type": "dxos.halo.credentials.Auth"
106
+ },
107
+ issuer: identityKey,
108
+ subject: identityKey,
109
+ signer
110
+ })
111
+ ]);
112
+ };
113
+ var createStubEdgeIdentity = () => {
114
+ const identityKey = PublicKey.random();
115
+ const deviceKey = PublicKey.random();
116
+ return {
117
+ identityKey: identityKey.toHex(),
118
+ peerKey: deviceKey.toHex(),
119
+ presentCredentials: async () => {
120
+ throw new Error("Stub identity does not support authentication.");
121
+ }
122
+ };
123
+ };
124
+
14
125
  // src/edge-client.ts
15
- import { Trigger, scheduleMicroTask, TriggerState, PersistentLifecycle, Event } from "@dxos/async";
126
+ import { Event, PersistentLifecycle, Trigger, TriggerState, scheduleMicroTask, scheduleTaskInterval as scheduleTaskInterval2 } from "@dxos/async";
16
127
  import { Resource as Resource2 } from "@dxos/context";
17
128
  import { log as log2, logInfo as logInfo2 } from "@dxos/log";
18
129
  import { EdgeStatus } from "@dxos/protocols/proto/dxos/client/services";
19
130
 
20
131
  // src/edge-identity.ts
21
- import { invariant } from "@dxos/invariant";
132
+ import { invariant as invariant2 } from "@dxos/invariant";
22
133
  import { schema } from "@dxos/protocols/proto";
23
- var __dxlog_file = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-identity.ts";
134
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-identity.ts";
24
135
  var handleAuthChallenge = async (failedResponse, identity) => {
25
- invariant(failedResponse.status === 401, void 0, {
26
- F: __dxlog_file,
136
+ invariant2(failedResponse.status === 401, void 0, {
137
+ F: __dxlog_file2,
27
138
  L: 21,
28
139
  S: void 0,
29
140
  A: [
@@ -32,8 +143,8 @@ var handleAuthChallenge = async (failedResponse, identity) => {
32
143
  ]
33
144
  });
34
145
  const headerValue = failedResponse.headers.get("Www-Authenticate");
35
- invariant(headerValue?.startsWith("VerifiablePresentation challenge="), void 0, {
36
- F: __dxlog_file,
146
+ invariant2(headerValue?.startsWith("VerifiablePresentation challenge="), void 0, {
147
+ F: __dxlog_file2,
37
148
  L: 24,
38
149
  S: void 0,
39
150
  A: [
@@ -42,8 +153,8 @@ var handleAuthChallenge = async (failedResponse, identity) => {
42
153
  ]
43
154
  });
44
155
  const challenge = headerValue?.slice("VerifiablePresentation challenge=".length);
45
- invariant(challenge, void 0, {
46
- F: __dxlog_file,
156
+ invariant2(challenge, void 0, {
157
+ F: __dxlog_file2,
47
158
  L: 27,
48
159
  S: void 0,
49
160
  A: [
@@ -61,7 +172,7 @@ var handleAuthChallenge = async (failedResponse, identity) => {
61
172
  import WebSocket from "isomorphic-ws";
62
173
  import { scheduleTask, scheduleTaskInterval } from "@dxos/async";
63
174
  import { Context, Resource } from "@dxos/context";
64
- import { invariant as invariant2 } from "@dxos/invariant";
175
+ import { invariant as invariant3 } from "@dxos/invariant";
65
176
  import { log, logInfo } from "@dxos/log";
66
177
  import { EdgeWebsocketProtocol } from "@dxos/protocols";
67
178
  import { buf } from "@dxos/protocols/buf";
@@ -72,12 +183,31 @@ function _ts_decorate(decorators, target, key, desc) {
72
183
  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;
73
184
  return c > 3 && r && Object.defineProperty(target, key, r), r;
74
185
  }
75
- var __dxlog_file2 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-ws-connection.ts";
186
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-ws-connection.ts";
76
187
  var SIGNAL_KEEPALIVE_INTERVAL = 4e3;
77
188
  var SIGNAL_KEEPALIVE_TIMEOUT = 12e3;
78
189
  var EdgeWsConnection = class extends Resource {
190
+ _identity;
191
+ _connectionInfo;
192
+ _callbacks;
193
+ _inactivityTimeoutCtx;
194
+ _ws;
195
+ _wsMuxer;
196
+ _lastReceivedMessageTimestamp = Date.now();
197
+ _openTimestamp;
198
+ // Latency tracking.
199
+ _pingTimestamp;
200
+ _rtt = 0;
201
+ // Rate tracking with sliding window.
202
+ _uploadRate = 0;
203
+ _downloadRate = 0;
204
+ _rateWindow = 1e4;
205
+ _rateUpdateInterval = 1e3;
206
+ _bytesSamples = [];
207
+ _messagesSent = 0;
208
+ _messagesReceived = 0;
79
209
  constructor(_identity, _connectionInfo, _callbacks) {
80
- super(), this._identity = _identity, this._connectionInfo = _connectionInfo, this._callbacks = _callbacks, this._lastReceivedMessageTimestamp = Date.now();
210
+ super(), this._identity = _identity, this._connectionInfo = _connectionInfo, this._callbacks = _callbacks;
81
211
  }
82
212
  get info() {
83
213
  return {
@@ -86,19 +216,37 @@ var EdgeWsConnection = class extends Resource {
86
216
  device: this._identity.peerKey
87
217
  };
88
218
  }
219
+ get rtt() {
220
+ return this._rtt;
221
+ }
222
+ get uptime() {
223
+ return this._openTimestamp ? (Date.now() - this._openTimestamp) / 1e3 : 0;
224
+ }
225
+ get uploadRate() {
226
+ return this._uploadRate;
227
+ }
228
+ get downloadRate() {
229
+ return this._downloadRate;
230
+ }
231
+ get messagesSent() {
232
+ return this._messagesSent;
233
+ }
234
+ get messagesReceived() {
235
+ return this._messagesReceived;
236
+ }
89
237
  send(message) {
90
- invariant2(this._ws, void 0, {
91
- F: __dxlog_file2,
92
- L: 53,
238
+ invariant3(this._ws, void 0, {
239
+ F: __dxlog_file3,
240
+ L: 93,
93
241
  S: this,
94
242
  A: [
95
243
  "this._ws",
96
244
  ""
97
245
  ]
98
246
  });
99
- invariant2(this._wsMuxer, void 0, {
100
- F: __dxlog_file2,
101
- L: 54,
247
+ invariant3(this._wsMuxer, void 0, {
248
+ F: __dxlog_file3,
249
+ L: 94,
102
250
  S: this,
103
251
  A: [
104
252
  "this._wsMuxer",
@@ -109,11 +257,12 @@ var EdgeWsConnection = class extends Resource {
109
257
  peerKey: this._identity.peerKey,
110
258
  payload: protocol.getPayloadType(message)
111
259
  }, {
112
- F: __dxlog_file2,
113
- L: 55,
260
+ F: __dxlog_file3,
261
+ L: 95,
114
262
  S: this,
115
263
  C: (f, a) => f(...a)
116
264
  });
265
+ this._messagesSent++;
117
266
  if (this._ws?.protocol.includes(EdgeWebsocketProtocol.V0)) {
118
267
  const binary = buf.toBinary(MessageSchema, message);
119
268
  if (binary.length > CLOUDFLARE_MESSAGE_MAX_BYTES) {
@@ -122,18 +271,21 @@ var EdgeWsConnection = class extends Resource {
122
271
  serviceId: message.serviceId,
123
272
  payload: protocol.getPayloadType(message)
124
273
  }, {
125
- F: __dxlog_file2,
126
- L: 59,
274
+ F: __dxlog_file3,
275
+ L: 100,
127
276
  S: this,
128
277
  C: (f, a) => f(...a)
129
278
  });
130
279
  return;
131
280
  }
281
+ this._recordBytes(binary.byteLength, 0);
132
282
  this._ws.send(binary);
133
283
  } else {
284
+ const binary = buf.toBinary(MessageSchema, message);
285
+ this._recordBytes(binary.byteLength, 0);
134
286
  this._wsMuxer.send(message).catch((e) => log.catch(e, void 0, {
135
- F: __dxlog_file2,
136
- L: 68,
287
+ F: __dxlog_file3,
288
+ L: 113,
137
289
  S: this,
138
290
  C: (f, a) => f(...a)
139
291
  }));
@@ -154,19 +306,21 @@ var EdgeWsConnection = class extends Resource {
154
306
  this._ws.onopen = () => {
155
307
  if (this.isOpen) {
156
308
  log("connected", void 0, {
157
- F: __dxlog_file2,
158
- L: 85,
309
+ F: __dxlog_file3,
310
+ L: 130,
159
311
  S: this,
160
312
  C: (f, a) => f(...a)
161
313
  });
314
+ this._openTimestamp = Date.now();
162
315
  this._callbacks.onConnected();
163
316
  this._scheduleHeartbeats();
317
+ this._scheduleRateCalculation();
164
318
  } else {
165
319
  log.verbose("connected after becoming inactive", {
166
320
  currentIdentity: this._identity
167
321
  }, {
168
- F: __dxlog_file2,
169
- L: 89,
322
+ F: __dxlog_file3,
323
+ L: 136,
170
324
  S: this,
171
325
  C: (f, a) => f(...a)
172
326
  });
@@ -174,12 +328,12 @@ var EdgeWsConnection = class extends Resource {
174
328
  };
175
329
  this._ws.onclose = (event) => {
176
330
  if (this.isOpen) {
177
- log.warn("disconnected while being open", {
331
+ log.warn("server disconnected", {
178
332
  code: event.code,
179
333
  reason: event.reason
180
334
  }, {
181
- F: __dxlog_file2,
182
- L: 94,
335
+ F: __dxlog_file3,
336
+ L: 141,
183
337
  S: this,
184
338
  C: (f, a) => f(...a)
185
339
  });
@@ -193,8 +347,8 @@ var EdgeWsConnection = class extends Resource {
193
347
  error: event.error,
194
348
  info: event.message
195
349
  }, {
196
- F: __dxlog_file2,
197
- L: 101,
350
+ F: __dxlog_file3,
351
+ L: 148,
198
352
  S: this,
199
353
  C: (f, a) => f(...a)
200
354
  });
@@ -203,8 +357,8 @@ var EdgeWsConnection = class extends Resource {
203
357
  log.verbose("error ignored on closed connection", {
204
358
  error: event.error
205
359
  }, {
206
- F: __dxlog_file2,
207
- L: 104,
360
+ F: __dxlog_file3,
361
+ L: 151,
208
362
  S: this,
209
363
  C: (f, a) => f(...a)
210
364
  });
@@ -215,8 +369,8 @@ var EdgeWsConnection = class extends Resource {
215
369
  log.verbose("message ignored on closed connection", {
216
370
  event: event.type
217
371
  }, {
218
- F: __dxlog_file2,
219
- L: 112,
372
+ F: __dxlog_file3,
373
+ L: 159,
220
374
  S: this,
221
375
  C: (f, a) => f(...a)
222
376
  });
@@ -224,21 +378,27 @@ var EdgeWsConnection = class extends Resource {
224
378
  }
225
379
  this._lastReceivedMessageTimestamp = Date.now();
226
380
  if (event.data === "__pong__") {
381
+ if (this._pingTimestamp) {
382
+ this._rtt = Date.now() - this._pingTimestamp;
383
+ this._pingTimestamp = void 0;
384
+ }
227
385
  this._rescheduleHeartbeatTimeout();
228
386
  return;
229
387
  }
230
388
  const bytes = await toUint8Array(event.data);
389
+ this._recordBytes(0, bytes.byteLength);
231
390
  if (!this.isOpen) {
232
391
  return;
233
392
  }
393
+ this._messagesReceived++;
234
394
  const message = this._ws?.protocol?.includes(EdgeWebsocketProtocol.V0) ? buf.fromBinary(MessageSchema, bytes) : muxer.receiveData(bytes);
235
395
  if (message) {
236
396
  log("received", {
237
397
  from: message.source,
238
398
  payload: protocol.getPayloadType(message)
239
399
  }, {
240
- F: __dxlog_file2,
241
- L: 130,
400
+ F: __dxlog_file3,
401
+ L: 185,
242
402
  S: this,
243
403
  C: (f, a) => f(...a)
244
404
  });
@@ -258,20 +418,20 @@ var EdgeWsConnection = class extends Resource {
258
418
  if (err instanceof Error && err.message.includes("WebSocket is closed before the connection is established.")) {
259
419
  return;
260
420
  }
261
- log.warn("Error closing websocket", {
421
+ log.warn("error closing websocket", {
262
422
  err
263
423
  }, {
264
- F: __dxlog_file2,
265
- L: 148,
424
+ F: __dxlog_file3,
425
+ L: 203,
266
426
  S: this,
267
427
  C: (f, a) => f(...a)
268
428
  });
269
429
  }
270
430
  }
271
431
  _scheduleHeartbeats() {
272
- invariant2(this._ws, void 0, {
273
- F: __dxlog_file2,
274
- L: 153,
432
+ invariant3(this._ws, void 0, {
433
+ F: __dxlog_file3,
434
+ L: 208,
275
435
  S: this,
276
436
  A: [
277
437
  "this._ws",
@@ -279,8 +439,10 @@ var EdgeWsConnection = class extends Resource {
279
439
  ]
280
440
  });
281
441
  scheduleTaskInterval(this._ctx, async () => {
442
+ this._pingTimestamp = Date.now();
282
443
  this._ws?.send("__ping__");
283
444
  }, SIGNAL_KEEPALIVE_INTERVAL);
445
+ this._pingTimestamp = Date.now();
284
446
  this._ws.send("__ping__");
285
447
  this._rescheduleHeartbeatTimeout();
286
448
  }
@@ -290,8 +452,8 @@ var EdgeWsConnection = class extends Resource {
290
452
  }
291
453
  void this._inactivityTimeoutCtx?.dispose();
292
454
  this._inactivityTimeoutCtx = new Context(void 0, {
293
- F: __dxlog_file2,
294
- L: 172
455
+ F: __dxlog_file3,
456
+ L: 229
295
457
  });
296
458
  scheduleTask(this._inactivityTimeoutCtx, () => {
297
459
  if (this.isOpen) {
@@ -299,8 +461,8 @@ var EdgeWsConnection = class extends Resource {
299
461
  log.warn("restart due to inactivity timeout", {
300
462
  lastReceivedMessageTimestamp: this._lastReceivedMessageTimestamp
301
463
  }, {
302
- F: __dxlog_file2,
303
- L: 178,
464
+ F: __dxlog_file3,
465
+ L: 235,
304
466
  S: this,
305
467
  C: (f, a) => f(...a)
306
468
  });
@@ -311,6 +473,47 @@ var EdgeWsConnection = class extends Resource {
311
473
  }
312
474
  }, SIGNAL_KEEPALIVE_TIMEOUT);
313
475
  }
476
+ _recordBytes(sent, received) {
477
+ const now = Date.now();
478
+ const currentSecond = Math.floor(now / 1e3) * 1e3;
479
+ const existingSample = this._bytesSamples.find((s) => Math.floor(s.timestamp / 1e3) * 1e3 === currentSecond);
480
+ if (existingSample) {
481
+ existingSample.sent += sent;
482
+ existingSample.received += received;
483
+ } else {
484
+ this._bytesSamples.push({
485
+ timestamp: now,
486
+ sent,
487
+ received
488
+ });
489
+ }
490
+ }
491
+ _scheduleRateCalculation() {
492
+ scheduleTaskInterval(this._ctx, async () => {
493
+ this._calculateRates();
494
+ }, this._rateUpdateInterval);
495
+ this._calculateRates();
496
+ }
497
+ _calculateRates() {
498
+ const now = Date.now();
499
+ const cutoff = now - this._rateWindow;
500
+ this._bytesSamples = this._bytesSamples.filter((s) => s.timestamp > cutoff);
501
+ if (this._bytesSamples.length === 0) {
502
+ this._uploadRate = 0;
503
+ this._downloadRate = 0;
504
+ return;
505
+ }
506
+ let totalSent = 0;
507
+ let totalReceived = 0;
508
+ const oldestTimestamp = Math.min(...this._bytesSamples.map((s) => s.timestamp));
509
+ const timeSpan = (now - oldestTimestamp) / 1e3;
510
+ for (const sample of this._bytesSamples) {
511
+ totalSent += sample.sent;
512
+ totalReceived += sample.received;
513
+ }
514
+ this._uploadRate = timeSpan > 0 ? Math.round(totalSent / timeSpan) : 0;
515
+ this._downloadRate = timeSpan > 0 ? Math.round(totalReceived / timeSpan) : 0;
516
+ }
314
517
  };
315
518
  _ts_decorate([
316
519
  logInfo
@@ -343,14 +546,25 @@ function _ts_decorate2(decorators, target, key, desc) {
343
546
  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;
344
547
  return c > 3 && r && Object.defineProperty(target, key, r), r;
345
548
  }
346
- var __dxlog_file3 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
549
+ var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
347
550
  var DEFAULT_TIMEOUT = 1e4;
551
+ var STATUS_REFRESH_INTERVAL = 1e3;
348
552
  var EdgeClient = class extends Resource2 {
553
+ _identity;
554
+ _config;
555
+ statusChanged = new Event();
556
+ _persistentLifecycle = new PersistentLifecycle({
557
+ start: async () => this._connect(),
558
+ stop: async (state) => this._disconnect(state)
559
+ });
560
+ _messageListeners = /* @__PURE__ */ new Set();
561
+ _reconnectListeners = /* @__PURE__ */ new Set();
562
+ _baseWsUrl;
563
+ _baseHttpUrl;
564
+ _currentConnection = void 0;
565
+ _ready = new Trigger();
349
566
  constructor(_identity, _config) {
350
- super(), this._identity = _identity, this._config = _config, this.statusChanged = new Event(), this._persistentLifecycle = new PersistentLifecycle({
351
- start: async () => this._connect(),
352
- stop: async (state) => this._disconnect(state)
353
- }), this._messageListeners = /* @__PURE__ */ new Set(), this._reconnectListeners = /* @__PURE__ */ new Set(), this._currentConnection = void 0, this._ready = new Trigger(), this._isActive = (connection) => connection === this._currentConnection;
567
+ super(), this._identity = _identity, this._config = _config;
354
568
  this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
355
569
  this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
356
570
  }
@@ -363,7 +577,15 @@ var EdgeClient = class extends Resource2 {
363
577
  };
364
578
  }
365
579
  get status() {
366
- return Boolean(this._currentConnection) && this._ready.state === TriggerState.RESOLVED ? EdgeStatus.CONNECTED : EdgeStatus.NOT_CONNECTED;
580
+ return {
581
+ state: Boolean(this._currentConnection) && this._ready.state === TriggerState.RESOLVED ? EdgeStatus.ConnectionState.CONNECTED : EdgeStatus.ConnectionState.NOT_CONNECTED,
582
+ uptime: this._currentConnection?.uptime ?? 0,
583
+ rtt: this._currentConnection?.rtt ?? 0,
584
+ rateBytesUp: this._currentConnection?.uploadRate ?? 0,
585
+ rateBytesDown: this._currentConnection?.downloadRate ?? 0,
586
+ messagesSent: this._currentConnection?.messagesSent ?? 0,
587
+ messagesReceived: this._currentConnection?.messagesReceived ?? 0
588
+ };
367
589
  }
368
590
  get identityKey() {
369
591
  return this._identity.identityKey;
@@ -377,8 +599,8 @@ var EdgeClient = class extends Resource2 {
377
599
  identity,
378
600
  oldIdentity: this._identity
379
601
  }, {
380
- F: __dxlog_file3,
381
- L: 99,
602
+ F: __dxlog_file4,
603
+ L: 118,
382
604
  S: this,
383
605
  C: (f, a) => f(...a)
384
606
  });
@@ -387,6 +609,30 @@ var EdgeClient = class extends Resource2 {
387
609
  void this._persistentLifecycle.scheduleRestart();
388
610
  }
389
611
  }
612
+ /**
613
+ * Send message.
614
+ * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.
615
+ */
616
+ async send(message) {
617
+ if (this._ready.state !== TriggerState.RESOLVED) {
618
+ log2("waiting for websocket", void 0, {
619
+ F: __dxlog_file4,
620
+ L: 131,
621
+ S: this,
622
+ C: (f, a) => f(...a)
623
+ });
624
+ await this._ready.wait({
625
+ timeout: this._config.timeout ?? DEFAULT_TIMEOUT
626
+ });
627
+ }
628
+ if (!this._currentConnection) {
629
+ throw new EdgeConnectionClosedError();
630
+ }
631
+ if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
632
+ throw new EdgeIdentityChangedError();
633
+ }
634
+ this._currentConnection.send(message);
635
+ }
390
636
  onMessage(listener) {
391
637
  this._messageListeners.add(listener);
392
638
  return () => this._messageListeners.delete(listener);
@@ -400,8 +646,8 @@ var EdgeClient = class extends Resource2 {
400
646
  listener();
401
647
  } catch (error) {
402
648
  log2.catch(error, void 0, {
403
- F: __dxlog_file3,
404
- L: 121,
649
+ F: __dxlog_file4,
650
+ L: 164,
405
651
  S: this,
406
652
  C: (f, a) => f(...a)
407
653
  });
@@ -418,8 +664,8 @@ var EdgeClient = class extends Resource2 {
418
664
  log2("opening...", {
419
665
  info: this.info
420
666
  }, {
421
- F: __dxlog_file3,
422
- L: 133,
667
+ F: __dxlog_file4,
668
+ L: 177,
423
669
  S: this,
424
670
  C: (f, a) => f(...a)
425
671
  });
@@ -427,12 +673,18 @@ var EdgeClient = class extends Resource2 {
427
673
  log2.warn("Error while opening connection", {
428
674
  err
429
675
  }, {
430
- F: __dxlog_file3,
431
- L: 135,
676
+ F: __dxlog_file4,
677
+ L: 179,
432
678
  S: this,
433
679
  C: (f, a) => f(...a)
434
680
  });
435
681
  });
682
+ scheduleTaskInterval2(this._ctx, async () => {
683
+ if (!this._currentConnection) {
684
+ return;
685
+ }
686
+ this.statusChanged.emit(this.status);
687
+ }, STATUS_REFRESH_INTERVAL);
436
688
  }
437
689
  /**
438
690
  * Close connection and free resources.
@@ -441,8 +693,8 @@ var EdgeClient = class extends Resource2 {
441
693
  log2("closing...", {
442
694
  peerKey: this._identity.peerKey
443
695
  }, {
444
- F: __dxlog_file3,
445
- L: 143,
696
+ F: __dxlog_file4,
697
+ L: 199,
446
698
  S: this,
447
699
  C: (f, a) => f(...a)
448
700
  });
@@ -458,8 +710,8 @@ var EdgeClient = class extends Resource2 {
458
710
  const protocolHeader = this._config.disableAuth ? void 0 : await this._createAuthHeader(path);
459
711
  if (this._identity !== identity) {
460
712
  log2("identity changed during auth header request", void 0, {
461
- F: __dxlog_file3,
462
- L: 157,
713
+ F: __dxlog_file4,
714
+ L: 213,
463
715
  S: this,
464
716
  C: (f, a) => f(...a)
465
717
  });
@@ -471,8 +723,8 @@ var EdgeClient = class extends Resource2 {
471
723
  url: url.toString(),
472
724
  protocolHeader
473
725
  }, {
474
- F: __dxlog_file3,
475
- L: 163,
726
+ F: __dxlog_file4,
727
+ L: 219,
476
728
  S: this,
477
729
  C: (f, a) => f(...a)
478
730
  });
@@ -486,8 +738,8 @@ var EdgeClient = class extends Resource2 {
486
738
  this._notifyReconnected();
487
739
  } else {
488
740
  log2.verbose("connected callback ignored, because connection is not active", void 0, {
489
- F: __dxlog_file3,
490
- L: 173,
741
+ F: __dxlog_file4,
742
+ L: 229,
491
743
  S: this,
492
744
  C: (f, a) => f(...a)
493
745
  });
@@ -499,8 +751,8 @@ var EdgeClient = class extends Resource2 {
499
751
  void this._persistentLifecycle.scheduleRestart();
500
752
  } else {
501
753
  log2.verbose("restart requested by inactive connection", void 0, {
502
- F: __dxlog_file3,
503
- L: 181,
754
+ F: __dxlog_file4,
755
+ L: 237,
504
756
  S: this,
505
757
  C: (f, a) => f(...a)
506
758
  });
@@ -515,8 +767,8 @@ var EdgeClient = class extends Resource2 {
515
767
  from: message.source,
516
768
  type: message.payload?.typeUrl
517
769
  }, {
518
- F: __dxlog_file3,
519
- L: 189,
770
+ F: __dxlog_file4,
771
+ L: 245,
520
772
  S: this,
521
773
  C: (f, a) => f(...a)
522
774
  });
@@ -552,8 +804,8 @@ var EdgeClient = class extends Resource2 {
552
804
  log2.error("ws reconnect listener failed", {
553
805
  err
554
806
  }, {
555
- F: __dxlog_file3,
556
- L: 225,
807
+ F: __dxlog_file4,
808
+ L: 280,
557
809
  S: this,
558
810
  C: (f, a) => f(...a)
559
811
  });
@@ -569,38 +821,14 @@ var EdgeClient = class extends Resource2 {
569
821
  err,
570
822
  payload: protocol.getPayloadType(message)
571
823
  }, {
572
- F: __dxlog_file3,
573
- L: 235,
824
+ F: __dxlog_file4,
825
+ L: 290,
574
826
  S: this,
575
827
  C: (f, a) => f(...a)
576
828
  });
577
829
  }
578
830
  }
579
831
  }
580
- /**
581
- * Send message.
582
- * NOTE: The message is guaranteed to be delivered but the service must respond with a message to confirm processing.
583
- */
584
- async send(message) {
585
- if (this._ready.state !== TriggerState.RESOLVED) {
586
- log2("waiting for websocket to become ready", void 0, {
587
- F: __dxlog_file3,
588
- L: 246,
589
- S: this,
590
- C: (f, a) => f(...a)
591
- });
592
- await this._ready.wait({
593
- timeout: this._config.timeout ?? DEFAULT_TIMEOUT
594
- });
595
- }
596
- if (!this._currentConnection) {
597
- throw new EdgeConnectionClosedError();
598
- }
599
- if (message.source && (message.source.peerKey !== this._identity.peerKey || message.source.identityKey !== this.identityKey)) {
600
- throw new EdgeIdentityChangedError();
601
- }
602
- this._currentConnection.send(message);
603
- }
604
832
  async _createAuthHeader(path) {
605
833
  const httpUrl = new URL(path, this._baseHttpUrl);
606
834
  httpUrl.protocol = getEdgeUrlWithProtocol(this._baseWsUrl.toString(), "http");
@@ -614,14 +842,15 @@ var EdgeClient = class extends Resource2 {
614
842
  status: response.status,
615
843
  statusText: response.statusText
616
844
  }, {
617
- F: __dxlog_file3,
618
- L: 271,
845
+ F: __dxlog_file4,
846
+ L: 302,
619
847
  S: this,
620
848
  C: (f, a) => f(...a)
621
849
  });
622
850
  return void 0;
623
851
  }
624
852
  }
853
+ _isActive = (connection) => connection === this._currentConnection;
625
854
  };
626
855
  _ts_decorate2([
627
856
  logInfo2
@@ -631,144 +860,39 @@ var encodePresentationWsAuthHeader = (encodedPresentation) => {
631
860
  return `base64url.bearer.authorization.dxos.org.${encodedToken}`;
632
861
  };
633
862
 
634
- // src/auth.ts
635
- import { createCredential, signPresentation } from "@dxos/credentials";
636
- import { invariant as invariant3 } from "@dxos/invariant";
637
- import { Keyring } from "@dxos/keyring";
638
- import { PublicKey } from "@dxos/keys";
639
- var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/auth.ts";
640
- var createDeviceEdgeIdentity = async (signer, key) => {
641
- return {
642
- identityKey: key.toHex(),
643
- peerKey: key.toHex(),
644
- presentCredentials: async ({ challenge }) => {
645
- return signPresentation({
646
- presentation: {
647
- credentials: [
648
- // Verifier requires at least one credential in the presentation to establish the subject.
649
- await createCredential({
650
- assertion: {
651
- "@type": "dxos.halo.credentials.Auth"
652
- },
653
- issuer: key,
654
- subject: key,
655
- signer
656
- })
657
- ]
658
- },
659
- signer,
660
- signerKey: key,
661
- nonce: challenge
662
- });
663
- }
664
- };
665
- };
666
- var createChainEdgeIdentity = async (signer, identityKey, peerKey, chain, credentials) => {
667
- const credentialsToSign = credentials.length > 0 ? credentials : [
668
- await createCredential({
669
- assertion: {
670
- "@type": "dxos.halo.credentials.Auth"
671
- },
672
- issuer: identityKey,
673
- subject: identityKey,
674
- signer,
675
- chain,
676
- signingKey: peerKey
677
- })
678
- ];
679
- return {
680
- identityKey: identityKey.toHex(),
681
- peerKey: peerKey.toHex(),
682
- presentCredentials: async ({ challenge }) => {
683
- invariant3(chain, void 0, {
684
- F: __dxlog_file4,
685
- L: 75,
686
- S: void 0,
687
- A: [
688
- "chain",
689
- ""
690
- ]
691
- });
692
- return signPresentation({
693
- presentation: {
694
- credentials: credentialsToSign
695
- },
696
- signer,
697
- nonce: challenge,
698
- signerKey: peerKey,
699
- chain
700
- });
701
- }
702
- };
703
- };
704
- var createEphemeralEdgeIdentity = async () => {
705
- const keyring = new Keyring();
706
- const key = await keyring.createKey();
707
- return createDeviceEdgeIdentity(keyring, key);
708
- };
709
- var createTestHaloEdgeIdentity = async (signer, identityKey, deviceKey) => {
710
- const deviceAdmission = await createCredential({
711
- assertion: {
712
- "@type": "dxos.halo.credentials.AuthorizedDevice",
713
- deviceKey,
714
- identityKey
715
- },
716
- issuer: identityKey,
717
- subject: deviceKey,
718
- signer
719
- });
720
- return createChainEdgeIdentity(signer, identityKey, deviceKey, {
721
- credential: deviceAdmission
722
- }, [
723
- await createCredential({
724
- assertion: {
725
- "@type": "dxos.halo.credentials.Auth"
726
- },
727
- issuer: identityKey,
728
- subject: identityKey,
729
- signer
730
- })
731
- ]);
732
- };
733
- var createStubEdgeIdentity = () => {
734
- const identityKey = PublicKey.random();
735
- const deviceKey = PublicKey.random();
736
- return {
737
- identityKey: identityKey.toHex(),
738
- peerKey: deviceKey.toHex(),
739
- presentCredentials: async () => {
740
- throw new Error("Stub identity does not support authentication.");
741
- }
742
- };
743
- };
744
-
745
863
  // src/edge-http-client.ts
746
- import { FetchHttpClient, HttpClient } from "@effect/platform";
747
- import { Effect as Effect2, pipe } from "effect";
864
+ import * as FetchHttpClient from "@effect/platform/FetchHttpClient";
865
+ import * as HttpClient from "@effect/platform/HttpClient";
866
+ import * as Effect2 from "effect/Effect";
867
+ import * as Function from "effect/Function";
748
868
  import { sleep } from "@dxos/async";
749
869
  import { Context as Context3 } from "@dxos/context";
870
+ import { runAndForwardErrors } from "@dxos/effect";
871
+ import { invariant as invariant4 } from "@dxos/invariant";
750
872
  import { log as log4 } from "@dxos/log";
751
873
  import { EdgeAuthChallengeError, EdgeCallFailedError } from "@dxos/protocols";
752
874
  import { createUrl } from "@dxos/util";
753
875
 
754
876
  // src/http-client.ts
755
- import { Context as Context2, Duration, Effect, Layer, Schedule } from "effect";
877
+ import * as Context2 from "effect/Context";
878
+ import * as Duration from "effect/Duration";
879
+ import * as Effect from "effect/Effect";
880
+ import * as Layer from "effect/Layer";
881
+ import * as Schedule from "effect/Schedule";
756
882
  import { log as log3 } from "@dxos/log";
757
883
  var __dxlog_file5 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/http-client.ts";
758
884
  var HttpConfig = class _HttpConfig extends Context2.Tag("HttpConfig")() {
759
- static {
760
- this.default = Layer.succeed(_HttpConfig, {
761
- timeout: Duration.millis(1e3),
762
- retryTimes: 3,
763
- retryBaseDelay: Duration.millis(1e3)
764
- });
765
- }
885
+ static default = Layer.succeed(_HttpConfig, {
886
+ timeout: Duration.millis(1e3),
887
+ retryTimes: 3,
888
+ retryBaseDelay: Duration.millis(1e3)
889
+ });
766
890
  };
767
- var withRetry = (effect, { timeout = Duration.millis(1e3), retryBaseDelay = Duration.millis(1e3), retryTimes = 3 } = {}) => {
891
+ var withRetry = (effect, { timeout: timeout2 = Duration.millis(1e3), retryBaseDelay = Duration.millis(1e3), retryTimes = 3 } = {}) => {
768
892
  return effect.pipe(Effect.flatMap((res) => (
769
893
  // Treat 500 errors as retryable?
770
894
  res.status === 500 ? Effect.fail(new Error(res.status.toString())) : res.json
771
- )), Effect.timeout(timeout), Effect.retry({
895
+ )), Effect.timeout(timeout2), Effect.retry({
772
896
  schedule: Schedule.exponential(retryBaseDelay).pipe(Schedule.jittered),
773
897
  times: retryTimes
774
898
  }));
@@ -777,14 +901,16 @@ var withRetryConfig = (effect) => Effect.gen(function* () {
777
901
  const config = yield* HttpConfig;
778
902
  return yield* withRetry(effect, config);
779
903
  });
780
- var withLogging = (effect) => effect.pipe(Effect.tap((res) => log3.info("response", {
781
- status: res.status
782
- }, {
783
- F: __dxlog_file5,
784
- L: 58,
785
- S: void 0,
786
- C: (f, a) => f(...a)
787
- })));
904
+ var withLogging = (effect) => effect.pipe(Effect.tap((res) => {
905
+ log3.info("response", {
906
+ status: res.status
907
+ }, {
908
+ F: __dxlog_file5,
909
+ L: 66,
910
+ S: void 0,
911
+ C: (f, a) => f(...a)
912
+ });
913
+ }));
788
914
  var encodeAuthHeader = (challenge) => {
789
915
  const encodedChallenge = Buffer.from(challenge).toString("base64");
790
916
  return `VerifiablePresentation pb;base64,${encodedChallenge}`;
@@ -795,14 +921,21 @@ var __dxlog_file6 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-http
795
921
  var DEFAULT_RETRY_TIMEOUT = 1500;
796
922
  var DEFAULT_RETRY_JITTER = 500;
797
923
  var DEFAULT_MAX_RETRIES_COUNT = 3;
924
+ var WARNING_BODY_SIZE = 10 * 1024 * 1024;
798
925
  var EdgeHttpClient = class {
926
+ _baseUrl;
927
+ _edgeIdentity;
928
+ /**
929
+ * Auth header is cached until receiving the next 401 from EDGE, at which point it gets refreshed.
930
+ */
931
+ _authHeader;
799
932
  constructor(baseUrl) {
800
933
  this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
801
934
  log4("created", {
802
935
  url: this._baseUrl
803
936
  }, {
804
937
  F: __dxlog_file6,
805
- L: 84,
938
+ L: 107,
806
939
  S: this,
807
940
  C: (f, a) => f(...a)
808
941
  });
@@ -822,7 +955,8 @@ var EdgeHttpClient = class {
822
955
  async getStatus(args) {
823
956
  return this._call(new URL("/status", this.baseUrl), {
824
957
  ...args,
825
- method: "GET"
958
+ method: "GET",
959
+ auth: true
826
960
  });
827
961
  }
828
962
  //
@@ -880,12 +1014,6 @@ var EdgeHttpClient = class {
880
1014
  //
881
1015
  // OAuth and credentials
882
1016
  //
883
- async listFunctions(args) {
884
- return this._call(new URL("/functions", this.baseUrl), {
885
- ...args,
886
- method: "GET"
887
- });
888
- }
889
1017
  async initiateOAuthFlow(body, args) {
890
1018
  return this._call(new URL("/oauth/initiate", this.baseUrl), {
891
1019
  ...args,
@@ -907,7 +1035,16 @@ var EdgeHttpClient = class {
907
1035
  // Queues
908
1036
  //
909
1037
  async queryQueue(subspaceTag, spaceId, query, args) {
910
- const { queueId } = query;
1038
+ const queueId = query.queueIds?.[0];
1039
+ invariant4(queueId, "queueId required", {
1040
+ F: __dxlog_file6,
1041
+ L: 216,
1042
+ S: this,
1043
+ A: [
1044
+ "queueId",
1045
+ "'queueId required'"
1046
+ ]
1047
+ });
911
1048
  return this._call(createUrl(new URL(`/spaces/${subspaceTag}/${spaceId}/queue/${queueId}/query`, this.baseUrl), {
912
1049
  after: query.after,
913
1050
  before: query.before,
@@ -940,6 +1077,19 @@ var EdgeHttpClient = class {
940
1077
  // Functions
941
1078
  //
942
1079
  async uploadFunction(pathParts, body, args) {
1080
+ const formData = new FormData();
1081
+ formData.append("name", body.name ?? "");
1082
+ formData.append("version", body.version);
1083
+ formData.append("ownerPublicKey", body.ownerPublicKey);
1084
+ formData.append("entryPoint", body.entryPoint);
1085
+ body.runtime && formData.append("runtime", body.runtime);
1086
+ for (const [filename, content] of Object.entries(body.assets)) {
1087
+ formData.append("assets", new Blob([
1088
+ content
1089
+ ], {
1090
+ type: getFileMimeType(filename)
1091
+ }), filename);
1092
+ }
943
1093
  const path = [
944
1094
  "functions",
945
1095
  ...pathParts.functionId ? [
@@ -948,8 +1098,35 @@ var EdgeHttpClient = class {
948
1098
  ].join("/");
949
1099
  return this._call(new URL(path, this.baseUrl), {
950
1100
  ...args,
951
- body,
952
- method: "PUT"
1101
+ body: formData,
1102
+ method: "PUT",
1103
+ json: false
1104
+ });
1105
+ }
1106
+ async listFunctions(args) {
1107
+ return this._call(new URL("/functions", this.baseUrl), {
1108
+ ...args,
1109
+ method: "GET"
1110
+ });
1111
+ }
1112
+ async invokeFunction(params, input, args) {
1113
+ const url = new URL(`/functions/${params.functionId}`, this.baseUrl);
1114
+ if (params.version) {
1115
+ url.searchParams.set("version", params.version);
1116
+ }
1117
+ if (params.spaceId) {
1118
+ url.searchParams.set("spaceId", params.spaceId.toString());
1119
+ }
1120
+ if (params.cpuTimeLimit) {
1121
+ url.searchParams.set("cpuTimeLimit", params.cpuTimeLimit.toString());
1122
+ }
1123
+ if (params.subrequestsLimit) {
1124
+ url.searchParams.set("subrequestsLimit", params.subrequestsLimit.toString());
1125
+ }
1126
+ return this._call(url, {
1127
+ ...args,
1128
+ body: input,
1129
+ method: "POST"
953
1130
  });
954
1131
  }
955
1132
  //
@@ -963,71 +1140,138 @@ var EdgeHttpClient = class {
963
1140
  });
964
1141
  }
965
1142
  //
1143
+ // Triggers
1144
+ //
1145
+ async getCronTriggers(spaceId) {
1146
+ return this._call(new URL(`/test/functions/${spaceId}/triggers/crons`, this.baseUrl), {
1147
+ method: "GET"
1148
+ });
1149
+ }
1150
+ async forceRunCronTrigger(spaceId, triggerId) {
1151
+ return this._call(new URL(`/test/functions/${spaceId}/triggers/crons/${triggerId}/run`, this.baseUrl), {
1152
+ method: "POST"
1153
+ });
1154
+ }
1155
+ //
1156
+ // Import/Export space.
1157
+ //
1158
+ async importBundle(spaceId, body, args) {
1159
+ return this._call(new URL(`/spaces/${spaceId}/import`, this.baseUrl), {
1160
+ ...args,
1161
+ body,
1162
+ method: "PUT"
1163
+ });
1164
+ }
1165
+ async exportBundle(spaceId, body, args) {
1166
+ return this._call(new URL(`/spaces/${spaceId}/export`, this.baseUrl), {
1167
+ ...args,
1168
+ body,
1169
+ method: "POST"
1170
+ });
1171
+ }
1172
+ //
966
1173
  // Internal
967
1174
  //
968
- async _fetch(url, args) {
969
- return pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"), Effect2.runPromise);
1175
+ async _fetch(url, _args) {
1176
+ return Function.pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"), runAndForwardErrors);
970
1177
  }
971
1178
  // TODO(burdon): Refactor with effect (see edge-http-client.test.ts).
972
1179
  async _call(url, args) {
973
1180
  const shouldRetry = createRetryHandler(args);
974
- const requestContext = args.context ?? new Context3(void 0, {
1181
+ const requestContext = args.context ?? Context3.default(void 0, {
975
1182
  F: __dxlog_file6,
976
- L: 293
1183
+ L: 408
977
1184
  });
978
1185
  log4("fetch", {
979
1186
  url,
980
1187
  request: args.body
981
1188
  }, {
982
1189
  F: __dxlog_file6,
983
- L: 294,
1190
+ L: 409,
984
1191
  S: this,
985
1192
  C: (f, a) => f(...a)
986
1193
  });
987
1194
  let handledAuth = false;
1195
+ const tryCount = 1;
988
1196
  while (true) {
989
- let processingError;
990
- let retryAfterHeaderValue = Number.NaN;
1197
+ let processingError = void 0;
991
1198
  try {
1199
+ if (!this._authHeader && args.auth) {
1200
+ const response2 = await fetch(new URL(`/auth`, this.baseUrl));
1201
+ if (response2.status === 401) {
1202
+ this._authHeader = await this._handleUnauthorized(response2);
1203
+ }
1204
+ }
992
1205
  const request = createRequest(args, this._authHeader);
1206
+ log4("call edge", {
1207
+ url,
1208
+ tryCount,
1209
+ authHeader: !!this._authHeader
1210
+ }, {
1211
+ F: __dxlog_file6,
1212
+ L: 424,
1213
+ S: this,
1214
+ C: (f, a) => f(...a)
1215
+ });
993
1216
  const response = await fetch(url, request);
994
- retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
995
1217
  if (response.ok) {
996
- const body = await response.json();
997
- if (body.success) {
998
- return body.data;
999
- }
1000
- log4.warn("unsuccessful edge response", {
1001
- url,
1002
- body
1003
- }, {
1218
+ const body2 = await response.clone().json();
1219
+ invariant4(body2, "Expected body to be present", {
1004
1220
  F: __dxlog_file6,
1005
- L: 310,
1221
+ L: 429,
1006
1222
  S: this,
1007
- C: (f, a) => f(...a)
1223
+ A: [
1224
+ "body",
1225
+ "'Expected body to be present'"
1226
+ ]
1008
1227
  });
1009
- if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
1010
- processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
1011
- } else {
1012
- processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
1228
+ if (!("success" in body2)) {
1229
+ return body2;
1230
+ }
1231
+ if (body2.success) {
1232
+ return body2.data;
1013
1233
  }
1014
1234
  } else if (response.status === 401 && !handledAuth) {
1015
1235
  this._authHeader = await this._handleUnauthorized(response);
1016
1236
  handledAuth = true;
1017
1237
  continue;
1238
+ }
1239
+ const body = response.headers.get("Content-Type") === "application/json" ? await response.clone().json() : void 0;
1240
+ invariant4(!body?.success, "Expected body to not be a failure response or undefined.", {
1241
+ F: __dxlog_file6,
1242
+ L: 445,
1243
+ S: this,
1244
+ A: [
1245
+ "!body?.success",
1246
+ "'Expected body to not be a failure response or undefined.'"
1247
+ ]
1248
+ });
1249
+ if (body?.data?.type === "auth_challenge" && typeof body?.data?.challenge === "string") {
1250
+ processingError = new EdgeAuthChallengeError(body.data.challenge, body.data);
1251
+ } else if (body?.success === false) {
1252
+ processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
1018
1253
  } else {
1019
- processingError = EdgeCallFailedError.fromHttpFailure(response);
1254
+ invariant4(!response.ok, "Expected response to not be ok.", {
1255
+ F: __dxlog_file6,
1256
+ L: 452,
1257
+ S: this,
1258
+ A: [
1259
+ "!response.ok",
1260
+ "'Expected response to not be ok.'"
1261
+ ]
1262
+ });
1263
+ processingError = await EdgeCallFailedError.fromHttpFailure(response);
1020
1264
  }
1021
1265
  } catch (error) {
1022
1266
  processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
1023
1267
  }
1024
- if (processingError.isRetryable && await shouldRetry(requestContext, retryAfterHeaderValue)) {
1025
- log4("retrying edge request", {
1268
+ if (processingError?.isRetryable && await shouldRetry(requestContext, processingError.retryAfterMs)) {
1269
+ log4.verbose("retrying edge request", {
1026
1270
  url,
1027
1271
  processingError
1028
1272
  }, {
1029
1273
  F: __dxlog_file6,
1030
- L: 328,
1274
+ L: 460,
1031
1275
  S: this,
1032
1276
  C: (f, a) => f(...a)
1033
1277
  });
@@ -1040,33 +1284,52 @@ var EdgeHttpClient = class {
1040
1284
  if (!this._edgeIdentity) {
1041
1285
  log4.warn("unauthorized response received before identity was set", void 0, {
1042
1286
  F: __dxlog_file6,
1043
- L: 337,
1287
+ L: 469,
1044
1288
  S: this,
1045
1289
  C: (f, a) => f(...a)
1046
1290
  });
1047
- throw EdgeCallFailedError.fromHttpFailure(response);
1291
+ throw await EdgeCallFailedError.fromHttpFailure(response);
1048
1292
  }
1049
1293
  const challenge = await handleAuthChallenge(response, this._edgeIdentity);
1050
1294
  return encodeAuthHeader(challenge);
1051
1295
  }
1052
1296
  };
1053
- var createRequest = ({ method, body }, authHeader) => {
1297
+ var createRequest = ({ method, body, json = true }, authHeader) => {
1298
+ let requestBody;
1299
+ const headers = {};
1300
+ if (json) {
1301
+ requestBody = body && JSON.stringify(body);
1302
+ headers["Content-Type"] = "application/json";
1303
+ } else {
1304
+ requestBody = body;
1305
+ }
1306
+ if (typeof requestBody === "string" && requestBody.length > WARNING_BODY_SIZE) {
1307
+ log4.warn("Request with large body", {
1308
+ bodySize: requestBody.length
1309
+ }, {
1310
+ F: __dxlog_file6,
1311
+ L: 493,
1312
+ S: void 0,
1313
+ C: (f, a) => f(...a)
1314
+ });
1315
+ }
1316
+ if (authHeader) {
1317
+ headers["Authorization"] = authHeader;
1318
+ }
1054
1319
  return {
1055
1320
  method,
1056
- body: body && JSON.stringify(body),
1057
- headers: authHeader ? {
1058
- Authorization: authHeader
1059
- } : void 0
1321
+ body: requestBody,
1322
+ headers
1060
1323
  };
1061
1324
  };
1062
- var createRetryHandler = ({ retry }) => {
1063
- if (!retry || retry.count < 1) {
1325
+ var createRetryHandler = ({ retry: retry2 }) => {
1326
+ if (!retry2 || retry2.count < 1) {
1064
1327
  return async () => false;
1065
1328
  }
1066
1329
  let retries = 0;
1067
- const maxRetries = retry.count ?? DEFAULT_MAX_RETRIES_COUNT;
1068
- const baseTimeout = retry.timeout ?? DEFAULT_RETRY_TIMEOUT;
1069
- const jitter = retry.jitter ?? DEFAULT_RETRY_JITTER;
1330
+ const maxRetries = retry2.count ?? DEFAULT_MAX_RETRIES_COUNT;
1331
+ const baseTimeout = retry2.timeout ?? DEFAULT_RETRY_TIMEOUT;
1332
+ const jitter = retry2.jitter ?? DEFAULT_RETRY_JITTER;
1070
1333
  return async (ctx, retryAfter) => {
1071
1334
  if (++retries > maxRetries || ctx.disposed) {
1072
1335
  return false;
@@ -1074,12 +1337,16 @@ var createRetryHandler = ({ retry }) => {
1074
1337
  if (retryAfter) {
1075
1338
  await sleep(retryAfter);
1076
1339
  } else {
1077
- const timeout = baseTimeout + Math.random() * jitter;
1078
- await sleep(timeout);
1340
+ const timeout2 = baseTimeout + Math.random() * jitter;
1341
+ await sleep(timeout2);
1079
1342
  }
1080
1343
  return true;
1081
1344
  };
1082
1345
  };
1346
+ var getFileMimeType = (filename) => [
1347
+ ".js",
1348
+ ".mjs"
1349
+ ].some((codeExtension) => filename.endsWith(codeExtension)) ? "application/javascript+module" : filename.endsWith(".wasm") ? "application/wasm" : "application/octet-stream";
1083
1350
  export {
1084
1351
  CLOUDFLARE_MESSAGE_MAX_BYTES,
1085
1352
  CLOUDFLARE_RPC_MAX_BYTES,
@@ -1087,6 +1354,7 @@ export {
1087
1354
  EdgeConnectionClosedError,
1088
1355
  EdgeHttpClient,
1089
1356
  EdgeIdentityChangedError,
1357
+ HttpConfig,
1090
1358
  Protocol,
1091
1359
  WebSocketMuxer,
1092
1360
  createChainEdgeIdentity,
@@ -1094,9 +1362,13 @@ export {
1094
1362
  createEphemeralEdgeIdentity,
1095
1363
  createStubEdgeIdentity,
1096
1364
  createTestHaloEdgeIdentity,
1365
+ encodeAuthHeader,
1097
1366
  getTypename,
1098
1367
  handleAuthChallenge,
1099
1368
  protocol,
1100
- toUint8Array
1369
+ toUint8Array,
1370
+ withLogging,
1371
+ withRetry,
1372
+ withRetryConfig
1101
1373
  };
1102
1374
  //# sourceMappingURL=index.mjs.map