@dxos/edge-client 0.8.4-main.c4373fc → 0.8.4-main.c85a9c8dae

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 (38) hide show
  1. package/dist/lib/{browser/chunk-IKP53CBQ.mjs → neutral/chunk-VESGVCLQ.mjs} +15 -44
  2. package/dist/lib/{browser/chunk-IKP53CBQ.mjs.map → neutral/chunk-VESGVCLQ.mjs.map} +2 -2
  3. package/dist/lib/{browser → neutral}/edge-ws-muxer.mjs +1 -1
  4. package/dist/lib/{browser → neutral}/index.mjs +292 -161
  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/{browser → neutral}/testing/index.mjs.map +2 -2
  9. package/dist/types/src/edge-client.d.ts.map +1 -1
  10. package/dist/types/src/edge-http-client.d.ts +18 -7
  11. package/dist/types/src/edge-http-client.d.ts.map +1 -1
  12. package/dist/types/src/edge-ws-connection.d.ts +19 -0
  13. package/dist/types/src/edge-ws-connection.d.ts.map +1 -1
  14. package/dist/types/src/http-client.d.ts.map +1 -1
  15. package/dist/types/src/testing/test-utils.d.ts +2 -2
  16. package/dist/types/src/testing/test-utils.d.ts.map +1 -1
  17. package/dist/types/tsconfig.tsbuildinfo +1 -1
  18. package/package.json +26 -24
  19. package/src/edge-client.test.ts +4 -4
  20. package/src/edge-client.ts +36 -5
  21. package/src/edge-http-client.test.ts +1 -1
  22. package/src/edge-http-client.ts +79 -36
  23. package/src/edge-ws-connection.ts +117 -4
  24. package/src/http-client.test.ts +3 -2
  25. package/src/http-client.ts +5 -1
  26. package/src/testing/test-utils.ts +7 -7
  27. package/dist/lib/browser/index.mjs.map +0 -7
  28. package/dist/lib/browser/meta.json +0 -1
  29. package/dist/lib/node-esm/chunk-DR5YNW5K.mjs +0 -332
  30. package/dist/lib/node-esm/chunk-DR5YNW5K.mjs.map +0 -7
  31. package/dist/lib/node-esm/edge-ws-muxer.mjs +0 -12
  32. package/dist/lib/node-esm/edge-ws-muxer.mjs.map +0 -7
  33. package/dist/lib/node-esm/index.mjs +0 -1257
  34. package/dist/lib/node-esm/index.mjs.map +0 -7
  35. package/dist/lib/node-esm/meta.json +0 -1
  36. package/dist/lib/node-esm/testing/index.mjs +0 -186
  37. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  38. /package/dist/lib/{browser → neutral}/edge-ws-muxer.mjs.map +0 -0
@@ -6,7 +6,7 @@ import {
6
6
  getTypename,
7
7
  protocol,
8
8
  toUint8Array
9
- } from "./chunk-IKP53CBQ.mjs";
9
+ } from "./chunk-VESGVCLQ.mjs";
10
10
 
11
11
  // src/index.ts
12
12
  export * from "@dxos/protocols/buf/dxos/edge/messenger_pb";
@@ -123,7 +123,7 @@ var createStubEdgeIdentity = () => {
123
123
  };
124
124
 
125
125
  // src/edge-client.ts
126
- import { Event, PersistentLifecycle, Trigger, TriggerState, scheduleMicroTask } from "@dxos/async";
126
+ import { Event, PersistentLifecycle, Trigger, TriggerState, scheduleMicroTask, scheduleTaskInterval as scheduleTaskInterval2 } from "@dxos/async";
127
127
  import { Resource as Resource2 } from "@dxos/context";
128
128
  import { log as log2, logInfo as logInfo2 } from "@dxos/log";
129
129
  import { EdgeStatus } from "@dxos/protocols/proto/dxos/client/services";
@@ -177,19 +177,6 @@ import { log, logInfo } from "@dxos/log";
177
177
  import { EdgeWebsocketProtocol } from "@dxos/protocols";
178
178
  import { buf } from "@dxos/protocols/buf";
179
179
  import { MessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
180
- function _define_property(obj, key, value) {
181
- if (key in obj) {
182
- Object.defineProperty(obj, key, {
183
- value,
184
- enumerable: true,
185
- configurable: true,
186
- writable: true
187
- });
188
- } else {
189
- obj[key] = value;
190
- }
191
- return obj;
192
- }
193
180
  function _ts_decorate(decorators, target, key, desc) {
194
181
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
195
182
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -200,6 +187,28 @@ var __dxlog_file3 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-ws-c
200
187
  var SIGNAL_KEEPALIVE_INTERVAL = 4e3;
201
188
  var SIGNAL_KEEPALIVE_TIMEOUT = 12e3;
202
189
  var EdgeWsConnection = class extends Resource {
190
+ _identity;
191
+ _connectionInfo;
192
+ _callbacks;
193
+ _inactivityTimeoutCtx;
194
+ _ws;
195
+ _wsMuxer;
196
+ _lastReceivedMessageTimestamp = Date.now();
197
+ _openTimestamp;
198
+ // Latency tracking.
199
+ _pingTimestamp;
200
+ _rtt = 0;
201
+ // Rate tracking with sliding window.
202
+ _uploadRate = 0;
203
+ _downloadRate = 0;
204
+ _rateWindow = 1e4;
205
+ _rateUpdateInterval = 1e3;
206
+ _bytesSamples = [];
207
+ _messagesSent = 0;
208
+ _messagesReceived = 0;
209
+ constructor(_identity, _connectionInfo, _callbacks) {
210
+ super(), this._identity = _identity, this._connectionInfo = _connectionInfo, this._callbacks = _callbacks;
211
+ }
203
212
  get info() {
204
213
  return {
205
214
  open: this.isOpen,
@@ -207,10 +216,28 @@ var EdgeWsConnection = class extends Resource {
207
216
  device: this._identity.peerKey
208
217
  };
209
218
  }
219
+ get rtt() {
220
+ return this._rtt;
221
+ }
222
+ get uptime() {
223
+ return this._openTimestamp ? (Date.now() - this._openTimestamp) / 1e3 : 0;
224
+ }
225
+ get uploadRate() {
226
+ return this._uploadRate;
227
+ }
228
+ get downloadRate() {
229
+ return this._downloadRate;
230
+ }
231
+ get messagesSent() {
232
+ return this._messagesSent;
233
+ }
234
+ get messagesReceived() {
235
+ return this._messagesReceived;
236
+ }
210
237
  send(message) {
211
238
  invariant3(this._ws, void 0, {
212
239
  F: __dxlog_file3,
213
- L: 53,
240
+ L: 93,
214
241
  S: this,
215
242
  A: [
216
243
  "this._ws",
@@ -219,7 +246,7 @@ var EdgeWsConnection = class extends Resource {
219
246
  });
220
247
  invariant3(this._wsMuxer, void 0, {
221
248
  F: __dxlog_file3,
222
- L: 54,
249
+ L: 94,
223
250
  S: this,
224
251
  A: [
225
252
  "this._wsMuxer",
@@ -231,10 +258,11 @@ var EdgeWsConnection = class extends Resource {
231
258
  payload: protocol.getPayloadType(message)
232
259
  }, {
233
260
  F: __dxlog_file3,
234
- L: 55,
261
+ L: 95,
235
262
  S: this,
236
263
  C: (f, a) => f(...a)
237
264
  });
265
+ this._messagesSent++;
238
266
  if (this._ws?.protocol.includes(EdgeWebsocketProtocol.V0)) {
239
267
  const binary = buf.toBinary(MessageSchema, message);
240
268
  if (binary.length > CLOUDFLARE_MESSAGE_MAX_BYTES) {
@@ -244,17 +272,20 @@ var EdgeWsConnection = class extends Resource {
244
272
  payload: protocol.getPayloadType(message)
245
273
  }, {
246
274
  F: __dxlog_file3,
247
- L: 59,
275
+ L: 100,
248
276
  S: this,
249
277
  C: (f, a) => f(...a)
250
278
  });
251
279
  return;
252
280
  }
281
+ this._recordBytes(binary.byteLength, 0);
253
282
  this._ws.send(binary);
254
283
  } else {
284
+ const binary = buf.toBinary(MessageSchema, message);
285
+ this._recordBytes(binary.byteLength, 0);
255
286
  this._wsMuxer.send(message).catch((e) => log.catch(e, void 0, {
256
287
  F: __dxlog_file3,
257
- L: 68,
288
+ L: 113,
258
289
  S: this,
259
290
  C: (f, a) => f(...a)
260
291
  }));
@@ -276,18 +307,20 @@ var EdgeWsConnection = class extends Resource {
276
307
  if (this.isOpen) {
277
308
  log("connected", void 0, {
278
309
  F: __dxlog_file3,
279
- L: 85,
310
+ L: 130,
280
311
  S: this,
281
312
  C: (f, a) => f(...a)
282
313
  });
314
+ this._openTimestamp = Date.now();
283
315
  this._callbacks.onConnected();
284
316
  this._scheduleHeartbeats();
317
+ this._scheduleRateCalculation();
285
318
  } else {
286
319
  log.verbose("connected after becoming inactive", {
287
320
  currentIdentity: this._identity
288
321
  }, {
289
322
  F: __dxlog_file3,
290
- L: 89,
323
+ L: 136,
291
324
  S: this,
292
325
  C: (f, a) => f(...a)
293
326
  });
@@ -295,12 +328,12 @@ var EdgeWsConnection = class extends Resource {
295
328
  };
296
329
  this._ws.onclose = (event) => {
297
330
  if (this.isOpen) {
298
- log.warn("disconnected while being open", {
331
+ log.warn("server disconnected", {
299
332
  code: event.code,
300
333
  reason: event.reason
301
334
  }, {
302
335
  F: __dxlog_file3,
303
- L: 94,
336
+ L: 141,
304
337
  S: this,
305
338
  C: (f, a) => f(...a)
306
339
  });
@@ -315,7 +348,7 @@ var EdgeWsConnection = class extends Resource {
315
348
  info: event.message
316
349
  }, {
317
350
  F: __dxlog_file3,
318
- L: 101,
351
+ L: 148,
319
352
  S: this,
320
353
  C: (f, a) => f(...a)
321
354
  });
@@ -325,7 +358,7 @@ var EdgeWsConnection = class extends Resource {
325
358
  error: event.error
326
359
  }, {
327
360
  F: __dxlog_file3,
328
- L: 104,
361
+ L: 151,
329
362
  S: this,
330
363
  C: (f, a) => f(...a)
331
364
  });
@@ -337,7 +370,7 @@ var EdgeWsConnection = class extends Resource {
337
370
  event: event.type
338
371
  }, {
339
372
  F: __dxlog_file3,
340
- L: 112,
373
+ L: 159,
341
374
  S: this,
342
375
  C: (f, a) => f(...a)
343
376
  });
@@ -345,13 +378,19 @@ var EdgeWsConnection = class extends Resource {
345
378
  }
346
379
  this._lastReceivedMessageTimestamp = Date.now();
347
380
  if (event.data === "__pong__") {
381
+ if (this._pingTimestamp) {
382
+ this._rtt = Date.now() - this._pingTimestamp;
383
+ this._pingTimestamp = void 0;
384
+ }
348
385
  this._rescheduleHeartbeatTimeout();
349
386
  return;
350
387
  }
351
388
  const bytes = await toUint8Array(event.data);
389
+ this._recordBytes(0, bytes.byteLength);
352
390
  if (!this.isOpen) {
353
391
  return;
354
392
  }
393
+ this._messagesReceived++;
355
394
  const message = this._ws?.protocol?.includes(EdgeWebsocketProtocol.V0) ? buf.fromBinary(MessageSchema, bytes) : muxer.receiveData(bytes);
356
395
  if (message) {
357
396
  log("received", {
@@ -359,7 +398,7 @@ var EdgeWsConnection = class extends Resource {
359
398
  payload: protocol.getPayloadType(message)
360
399
  }, {
361
400
  F: __dxlog_file3,
362
- L: 130,
401
+ L: 185,
363
402
  S: this,
364
403
  C: (f, a) => f(...a)
365
404
  });
@@ -383,7 +422,7 @@ var EdgeWsConnection = class extends Resource {
383
422
  err
384
423
  }, {
385
424
  F: __dxlog_file3,
386
- L: 148,
425
+ L: 203,
387
426
  S: this,
388
427
  C: (f, a) => f(...a)
389
428
  });
@@ -392,7 +431,7 @@ var EdgeWsConnection = class extends Resource {
392
431
  _scheduleHeartbeats() {
393
432
  invariant3(this._ws, void 0, {
394
433
  F: __dxlog_file3,
395
- L: 153,
434
+ L: 208,
396
435
  S: this,
397
436
  A: [
398
437
  "this._ws",
@@ -400,8 +439,10 @@ var EdgeWsConnection = class extends Resource {
400
439
  ]
401
440
  });
402
441
  scheduleTaskInterval(this._ctx, async () => {
442
+ this._pingTimestamp = Date.now();
403
443
  this._ws?.send("__ping__");
404
444
  }, SIGNAL_KEEPALIVE_INTERVAL);
445
+ this._pingTimestamp = Date.now();
405
446
  this._ws.send("__ping__");
406
447
  this._rescheduleHeartbeatTimeout();
407
448
  }
@@ -412,7 +453,7 @@ var EdgeWsConnection = class extends Resource {
412
453
  void this._inactivityTimeoutCtx?.dispose();
413
454
  this._inactivityTimeoutCtx = new Context(void 0, {
414
455
  F: __dxlog_file3,
415
- L: 172
456
+ L: 229
416
457
  });
417
458
  scheduleTask(this._inactivityTimeoutCtx, () => {
418
459
  if (this.isOpen) {
@@ -421,7 +462,7 @@ var EdgeWsConnection = class extends Resource {
421
462
  lastReceivedMessageTimestamp: this._lastReceivedMessageTimestamp
422
463
  }, {
423
464
  F: __dxlog_file3,
424
- L: 178,
465
+ L: 235,
425
466
  S: this,
426
467
  C: (f, a) => f(...a)
427
468
  });
@@ -432,8 +473,46 @@ var EdgeWsConnection = class extends Resource {
432
473
  }
433
474
  }, SIGNAL_KEEPALIVE_TIMEOUT);
434
475
  }
435
- constructor(_identity, _connectionInfo, _callbacks) {
436
- super(), _define_property(this, "_identity", void 0), _define_property(this, "_connectionInfo", void 0), _define_property(this, "_callbacks", void 0), _define_property(this, "_inactivityTimeoutCtx", void 0), _define_property(this, "_ws", void 0), _define_property(this, "_wsMuxer", void 0), _define_property(this, "_lastReceivedMessageTimestamp", void 0), this._identity = _identity, this._connectionInfo = _connectionInfo, this._callbacks = _callbacks, this._lastReceivedMessageTimestamp = Date.now();
476
+ _recordBytes(sent, received) {
477
+ const now = Date.now();
478
+ const currentSecond = Math.floor(now / 1e3) * 1e3;
479
+ const existingSample = this._bytesSamples.find((s) => Math.floor(s.timestamp / 1e3) * 1e3 === currentSecond);
480
+ if (existingSample) {
481
+ existingSample.sent += sent;
482
+ existingSample.received += received;
483
+ } else {
484
+ this._bytesSamples.push({
485
+ timestamp: now,
486
+ sent,
487
+ received
488
+ });
489
+ }
490
+ }
491
+ _scheduleRateCalculation() {
492
+ scheduleTaskInterval(this._ctx, async () => {
493
+ this._calculateRates();
494
+ }, this._rateUpdateInterval);
495
+ this._calculateRates();
496
+ }
497
+ _calculateRates() {
498
+ const now = Date.now();
499
+ const cutoff = now - this._rateWindow;
500
+ this._bytesSamples = this._bytesSamples.filter((s) => s.timestamp > cutoff);
501
+ if (this._bytesSamples.length === 0) {
502
+ this._uploadRate = 0;
503
+ this._downloadRate = 0;
504
+ return;
505
+ }
506
+ let totalSent = 0;
507
+ let totalReceived = 0;
508
+ const oldestTimestamp = Math.min(...this._bytesSamples.map((s) => s.timestamp));
509
+ const timeSpan = (now - oldestTimestamp) / 1e3;
510
+ for (const sample of this._bytesSamples) {
511
+ totalSent += sample.sent;
512
+ totalReceived += sample.received;
513
+ }
514
+ this._uploadRate = timeSpan > 0 ? Math.round(totalSent / timeSpan) : 0;
515
+ this._downloadRate = timeSpan > 0 ? Math.round(totalReceived / timeSpan) : 0;
437
516
  }
438
517
  };
439
518
  _ts_decorate([
@@ -461,19 +540,6 @@ var getEdgeUrlWithProtocol = (baseUrl, protocol2) => {
461
540
  };
462
541
 
463
542
  // src/edge-client.ts
464
- function _define_property2(obj, key, value) {
465
- if (key in obj) {
466
- Object.defineProperty(obj, key, {
467
- value,
468
- enumerable: true,
469
- configurable: true,
470
- writable: true
471
- });
472
- } else {
473
- obj[key] = value;
474
- }
475
- return obj;
476
- }
477
543
  function _ts_decorate2(decorators, target, key, desc) {
478
544
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
479
545
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -482,7 +548,26 @@ function _ts_decorate2(decorators, target, key, desc) {
482
548
  }
483
549
  var __dxlog_file4 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-client.ts";
484
550
  var DEFAULT_TIMEOUT = 1e4;
551
+ var STATUS_REFRESH_INTERVAL = 1e3;
485
552
  var EdgeClient = class extends Resource2 {
553
+ _identity;
554
+ _config;
555
+ statusChanged = new Event();
556
+ _persistentLifecycle = new PersistentLifecycle({
557
+ start: async () => this._connect(),
558
+ stop: async (state) => this._disconnect(state)
559
+ });
560
+ _messageListeners = /* @__PURE__ */ new Set();
561
+ _reconnectListeners = /* @__PURE__ */ new Set();
562
+ _baseWsUrl;
563
+ _baseHttpUrl;
564
+ _currentConnection = void 0;
565
+ _ready = new Trigger();
566
+ constructor(_identity, _config) {
567
+ super(), this._identity = _identity, this._config = _config;
568
+ this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
569
+ this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
570
+ }
486
571
  get info() {
487
572
  return {
488
573
  open: this.isOpen,
@@ -492,7 +577,15 @@ var EdgeClient = class extends Resource2 {
492
577
  };
493
578
  }
494
579
  get status() {
495
- return Boolean(this._currentConnection) && this._ready.state === TriggerState.RESOLVED ? EdgeStatus.CONNECTED : EdgeStatus.NOT_CONNECTED;
580
+ return {
581
+ state: Boolean(this._currentConnection) && this._ready.state === TriggerState.RESOLVED ? EdgeStatus.ConnectionState.CONNECTED : EdgeStatus.ConnectionState.NOT_CONNECTED,
582
+ uptime: this._currentConnection?.uptime ?? 0,
583
+ rtt: this._currentConnection?.rtt ?? 0,
584
+ rateBytesUp: this._currentConnection?.uploadRate ?? 0,
585
+ rateBytesDown: this._currentConnection?.downloadRate ?? 0,
586
+ messagesSent: this._currentConnection?.messagesSent ?? 0,
587
+ messagesReceived: this._currentConnection?.messagesReceived ?? 0
588
+ };
496
589
  }
497
590
  get identityKey() {
498
591
  return this._identity.identityKey;
@@ -507,7 +600,7 @@ var EdgeClient = class extends Resource2 {
507
600
  oldIdentity: this._identity
508
601
  }, {
509
602
  F: __dxlog_file4,
510
- L: 99,
603
+ L: 118,
511
604
  S: this,
512
605
  C: (f, a) => f(...a)
513
606
  });
@@ -524,7 +617,7 @@ var EdgeClient = class extends Resource2 {
524
617
  if (this._ready.state !== TriggerState.RESOLVED) {
525
618
  log2("waiting for websocket", void 0, {
526
619
  F: __dxlog_file4,
527
- L: 112,
620
+ L: 131,
528
621
  S: this,
529
622
  C: (f, a) => f(...a)
530
623
  });
@@ -554,7 +647,7 @@ var EdgeClient = class extends Resource2 {
554
647
  } catch (error) {
555
648
  log2.catch(error, void 0, {
556
649
  F: __dxlog_file4,
557
- L: 145,
650
+ L: 164,
558
651
  S: this,
559
652
  C: (f, a) => f(...a)
560
653
  });
@@ -572,7 +665,7 @@ var EdgeClient = class extends Resource2 {
572
665
  info: this.info
573
666
  }, {
574
667
  F: __dxlog_file4,
575
- L: 158,
668
+ L: 177,
576
669
  S: this,
577
670
  C: (f, a) => f(...a)
578
671
  });
@@ -581,11 +674,17 @@ var EdgeClient = class extends Resource2 {
581
674
  err
582
675
  }, {
583
676
  F: __dxlog_file4,
584
- L: 160,
677
+ L: 179,
585
678
  S: this,
586
679
  C: (f, a) => f(...a)
587
680
  });
588
681
  });
682
+ scheduleTaskInterval2(this._ctx, async () => {
683
+ if (!this._currentConnection) {
684
+ return;
685
+ }
686
+ this.statusChanged.emit(this.status);
687
+ }, STATUS_REFRESH_INTERVAL);
589
688
  }
590
689
  /**
591
690
  * Close connection and free resources.
@@ -595,7 +694,7 @@ var EdgeClient = class extends Resource2 {
595
694
  peerKey: this._identity.peerKey
596
695
  }, {
597
696
  F: __dxlog_file4,
598
- L: 168,
697
+ L: 199,
599
698
  S: this,
600
699
  C: (f, a) => f(...a)
601
700
  });
@@ -612,7 +711,7 @@ var EdgeClient = class extends Resource2 {
612
711
  if (this._identity !== identity) {
613
712
  log2("identity changed during auth header request", void 0, {
614
713
  F: __dxlog_file4,
615
- L: 182,
714
+ L: 213,
616
715
  S: this,
617
716
  C: (f, a) => f(...a)
618
717
  });
@@ -625,7 +724,7 @@ var EdgeClient = class extends Resource2 {
625
724
  protocolHeader
626
725
  }, {
627
726
  F: __dxlog_file4,
628
- L: 188,
727
+ L: 219,
629
728
  S: this,
630
729
  C: (f, a) => f(...a)
631
730
  });
@@ -640,7 +739,7 @@ var EdgeClient = class extends Resource2 {
640
739
  } else {
641
740
  log2.verbose("connected callback ignored, because connection is not active", void 0, {
642
741
  F: __dxlog_file4,
643
- L: 198,
742
+ L: 229,
644
743
  S: this,
645
744
  C: (f, a) => f(...a)
646
745
  });
@@ -653,7 +752,7 @@ var EdgeClient = class extends Resource2 {
653
752
  } else {
654
753
  log2.verbose("restart requested by inactive connection", void 0, {
655
754
  F: __dxlog_file4,
656
- L: 206,
755
+ L: 237,
657
756
  S: this,
658
757
  C: (f, a) => f(...a)
659
758
  });
@@ -669,7 +768,7 @@ var EdgeClient = class extends Resource2 {
669
768
  type: message.payload?.typeUrl
670
769
  }, {
671
770
  F: __dxlog_file4,
672
- L: 214,
771
+ L: 245,
673
772
  S: this,
674
773
  C: (f, a) => f(...a)
675
774
  });
@@ -706,7 +805,7 @@ var EdgeClient = class extends Resource2 {
706
805
  err
707
806
  }, {
708
807
  F: __dxlog_file4,
709
- L: 249,
808
+ L: 280,
710
809
  S: this,
711
810
  C: (f, a) => f(...a)
712
811
  });
@@ -723,7 +822,7 @@ var EdgeClient = class extends Resource2 {
723
822
  payload: protocol.getPayloadType(message)
724
823
  }, {
725
824
  F: __dxlog_file4,
726
- L: 259,
825
+ L: 290,
727
826
  S: this,
728
827
  C: (f, a) => f(...a)
729
828
  });
@@ -744,21 +843,14 @@ var EdgeClient = class extends Resource2 {
744
843
  statusText: response.statusText
745
844
  }, {
746
845
  F: __dxlog_file4,
747
- L: 271,
846
+ L: 302,
748
847
  S: this,
749
848
  C: (f, a) => f(...a)
750
849
  });
751
850
  return void 0;
752
851
  }
753
852
  }
754
- constructor(_identity, _config) {
755
- super(), _define_property2(this, "_identity", void 0), _define_property2(this, "_config", void 0), _define_property2(this, "statusChanged", void 0), _define_property2(this, "_persistentLifecycle", void 0), _define_property2(this, "_messageListeners", void 0), _define_property2(this, "_reconnectListeners", void 0), _define_property2(this, "_baseWsUrl", void 0), _define_property2(this, "_baseHttpUrl", void 0), _define_property2(this, "_currentConnection", void 0), _define_property2(this, "_ready", void 0), _define_property2(this, "_isActive", void 0), this._identity = _identity, this._config = _config, this.statusChanged = new Event(), this._persistentLifecycle = new PersistentLifecycle({
756
- start: async () => this._connect(),
757
- stop: async (state) => this._disconnect(state)
758
- }), this._messageListeners = /* @__PURE__ */ new Set(), this._reconnectListeners = /* @__PURE__ */ new Set(), this._currentConnection = void 0, this._ready = new Trigger(), this._isActive = (connection) => connection === this._currentConnection;
759
- this._baseWsUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "ws");
760
- this._baseHttpUrl = getEdgeUrlWithProtocol(_config.socketEndpoint, "http");
761
- }
853
+ _isActive = (connection) => connection === this._currentConnection;
762
854
  };
763
855
  _ts_decorate2([
764
856
  logInfo2
@@ -775,6 +867,8 @@ import * as Effect2 from "effect/Effect";
775
867
  import * as Function from "effect/Function";
776
868
  import { sleep } from "@dxos/async";
777
869
  import { Context as Context3 } from "@dxos/context";
870
+ import { runAndForwardErrors } from "@dxos/effect";
871
+ import { invariant as invariant4 } from "@dxos/invariant";
778
872
  import { log as log4 } from "@dxos/log";
779
873
  import { EdgeAuthChallengeError, EdgeCallFailedError } from "@dxos/protocols";
780
874
  import { createUrl } from "@dxos/util";
@@ -786,28 +880,14 @@ import * as Effect from "effect/Effect";
786
880
  import * as Layer from "effect/Layer";
787
881
  import * as Schedule from "effect/Schedule";
788
882
  import { log as log3 } from "@dxos/log";
789
- function _define_property3(obj, key, value) {
790
- if (key in obj) {
791
- Object.defineProperty(obj, key, {
792
- value,
793
- enumerable: true,
794
- configurable: true,
795
- writable: true
796
- });
797
- } else {
798
- obj[key] = value;
799
- }
800
- return obj;
801
- }
802
883
  var __dxlog_file5 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/http-client.ts";
803
- var _Context_Tag;
804
- var HttpConfig = class extends (_Context_Tag = Context2.Tag("HttpConfig")()) {
884
+ var HttpConfig = class _HttpConfig extends Context2.Tag("HttpConfig")() {
885
+ static default = Layer.succeed(_HttpConfig, {
886
+ timeout: Duration.millis(1e3),
887
+ retryTimes: 3,
888
+ retryBaseDelay: Duration.millis(1e3)
889
+ });
805
890
  };
806
- _define_property3(HttpConfig, "default", Layer.succeed(HttpConfig, {
807
- timeout: Duration.millis(1e3),
808
- retryTimes: 3,
809
- retryBaseDelay: Duration.millis(1e3)
810
- }));
811
891
  var withRetry = (effect, { timeout: timeout2 = Duration.millis(1e3), retryBaseDelay = Duration.millis(1e3), retryTimes = 3 } = {}) => {
812
892
  return effect.pipe(Effect.flatMap((res) => (
813
893
  // Treat 500 errors as retryable?
@@ -821,39 +901,45 @@ var withRetryConfig = (effect) => Effect.gen(function* () {
821
901
  const config = yield* HttpConfig;
822
902
  return yield* withRetry(effect, config);
823
903
  });
824
- var withLogging = (effect) => effect.pipe(Effect.tap((res) => log3.info("response", {
825
- status: res.status
826
- }, {
827
- F: __dxlog_file5,
828
- L: 64,
829
- S: void 0,
830
- C: (f, a) => f(...a)
831
- })));
904
+ var withLogging = (effect) => effect.pipe(Effect.tap((res) => {
905
+ log3.info("response", {
906
+ status: res.status
907
+ }, {
908
+ F: __dxlog_file5,
909
+ L: 66,
910
+ S: void 0,
911
+ C: (f, a) => f(...a)
912
+ });
913
+ }));
832
914
  var encodeAuthHeader = (challenge) => {
833
915
  const encodedChallenge = Buffer.from(challenge).toString("base64");
834
916
  return `VerifiablePresentation pb;base64,${encodedChallenge}`;
835
917
  };
836
918
 
837
919
  // src/edge-http-client.ts
838
- function _define_property4(obj, key, value) {
839
- if (key in obj) {
840
- Object.defineProperty(obj, key, {
841
- value,
842
- enumerable: true,
843
- configurable: true,
844
- writable: true
845
- });
846
- } else {
847
- obj[key] = value;
848
- }
849
- return obj;
850
- }
851
920
  var __dxlog_file6 = "/__w/dxos/dxos/packages/core/mesh/edge-client/src/edge-http-client.ts";
852
921
  var DEFAULT_RETRY_TIMEOUT = 1500;
853
922
  var DEFAULT_RETRY_JITTER = 500;
854
923
  var DEFAULT_MAX_RETRIES_COUNT = 3;
855
924
  var WARNING_BODY_SIZE = 10 * 1024 * 1024;
856
925
  var EdgeHttpClient = class {
926
+ _baseUrl;
927
+ _edgeIdentity;
928
+ /**
929
+ * Auth header is cached until receiving the next 401 from EDGE, at which point it gets refreshed.
930
+ */
931
+ _authHeader;
932
+ constructor(baseUrl) {
933
+ this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
934
+ log4("created", {
935
+ url: this._baseUrl
936
+ }, {
937
+ F: __dxlog_file6,
938
+ L: 110,
939
+ S: this,
940
+ C: (f, a) => f(...a)
941
+ });
942
+ }
857
943
  get baseUrl() {
858
944
  return this._baseUrl;
859
945
  }
@@ -869,7 +955,8 @@ var EdgeHttpClient = class {
869
955
  async getStatus(args) {
870
956
  return this._call(new URL("/status", this.baseUrl), {
871
957
  ...args,
872
- method: "GET"
958
+ method: "GET",
959
+ auth: true
873
960
  });
874
961
  }
875
962
  //
@@ -948,7 +1035,16 @@ var EdgeHttpClient = class {
948
1035
  // Queues
949
1036
  //
950
1037
  async queryQueue(subspaceTag, spaceId, query, args) {
951
- const { queueId } = query;
1038
+ const queueId = query.queueIds?.[0];
1039
+ invariant4(queueId, "queueId required", {
1040
+ F: __dxlog_file6,
1041
+ L: 219,
1042
+ S: this,
1043
+ A: [
1044
+ "queueId",
1045
+ "'queueId required'"
1046
+ ]
1047
+ });
952
1048
  return this._call(createUrl(new URL(`/spaces/${subspaceTag}/${spaceId}/queue/${queueId}/query`, this.baseUrl), {
953
1049
  after: query.after,
954
1050
  before: query.before,
@@ -986,6 +1082,7 @@ var EdgeHttpClient = class {
986
1082
  formData.append("version", body.version);
987
1083
  formData.append("ownerPublicKey", body.ownerPublicKey);
988
1084
  formData.append("entryPoint", body.entryPoint);
1085
+ body.runtime && formData.append("runtime", body.runtime);
989
1086
  for (const [filename, content] of Object.entries(body.assets)) {
990
1087
  formData.append("assets", new Blob([
991
1088
  content
@@ -1029,8 +1126,7 @@ var EdgeHttpClient = class {
1029
1126
  return this._call(url, {
1030
1127
  ...args,
1031
1128
  body: input,
1032
- method: "POST",
1033
- rawResponse: true
1129
+ method: "POST"
1034
1130
  });
1035
1131
  }
1036
1132
  //
@@ -1051,6 +1147,24 @@ var EdgeHttpClient = class {
1051
1147
  method: "GET"
1052
1148
  });
1053
1149
  }
1150
+ async forceRunCronTrigger(spaceId, triggerId) {
1151
+ return this._call(new URL(`/test/functions/${spaceId}/triggers/crons/${triggerId}/run`, this.baseUrl), {
1152
+ method: "POST"
1153
+ });
1154
+ }
1155
+ //
1156
+ // Query
1157
+ //
1158
+ /**
1159
+ * Execute a QueryAST query against a space.
1160
+ */
1161
+ async execQuery(spaceId, body, args) {
1162
+ return this._call(new URL(`/spaces/${spaceId}/exec-query`, this.baseUrl), {
1163
+ ...args,
1164
+ body,
1165
+ method: "POST"
1166
+ });
1167
+ }
1054
1168
  //
1055
1169
  // Import/Export space.
1056
1170
  //
@@ -1071,75 +1185,106 @@ var EdgeHttpClient = class {
1071
1185
  //
1072
1186
  // Internal
1073
1187
  //
1074
- async _fetch(url, args) {
1075
- return Function.pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"), Effect2.runPromise);
1188
+ async _fetch(url, _args) {
1189
+ return Function.pipe(HttpClient.get(url), withLogging, withRetryConfig, Effect2.provide(FetchHttpClient.layer), Effect2.provide(HttpConfig.default), Effect2.withSpan("EdgeHttpClient"), runAndForwardErrors);
1076
1190
  }
1077
1191
  // TODO(burdon): Refactor with effect (see edge-http-client.test.ts).
1078
1192
  async _call(url, args) {
1079
1193
  const shouldRetry = createRetryHandler(args);
1080
- const requestContext = args.context ?? new Context3(void 0, {
1194
+ const requestContext = args.context ?? Context3.default(void 0, {
1081
1195
  F: __dxlog_file6,
1082
- L: 391
1196
+ L: 426
1083
1197
  });
1084
1198
  log4("fetch", {
1085
1199
  url,
1086
1200
  request: args.body
1087
1201
  }, {
1088
1202
  F: __dxlog_file6,
1089
- L: 392,
1203
+ L: 427,
1090
1204
  S: this,
1091
1205
  C: (f, a) => f(...a)
1092
1206
  });
1093
1207
  let handledAuth = false;
1208
+ const tryCount = 1;
1094
1209
  while (true) {
1095
1210
  let processingError = void 0;
1096
- let retryAfterHeaderValue = Number.NaN;
1097
1211
  try {
1212
+ if (!this._authHeader && args.auth) {
1213
+ const response2 = await fetch(new URL(`/auth`, this.baseUrl));
1214
+ if (response2.status === 401) {
1215
+ this._authHeader = await this._handleUnauthorized(response2);
1216
+ }
1217
+ }
1098
1218
  const request = createRequest(args, this._authHeader);
1219
+ log4("call edge", {
1220
+ url,
1221
+ tryCount,
1222
+ authHeader: !!this._authHeader
1223
+ }, {
1224
+ F: __dxlog_file6,
1225
+ L: 442,
1226
+ S: this,
1227
+ C: (f, a) => f(...a)
1228
+ });
1099
1229
  const response = await fetch(url, request);
1100
- retryAfterHeaderValue = Number(response.headers.get("Retry-After"));
1101
1230
  if (response.ok) {
1102
- const body = await response.json();
1103
- if (args.rawResponse) {
1104
- return body;
1105
- }
1106
- if (!("success" in body)) {
1107
- return body;
1108
- }
1109
- if (body.success) {
1110
- return body.data;
1111
- }
1112
- log4.warn("unsuccessful edge response", {
1113
- url,
1114
- body
1115
- }, {
1231
+ const body2 = await response.clone().json();
1232
+ invariant4(body2, "Expected body to be present", {
1116
1233
  F: __dxlog_file6,
1117
- L: 417,
1234
+ L: 447,
1118
1235
  S: this,
1119
- C: (f, a) => f(...a)
1236
+ A: [
1237
+ "body",
1238
+ "'Expected body to be present'"
1239
+ ]
1120
1240
  });
1121
- if (body.errorData?.type === "auth_challenge" && typeof body.errorData?.challenge === "string") {
1122
- processingError = new EdgeAuthChallengeError(body.errorData.challenge, body.errorData);
1123
- } else if (body.errorData) {
1124
- processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
1241
+ if (!("success" in body2)) {
1242
+ return body2;
1243
+ }
1244
+ if (body2.success) {
1245
+ return body2.data;
1125
1246
  }
1126
1247
  } else if (response.status === 401 && !handledAuth) {
1127
1248
  this._authHeader = await this._handleUnauthorized(response);
1128
1249
  handledAuth = true;
1129
1250
  continue;
1251
+ }
1252
+ const body = response.headers.get("Content-Type") === "application/json" ? await response.clone().json() : void 0;
1253
+ invariant4(!body?.success, "Expected body to not be a failure response or undefined.", {
1254
+ F: __dxlog_file6,
1255
+ L: 463,
1256
+ S: this,
1257
+ A: [
1258
+ "!body?.success",
1259
+ "'Expected body to not be a failure response or undefined.'"
1260
+ ]
1261
+ });
1262
+ if (body?.data?.type === "auth_challenge" && typeof body?.data?.challenge === "string") {
1263
+ processingError = new EdgeAuthChallengeError(body.data.challenge, body.data);
1264
+ } else if (body?.success === false) {
1265
+ processingError = EdgeCallFailedError.fromUnsuccessfulResponse(response, body);
1130
1266
  } else {
1267
+ invariant4(!response.ok, "Expected response to not be ok.", {
1268
+ F: __dxlog_file6,
1269
+ L: 470,
1270
+ S: this,
1271
+ A: [
1272
+ "!response.ok",
1273
+ "'Expected response to not be ok.'"
1274
+ ]
1275
+ });
1131
1276
  processingError = await EdgeCallFailedError.fromHttpFailure(response);
1132
1277
  }
1133
1278
  } catch (error) {
1134
1279
  processingError = EdgeCallFailedError.fromProcessingFailureCause(error);
1135
1280
  }
1136
- if (processingError?.isRetryable && await shouldRetry(requestContext, retryAfterHeaderValue)) {
1137
- log4("retrying edge request", {
1281
+ if (processingError?.isRetryable && await shouldRetry(requestContext, processingError.retryAfterMs)) {
1282
+ log4.verbose("retrying edge request", {
1138
1283
  url,
1139
1284
  processingError
1140
1285
  }, {
1141
1286
  F: __dxlog_file6,
1142
- L: 435,
1287
+ L: 478,
1143
1288
  S: this,
1144
1289
  C: (f, a) => f(...a)
1145
1290
  });
@@ -1152,7 +1297,7 @@ var EdgeHttpClient = class {
1152
1297
  if (!this._edgeIdentity) {
1153
1298
  log4.warn("unauthorized response received before identity was set", void 0, {
1154
1299
  F: __dxlog_file6,
1155
- L: 444,
1300
+ L: 487,
1156
1301
  S: this,
1157
1302
  C: (f, a) => f(...a)
1158
1303
  });
@@ -1161,20 +1306,6 @@ var EdgeHttpClient = class {
1161
1306
  const challenge = await handleAuthChallenge(response, this._edgeIdentity);
1162
1307
  return encodeAuthHeader(challenge);
1163
1308
  }
1164
- constructor(baseUrl) {
1165
- _define_property4(this, "_baseUrl", void 0);
1166
- _define_property4(this, "_edgeIdentity", void 0);
1167
- _define_property4(this, "_authHeader", void 0);
1168
- this._baseUrl = getEdgeUrlWithProtocol(baseUrl, "http");
1169
- log4("created", {
1170
- url: this._baseUrl
1171
- }, {
1172
- F: __dxlog_file6,
1173
- L: 99,
1174
- S: this,
1175
- C: (f, a) => f(...a)
1176
- });
1177
- }
1178
1309
  };
1179
1310
  var createRequest = ({ method, body, json = true }, authHeader) => {
1180
1311
  let requestBody;
@@ -1190,7 +1321,7 @@ var createRequest = ({ method, body, json = true }, authHeader) => {
1190
1321
  bodySize: requestBody.length
1191
1322
  }, {
1192
1323
  F: __dxlog_file6,
1193
- L: 468,
1324
+ L: 511,
1194
1325
  S: void 0,
1195
1326
  C: (f, a) => f(...a)
1196
1327
  });