@dxos/echo-pipeline 0.8.1-main.ba2dec9 → 0.8.1-staging.31c3ee1

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 (28) hide show
  1. package/dist/lib/browser/index.mjs +205 -100
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +207 -108
  5. package/dist/lib/node/index.cjs.map +3 -3
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +205 -100
  8. package/dist/lib/node-esm/index.mjs.map +3 -3
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/automerge/automerge-host.d.ts +2 -1
  11. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  12. package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
  13. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts +1 -0
  14. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
  15. package/dist/types/src/automerge/mesh-echo-replicator.d.ts +8 -2
  16. package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
  17. package/dist/types/src/db-host/database-root.d.ts +2 -1
  18. package/dist/types/src/db-host/database-root.d.ts.map +1 -1
  19. package/dist/types/src/db-host/echo-host.d.ts +1 -0
  20. package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
  21. package/package.json +34 -34
  22. package/src/automerge/automerge-host.ts +19 -1
  23. package/src/automerge/collection-synchronizer.ts +28 -0
  24. package/src/automerge/mesh-echo-replicator-connection.ts +5 -7
  25. package/src/automerge/mesh-echo-replicator.ts +44 -12
  26. package/src/db-host/database-root.ts +20 -1
  27. package/src/db-host/echo-host.ts +4 -0
  28. package/src/edge/echo-edge-replicator.ts +6 -6
@@ -199,20 +199,28 @@ var DocumentsSynchronizer = class extends Resource {
199
199
  // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
200
200
  import { Event as Event2, asyncTimeout } from "@dxos/async";
201
201
  import { getBackend, getHeads, isAutomerge, equals as headsEquals, save } from "@dxos/automerge/automerge";
202
- import { Repo } from "@dxos/automerge/automerge-repo";
202
+ import { Repo, interpretAsDocumentId } from "@dxos/automerge/automerge-repo";
203
203
  import { Context, Resource as Resource4, cancelWithContext } from "@dxos/context";
204
204
  import { invariant as invariant3 } from "@dxos/invariant";
205
205
  import { PublicKey } from "@dxos/keys";
206
206
  import { log as log4 } from "@dxos/log";
207
207
  import { objectPointerCodec } from "@dxos/protocols";
208
- import { trace } from "@dxos/tracing";
208
+ import { trace as trace2 } from "@dxos/tracing";
209
+ import { bufferToArray } from "@dxos/util";
209
210
 
210
211
  // packages/core/echo/echo-pipeline/src/automerge/collection-synchronizer.ts
211
212
  import { asyncReturn, Event, scheduleTask, scheduleTaskInterval } from "@dxos/async";
212
213
  import { next as am } from "@dxos/automerge/automerge";
213
214
  import { Resource as Resource2 } from "@dxos/context";
214
215
  import { log as log2 } from "@dxos/log";
216
+ import { trace } from "@dxos/tracing";
215
217
  import { defaultMap } from "@dxos/util";
218
+ function _ts_decorate(decorators, target, key, desc) {
219
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
220
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
221
+ 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;
222
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
223
+ }
216
224
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/collection-synchronizer.ts";
217
225
  var MIN_QUERY_INTERVAL = 5e3;
218
226
  var POLL_INTERVAL = 3e4;
@@ -255,7 +263,7 @@ var CollectionSynchronizer = class extends Resource2 {
255
263
  state
256
264
  }, {
257
265
  F: __dxlog_file2,
258
- L: 73,
266
+ L: 75,
259
267
  S: this,
260
268
  C: (f, a) => f(...a)
261
269
  });
@@ -274,7 +282,7 @@ var CollectionSynchronizer = class extends Resource2 {
274
282
  collectionId
275
283
  }, {
276
284
  F: __dxlog_file2,
277
- L: 87,
285
+ L: 89,
278
286
  S: this,
279
287
  C: (f, a) => f(...a)
280
288
  });
@@ -304,6 +312,17 @@ var CollectionSynchronizer = class extends Resource2 {
304
312
  * Callback when a connection to a peer is established.
305
313
  */
306
314
  onConnectionOpen(peerId) {
315
+ const spanId = getSpanName(peerId);
316
+ trace.spanStart({
317
+ id: spanId,
318
+ methodName: spanId,
319
+ instance: this,
320
+ parentCtx: this._ctx,
321
+ showInBrowserTimeline: true,
322
+ attributes: {
323
+ peerId
324
+ }
325
+ });
307
326
  this._connectedPeers.add(peerId);
308
327
  queueMicrotask(async () => {
309
328
  if (this._ctx.disposed) {
@@ -346,7 +365,7 @@ var CollectionSynchronizer = class extends Resource2 {
346
365
  state
347
366
  }, {
348
367
  F: __dxlog_file2,
349
- L: 159,
368
+ L: 170,
350
369
  S: this,
351
370
  C: (f, a) => f(...a)
352
371
  });
@@ -356,6 +375,21 @@ var CollectionSynchronizer = class extends Resource2 {
356
375
  documents: {}
357
376
  };
358
377
  const diff = diffCollectionState(existingState, state);
378
+ const spanId = getSpanName(peerId);
379
+ if (diff.different.length === 0) {
380
+ trace.spanEnd(spanId);
381
+ } else {
382
+ trace.spanStart({
383
+ id: spanId,
384
+ methodName: spanId,
385
+ instance: this,
386
+ parentCtx: this._ctx,
387
+ showInBrowserTimeline: true,
388
+ attributes: {
389
+ peerId
390
+ }
391
+ });
392
+ }
359
393
  if (diff.missingOnLocal.length > 0 || diff.different.length > 0) {
360
394
  perCollectionState.remoteStates.set(peerId, state);
361
395
  this.remoteStateUpdated.emit({
@@ -383,6 +417,9 @@ var CollectionSynchronizer = class extends Resource2 {
383
417
  }
384
418
  }
385
419
  };
420
+ CollectionSynchronizer = _ts_decorate([
421
+ trace.resource()
422
+ ], CollectionSynchronizer);
386
423
  var diffCollectionState = (local, remote) => {
387
424
  const allDocuments = /* @__PURE__ */ new Set([
388
425
  ...Object.keys(local.documents),
@@ -419,6 +456,9 @@ var validateCollectionState = (state) => {
419
456
  var isValidDocumentId = (documentId) => {
420
457
  return typeof documentId === "string" && !documentId.includes(":");
421
458
  };
459
+ var getSpanName = (peerId) => {
460
+ return `collection-sync-${peerId}`;
461
+ };
422
462
 
423
463
  // packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts
424
464
  import { synchronized, Trigger } from "@dxos/async";
@@ -434,7 +474,7 @@ var isCollectionQueryMessage = (message) => message.type === MESSAGE_TYPE_COLLEC
434
474
  var isCollectionStateMessage = (message) => message.type === MESSAGE_TYPE_COLLECTION_STATE;
435
475
 
436
476
  // packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts
437
- function _ts_decorate(decorators, target, key, desc) {
477
+ function _ts_decorate2(decorators, target, key, desc) {
438
478
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
439
479
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
440
480
  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;
@@ -763,16 +803,16 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
763
803
  });
764
804
  }
765
805
  };
766
- _ts_decorate([
806
+ _ts_decorate2([
767
807
  synchronized
768
808
  ], EchoNetworkAdapter.prototype, "open", null);
769
- _ts_decorate([
809
+ _ts_decorate2([
770
810
  synchronized
771
811
  ], EchoNetworkAdapter.prototype, "close", null);
772
- _ts_decorate([
812
+ _ts_decorate2([
773
813
  synchronized
774
814
  ], EchoNetworkAdapter.prototype, "addReplicator", null);
775
- _ts_decorate([
815
+ _ts_decorate2([
776
816
  synchronized
777
817
  ], EchoNetworkAdapter.prototype, "removeReplicator", null);
778
818
  var createEchoPeerMetadata = () => ({
@@ -910,7 +950,7 @@ var encodingOptions = {
910
950
  var isLevelDbNotFoundError = (err) => err.code === "LEVEL_NOT_FOUND";
911
951
 
912
952
  // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
913
- function _ts_decorate2(decorators, target, key, desc) {
953
+ function _ts_decorate3(decorators, target, key, desc) {
914
954
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
915
955
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
916
956
  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;
@@ -1027,16 +1067,29 @@ var AutomergeHost = class extends Resource4 {
1027
1067
  }
1028
1068
  return handle;
1029
1069
  }
1070
+ async exportDoc(ctx, id) {
1071
+ const documentId = interpretAsDocumentId(id);
1072
+ const chunks = await this._storage.loadRange([
1073
+ documentId
1074
+ ]);
1075
+ return bufferToArray(Buffer.concat(chunks.map((c) => c.data)));
1076
+ }
1030
1077
  /**
1031
1078
  * Create new persisted document.
1032
1079
  */
1033
1080
  createDoc(initialValue, opts) {
1034
1081
  if (opts?.preserveHistory) {
1082
+ if (initialValue instanceof Uint8Array) {
1083
+ return this._repo.import(initialValue);
1084
+ }
1035
1085
  if (!isAutomerge(initialValue)) {
1036
1086
  throw new TypeError("Initial value must be an Automerge document");
1037
1087
  }
1038
1088
  return this._repo.import(save(initialValue));
1039
1089
  } else {
1090
+ if (initialValue instanceof Uint8Array) {
1091
+ throw new Error("Cannot create document from Uint8Array without preserving history");
1092
+ }
1040
1093
  return this._repo.create(initialValue);
1041
1094
  }
1042
1095
  }
@@ -1059,7 +1112,7 @@ var AutomergeHost = class extends Resource4 {
1059
1112
  await Promise.all(headsToWait.map(async (entry, index) => {
1060
1113
  const handle = await this.loadDoc(Context.default(void 0, {
1061
1114
  F: __dxlog_file4,
1062
- L: 264
1115
+ L: 282
1063
1116
  }), entry.documentId);
1064
1117
  await waitForHeads(handle, entry.heads);
1065
1118
  }));
@@ -1072,7 +1125,7 @@ var AutomergeHost = class extends Resource4 {
1072
1125
  documentId
1073
1126
  }, {
1074
1127
  F: __dxlog_file4,
1075
- L: 276,
1128
+ L: 294,
1076
1129
  S: this,
1077
1130
  C: (f, a) => f(...a)
1078
1131
  });
@@ -1088,7 +1141,7 @@ var AutomergeHost = class extends Resource4 {
1088
1141
  documentId
1089
1142
  }, {
1090
1143
  F: __dxlog_file4,
1091
- L: 280,
1144
+ L: 298,
1092
1145
  S: this,
1093
1146
  C: (f, a) => f(...a)
1094
1147
  });
@@ -1097,7 +1150,7 @@ var AutomergeHost = class extends Resource4 {
1097
1150
  const doc = handle.docSync();
1098
1151
  invariant3(doc, void 0, {
1099
1152
  F: __dxlog_file4,
1100
- L: 285,
1153
+ L: 303,
1101
1154
  S: this,
1102
1155
  A: [
1103
1156
  "doc",
@@ -1111,7 +1164,7 @@ var AutomergeHost = class extends Resource4 {
1111
1164
  }
1112
1165
  log4.info("done re-indexing heads", void 0, {
1113
1166
  F: __dxlog_file4,
1114
- L: 292,
1167
+ L: 310,
1115
1168
  S: this,
1116
1169
  C: (f, a) => f(...a)
1117
1170
  });
@@ -1326,7 +1379,7 @@ var AutomergeHost = class extends Resource4 {
1326
1379
  count: toReplicate.length
1327
1380
  }, {
1328
1381
  F: __dxlog_file4,
1329
- L: 531,
1382
+ L: 549,
1330
1383
  S: this,
1331
1384
  C: (f, a) => f(...a)
1332
1385
  });
@@ -1352,21 +1405,21 @@ var AutomergeHost = class extends Resource4 {
1352
1405
  }
1353
1406
  }
1354
1407
  };
1355
- _ts_decorate2([
1356
- trace.info()
1408
+ _ts_decorate3([
1409
+ trace2.info()
1357
1410
  ], AutomergeHost.prototype, "_peerId", void 0);
1358
- _ts_decorate2([
1359
- trace.info({
1411
+ _ts_decorate3([
1412
+ trace2.info({
1360
1413
  depth: null
1361
1414
  })
1362
1415
  ], AutomergeHost.prototype, "_automergePeers", null);
1363
- _ts_decorate2([
1364
- trace.span({
1416
+ _ts_decorate3([
1417
+ trace2.span({
1365
1418
  showInBrowserTimeline: true
1366
1419
  })
1367
1420
  ], AutomergeHost.prototype, "flush", null);
1368
- AutomergeHost = _ts_decorate2([
1369
- trace.resource()
1421
+ AutomergeHost = _ts_decorate3([
1422
+ trace2.resource()
1370
1423
  ], AutomergeHost);
1371
1424
  var getSpaceKeyFromDoc = (doc) => {
1372
1425
  const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;
@@ -1393,7 +1446,7 @@ var changeIsPresentInDoc = (doc, changeHash) => {
1393
1446
  var decodeCollectionState = (state) => {
1394
1447
  invariant3(typeof state === "object" && state !== null, "Invalid state", {
1395
1448
  F: __dxlog_file4,
1396
- L: 592,
1449
+ L: 610,
1397
1450
  S: void 0,
1398
1451
  A: [
1399
1452
  "typeof state === 'object' && state !== null",
@@ -1472,7 +1525,7 @@ var MeshReplicatorConnection = class extends Resource5 {
1472
1525
  remotePeerId: remotePeerId.toHex()
1473
1526
  }, {
1474
1527
  F: __dxlog_file5,
1475
- L: 85,
1528
+ L: 79,
1476
1529
  S: this,
1477
1530
  C: (f, a) => f(...a)
1478
1531
  });
@@ -1499,7 +1552,7 @@ var MeshReplicatorConnection = class extends Resource5 {
1499
1552
  get peerId() {
1500
1553
  invariant4(this._remotePeerId != null, "Remote peer has not connected yet.", {
1501
1554
  F: __dxlog_file5,
1502
- L: 111,
1555
+ L: 105,
1503
1556
  S: this,
1504
1557
  A: [
1505
1558
  "this._remotePeerId != null",
@@ -1508,6 +1561,9 @@ var MeshReplicatorConnection = class extends Resource5 {
1508
1561
  });
1509
1562
  return this._remotePeerId;
1510
1563
  }
1564
+ get isEnabled() {
1565
+ return this._isEnabled;
1566
+ }
1511
1567
  async shouldAdvertise(params) {
1512
1568
  return this._params.shouldAdvertise(params);
1513
1569
  }
@@ -1521,7 +1577,7 @@ var MeshReplicatorConnection = class extends Resource5 {
1521
1577
  enable() {
1522
1578
  invariant4(this._remotePeerId != null, "Remote peer has not connected yet.", {
1523
1579
  F: __dxlog_file5,
1524
- L: 128,
1580
+ L: 126,
1525
1581
  S: this,
1526
1582
  A: [
1527
1583
  "this._remotePeerId != null",
@@ -1552,7 +1608,7 @@ var logSendSync = (message) => {
1552
1608
  };
1553
1609
  }, {
1554
1610
  F: __dxlog_file5,
1555
- L: 141,
1611
+ L: 139,
1556
1612
  S: void 0,
1557
1613
  C: (f, a) => f(...a)
1558
1614
  });
@@ -1581,12 +1637,18 @@ var getSpaceIdFromCollectionId = (collectionId) => {
1581
1637
  var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts";
1582
1638
  var MeshEchoReplicator = class {
1583
1639
  constructor() {
1584
- this._connections = /* @__PURE__ */ new Set();
1585
1640
  /**
1586
- * Using automerge peerId as a key.
1641
+ * We might have multiple connections open with a peer (one per space), but there'll be only one enabled
1642
+ * connection at any given moment, because there's a single repo for all the spaces.
1643
+ * When a connection closes (space was closed) it gets removed from the list and the next connection
1644
+ * in the line gets enabled.
1587
1645
  */
1588
1646
  this._connectionsPerPeer = /* @__PURE__ */ new Map();
1589
1647
  /**
1648
+ * A set of all connections (enabled and disabled).
1649
+ */
1650
+ this._connections = /* @__PURE__ */ new Set();
1651
+ /**
1590
1652
  * spaceId -> deviceKey[]
1591
1653
  */
1592
1654
  this._authorizedDevices = /* @__PURE__ */ new Map();
@@ -1596,8 +1658,10 @@ var MeshEchoReplicator = class {
1596
1658
  this._context = context;
1597
1659
  }
1598
1660
  async disconnect() {
1599
- for (const connection of this._connectionsPerPeer.values()) {
1600
- this._context?.onConnectionClosed(connection);
1661
+ for (const connection of this._connections) {
1662
+ if (connection.isEnabled) {
1663
+ this._context?.onConnectionClosed(connection);
1664
+ }
1601
1665
  }
1602
1666
  for (const connection of this._connections) {
1603
1667
  await connection.close();
@@ -1609,7 +1673,7 @@ var MeshEchoReplicator = class {
1609
1673
  createExtension(extensionFactory) {
1610
1674
  invariant6(this._context, void 0, {
1611
1675
  F: __dxlog_file7,
1612
- L: 57,
1676
+ L: 67,
1613
1677
  S: this,
1614
1678
  A: [
1615
1679
  "this._context",
@@ -1624,23 +1688,28 @@ var MeshEchoReplicator = class {
1624
1688
  peerId: connection.peerId
1625
1689
  }, {
1626
1690
  F: __dxlog_file7,
1627
- L: 63,
1691
+ L: 73,
1628
1692
  S: this,
1629
1693
  C: (f, a) => f(...a)
1630
1694
  });
1631
1695
  invariant6(this._context, void 0, {
1632
1696
  F: __dxlog_file7,
1633
- L: 64,
1697
+ L: 74,
1634
1698
  S: this,
1635
1699
  A: [
1636
1700
  "this._context",
1637
1701
  ""
1638
1702
  ]
1639
1703
  });
1640
- if (this._connectionsPerPeer.has(connection.peerId)) {
1641
- this._context.onConnectionAuthScopeChanged(connection);
1704
+ const existingConnections = this._connectionsPerPeer.get(connection.peerId);
1705
+ if (existingConnections?.length) {
1706
+ const enabledConnection = existingConnections[0];
1707
+ this._context.onConnectionAuthScopeChanged(enabledConnection);
1708
+ existingConnections.push(connection);
1642
1709
  } else {
1643
- this._connectionsPerPeer.set(connection.peerId, connection);
1710
+ this._connectionsPerPeer.set(connection.peerId, [
1711
+ connection
1712
+ ]);
1644
1713
  this._context.onConnectionOpen(connection);
1645
1714
  connection.enable();
1646
1715
  }
@@ -1650,14 +1719,33 @@ var MeshEchoReplicator = class {
1650
1719
  peerId: connection.peerId
1651
1720
  }, {
1652
1721
  F: __dxlog_file7,
1653
- L: 75,
1722
+ L: 88,
1654
1723
  S: this,
1655
1724
  C: (f, a) => f(...a)
1656
1725
  });
1657
- this._context?.onConnectionClosed(connection);
1658
- this._connectionsPerPeer.delete(connection.peerId);
1659
- connection.disable();
1660
1726
  this._connections.delete(connection);
1727
+ const existingConnections = this._connectionsPerPeer.get(connection.peerId) ?? [];
1728
+ const index = existingConnections.indexOf(connection);
1729
+ if (index < 0) {
1730
+ log6.warn("disconnected connection not found", {
1731
+ peerId: connection.peerId
1732
+ }, {
1733
+ F: __dxlog_file7,
1734
+ L: 96,
1735
+ S: this,
1736
+ C: (f, a) => f(...a)
1737
+ });
1738
+ return;
1739
+ }
1740
+ existingConnections.splice(index, 1);
1741
+ if (connection.isEnabled) {
1742
+ this._context?.onConnectionClosed(connection);
1743
+ connection.disable();
1744
+ if (existingConnections.length > 0) {
1745
+ this._context?.onConnectionOpen(existingConnections[0]);
1746
+ existingConnections[0].enable();
1747
+ }
1748
+ }
1661
1749
  },
1662
1750
  shouldAdvertise: async (params) => {
1663
1751
  log6("shouldAdvertise", {
@@ -1665,13 +1753,13 @@ var MeshEchoReplicator = class {
1665
1753
  documentId: params.documentId
1666
1754
  }, {
1667
1755
  F: __dxlog_file7,
1668
- L: 82,
1756
+ L: 114,
1669
1757
  S: this,
1670
1758
  C: (f, a) => f(...a)
1671
1759
  });
1672
1760
  invariant6(this._context, void 0, {
1673
1761
  F: __dxlog_file7,
1674
- L: 83,
1762
+ L: 115,
1675
1763
  S: this,
1676
1764
  A: [
1677
1765
  "this._context",
@@ -1691,7 +1779,7 @@ var MeshEchoReplicator = class {
1691
1779
  acceptDocument: remoteDocumentExists
1692
1780
  }, {
1693
1781
  F: __dxlog_file7,
1694
- L: 91,
1782
+ L: 123,
1695
1783
  S: this,
1696
1784
  C: (f, a) => f(...a)
1697
1785
  });
@@ -1705,7 +1793,7 @@ var MeshEchoReplicator = class {
1705
1793
  documentId: params.documentId
1706
1794
  }, {
1707
1795
  F: __dxlog_file7,
1708
- L: 107,
1796
+ L: 139,
1709
1797
  S: this,
1710
1798
  C: (f, a) => f(...a)
1711
1799
  });
@@ -1721,7 +1809,7 @@ var MeshEchoReplicator = class {
1721
1809
  isAuthorized
1722
1810
  }, {
1723
1811
  F: __dxlog_file7,
1724
- L: 115,
1812
+ L: 147,
1725
1813
  S: this,
1726
1814
  C: (f, a) => f(...a)
1727
1815
  });
@@ -1729,7 +1817,7 @@ var MeshEchoReplicator = class {
1729
1817
  } catch (err) {
1730
1818
  log6.catch(err, void 0, {
1731
1819
  F: __dxlog_file7,
1732
- L: 125,
1820
+ L: 157,
1733
1821
  S: this,
1734
1822
  C: (f, a) => f(...a)
1735
1823
  });
@@ -1745,7 +1833,7 @@ var MeshEchoReplicator = class {
1745
1833
  collectionId
1746
1834
  }, {
1747
1835
  F: __dxlog_file7,
1748
- L: 135,
1836
+ L: 167,
1749
1837
  S: this,
1750
1838
  C: (f, a) => f(...a)
1751
1839
  });
@@ -1764,14 +1852,14 @@ var MeshEchoReplicator = class {
1764
1852
  deviceKey
1765
1853
  }, {
1766
1854
  F: __dxlog_file7,
1767
- L: 152,
1855
+ L: 184,
1768
1856
  S: this,
1769
1857
  C: (f, a) => f(...a)
1770
1858
  });
1771
1859
  const spaceId = await createIdFromSpaceKey(spaceKey);
1772
1860
  defaultMap2(this._authorizedDevices, spaceId, () => new ComplexSet(PublicKey2.hash)).add(deviceKey);
1773
1861
  for (const connection of this._connections) {
1774
- if (connection.remoteDeviceKey && connection.remoteDeviceKey.equals(deviceKey)) {
1862
+ if (connection.isEnabled && connection.remoteDeviceKey && connection.remoteDeviceKey.equals(deviceKey)) {
1775
1863
  if (this._connectionsPerPeer.has(connection.peerId)) {
1776
1864
  this._context?.onConnectionAuthScopeChanged(connection);
1777
1865
  }
@@ -1781,9 +1869,9 @@ var MeshEchoReplicator = class {
1781
1869
  };
1782
1870
 
1783
1871
  // packages/core/echo/echo-pipeline/src/automerge/echo-data-monitor.ts
1784
- import { trace as trace2 } from "@dxos/tracing";
1872
+ import { trace as trace3 } from "@dxos/tracing";
1785
1873
  import { CircularBuffer, mapValues, SlidingWindowSummary } from "@dxos/util";
1786
- function _ts_decorate3(decorators, target, key, desc) {
1874
+ function _ts_decorate4(decorators, target, key, desc) {
1787
1875
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1788
1876
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1789
1877
  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;
@@ -1916,14 +2004,14 @@ var EchoDataMonitor = class {
1916
2004
  for (const [metricName, metric, summary] of toReport) {
1917
2005
  summary.record(metric);
1918
2006
  if (metric > 0) {
1919
- trace2.metrics.distribution(`dxos.echo.${metricName}-rate`, metric);
1920
- trace2.metrics.increment(`dxos.echo.${metricName}`, 1, {
2007
+ trace3.metrics.distribution(`dxos.echo.${metricName}-rate`, metric);
2008
+ trace3.metrics.increment(`dxos.echo.${metricName}`, 1, {
1921
2009
  tags: {
1922
2010
  status: "busy"
1923
2011
  }
1924
2012
  });
1925
2013
  } else {
1926
- trace2.metrics.increment(`dxos.echo.${metricName}`, 1, {
2014
+ trace3.metrics.increment(`dxos.echo.${metricName}`, 1, {
1927
2015
  tags: {
1928
2016
  status: "idle"
1929
2017
  }
@@ -1944,7 +2032,7 @@ var EchoDataMonitor = class {
1944
2032
  this._activeCounters.storage.storedChunks++;
1945
2033
  this._activeCounters.storage.storedBytes += count;
1946
2034
  this._storageAverages.storedChunkSize.record(count);
1947
- trace2.metrics.distribution("dxos.echo.storage.bytes-stored", count, {
2035
+ trace3.metrics.distribution("dxos.echo.storage.bytes-stored", count, {
1948
2036
  unit: "bytes"
1949
2037
  });
1950
2038
  }
@@ -1958,7 +2046,7 @@ var EchoDataMonitor = class {
1958
2046
  this._activeCounters.storage.loadedChunks++;
1959
2047
  this._activeCounters.storage.loadedBytes += count;
1960
2048
  this._storageAverages.loadedChunkSize.record(count);
1961
- trace2.metrics.distribution("dxos.echo.storage.bytes-loaded", count, {
2049
+ trace3.metrics.distribution("dxos.echo.storage.bytes-loaded", count, {
1962
2050
  unit: "bytes"
1963
2051
  });
1964
2052
  }
@@ -1976,15 +2064,15 @@ var EchoDataMonitor = class {
1976
2064
  } else {
1977
2065
  metricsGroupName = "collection-sync";
1978
2066
  }
1979
- trace2.metrics.distribution(`dxos.echo.${metricsGroupName}.bytes-sent`, bytes, {
2067
+ trace3.metrics.distribution(`dxos.echo.${metricsGroupName}.bytes-sent`, bytes, {
1980
2068
  unit: "bytes",
1981
2069
  tags
1982
2070
  });
1983
- trace2.metrics.distribution(`dxos.echo.${metricsGroupName}.send-duration`, duration, {
2071
+ trace3.metrics.distribution(`dxos.echo.${metricsGroupName}.send-duration`, duration, {
1984
2072
  unit: "millisecond",
1985
2073
  tags
1986
2074
  });
1987
- trace2.metrics.increment(`dxos.echo.${metricsGroupName}.send-status`, 1, {
2075
+ trace3.metrics.increment(`dxos.echo.${metricsGroupName}.send-status`, 1, {
1988
2076
  tags: {
1989
2077
  ...tags,
1990
2078
  success: true
@@ -2006,12 +2094,12 @@ var EchoDataMonitor = class {
2006
2094
  if (isAutomergeProtocolMessage(message)) {
2007
2095
  this._activeCounters.replication.received++;
2008
2096
  this._replicationAverages.receivedMessageSize.record(bytes);
2009
- trace2.metrics.distribution("dxos.echo.replication.bytes-received", bytes, {
2097
+ trace3.metrics.distribution("dxos.echo.replication.bytes-received", bytes, {
2010
2098
  unit: "bytes",
2011
2099
  tags
2012
2100
  });
2013
2101
  } else {
2014
- trace2.metrics.distribution("dxos.echo.collection-sync.bytes-received", bytes, {
2102
+ trace3.metrics.distribution("dxos.echo.collection-sync.bytes-received", bytes, {
2015
2103
  unit: "bytes",
2016
2104
  tags
2017
2105
  });
@@ -2031,12 +2119,12 @@ var EchoDataMonitor = class {
2031
2119
  };
2032
2120
  if (isAutomergeProtocolMessage(message)) {
2033
2121
  this._activeCounters.replication.failed++;
2034
- trace2.metrics.increment("dxos.echo.replication.send-status", 1, {
2122
+ trace3.metrics.increment("dxos.echo.replication.send-status", 1, {
2035
2123
  unit: "bytes",
2036
2124
  tags
2037
2125
  });
2038
2126
  } else {
2039
- trace2.metrics.increment("dxos.echo.collection-sync.send-status", 1, {
2127
+ trace3.metrics.increment("dxos.echo.collection-sync.send-status", 1, {
2040
2128
  unit: "bytes",
2041
2129
  tags
2042
2130
  });
@@ -2071,8 +2159,8 @@ var EchoDataMonitor = class {
2071
2159
  return result;
2072
2160
  }
2073
2161
  };
2074
- EchoDataMonitor = _ts_decorate3([
2075
- trace2.resource()
2162
+ EchoDataMonitor = _ts_decorate4([
2163
+ trace3.resource()
2076
2164
  ], EchoDataMonitor);
2077
2165
  var isAutomergeProtocolMessage = (message) => {
2078
2166
  return !(isCollectionQueryMessage(message) || isCollectionStateMessage(message));
@@ -2290,7 +2378,7 @@ import { createIdFromSpaceKey as createIdFromSpaceKey3, SpaceDocVersion as Space
2290
2378
  import { IndexMetadataStore, IndexStore, Indexer } from "@dxos/indexing";
2291
2379
  import { invariant as invariant11 } from "@dxos/invariant";
2292
2380
  import { IndexKind } from "@dxos/protocols/proto/dxos/echo/indexing";
2293
- import { trace as trace5 } from "@dxos/tracing";
2381
+ import { trace as trace6 } from "@dxos/tracing";
2294
2382
 
2295
2383
  // packages/core/echo/echo-pipeline/src/db-host/documents-iterator.ts
2296
2384
  import * as A3 from "@dxos/automerge/automerge";
@@ -2387,7 +2475,7 @@ import { Stream as Stream2 } from "@dxos/codec-protobuf/stream";
2387
2475
  import { Context as Context4, Resource as Resource7 } from "@dxos/context";
2388
2476
  import { log as log9 } from "@dxos/log";
2389
2477
  import { objectPointerCodec as objectPointerCodec4 } from "@dxos/protocols";
2390
- import { trace as trace4 } from "@dxos/tracing";
2478
+ import { trace as trace5 } from "@dxos/tracing";
2391
2479
 
2392
2480
  // packages/core/echo/echo-pipeline/src/db-host/query-state.ts
2393
2481
  import { Context as Context3, LifecycleState as LifecycleState3, Resource as Resource6 } from "@dxos/context";
@@ -2395,9 +2483,9 @@ import { createIdFromSpaceKey as createIdFromSpaceKey2 } from "@dxos/echo-protoc
2395
2483
  import { invariant as invariant9 } from "@dxos/invariant";
2396
2484
  import { DXN, PublicKey as PublicKey3 } from "@dxos/keys";
2397
2485
  import { objectPointerCodec as objectPointerCodec3 } from "@dxos/protocols";
2398
- import { trace as trace3 } from "@dxos/tracing";
2486
+ import { trace as trace4 } from "@dxos/tracing";
2399
2487
  import { isNonNullable as isNonNullable2 } from "@dxos/util";
2400
- function _ts_decorate4(decorators, target, key, desc) {
2488
+ function _ts_decorate5(decorators, target, key, desc) {
2401
2489
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2402
2490
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2403
2491
  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;
@@ -2497,19 +2585,19 @@ var QueryState = class extends Resource6 {
2497
2585
  };
2498
2586
  }
2499
2587
  };
2500
- _ts_decorate4([
2501
- trace3.info({
2588
+ _ts_decorate5([
2589
+ trace4.info({
2502
2590
  depth: null
2503
2591
  })
2504
2592
  ], QueryState.prototype, "filter", void 0);
2505
- _ts_decorate4([
2506
- trace3.info()
2593
+ _ts_decorate5([
2594
+ trace4.info()
2507
2595
  ], QueryState.prototype, "metrics", void 0);
2508
- _ts_decorate4([
2509
- trace3.info()
2596
+ _ts_decorate5([
2597
+ trace4.info()
2510
2598
  ], QueryState.prototype, "active", null);
2511
- _ts_decorate4([
2512
- trace3.span({
2599
+ _ts_decorate5([
2600
+ trace4.span({
2513
2601
  showInBrowserTimeline: true,
2514
2602
  op: "db.query",
2515
2603
  attributes: {
@@ -2517,8 +2605,8 @@ _ts_decorate4([
2517
2605
  }
2518
2606
  })
2519
2607
  ], QueryState.prototype, "execQuery", null);
2520
- QueryState = _ts_decorate4([
2521
- trace3.resource()
2608
+ QueryState = _ts_decorate5([
2609
+ trace4.resource()
2522
2610
  ], QueryState);
2523
2611
  var filterToIndexQuery = (filter) => {
2524
2612
  invariant9(!(filter.type && (filter.or ?? []).length > 0), "Cannot mix type and or filters.", {
@@ -2586,7 +2674,7 @@ var QueryServiceImpl = class extends Resource7 {
2586
2674
  }
2587
2675
  }));
2588
2676
  });
2589
- trace4.diagnostic({
2677
+ trace5.diagnostic({
2590
2678
  id: "active-queries",
2591
2679
  name: "Active Queries",
2592
2680
  fetch: () => {
@@ -2756,10 +2844,11 @@ var createDocumentsIterator = (automergeHost) => (
2756
2844
  // packages/core/echo/echo-pipeline/src/db-host/space-state-manager.ts
2757
2845
  import isEqual from "lodash.isequal";
2758
2846
  import { Event as Event3, UpdateScheduler as UpdateScheduler3 } from "@dxos/async";
2759
- import { interpretAsDocumentId } from "@dxos/automerge/automerge-repo";
2847
+ import { interpretAsDocumentId as interpretAsDocumentId3 } from "@dxos/automerge/automerge-repo";
2760
2848
  import { Resource as Resource8, Context as Context5 } from "@dxos/context";
2761
2849
 
2762
2850
  // packages/core/echo/echo-pipeline/src/db-host/database-root.ts
2851
+ import { interpretAsDocumentId as interpretAsDocumentId2 } from "@dxos/automerge/automerge-repo";
2763
2852
  import { SpaceDocVersion as SpaceDocVersion2 } from "@dxos/echo-protocol";
2764
2853
  import { invariant as invariant10 } from "@dxos/invariant";
2765
2854
 
@@ -2796,6 +2885,19 @@ var measureDocMetrics = (doc) => {
2796
2885
  // packages/core/echo/echo-pipeline/src/db-host/database-root.ts
2797
2886
  var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/database-root.ts";
2798
2887
  var DatabaseRoot = class {
2888
+ static mapLinks(doc, mapping) {
2889
+ doc.change((d) => {
2890
+ if (!d.links) {
2891
+ return;
2892
+ }
2893
+ for (const [key, value] of Object.entries(d.links)) {
2894
+ const documentId = interpretAsDocumentId2(value.toString());
2895
+ if (mapping[documentId]) {
2896
+ d.links[key] = `automerge:${mapping[documentId]}`;
2897
+ }
2898
+ }
2899
+ });
2900
+ }
2799
2901
  constructor(_rootHandle) {
2800
2902
  this._rootHandle = _rootHandle;
2801
2903
  }
@@ -2846,7 +2948,7 @@ var DatabaseRoot = class {
2846
2948
  const doc = this.docSync();
2847
2949
  invariant10(doc, void 0, {
2848
2950
  F: __dxlog_file13,
2849
- L: 74,
2951
+ L: 93,
2850
2952
  S: this,
2851
2953
  A: [
2852
2954
  "doc",
@@ -2916,7 +3018,7 @@ var SpaceStateManager = class extends Resource8 {
2916
3018
  const documentListCheckScheduler = new UpdateScheduler3(ctx, async () => {
2917
3019
  const documentIds = [
2918
3020
  root.documentId,
2919
- ...root.getAllLinkedDocuments().map((url) => interpretAsDocumentId(url))
3021
+ ...root.getAllLinkedDocuments().map((url) => interpretAsDocumentId3(url))
2920
3022
  ];
2921
3023
  if (!isEqual(documentIds, this._lastSpaceDocumentList.get(spaceId))) {
2922
3024
  this._lastSpaceDocumentList.set(spaceId, documentIds);
@@ -2987,7 +3089,7 @@ var EchoHost = class extends Resource9 {
2987
3089
  await this._indexer.updateIndexes();
2988
3090
  }
2989
3091
  });
2990
- trace5.diagnostic({
3092
+ trace6.diagnostic({
2991
3093
  id: "echo-stats",
2992
3094
  name: "Echo Stats",
2993
3095
  fetch: async () => {
@@ -2997,7 +3099,7 @@ var EchoHost = class extends Resource9 {
2997
3099
  };
2998
3100
  }
2999
3101
  });
3000
- trace5.diagnostic({
3102
+ trace6.diagnostic({
3001
3103
  id: "database-roots",
3002
3104
  name: "Database Roots",
3003
3105
  fetch: async () => {
@@ -3010,7 +3112,7 @@ var EchoHost = class extends Resource9 {
3010
3112
  }));
3011
3113
  }
3012
3114
  });
3013
- trace5.diagnostic({
3115
+ trace6.diagnostic({
3014
3116
  id: "database-root-metrics",
3015
3117
  name: "Database Roots (with metrics)",
3016
3118
  fetch: async () => {
@@ -3077,6 +3179,9 @@ var EchoHost = class extends Resource9 {
3077
3179
  async loadDoc(ctx, documentId, opts) {
3078
3180
  return await this._automergeHost.loadDoc(ctx, documentId, opts);
3079
3181
  }
3182
+ async exportDoc(ctx, id) {
3183
+ return await this._automergeHost.exportDoc(ctx, id);
3184
+ }
3080
3185
  /**
3081
3186
  * Create new persisted document.
3082
3187
  */
@@ -3089,7 +3194,7 @@ var EchoHost = class extends Resource9 {
3089
3194
  async createSpaceRoot(spaceKey) {
3090
3195
  invariant11(this._lifecycleState === LifecycleState4.OPEN, void 0, {
3091
3196
  F: __dxlog_file15,
3092
- L: 220,
3197
+ L: 224,
3093
3198
  S: this,
3094
3199
  A: [
3095
3200
  "this._lifecycleState === LifecycleState.OPEN",
@@ -3117,7 +3222,7 @@ var EchoHost = class extends Resource9 {
3117
3222
  async openSpaceRoot(spaceId, automergeUrl) {
3118
3223
  invariant11(this._lifecycleState === LifecycleState4.OPEN, void 0, {
3119
3224
  F: __dxlog_file15,
3120
- L: 239,
3225
+ L: 243,
3121
3226
  S: this,
3122
3227
  A: [
3123
3228
  "this._lifecycleState === LifecycleState.OPEN",
@@ -3155,7 +3260,7 @@ import { log as log12 } from "@dxos/log";
3155
3260
  import { EdgeService } from "@dxos/protocols";
3156
3261
  import { buf } from "@dxos/protocols/buf";
3157
3262
  import { MessageSchema as RouterMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
3158
- import { bufferToArray } from "@dxos/util";
3263
+ import { bufferToArray as bufferToArray2 } from "@dxos/util";
3159
3264
 
3160
3265
  // packages/core/echo/echo-pipeline/src/edge/inflight-request-limiter.ts
3161
3266
  import { Trigger as Trigger2 } from "@dxos/async";
@@ -3292,7 +3397,7 @@ var EchoEdgeReplicator = class {
3292
3397
  this._sharePolicyEnabled = !disableSharePolicy;
3293
3398
  }
3294
3399
  async connect(context) {
3295
- log12.info("connect", {
3400
+ log12.info("connecting...", {
3296
3401
  peerId: context.peerId,
3297
3402
  connectedSpaces: this._connectedSpaces.size
3298
3403
  }, {
@@ -3485,7 +3590,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
3485
3590
  });
3486
3591
  }
3487
3592
  async _open(ctx) {
3488
- log12("open", void 0, {
3593
+ log12("opening...", void 0, {
3489
3594
  F: __dxlog_file17,
3490
3595
  L: 251,
3491
3596
  S: this,
@@ -3498,7 +3603,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
3498
3603
  await this._onRemoteConnected();
3499
3604
  }
3500
3605
  async _close() {
3501
- log12("close", void 0, {
3606
+ log12("closing...", void 0, {
3502
3607
  F: __dxlog_file17,
3503
3608
  L: 266,
3504
3609
  S: this,
@@ -3530,7 +3635,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
3530
3635
  documentId: params.documentId,
3531
3636
  peerId: this._remotePeerId
3532
3637
  });
3533
- log12.verbose("edge-replicator document not found locally for share policy check", {
3638
+ log12.verbose("document not found locally for share policy check", {
3534
3639
  documentId: params.documentId,
3535
3640
  acceptDocument: remoteDocumentExists,
3536
3641
  remoteId: this._remotePeerId
@@ -3556,7 +3661,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
3556
3661
  return;
3557
3662
  }
3558
3663
  const payload = cbor2.decode(message.payload.value);
3559
- log12.verbose("edge replicator receive", {
3664
+ log12.verbose("received", {
3560
3665
  type: payload.type,
3561
3666
  documentId: payload.type === "sync" && payload.documentId,
3562
3667
  remoteId: this._remotePeerId
@@ -3579,7 +3684,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
3579
3684
  }
3580
3685
  async _sendMessage(message) {
3581
3686
  message.targetId = this._targetServiceId;
3582
- log12.verbose("edge replicator send", {
3687
+ log12.verbose("sending...", {
3583
3688
  type: message.type,
3584
3689
  documentId: message.type === "sync" && message.documentId,
3585
3690
  remoteId: this._remotePeerId
@@ -3597,7 +3702,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
3597
3702
  peerKey: this._edgeConnection.peerKey
3598
3703
  },
3599
3704
  payload: {
3600
- value: bufferToArray(encoded)
3705
+ value: bufferToArray2(encoded)
3601
3706
  }
3602
3707
  }));
3603
3708
  }