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

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