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