@dxos/echo-pipeline 0.8.4-main.dedc0f3 → 0.8.4-main.e8ec1fe

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 (53) hide show
  1. package/dist/lib/browser/{chunk-I4JBIZSN.mjs → chunk-FR6GJ4S4.mjs} +341 -427
  2. package/dist/lib/browser/{chunk-I4JBIZSN.mjs.map → chunk-FR6GJ4S4.mjs.map} +2 -2
  3. package/dist/lib/browser/{chunk-MBMJB3V7.mjs → chunk-WJJXJTNS.mjs} +62 -4
  4. package/dist/lib/browser/chunk-WJJXJTNS.mjs.map +7 -0
  5. package/dist/lib/browser/filter/index.mjs +1 -1
  6. package/dist/lib/browser/index.mjs +797 -802
  7. package/dist/lib/browser/index.mjs.map +3 -3
  8. package/dist/lib/browser/meta.json +1 -1
  9. package/dist/lib/browser/testing/index.mjs +65 -106
  10. package/dist/lib/browser/testing/index.mjs.map +3 -3
  11. package/dist/lib/node-esm/{chunk-YOL7JY5W.mjs → chunk-JQCCVDLT.mjs} +341 -427
  12. package/dist/lib/node-esm/{chunk-YOL7JY5W.mjs.map → chunk-JQCCVDLT.mjs.map} +2 -2
  13. package/dist/lib/node-esm/{chunk-XJZTCD4G.mjs → chunk-LEQ77KAT.mjs} +62 -4
  14. package/dist/lib/node-esm/chunk-LEQ77KAT.mjs.map +7 -0
  15. package/dist/lib/node-esm/filter/index.mjs +1 -1
  16. package/dist/lib/node-esm/index.mjs +797 -802
  17. package/dist/lib/node-esm/index.mjs.map +3 -3
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/testing/index.mjs +65 -106
  20. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  21. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  22. package/dist/types/src/automerge/collection-synchronizer.d.ts +2 -1
  23. package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
  24. package/dist/types/src/db-host/query-service.d.ts.map +1 -1
  25. package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
  26. package/dist/types/src/filter/filter-match.d.ts +2 -2
  27. package/dist/types/src/filter/filter-match.d.ts.map +1 -1
  28. package/dist/types/src/query/errors.d.ts +14 -13
  29. package/dist/types/src/query/errors.d.ts.map +1 -1
  30. package/dist/types/src/query/query-executor.d.ts +9 -0
  31. package/dist/types/src/query/query-executor.d.ts.map +1 -1
  32. package/dist/types/src/query/query-planner.d.ts.map +1 -1
  33. package/dist/types/src/testing/test-data.d.ts.map +1 -1
  34. package/dist/types/src/testing/test-schema.d.ts +1 -1
  35. package/dist/types/src/testing/test-schema.d.ts.map +1 -1
  36. package/dist/types/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +37 -39
  38. package/src/automerge/automerge-host.ts +34 -21
  39. package/src/automerge/collection-synchronizer.test.ts +4 -3
  40. package/src/automerge/collection-synchronizer.ts +14 -9
  41. package/src/db-host/echo-host.ts +1 -1
  42. package/src/db-host/query-service.ts +2 -1
  43. package/src/edge/echo-edge-replicator.ts +30 -9
  44. package/src/filter/filter-match.test.ts +32 -12
  45. package/src/filter/filter-match.ts +88 -11
  46. package/src/query/errors.ts +2 -0
  47. package/src/query/query-executor.ts +121 -36
  48. package/src/query/query-planner.test.ts +90 -5
  49. package/src/query/query-planner.ts +48 -12
  50. package/src/testing/test-data.ts +1 -1
  51. package/src/testing/test-schema.ts +1 -1
  52. package/dist/lib/browser/chunk-MBMJB3V7.mjs.map +0 -7
  53. package/dist/lib/node-esm/chunk-XJZTCD4G.mjs.map +0 -7
@@ -3,7 +3,7 @@ import {
3
3
  filterMatchObject,
4
4
  filterMatchObjectJSON,
5
5
  filterMatchValue
6
- } from "./chunk-MBMJB3V7.mjs";
6
+ } from "./chunk-WJJXJTNS.mjs";
7
7
  import {
8
8
  AuthExtension,
9
9
  AuthStatus,
@@ -26,7 +26,7 @@ import {
26
26
  mapTimeframeToFeedIndexes,
27
27
  startAfter,
28
28
  valueEncoding
29
- } from "./chunk-I4JBIZSN.mjs";
29
+ } from "./chunk-FR6GJ4S4.mjs";
30
30
  import "./chunk-CGS2ULMK.mjs";
31
31
 
32
32
  // src/db-host/data-service.ts
@@ -39,7 +39,6 @@ import { log as log7 } from "@dxos/log";
39
39
  // src/automerge/automerge-host.ts
40
40
  import { getBackend, getHeads, equals as headsEquals, isAutomerge, save } from "@automerge/automerge";
41
41
  import { Repo, interpretAsDocumentId } from "@automerge/automerge-repo";
42
- import { exportBundle } from "@automerge/automerge-repo-bundles";
43
42
  import { DeferredTask, Event as Event2, asyncTimeout } from "@dxos/async";
44
43
  import { Context, Resource as Resource3, cancelWithContext } from "@dxos/context";
45
44
  import { DatabaseDirectory } from "@dxos/echo-protocol";
@@ -48,28 +47,17 @@ import { PublicKey } from "@dxos/keys";
48
47
  import { log as log3 } from "@dxos/log";
49
48
  import { objectPointerCodec } from "@dxos/protocols";
50
49
  import { trace as trace2 } from "@dxos/tracing";
51
- import { ComplexSet, bufferToArray, range } from "@dxos/util";
50
+ import { ComplexSet, bufferToArray, isNonNullable as isNonNullable2, range } from "@dxos/util";
52
51
 
53
52
  // src/automerge/collection-synchronizer.ts
54
- import { next as am } from "@automerge/automerge";
53
+ import { next as A } from "@automerge/automerge";
54
+ import * as Array2 from "effect/Array";
55
+ import * as Record from "effect/Record";
55
56
  import { Event, asyncReturn, scheduleTask, scheduleTaskInterval } from "@dxos/async";
56
57
  import { Resource } from "@dxos/context";
57
58
  import { log } from "@dxos/log";
58
59
  import { trace } from "@dxos/tracing";
59
60
  import { defaultMap } from "@dxos/util";
60
- function _define_property(obj, key, value) {
61
- if (key in obj) {
62
- Object.defineProperty(obj, key, {
63
- value,
64
- enumerable: true,
65
- configurable: true,
66
- writable: true
67
- });
68
- } else {
69
- obj[key] = value;
70
- }
71
- return obj;
72
- }
73
61
  function _ts_decorate(decorators, target, key, desc) {
74
62
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
75
63
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -80,6 +68,22 @@ var __dxlog_file = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerg
80
68
  var MIN_QUERY_INTERVAL = 5e3;
81
69
  var POLL_INTERVAL = 3e4;
82
70
  var CollectionSynchronizer = class extends Resource {
71
+ _sendCollectionState;
72
+ _queryCollectionState;
73
+ _shouldSyncCollection;
74
+ /**
75
+ * CollectionId -> State.
76
+ */
77
+ _perCollectionStates = /* @__PURE__ */ new Map();
78
+ _activeCollections = /* @__PURE__ */ new Set();
79
+ _connectedPeers = /* @__PURE__ */ new Set();
80
+ remoteStateUpdated = new Event();
81
+ constructor(params) {
82
+ super();
83
+ this._sendCollectionState = params.sendCollectionState;
84
+ this._queryCollectionState = params.queryCollectionState;
85
+ this._shouldSyncCollection = params.shouldSyncCollection;
86
+ }
83
87
  async _open(ctx) {
84
88
  scheduleTaskInterval(this._ctx, async () => {
85
89
  for (const collectionId of this._perCollectionStates.keys()) {
@@ -105,7 +109,7 @@ var CollectionSynchronizer = class extends Resource {
105
109
  state
106
110
  }, {
107
111
  F: __dxlog_file,
108
- L: 76,
112
+ L: 78,
109
113
  S: this,
110
114
  C: (f, a) => f(...a)
111
115
  });
@@ -124,7 +128,7 @@ var CollectionSynchronizer = class extends Resource {
124
128
  collectionId
125
129
  }, {
126
130
  F: __dxlog_file,
127
- L: 90,
131
+ L: 92,
128
132
  S: this,
129
133
  C: (f, a) => f(...a)
130
134
  });
@@ -207,7 +211,7 @@ var CollectionSynchronizer = class extends Resource {
207
211
  state
208
212
  }, {
209
213
  F: __dxlog_file,
210
- L: 171,
214
+ L: 173,
211
215
  S: this,
212
216
  C: (f, a) => f(...a)
213
217
  });
@@ -258,33 +262,28 @@ var CollectionSynchronizer = class extends Resource {
258
262
  }
259
263
  }
260
264
  }
261
- constructor(params) {
262
- super(), _define_property(this, "_sendCollectionState", void 0), _define_property(this, "_queryCollectionState", void 0), _define_property(this, "_shouldSyncCollection", void 0), /**
263
- * CollectionId -> State.
264
- */
265
- _define_property(this, "_perCollectionStates", /* @__PURE__ */ new Map()), _define_property(this, "_activeCollections", /* @__PURE__ */ new Set()), _define_property(this, "_connectedPeers", /* @__PURE__ */ new Set()), _define_property(this, "remoteStateUpdated", new Event());
266
- this._sendCollectionState = params.sendCollectionState;
267
- this._queryCollectionState = params.queryCollectionState;
268
- this._shouldSyncCollection = params.shouldSyncCollection;
269
- }
270
265
  };
271
266
  CollectionSynchronizer = _ts_decorate([
272
267
  trace.resource()
273
268
  ], CollectionSynchronizer);
274
269
  var diffCollectionState = (local, remote) => {
275
- const allDocuments = /* @__PURE__ */ new Set([
276
- ...Object.keys(local.documents),
277
- ...Object.keys(remote.documents)
278
- ]);
270
+ const localDocuments = Record.filter(local.documents, (heads) => heads.length > 0);
271
+ const remoteDocuments = Record.filter(remote.documents, (heads) => heads.length > 0);
272
+ const allDocuments = [
273
+ .../* @__PURE__ */ new Set([
274
+ ...Record.keys(localDocuments),
275
+ ...Record.keys(remoteDocuments)
276
+ ])
277
+ ];
279
278
  const missingOnRemote = [];
280
279
  const missingOnLocal = [];
281
280
  const different = [];
282
281
  for (const documentId of allDocuments) {
283
- if (!local.documents[documentId] || local.documents[documentId].length === 0) {
282
+ if (!localDocuments[documentId]) {
284
283
  missingOnLocal.push(documentId);
285
- } else if (!remote.documents[documentId] || remote.documents[documentId].length === 0) {
284
+ } else if (!remoteDocuments[documentId]) {
286
285
  missingOnRemote.push(documentId);
287
- } else if (!am.equals(local.documents[documentId], remote.documents[documentId])) {
286
+ } else if (!A.equals(local.documents[documentId], remote.documents[documentId])) {
288
287
  different.push(documentId);
289
288
  }
290
289
  }
@@ -299,7 +298,7 @@ var validateCollectionState = (state) => {
299
298
  if (!isValidDocumentId(documentId)) {
300
299
  throw new Error(`Invalid documentId: ${documentId}`);
301
300
  }
302
- if (Array.isArray(heads) && heads.some((head) => typeof head !== "string")) {
301
+ if (Array2.isArray(heads) && heads.some((head) => typeof head !== "string")) {
303
302
  throw new Error(`Invalid heads: ${heads}`);
304
303
  }
305
304
  });
@@ -325,19 +324,6 @@ var isCollectionQueryMessage = (message) => message.type === MESSAGE_TYPE_COLLEC
325
324
  var isCollectionStateMessage = (message) => message.type === MESSAGE_TYPE_COLLECTION_STATE;
326
325
 
327
326
  // src/automerge/echo-network-adapter.ts
328
- function _define_property2(obj, key, value) {
329
- if (key in obj) {
330
- Object.defineProperty(obj, key, {
331
- value,
332
- enumerable: true,
333
- configurable: true,
334
- writable: true
335
- });
336
- } else {
337
- obj[key] = value;
338
- }
339
- return obj;
340
- }
341
327
  function _ts_decorate2(decorators, target, key, desc) {
342
328
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
343
329
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -346,6 +332,18 @@ function _ts_decorate2(decorators, target, key, desc) {
346
332
  }
347
333
  var __dxlog_file2 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts";
348
334
  var EchoNetworkAdapter = class extends NetworkAdapter {
335
+ _params;
336
+ _replicators = /* @__PURE__ */ new Set();
337
+ /**
338
+ * Remote peer id -> connection.
339
+ */
340
+ _connections = /* @__PURE__ */ new Map();
341
+ _lifecycleState = LifecycleState.CLOSED;
342
+ _connected = new Trigger();
343
+ _ready = new Trigger();
344
+ constructor(_params) {
345
+ super(), this._params = _params;
346
+ }
349
347
  isReady() {
350
348
  return this._lifecycleState === LifecycleState.OPEN;
351
349
  }
@@ -675,12 +673,6 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
675
673
  peerMetadata: createEchoPeerMetadata()
676
674
  });
677
675
  }
678
- constructor(_params) {
679
- super(), _define_property2(this, "_params", void 0), _define_property2(this, "_replicators", void 0), /**
680
- * Remote peer id -> connection.
681
- */
682
- _define_property2(this, "_connections", void 0), _define_property2(this, "_lifecycleState", void 0), _define_property2(this, "_connected", void 0), _define_property2(this, "_ready", void 0), this._params = _params, this._replicators = /* @__PURE__ */ new Set(), this._connections = /* @__PURE__ */ new Map(), this._lifecycleState = LifecycleState.CLOSED, this._connected = new Trigger(), this._ready = new Trigger();
683
- }
684
676
  };
685
677
  _ts_decorate2([
686
678
  synchronized
@@ -702,20 +694,11 @@ var isEchoPeerMetadata = (metadata) => metadata?.dxos_peerSource === "EchoNetwor
702
694
 
703
695
  // src/automerge/heads-store.ts
704
696
  import { headsEncoding } from "@dxos/indexing";
705
- function _define_property3(obj, key, value) {
706
- if (key in obj) {
707
- Object.defineProperty(obj, key, {
708
- value,
709
- enumerable: true,
710
- configurable: true,
711
- writable: true
712
- });
713
- } else {
714
- obj[key] = value;
715
- }
716
- return obj;
717
- }
718
697
  var HeadsStore = class {
698
+ _db;
699
+ constructor({ db }) {
700
+ this._db = db;
701
+ }
719
702
  setHeads(documentId, heads, batch) {
720
703
  batch.put(documentId, heads, {
721
704
  sublevel: this._db,
@@ -730,28 +713,15 @@ var HeadsStore = class {
730
713
  valueEncoding: headsEncoding
731
714
  });
732
715
  }
733
- constructor({ db }) {
734
- _define_property3(this, "_db", void 0);
735
- this._db = db;
736
- }
737
716
  };
738
717
 
739
718
  // src/automerge/leveldb-storage-adapter.ts
740
719
  import { Resource as Resource2 } from "@dxos/context";
741
- function _define_property4(obj, key, value) {
742
- if (key in obj) {
743
- Object.defineProperty(obj, key, {
744
- value,
745
- enumerable: true,
746
- configurable: true,
747
- writable: true
748
- });
749
- } else {
750
- obj[key] = value;
751
- }
752
- return obj;
753
- }
754
720
  var LevelDBStorageAdapter = class extends Resource2 {
721
+ _params;
722
+ constructor(_params) {
723
+ super(), this._params = _params;
724
+ }
755
725
  async load(keyArray) {
756
726
  try {
757
727
  if (!this.isOpen) {
@@ -839,9 +809,6 @@ var LevelDBStorageAdapter = class extends Resource2 {
839
809
  }
840
810
  await batch.write();
841
811
  }
842
- constructor(_params) {
843
- super(), _define_property4(this, "_params", void 0), this._params = _params;
844
- }
845
812
  };
846
813
  var keyEncoder = {
847
814
  encode: (key) => Buffer.from(key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-")),
@@ -855,19 +822,6 @@ var encodingOptions = {
855
822
  var isLevelDbNotFoundError = (err) => err.code === "LEVEL_NOT_FOUND";
856
823
 
857
824
  // src/automerge/automerge-host.ts
858
- function _define_property5(obj, key, value) {
859
- if (key in obj) {
860
- Object.defineProperty(obj, key, {
861
- value,
862
- enumerable: true,
863
- configurable: true,
864
- writable: true
865
- });
866
- } else {
867
- obj[key] = value;
868
- }
869
- return obj;
870
- }
871
825
  function _ts_decorate3(decorators, target, key, desc) {
872
826
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
873
827
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -885,6 +839,57 @@ var BUNDLE_SIZE = 100;
885
839
  var BUNDLE_SYNC_CONCURRENCY = 2;
886
840
  var BUNDLE_SYNC_THRESHOLD = 50;
887
841
  var AutomergeHost = class extends Resource3 {
842
+ _db;
843
+ _indexMetadataStore;
844
+ _echoNetworkAdapter;
845
+ _collectionSynchronizer = new CollectionSynchronizer({
846
+ queryCollectionState: this._queryCollectionState.bind(this),
847
+ sendCollectionState: this._sendCollectionState.bind(this),
848
+ shouldSyncCollection: this._shouldSyncCollection.bind(this)
849
+ });
850
+ _repo;
851
+ _storage;
852
+ _headsStore;
853
+ _syncTask = void 0;
854
+ /**
855
+ * Cache of collections that would be synced on next sync task run.
856
+ */
857
+ _collectionsToSync = new ComplexSet(({ collectionId, peerId }) => `${collectionId}|${peerId}`);
858
+ _peerId;
859
+ _peerIdProvider;
860
+ _getSpaceKeyByRootDocumentId;
861
+ collectionStateUpdated = new Event2();
862
+ /**
863
+ * Fired after a batch of documents was saved to disk.
864
+ */
865
+ documentsSaved = new Event2();
866
+ _headsUpdates = /* @__PURE__ */ new Map();
867
+ _onHeadsChangedTask;
868
+ constructor({ db, indexMetadataStore, dataMonitor, peerIdProvider, getSpaceKeyByRootDocumentId }) {
869
+ super();
870
+ this._db = db;
871
+ this._storage = new LevelDBStorageAdapter({
872
+ db: db.sublevel("automerge"),
873
+ callbacks: {
874
+ beforeSave: async (params) => this._beforeSave(params),
875
+ afterSave: async (key) => this._afterSave(key)
876
+ },
877
+ monitor: dataMonitor
878
+ });
879
+ this._echoNetworkAdapter = new EchoNetworkAdapter({
880
+ getContainingSpaceForDocument: this._getContainingSpaceForDocument.bind(this),
881
+ isDocumentInRemoteCollection: this._isDocumentInRemoteCollection.bind(this),
882
+ onCollectionStateQueried: this._onCollectionStateQueried.bind(this),
883
+ onCollectionStateReceived: this._onCollectionStateReceived.bind(this),
884
+ monitor: dataMonitor
885
+ });
886
+ this._headsStore = new HeadsStore({
887
+ db: db.sublevel("heads")
888
+ });
889
+ this._indexMetadataStore = indexMetadataStore;
890
+ this._peerIdProvider = peerIdProvider;
891
+ this._getSpaceKeyByRootDocumentId = getSpaceKeyByRootDocumentId;
892
+ }
888
893
  async _open() {
889
894
  this._peerId = `host-${this._peerIdProvider?.() ?? PublicKey.random().toHex()}`;
890
895
  this._onHeadsChangedTask = new DeferredTask(this._ctx, async () => {
@@ -934,7 +939,7 @@ var AutomergeHost = class extends Resource3 {
934
939
  err
935
940
  }, {
936
941
  F: __dxlog_file3,
937
- L: 224,
942
+ L: 223,
938
943
  S: this,
939
944
  C: (f, a) => f(...a)
940
945
  });
@@ -968,7 +973,7 @@ var AutomergeHost = class extends Resource3 {
968
973
  async addReplicator(replicator) {
969
974
  invariant2(this.isOpen, "AutomergeHost is not open", {
970
975
  F: __dxlog_file3,
971
- L: 260,
976
+ L: 259,
972
977
  S: this,
973
978
  A: [
974
979
  "this.isOpen",
@@ -980,7 +985,7 @@ var AutomergeHost = class extends Resource3 {
980
985
  async removeReplicator(replicator) {
981
986
  invariant2(this.isOpen, "AutomergeHost is not open", {
982
987
  F: __dxlog_file3,
983
- L: 265,
988
+ L: 264,
984
989
  S: this,
985
990
  A: [
986
991
  "this.isOpen",
@@ -995,7 +1000,7 @@ var AutomergeHost = class extends Resource3 {
995
1000
  async loadDoc(ctx, documentId, opts) {
996
1001
  invariant2(this.isOpen, "AutomergeHost is not open", {
997
1002
  F: __dxlog_file3,
998
- L: 273,
1003
+ L: 272,
999
1004
  S: this,
1000
1005
  A: [
1001
1006
  "this.isOpen",
@@ -1021,7 +1026,7 @@ var AutomergeHost = class extends Resource3 {
1021
1026
  async exportDoc(ctx, id) {
1022
1027
  invariant2(this.isOpen, "AutomergeHost is not open", {
1023
1028
  F: __dxlog_file3,
1024
- L: 296,
1029
+ L: 295,
1025
1030
  S: this,
1026
1031
  A: [
1027
1032
  "this.isOpen",
@@ -1040,7 +1045,7 @@ var AutomergeHost = class extends Resource3 {
1040
1045
  createDoc(initialValue, opts) {
1041
1046
  invariant2(this.isOpen, "AutomergeHost is not open", {
1042
1047
  F: __dxlog_file3,
1043
- L: 307,
1048
+ L: 306,
1044
1049
  S: this,
1045
1050
  A: [
1046
1051
  "this.isOpen",
@@ -1065,7 +1070,7 @@ var AutomergeHost = class extends Resource3 {
1065
1070
  async waitUntilHeadsReplicated(heads) {
1066
1071
  invariant2(this.isOpen, "AutomergeHost is not open", {
1067
1072
  F: __dxlog_file3,
1068
- L: 329,
1073
+ L: 328,
1069
1074
  S: this,
1070
1075
  A: [
1071
1076
  "this.isOpen",
@@ -1087,10 +1092,10 @@ var AutomergeHost = class extends Resource3 {
1087
1092
  return !(currentHeads !== null && headsEquals(currentHeads, targetHeads));
1088
1093
  });
1089
1094
  if (headsToWait.length > 0) {
1090
- await Promise.all(headsToWait.map(async (entry, index) => {
1095
+ await Promise.all(headsToWait.map(async (entry) => {
1091
1096
  const handle = await this.loadDoc(Context.default(void 0, {
1092
1097
  F: __dxlog_file3,
1093
- L: 347
1098
+ L: 346
1094
1099
  }), entry.documentId);
1095
1100
  await waitForHeads(handle, entry.heads);
1096
1101
  }));
@@ -1100,7 +1105,7 @@ var AutomergeHost = class extends Resource3 {
1100
1105
  async reIndexHeads(documentIds) {
1101
1106
  invariant2(this.isOpen, "AutomergeHost is not open", {
1102
1107
  F: __dxlog_file3,
1103
- L: 360,
1108
+ L: 359,
1104
1109
  S: this,
1105
1110
  A: [
1106
1111
  "this.isOpen",
@@ -1112,7 +1117,7 @@ var AutomergeHost = class extends Resource3 {
1112
1117
  documentId
1113
1118
  }, {
1114
1119
  F: __dxlog_file3,
1115
- L: 362,
1120
+ L: 361,
1116
1121
  S: this,
1117
1122
  C: (f, a) => f(...a)
1118
1123
  });
@@ -1122,7 +1127,7 @@ var AutomergeHost = class extends Resource3 {
1122
1127
  documentId
1123
1128
  }, {
1124
1129
  F: __dxlog_file3,
1125
- L: 365,
1130
+ L: 364,
1126
1131
  S: this,
1127
1132
  C: (f, a) => f(...a)
1128
1133
  });
@@ -1135,7 +1140,7 @@ var AutomergeHost = class extends Resource3 {
1135
1140
  }
1136
1141
  log3("done re-indexing heads", void 0, {
1137
1142
  F: __dxlog_file3,
1138
- L: 374,
1143
+ L: 373,
1139
1144
  S: this,
1140
1145
  C: (f, a) => f(...a)
1141
1146
  });
@@ -1145,9 +1150,6 @@ var AutomergeHost = class extends Resource3 {
1145
1150
  // NOTE: If both peers return sharePolicy=false the replication will not happen
1146
1151
  // https://github.com/automerge/automerge-repo/pull/292
1147
1152
  async _sharePolicy(peerId, documentId) {
1148
- if (peerId.startsWith("client-")) {
1149
- return false;
1150
- }
1151
1153
  if (!documentId) {
1152
1154
  return false;
1153
1155
  }
@@ -1213,7 +1215,7 @@ var AutomergeHost = class extends Resource3 {
1213
1215
  this._headsUpdates.set(documentId, heads);
1214
1216
  invariant2(this._onHeadsChangedTask, "onHeadsChangedTask is not initialized", {
1215
1217
  F: __dxlog_file3,
1216
- L: 450,
1218
+ L: 445,
1217
1219
  S: this,
1218
1220
  A: [
1219
1221
  "this._onHeadsChangedTask",
@@ -1257,11 +1259,12 @@ var AutomergeHost = class extends Resource3 {
1257
1259
  * Flush documents to disk.
1258
1260
  */
1259
1261
  async flush({ documentIds } = {}) {
1260
- const loadedDocuments = documentIds?.filter((documentId) => {
1262
+ const loadedDocuments = (documentIds ?? Object.keys(this._repo.handles)).filter((documentId) => {
1261
1263
  const handle = this._repo.handles[documentId];
1262
1264
  return handle && handle.isReady();
1263
1265
  });
1264
1266
  await this._repo.flush(loadedDocuments);
1267
+ await this._onHeadsChangedTask?.runBlocking();
1265
1268
  }
1266
1269
  async getHeads(documentIds) {
1267
1270
  const result = [];
@@ -1396,7 +1399,7 @@ var AutomergeHost = class extends Resource3 {
1396
1399
  amount: missingOnRemote.length
1397
1400
  }, {
1398
1401
  F: __dxlog_file3,
1399
- L: 649,
1402
+ L: 650,
1400
1403
  S: this,
1401
1404
  C: (f, a) => f(...a)
1402
1405
  });
@@ -1409,7 +1412,7 @@ var AutomergeHost = class extends Resource3 {
1409
1412
  amount: missingOnRemote.length
1410
1413
  }, {
1411
1414
  F: __dxlog_file3,
1412
- L: 653,
1415
+ L: 654,
1413
1416
  S: this,
1414
1417
  C: (f, a) => f(...a)
1415
1418
  });
@@ -1420,7 +1423,7 @@ var AutomergeHost = class extends Resource3 {
1420
1423
  amount: missingOnLocal.length
1421
1424
  }, {
1422
1425
  F: __dxlog_file3,
1423
- L: 661,
1426
+ L: 662,
1424
1427
  S: this,
1425
1428
  C: (f, a) => f(...a)
1426
1429
  });
@@ -1433,7 +1436,7 @@ var AutomergeHost = class extends Resource3 {
1433
1436
  amount: missingOnLocal.length
1434
1437
  }, {
1435
1438
  F: __dxlog_file3,
1436
- L: 665,
1439
+ L: 666,
1437
1440
  S: this,
1438
1441
  C: (f, a) => f(...a)
1439
1442
  });
@@ -1449,7 +1452,7 @@ var AutomergeHost = class extends Resource3 {
1449
1452
  count: toReplicateWithoutBatching.length
1450
1453
  }, {
1451
1454
  F: __dxlog_file3,
1452
- L: 677,
1455
+ L: 678,
1453
1456
  S: this,
1454
1457
  C: (f, a) => f(...a)
1455
1458
  });
@@ -1477,7 +1480,7 @@ var AutomergeHost = class extends Resource3 {
1477
1480
  err
1478
1481
  }, {
1479
1482
  F: __dxlog_file3,
1480
- L: 708,
1483
+ L: 709,
1481
1484
  S: this,
1482
1485
  C: (f, a) => f(...a)
1483
1486
  });
@@ -1493,13 +1496,38 @@ var AutomergeHost = class extends Resource3 {
1493
1496
  if (this._ctx.disposed) {
1494
1497
  return;
1495
1498
  }
1496
- const handles = documentIds.map((documentId) => this._repo.handles[documentId]);
1497
- const bundle = exportBundle(this._repo, handles);
1498
- await this._echoNetworkAdapter.pushBundle(peerId, Array.from(bundle.docs.entries()).map(([documentId, doc]) => ({
1499
- documentId,
1500
- data: doc.data,
1501
- heads: doc.heads
1502
- })));
1499
+ const docs = documentIds.map((documentId) => {
1500
+ const handle = this._repo.handles[documentId];
1501
+ if (!handle || !handle.isReady()) {
1502
+ log3.warn("document not ready, skipping", {
1503
+ documentId
1504
+ }, {
1505
+ F: __dxlog_file3,
1506
+ L: 727,
1507
+ S: this,
1508
+ C: (f, a) => f(...a)
1509
+ });
1510
+ return;
1511
+ }
1512
+ const doc = handle.doc();
1513
+ if (!doc) {
1514
+ log3.warn("document not available, skipping", {
1515
+ documentId
1516
+ }, {
1517
+ F: __dxlog_file3,
1518
+ L: 732,
1519
+ S: this,
1520
+ C: (f, a) => f(...a)
1521
+ });
1522
+ return;
1523
+ }
1524
+ return {
1525
+ documentId,
1526
+ data: save(doc),
1527
+ heads: getHeads(doc)
1528
+ };
1529
+ });
1530
+ await this._echoNetworkAdapter.pushBundle(peerId, docs.filter(isNonNullable2));
1503
1531
  }
1504
1532
  async _pullInBundles(peerId, documentIds) {
1505
1533
  const documentsToPull = [
@@ -1520,7 +1548,7 @@ var AutomergeHost = class extends Resource3 {
1520
1548
  err
1521
1549
  }, {
1522
1550
  F: __dxlog_file3,
1523
- L: 752,
1551
+ L: 762,
1524
1552
  S: this,
1525
1553
  C: (f, a) => f(...a)
1526
1554
  });
@@ -1558,9 +1586,12 @@ var AutomergeHost = class extends Resource3 {
1558
1586
  const collectionsChanged = /* @__PURE__ */ new Set();
1559
1587
  for (const collectionId of this._collectionSynchronizer.getRegisteredCollectionIds()) {
1560
1588
  const state = this._collectionSynchronizer.getLocalCollectionState(collectionId);
1589
+ if (!state) {
1590
+ continue;
1591
+ }
1561
1592
  let newState;
1562
1593
  for (const [documentId, heads] of docHeads) {
1563
- if (state?.documents[documentId]) {
1594
+ if (documentId in state.documents) {
1564
1595
  if (!newState) {
1565
1596
  newState = structuredClone(state);
1566
1597
  }
@@ -1578,41 +1609,6 @@ var AutomergeHost = class extends Resource3 {
1578
1609
  });
1579
1610
  }
1580
1611
  }
1581
- constructor({ db, indexMetadataStore, dataMonitor, peerIdProvider, getSpaceKeyByRootDocumentId }) {
1582
- super(), _define_property5(this, "_db", void 0), _define_property5(this, "_indexMetadataStore", void 0), _define_property5(this, "_echoNetworkAdapter", void 0), _define_property5(this, "_collectionSynchronizer", new CollectionSynchronizer({
1583
- queryCollectionState: this._queryCollectionState.bind(this),
1584
- sendCollectionState: this._sendCollectionState.bind(this),
1585
- shouldSyncCollection: this._shouldSyncCollection.bind(this)
1586
- })), _define_property5(this, "_repo", void 0), _define_property5(this, "_storage", void 0), _define_property5(this, "_headsStore", void 0), _define_property5(this, "_syncTask", void 0), /**
1587
- * Cache of collections that would be synced on next sync task run.
1588
- */
1589
- _define_property5(this, "_collectionsToSync", new ComplexSet(({ collectionId, peerId }) => `${collectionId}|${peerId}`)), _define_property5(this, "_peerId", void 0), _define_property5(this, "_peerIdProvider", void 0), _define_property5(this, "_getSpaceKeyByRootDocumentId", void 0), _define_property5(this, "collectionStateUpdated", new Event2()), /**
1590
- * Fired after a batch of documents was saved to disk.
1591
- */
1592
- _define_property5(this, "documentsSaved", new Event2()), _define_property5(this, "_headsUpdates", /* @__PURE__ */ new Map()), _define_property5(this, "_onHeadsChangedTask", void 0);
1593
- this._db = db;
1594
- this._storage = new LevelDBStorageAdapter({
1595
- db: db.sublevel("automerge"),
1596
- callbacks: {
1597
- beforeSave: async (params) => this._beforeSave(params),
1598
- afterSave: async (key) => this._afterSave(key)
1599
- },
1600
- monitor: dataMonitor
1601
- });
1602
- this._echoNetworkAdapter = new EchoNetworkAdapter({
1603
- getContainingSpaceForDocument: this._getContainingSpaceForDocument.bind(this),
1604
- isDocumentInRemoteCollection: this._isDocumentInRemoteCollection.bind(this),
1605
- onCollectionStateQueried: this._onCollectionStateQueried.bind(this),
1606
- onCollectionStateReceived: this._onCollectionStateReceived.bind(this),
1607
- monitor: dataMonitor
1608
- });
1609
- this._headsStore = new HeadsStore({
1610
- db: db.sublevel("heads")
1611
- });
1612
- this._indexMetadataStore = indexMetadataStore;
1613
- this._peerIdProvider = peerIdProvider;
1614
- this._getSpaceKeyByRootDocumentId = getSpaceKeyByRootDocumentId;
1615
- }
1616
1612
  };
1617
1613
  _ts_decorate3([
1618
1614
  trace2.info()
@@ -1648,7 +1644,7 @@ var changeIsPresentInDoc = (doc, changeHash) => {
1648
1644
  var decodeCollectionState = (state) => {
1649
1645
  invariant2(typeof state === "object" && state !== null, "Invalid state", {
1650
1646
  F: __dxlog_file3,
1651
- L: 832,
1647
+ L: 845,
1652
1648
  S: void 0,
1653
1649
  A: [
1654
1650
  "typeof state === 'object' && state !== null",
@@ -1668,81 +1664,24 @@ import { log as log5 } from "@dxos/log";
1668
1664
  import { ComplexSet as ComplexSet2, defaultMap as defaultMap2 } from "@dxos/util";
1669
1665
 
1670
1666
  // src/automerge/mesh-echo-replicator-connection.ts
1671
- import * as A from "@automerge/automerge";
1667
+ import * as A2 from "@automerge/automerge";
1672
1668
  import { cbor } from "@automerge/automerge-repo";
1673
1669
  import { Resource as Resource4 } from "@dxos/context";
1674
1670
  import { invariant as invariant3 } from "@dxos/invariant";
1675
1671
  import { log as log4 } from "@dxos/log";
1676
1672
  import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
1677
- function _define_property6(obj, key, value) {
1678
- if (key in obj) {
1679
- Object.defineProperty(obj, key, {
1680
- value,
1681
- enumerable: true,
1682
- configurable: true,
1683
- writable: true
1684
- });
1685
- } else {
1686
- obj[key] = value;
1687
- }
1688
- return obj;
1689
- }
1690
1673
  var __dxlog_file4 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts";
1691
1674
  var DEFAULT_FACTORY = (params) => new AutomergeReplicator(...params);
1692
1675
  var MeshReplicatorConnection = class extends Resource4 {
1693
- _disconnectIfEnabled() {
1694
- if (this._isEnabled) {
1695
- this._params.onRemoteDisconnected();
1696
- }
1697
- }
1698
- get peerId() {
1699
- invariant3(this._remotePeerId != null, "Remote peer has not connected yet.", {
1700
- F: __dxlog_file4,
1701
- L: 106,
1702
- S: this,
1703
- A: [
1704
- "this._remotePeerId != null",
1705
- "'Remote peer has not connected yet.'"
1706
- ]
1707
- });
1708
- return this._remotePeerId;
1709
- }
1710
- get isEnabled() {
1711
- return this._isEnabled;
1712
- }
1713
- get bundleSyncEnabled() {
1714
- return false;
1715
- }
1716
- async shouldAdvertise(params) {
1717
- return this._params.shouldAdvertise(params);
1718
- }
1719
- shouldSyncCollection(params) {
1720
- return this._params.shouldSyncCollection(params);
1721
- }
1722
- /**
1723
- * Start exchanging messages with the remote peer.
1724
- * Call after the remote peer has connected.
1725
- */
1726
- enable() {
1727
- invariant3(this._remotePeerId != null, "Remote peer has not connected yet.", {
1728
- F: __dxlog_file4,
1729
- L: 131,
1730
- S: this,
1731
- A: [
1732
- "this._remotePeerId != null",
1733
- "'Remote peer has not connected yet.'"
1734
- ]
1735
- });
1736
- this._isEnabled = true;
1737
- }
1738
- /**
1739
- * Stop exchanging messages with the remote peer.
1740
- */
1741
- disable() {
1742
- this._isEnabled = false;
1743
- }
1676
+ _params;
1677
+ readable;
1678
+ writable;
1679
+ remoteDeviceKey = null;
1680
+ replicatorExtension;
1681
+ _remotePeerId = null;
1682
+ _isEnabled = false;
1744
1683
  constructor(_params) {
1745
- super(), _define_property6(this, "_params", void 0), _define_property6(this, "readable", void 0), _define_property6(this, "writable", void 0), _define_property6(this, "remoteDeviceKey", void 0), _define_property6(this, "replicatorExtension", void 0), _define_property6(this, "_remotePeerId", void 0), _define_property6(this, "_isEnabled", void 0), this._params = _params, this.remoteDeviceKey = null, this._remotePeerId = null, this._isEnabled = false;
1684
+ super(), this._params = _params;
1746
1685
  let readableStreamController;
1747
1686
  this.readable = new ReadableStream({
1748
1687
  start: (controller) => {
@@ -1806,10 +1745,61 @@ var MeshReplicatorConnection = class extends Resource4 {
1806
1745
  }
1807
1746
  ]);
1808
1747
  }
1748
+ _disconnectIfEnabled() {
1749
+ if (this._isEnabled) {
1750
+ this._params.onRemoteDisconnected();
1751
+ }
1752
+ }
1753
+ get peerId() {
1754
+ invariant3(this._remotePeerId != null, "Remote peer has not connected yet.", {
1755
+ F: __dxlog_file4,
1756
+ L: 106,
1757
+ S: this,
1758
+ A: [
1759
+ "this._remotePeerId != null",
1760
+ "'Remote peer has not connected yet.'"
1761
+ ]
1762
+ });
1763
+ return this._remotePeerId;
1764
+ }
1765
+ get isEnabled() {
1766
+ return this._isEnabled;
1767
+ }
1768
+ get bundleSyncEnabled() {
1769
+ return false;
1770
+ }
1771
+ async shouldAdvertise(params) {
1772
+ return this._params.shouldAdvertise(params);
1773
+ }
1774
+ shouldSyncCollection(params) {
1775
+ return this._params.shouldSyncCollection(params);
1776
+ }
1777
+ /**
1778
+ * Start exchanging messages with the remote peer.
1779
+ * Call after the remote peer has connected.
1780
+ */
1781
+ enable() {
1782
+ invariant3(this._remotePeerId != null, "Remote peer has not connected yet.", {
1783
+ F: __dxlog_file4,
1784
+ L: 131,
1785
+ S: this,
1786
+ A: [
1787
+ "this._remotePeerId != null",
1788
+ "'Remote peer has not connected yet.'"
1789
+ ]
1790
+ });
1791
+ this._isEnabled = true;
1792
+ }
1793
+ /**
1794
+ * Stop exchanging messages with the remote peer.
1795
+ */
1796
+ disable() {
1797
+ this._isEnabled = false;
1798
+ }
1809
1799
  };
1810
1800
  var logSendSync = (message) => {
1811
1801
  log4("sendSyncMessage", () => {
1812
- const decodedSyncMessage = message.type === "sync" && message.data ? A.decodeSyncMessage(message.data) : void 0;
1802
+ const decodedSyncMessage = message.type === "sync" && message.data ? A2.decodeSyncMessage(message.data) : void 0;
1813
1803
  return {
1814
1804
  sync: decodedSyncMessage && {
1815
1805
  headsLength: decodedSyncMessage.heads.length,
@@ -1848,21 +1838,24 @@ var getSpaceIdFromCollectionId = (collectionId) => {
1848
1838
  };
1849
1839
 
1850
1840
  // src/automerge/mesh-echo-replicator.ts
1851
- function _define_property7(obj, key, value) {
1852
- if (key in obj) {
1853
- Object.defineProperty(obj, key, {
1854
- value,
1855
- enumerable: true,
1856
- configurable: true,
1857
- writable: true
1858
- });
1859
- } else {
1860
- obj[key] = value;
1861
- }
1862
- return obj;
1863
- }
1864
1841
  var __dxlog_file6 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts";
1865
1842
  var MeshEchoReplicator = class {
1843
+ /**
1844
+ * We might have multiple connections open with a peer (one per space), but there'll be only one enabled
1845
+ * connection at any given moment, because there's a single repo for all the spaces.
1846
+ * When a connection closes (space was closed) it gets removed from the list and the next connection
1847
+ * in the line gets enabled.
1848
+ */
1849
+ _connectionsPerPeer = /* @__PURE__ */ new Map();
1850
+ /**
1851
+ * A set of all connections (enabled and disabled).
1852
+ */
1853
+ _connections = /* @__PURE__ */ new Set();
1854
+ /**
1855
+ * spaceId -> deviceKey[]
1856
+ */
1857
+ _authorizedDevices = /* @__PURE__ */ new Map();
1858
+ _context = null;
1866
1859
  async connect(context) {
1867
1860
  this._context = context;
1868
1861
  }
@@ -2075,30 +2068,11 @@ var MeshEchoReplicator = class {
2075
2068
  }
2076
2069
  }
2077
2070
  }
2078
- constructor() {
2079
- _define_property7(this, "_connectionsPerPeer", /* @__PURE__ */ new Map());
2080
- _define_property7(this, "_connections", /* @__PURE__ */ new Set());
2081
- _define_property7(this, "_authorizedDevices", /* @__PURE__ */ new Map());
2082
- _define_property7(this, "_context", null);
2083
- }
2084
2071
  };
2085
2072
 
2086
2073
  // src/automerge/echo-data-monitor.ts
2087
2074
  import { trace as trace3 } from "@dxos/tracing";
2088
2075
  import { CircularBuffer, SlidingWindowSummary, mapValues } from "@dxos/util";
2089
- function _define_property8(obj, key, value) {
2090
- if (key in obj) {
2091
- Object.defineProperty(obj, key, {
2092
- value,
2093
- enumerable: true,
2094
- configurable: true,
2095
- writable: true
2096
- });
2097
- } else {
2098
- obj[key] = value;
2099
- }
2100
- return obj;
2101
- }
2102
2076
  function _ts_decorate4(decorators, target, key, desc) {
2103
2077
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2104
2078
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -2108,6 +2082,22 @@ function _ts_decorate4(decorators, target, key, desc) {
2108
2082
  var PER_SECOND_RATE_AVG_WINDOW_SIZE = 5;
2109
2083
  var DEFAULT_AVG_WINDOW_SIZE = 25;
2110
2084
  var EchoDataMonitor = class {
2085
+ _params;
2086
+ _lastTick = 0;
2087
+ _activeCounters = createLocalCounters();
2088
+ _lastCompleteCounters;
2089
+ _localTimeSeries = createLocalTimeSeries();
2090
+ _storageAverages = createStorageAverages();
2091
+ _replicationAverages = createNetworkAverages();
2092
+ _sizeByMessage = {};
2093
+ _lastReceivedMessages = new CircularBuffer(100);
2094
+ _lastSentMessages = new CircularBuffer(100);
2095
+ _connectionsCount = 0;
2096
+ constructor(_params = {
2097
+ timeSeriesLength: 30
2098
+ }) {
2099
+ this._params = _params;
2100
+ }
2111
2101
  tick(timeMs) {
2112
2102
  this._advanceTimeWindow(timeMs - this._lastTick);
2113
2103
  this._lastTick = timeMs;
@@ -2347,9 +2337,8 @@ var EchoDataMonitor = class {
2347
2337
  messageCounts.failed++;
2348
2338
  }
2349
2339
  _getStatsForType(message) {
2350
- var _this__sizeByMessage, _message_type, _this__activeCounters_byType, _message_type1;
2351
- const messageSize = (_this__sizeByMessage = this._sizeByMessage)[_message_type = message.type] ?? (_this__sizeByMessage[_message_type] = createSlidingWindow());
2352
- const messageCounts = (_this__activeCounters_byType = this._activeCounters.byType)[_message_type1 = message.type] ?? (_this__activeCounters_byType[_message_type1] = createMessageCounter());
2340
+ const messageSize = this._sizeByMessage[message.type] ??= createSlidingWindow();
2341
+ const messageCounts = this._activeCounters.byType[message.type] ??= createMessageCounter();
2353
2342
  return {
2354
2343
  messageCounts,
2355
2344
  messageSize
@@ -2358,48 +2347,21 @@ var EchoDataMonitor = class {
2358
2347
  _computeMessageHistogram(groupKey) {
2359
2348
  const result = {};
2360
2349
  for (const receivedMessage of this._lastReceivedMessages) {
2361
- var _result, _receivedMessage_groupKey;
2362
- const counters = (_result = result)[_receivedMessage_groupKey = receivedMessage[groupKey]] ?? (_result[_receivedMessage_groupKey] = {
2350
+ const counters = result[receivedMessage[groupKey]] ??= {
2363
2351
  received: 0,
2364
2352
  sent: 0
2365
- });
2353
+ };
2366
2354
  counters.received++;
2367
2355
  }
2368
2356
  for (const receivedMessage of this._lastSentMessages) {
2369
- var _result1, _receivedMessage_groupKey1;
2370
- const counters = (_result1 = result)[_receivedMessage_groupKey1 = receivedMessage[groupKey]] ?? (_result1[_receivedMessage_groupKey1] = {
2357
+ const counters = result[receivedMessage[groupKey]] ??= {
2371
2358
  received: 0,
2372
2359
  sent: 0
2373
- });
2360
+ };
2374
2361
  counters.sent++;
2375
2362
  }
2376
2363
  return result;
2377
2364
  }
2378
- constructor(_params = {
2379
- timeSeriesLength: 30
2380
- }) {
2381
- _define_property8(this, "_params", void 0);
2382
- _define_property8(this, "_lastTick", void 0);
2383
- _define_property8(this, "_activeCounters", void 0);
2384
- _define_property8(this, "_lastCompleteCounters", void 0);
2385
- _define_property8(this, "_localTimeSeries", void 0);
2386
- _define_property8(this, "_storageAverages", void 0);
2387
- _define_property8(this, "_replicationAverages", void 0);
2388
- _define_property8(this, "_sizeByMessage", void 0);
2389
- _define_property8(this, "_lastReceivedMessages", void 0);
2390
- _define_property8(this, "_lastSentMessages", void 0);
2391
- _define_property8(this, "_connectionsCount", void 0);
2392
- this._params = _params;
2393
- this._lastTick = 0;
2394
- this._activeCounters = createLocalCounters();
2395
- this._localTimeSeries = createLocalTimeSeries();
2396
- this._storageAverages = createStorageAverages();
2397
- this._replicationAverages = createNetworkAverages();
2398
- this._sizeByMessage = {};
2399
- this._lastReceivedMessages = new CircularBuffer(100);
2400
- this._lastSentMessages = new CircularBuffer(100);
2401
- this._connectionsCount = 0;
2402
- }
2403
2365
  };
2404
2366
  EchoDataMonitor = _ts_decorate4([
2405
2367
  trace3.resource()
@@ -2472,29 +2434,30 @@ var getByteCount = (message) => {
2472
2434
  };
2473
2435
 
2474
2436
  // src/db-host/documents-synchronizer.ts
2475
- import { next as A2 } from "@automerge/automerge";
2437
+ import { next as A3 } from "@automerge/automerge";
2476
2438
  import { UpdateScheduler, sleep } from "@dxos/async";
2477
2439
  import { LifecycleState as LifecycleState2, Resource as Resource5, cancelWithContext as cancelWithContext2 } from "@dxos/context";
2478
2440
  import { invariant as invariant6 } from "@dxos/invariant";
2479
2441
  import { log as log6 } from "@dxos/log";
2480
- function _define_property9(obj, key, value) {
2481
- if (key in obj) {
2482
- Object.defineProperty(obj, key, {
2483
- value,
2484
- enumerable: true,
2485
- configurable: true,
2486
- writable: true
2487
- });
2488
- } else {
2489
- obj[key] = value;
2490
- }
2491
- return obj;
2492
- }
2493
2442
  var __dxlog_file7 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/documents-synchronizer.ts";
2494
2443
  var MAX_UPDATE_FREQ = 10;
2495
2444
  var WRAP_AROUND_RETRY_LIMIT = 3;
2496
2445
  var WRAP_AROUND_RETRY_INITIAL_DELAY = 100;
2497
2446
  var DocumentsSynchronizer = class extends Resource5 {
2447
+ _params;
2448
+ _syncStates = /* @__PURE__ */ new Map();
2449
+ /**
2450
+ * Documents that have pending updates.
2451
+ * Used to batch updates.
2452
+ */
2453
+ _pendingUpdates = /* @__PURE__ */ new Set();
2454
+ /**
2455
+ * Job that schedules if there are pending updates.
2456
+ */
2457
+ _sendUpdatesJob = void 0;
2458
+ constructor(_params) {
2459
+ super(), this._params = _params;
2460
+ }
2498
2461
  addDocuments(documentIds, retryCounter = 0, wrapAroundRetryDelay = WRAP_AROUND_RETRY_INITIAL_DELAY) {
2499
2462
  if (retryCounter > WRAP_AROUND_RETRY_LIMIT) {
2500
2463
  log6.warn("Failed to load document, retry limit reached", {
@@ -2613,11 +2576,11 @@ var DocumentsSynchronizer = class extends Resource5 {
2613
2576
  return;
2614
2577
  }
2615
2578
  const doc = handle.doc();
2616
- const mutation = syncState.lastSentHead ? A2.saveSince(doc, syncState.lastSentHead) : A2.save(doc);
2579
+ const mutation = syncState.lastSentHead ? A3.saveSince(doc, syncState.lastSentHead) : A3.save(doc);
2617
2580
  if (mutation.length === 0) {
2618
2581
  return;
2619
2582
  }
2620
- syncState.lastSentHead = A2.getHeads(doc);
2583
+ syncState.lastSentHead = A3.getHeads(doc);
2621
2584
  return mutation;
2622
2585
  }
2623
2586
  _writeMutation(documentId, mutation, isNew) {
@@ -2629,7 +2592,7 @@ var DocumentsSynchronizer = class extends Resource5 {
2629
2592
  docId: documentId
2630
2593
  });
2631
2594
  const syncState = this._startSync(newHandle);
2632
- syncState.lastSentHead = A2.getHeads(newHandle.doc());
2595
+ syncState.lastSentHead = A3.getHeads(newHandle.doc());
2633
2596
  } else {
2634
2597
  const syncState = this._syncStates.get(documentId);
2635
2598
  invariant6(syncState, "Sync state for document not found", {
@@ -2641,43 +2604,33 @@ var DocumentsSynchronizer = class extends Resource5 {
2641
2604
  "'Sync state for document not found'"
2642
2605
  ]
2643
2606
  });
2644
- const headsBefore = A2.getHeads(syncState.handle.doc());
2607
+ const headsBefore = A3.getHeads(syncState.handle.doc());
2645
2608
  this._params.repo.import(mutation, {
2646
2609
  docId: documentId
2647
2610
  });
2648
- if (A2.equals(headsBefore, syncState.lastSentHead)) {
2649
- syncState.lastSentHead = A2.getHeads(syncState.handle.doc());
2611
+ if (A3.equals(headsBefore, syncState.lastSentHead)) {
2612
+ syncState.lastSentHead = A3.getHeads(syncState.handle.doc());
2650
2613
  }
2651
2614
  }
2652
2615
  }
2653
- constructor(_params) {
2654
- super(), _define_property9(this, "_params", void 0), _define_property9(this, "_syncStates", void 0), /**
2655
- * Documents that have pending updates.
2656
- * Used to batch updates.
2657
- */
2658
- _define_property9(this, "_pendingUpdates", void 0), /**
2659
- * Job that schedules if there are pending updates.
2660
- */
2661
- _define_property9(this, "_sendUpdatesJob", void 0), this._params = _params, this._syncStates = /* @__PURE__ */ new Map(), this._pendingUpdates = /* @__PURE__ */ new Set(), this._sendUpdatesJob = void 0;
2662
- }
2663
2616
  };
2664
2617
 
2665
2618
  // src/db-host/data-service.ts
2666
- function _define_property10(obj, key, value) {
2667
- if (key in obj) {
2668
- Object.defineProperty(obj, key, {
2669
- value,
2670
- enumerable: true,
2671
- configurable: true,
2672
- writable: true
2673
- });
2674
- } else {
2675
- obj[key] = value;
2676
- }
2677
- return obj;
2678
- }
2679
2619
  var __dxlog_file8 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/data-service.ts";
2680
2620
  var DataServiceImpl = class {
2621
+ /**
2622
+ * Map of subscriptions.
2623
+ * subscriptionId -> DocumentsSynchronizer
2624
+ */
2625
+ _subscriptions = /* @__PURE__ */ new Map();
2626
+ _automergeHost;
2627
+ _spaceStateManager;
2628
+ _updateIndexes;
2629
+ constructor(params) {
2630
+ this._automergeHost = params.automergeHost;
2631
+ this._spaceStateManager = params.spaceStateManager;
2632
+ this._updateIndexes = params.updateIndexes;
2633
+ }
2681
2634
  subscribe(request) {
2682
2635
  return new Stream(({ next, ready }) => {
2683
2636
  const synchronizer = new DocumentsSynchronizer({
@@ -2798,15 +2751,6 @@ var DataServiceImpl = class {
2798
2751
  scheduler.trigger();
2799
2752
  });
2800
2753
  }
2801
- constructor(params) {
2802
- _define_property10(this, "_subscriptions", /* @__PURE__ */ new Map());
2803
- _define_property10(this, "_automergeHost", void 0);
2804
- _define_property10(this, "_spaceStateManager", void 0);
2805
- _define_property10(this, "_updateIndexes", void 0);
2806
- this._automergeHost = params.automergeHost;
2807
- this._spaceStateManager = params.spaceStateManager;
2808
- this._updateIndexes = params.updateIndexes;
2809
- }
2810
2754
  };
2811
2755
 
2812
2756
  // src/db-host/echo-host.ts
@@ -2819,7 +2763,7 @@ import { IndexKind } from "@dxos/protocols/proto/dxos/echo/indexing";
2819
2763
  import { trace as trace5 } from "@dxos/tracing";
2820
2764
 
2821
2765
  // src/db-host/documents-iterator.ts
2822
- import * as A3 from "@automerge/automerge";
2766
+ import * as A4 from "@automerge/automerge";
2823
2767
  import { Context as Context2 } from "@dxos/context";
2824
2768
  import { DatabaseDirectory as DatabaseDirectory2, SpaceDocVersion } from "@dxos/echo-protocol";
2825
2769
  import { invariant as invariant8 } from "@dxos/invariant";
@@ -2850,10 +2794,10 @@ var createSelectedDocumentsIterator = (automergeHost) => (
2850
2794
  ""
2851
2795
  ]
2852
2796
  });
2853
- const currentHeads = A3.getHeads(doc);
2854
- if (!A3.equals(currentHeads, heads)) {
2797
+ const currentHeads = A4.getHeads(doc);
2798
+ if (!A4.equals(currentHeads, heads)) {
2855
2799
  const begin = Date.now();
2856
- doc = A3.view(doc, heads);
2800
+ doc = A4.view(doc, heads);
2857
2801
  const end = Date.now();
2858
2802
  if (end - begin > LOG_VIEW_OPERATION_THRESHOLD) {
2859
2803
  log8("Checking out document version is taking too long", {
@@ -2908,7 +2852,7 @@ var createSelectedDocumentsIterator = (automergeHost) => (
2908
2852
 
2909
2853
  // src/db-host/query-service.ts
2910
2854
  import { getHeads as getHeads3 } from "@automerge/automerge";
2911
- import { Schema } from "effect";
2855
+ import * as Schema from "effect/Schema";
2912
2856
  import { DeferredTask as DeferredTask2, scheduleMicroTask, synchronized as synchronized2 } from "@dxos/async";
2913
2857
  import { Stream as Stream2 } from "@dxos/codec-protobuf/stream";
2914
2858
  import { Context as Context4, Resource as Resource7 } from "@dxos/context";
@@ -2919,7 +2863,8 @@ import { objectPointerCodec as objectPointerCodec4 } from "@dxos/protocols";
2919
2863
  import { trace as trace4 } from "@dxos/tracing";
2920
2864
 
2921
2865
  // src/query/query-executor.ts
2922
- import { Match, Predicate } from "effect";
2866
+ import * as Match from "effect/Match";
2867
+ import * as Predicate from "effect/Predicate";
2923
2868
  import { Context as Context3, ContextDisposedError, LifecycleState as LifecycleState3, Resource as Resource6 } from "@dxos/context";
2924
2869
  import { DatabaseDirectory as DatabaseDirectory3, ObjectStructure, isEncodedReference } from "@dxos/echo-protocol";
2925
2870
  import { EscapedPropPath } from "@dxos/indexing";
@@ -2927,7 +2872,7 @@ import { invariant as invariant10 } from "@dxos/invariant";
2927
2872
  import { DXN, PublicKey as PublicKey3 } from "@dxos/keys";
2928
2873
  import { log as log9 } from "@dxos/log";
2929
2874
  import { objectPointerCodec as objectPointerCodec3 } from "@dxos/protocols";
2930
- import { getDeep, isNonNullable as isNonNullable2 } from "@dxos/util";
2875
+ import { getDeep, isNonNullable as isNonNullable3 } from "@dxos/util";
2931
2876
 
2932
2877
  // src/query/query-planner.ts
2933
2878
  import { Order } from "@dxos/echo";
@@ -2937,6 +2882,8 @@ import { invariant as invariant9 } from "@dxos/invariant";
2937
2882
  import { BaseError } from "@dxos/errors";
2938
2883
  var QueryError = class extends BaseError.extend("QUERY_ERROR") {
2939
2884
  };
2885
+ var InvalidQueryError = class extends QueryError.extend("INVALID_QUERY") {
2886
+ };
2940
2887
 
2941
2888
  // src/query/plan.ts
2942
2889
  (function(QueryPlan2) {
@@ -2960,24 +2907,18 @@ var QueryError = class extends BaseError.extend("QUERY_ERROR") {
2960
2907
  var QueryPlan;
2961
2908
 
2962
2909
  // src/query/query-planner.ts
2963
- function _define_property11(obj, key, value) {
2964
- if (key in obj) {
2965
- Object.defineProperty(obj, key, {
2966
- value,
2967
- enumerable: true,
2968
- configurable: true,
2969
- writable: true
2970
- });
2971
- } else {
2972
- obj[key] = value;
2973
- }
2974
- return obj;
2975
- }
2976
2910
  var __dxlog_file10 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-planner.ts";
2977
2911
  var DEFAULT_OPTIONS = {
2978
2912
  defaultTextSearchKind: "full-text"
2979
2913
  };
2980
2914
  var QueryPlanner = class {
2915
+ _options;
2916
+ constructor(options) {
2917
+ this._options = {
2918
+ ...DEFAULT_OPTIONS,
2919
+ ...options
2920
+ };
2921
+ }
2981
2922
  createPlan(query) {
2982
2923
  let plan = this._generate(query, {
2983
2924
  ...DEFAULT_CONTEXT,
@@ -3011,7 +2952,8 @@ var QueryPlanner = class {
3011
2952
  case "order":
3012
2953
  return this._generateOrderClause(query, context);
3013
2954
  default:
3014
- throw new QueryError(`Unsupported query type: ${query.type}`, {
2955
+ throw new QueryError({
2956
+ message: `Unsupported query type: ${query.type}`,
3015
2957
  context: {
3016
2958
  query: context.originalQuery
3017
2959
  }
@@ -3035,10 +2977,11 @@ var QueryPlanner = class {
3035
2977
  }
3036
2978
  // TODO(dmaretskyi): This can be rewritten as a function of (filter[]) -> (selection ? undefined, rest: filter[]) that recurses onto itself.
3037
2979
  // TODO(dmaretskyi): If the tip of the query ast is a [select, ...filter] shape we can reorder the filters so the query is most efficient.
3038
- _generateSelectionFromFilter(filter, context) {
3039
- switch (filter.type) {
2980
+ _generateSelectionFromFilter(filter2, context) {
2981
+ switch (filter2.type) {
2982
+ // Props
3040
2983
  case "object": {
3041
- if (context.selectionInverted && filter.id === void 0 && filter.typename === null && Object.keys(filter.props).length === 0) {
2984
+ if (context.selectionInverted && filter2.id === void 0 && filter2.typename === null && Object.keys(filter2.props).length === 0) {
3042
2985
  return QueryPlan.Plan.make([
3043
2986
  {
3044
2987
  _tag: "ClearWorkingSetStep"
@@ -3047,32 +2990,33 @@ var QueryPlanner = class {
3047
2990
  ]);
3048
2991
  }
3049
2992
  if (context.selectionInverted) {
3050
- throw new QueryError("Query too complex", {
2993
+ throw new QueryError({
2994
+ message: "Query too complex",
3051
2995
  context: {
3052
2996
  query: context.originalQuery
3053
2997
  }
3054
2998
  });
3055
2999
  }
3056
- if (filter.id && filter.id?.length > 0) {
3000
+ if (filter2.id && filter2.id?.length > 0) {
3057
3001
  return QueryPlan.Plan.make([
3058
3002
  {
3059
3003
  _tag: "SelectStep",
3060
3004
  spaces: context.selectionSpaces,
3061
3005
  selector: {
3062
3006
  _tag: "IdSelector",
3063
- objectIds: filter.id
3007
+ objectIds: filter2.id
3064
3008
  }
3065
3009
  },
3066
3010
  ...this._generateDeletedHandlingSteps(context),
3067
3011
  {
3068
3012
  _tag: "FilterStep",
3069
3013
  filter: {
3070
- ...filter,
3014
+ ...filter2,
3071
3015
  id: void 0
3072
3016
  }
3073
3017
  }
3074
3018
  ]);
3075
- } else if (filter.typename) {
3019
+ } else if (filter2.typename) {
3076
3020
  return QueryPlan.Plan.make([
3077
3021
  {
3078
3022
  _tag: "SelectStep",
@@ -3080,17 +3024,17 @@ var QueryPlanner = class {
3080
3024
  selector: {
3081
3025
  _tag: "TypeSelector",
3082
3026
  typename: [
3083
- filter.typename
3027
+ filter2.typename
3084
3028
  ],
3085
3029
  inverted: false
3086
3030
  }
3087
3031
  },
3088
3032
  ...this._generateDeletedHandlingSteps(context),
3033
+ // TODO(dmaretskyi): Normally we could skip filtering by typename here, but since the index does not separate schema versions, we need to do additional filter to only select the correct version.
3089
3034
  {
3090
3035
  _tag: "FilterStep",
3091
3036
  filter: {
3092
- ...filter,
3093
- typename: null
3037
+ ...filter2
3094
3038
  }
3095
3039
  }
3096
3040
  ]);
@@ -3107,12 +3051,32 @@ var QueryPlanner = class {
3107
3051
  {
3108
3052
  _tag: "FilterStep",
3109
3053
  filter: {
3110
- ...filter
3054
+ ...filter2
3111
3055
  }
3112
3056
  }
3113
3057
  ]);
3114
3058
  }
3115
3059
  }
3060
+ // Tag
3061
+ case "tag": {
3062
+ return QueryPlan.Plan.make([
3063
+ {
3064
+ _tag: "SelectStep",
3065
+ spaces: context.selectionSpaces,
3066
+ selector: {
3067
+ _tag: "WildcardSelector"
3068
+ }
3069
+ },
3070
+ ...this._generateDeletedHandlingSteps(context),
3071
+ {
3072
+ _tag: "FilterStep",
3073
+ filter: {
3074
+ ...filter2
3075
+ }
3076
+ }
3077
+ ]);
3078
+ }
3079
+ // Text
3116
3080
  case "text-search": {
3117
3081
  return QueryPlan.Plan.make([
3118
3082
  {
@@ -3120,55 +3084,61 @@ var QueryPlanner = class {
3120
3084
  spaces: context.selectionSpaces,
3121
3085
  selector: {
3122
3086
  _tag: "TextSelector",
3123
- text: filter.text,
3124
- searchKind: filter.searchKind ?? this._options.defaultTextSearchKind
3087
+ text: filter2.text,
3088
+ searchKind: filter2.searchKind ?? this._options.defaultTextSearchKind
3125
3089
  }
3126
3090
  },
3127
3091
  ...this._generateDeletedHandlingSteps(context)
3128
3092
  ]);
3129
3093
  }
3094
+ // Compare
3130
3095
  case "compare":
3131
- throw new QueryError("Query too complex", {
3096
+ throw new QueryError({
3097
+ message: "Query too complex",
3132
3098
  context: {
3133
3099
  query: context.originalQuery
3134
3100
  }
3135
3101
  });
3136
3102
  case "in":
3137
- throw new QueryError("Query too complex", {
3103
+ throw new QueryError({
3104
+ message: "Query too complex",
3138
3105
  context: {
3139
3106
  query: context.originalQuery
3140
3107
  }
3141
3108
  });
3142
3109
  case "range":
3143
- throw new QueryError("Query too complex", {
3110
+ throw new QueryError({
3111
+ message: "Query too complex",
3144
3112
  context: {
3145
3113
  query: context.originalQuery
3146
3114
  }
3147
3115
  });
3116
+ // Boolean
3148
3117
  case "not":
3149
- return this._generateSelectionFromFilter(filter.filter, {
3118
+ return this._generateSelectionFromFilter(filter2.filter, {
3150
3119
  ...context,
3151
3120
  selectionInverted: !context.selectionInverted
3152
3121
  });
3153
3122
  case "and":
3154
- throw new QueryError("Query too complex", {
3123
+ throw new QueryError({
3124
+ message: "Query too complex",
3155
3125
  context: {
3156
3126
  query: context.originalQuery
3157
3127
  }
3158
3128
  });
3159
3129
  case "or":
3160
- if (filter.filters.every(isTrivialTypenameFilter)) {
3161
- const typenames = filter.filters.map((f) => {
3162
- invariant9(f.type === "object" && f.typename !== null, void 0, {
3130
+ if (filter2.filters.every(isTrivialTypenameFilter)) {
3131
+ const typenames = filter2.filters.map((filter3) => {
3132
+ invariant9(filter3.type === "object" && filter3.typename !== null, void 0, {
3163
3133
  F: __dxlog_file10,
3164
- L: 195,
3134
+ L: 225,
3165
3135
  S: this,
3166
3136
  A: [
3167
- "f.type === 'object' && f.typename !== null",
3137
+ "filter.type === 'object' && filter.typename !== null",
3168
3138
  ""
3169
3139
  ]
3170
3140
  });
3171
- return f.typename;
3141
+ return filter3.typename;
3172
3142
  });
3173
3143
  return QueryPlan.Plan.make([
3174
3144
  {
@@ -3180,17 +3150,25 @@ var QueryPlanner = class {
3180
3150
  inverted: context.selectionInverted
3181
3151
  }
3182
3152
  },
3183
- ...this._generateDeletedHandlingSteps(context)
3153
+ ...this._generateDeletedHandlingSteps(context),
3154
+ {
3155
+ _tag: "FilterStep",
3156
+ filter: {
3157
+ ...filter2
3158
+ }
3159
+ }
3184
3160
  ]);
3185
3161
  } else {
3186
- throw new QueryError("Query too complex", {
3162
+ throw new QueryError({
3163
+ message: "Query too complex",
3187
3164
  context: {
3188
3165
  query: context.originalQuery
3189
3166
  }
3190
3167
  });
3191
3168
  }
3192
3169
  default:
3193
- throw new QueryError(`Unsupported filter type: ${filter.type}`, {
3170
+ throw new QueryError({
3171
+ message: `Unsupported filter type: ${filter2.type}`,
3194
3172
  context: {
3195
3173
  query: context.originalQuery
3196
3174
  }
@@ -3429,13 +3407,6 @@ var QueryPlanner = class {
3429
3407
  }
3430
3408
  ]);
3431
3409
  }
3432
- constructor(options) {
3433
- _define_property11(this, "_options", void 0);
3434
- this._options = {
3435
- ...DEFAULT_OPTIONS,
3436
- ...options
3437
- };
3438
- }
3439
3410
  };
3440
3411
  var DEFAULT_CONTEXT = {
3441
3412
  originalQuery: null,
@@ -3456,26 +3427,12 @@ var createRelationTraversalStep = (direction) => ({
3456
3427
  direction
3457
3428
  }
3458
3429
  });
3459
- var isTrivialTypenameFilter = (filter) => {
3460
- return filter.type === "object" && filter.typename !== null && Object.keys(filter.props).length === 0 && (filter.id === void 0 || filter.id.length === 0) && (filter.foreignKeys === void 0 || filter.foreignKeys.length === 0);
3430
+ var isTrivialTypenameFilter = (filter2) => {
3431
+ return filter2.type === "object" && filter2.typename !== null && Object.keys(filter2.props).length === 0 && (filter2.id === void 0 || filter2.id.length === 0) && (filter2.foreignKeys === void 0 || filter2.foreignKeys.length === 0);
3461
3432
  };
3462
3433
 
3463
3434
  // src/query/query-executor.ts
3464
- function _define_property12(obj, key, value) {
3465
- if (key in obj) {
3466
- Object.defineProperty(obj, key, {
3467
- value,
3468
- enumerable: true,
3469
- configurable: true,
3470
- writable: true
3471
- });
3472
- } else {
3473
- obj[key] = value;
3474
- }
3475
- return obj;
3476
- }
3477
3435
  var __dxlog_file11 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-executor.ts";
3478
- var isNullable = Predicate.isNullable;
3479
3436
  var ExecutionTrace = Object.freeze({
3480
3437
  makeEmpty: () => ({
3481
3438
  name: "Empty",
@@ -3483,11 +3440,57 @@ var ExecutionTrace = Object.freeze({
3483
3440
  objectCount: 0,
3484
3441
  documentsLoaded: 0,
3485
3442
  indexHits: 0,
3443
+ beginTs: 0,
3444
+ endTs: 0,
3486
3445
  indexQueryTime: 0,
3487
3446
  documentLoadTime: 0,
3488
3447
  executionTime: 0,
3489
3448
  children: []
3490
3449
  }),
3450
+ markEnd: (trace6) => {
3451
+ trace6.endTs = performance.now();
3452
+ trace6.executionTime = trace6.endTs - trace6.beginTs;
3453
+ },
3454
+ putOnPerformanceTimeline: (trace6) => {
3455
+ performance.measure(trace6.name, {
3456
+ start: trace6.beginTs,
3457
+ end: trace6.endTs,
3458
+ detail: {
3459
+ devtools: {
3460
+ dataType: "track-entry",
3461
+ track: "Query Execution",
3462
+ trackGroup: "ECHO",
3463
+ color: "tertiary-dark",
3464
+ properties: [
3465
+ [
3466
+ "objectCount",
3467
+ trace6.objectCount
3468
+ ],
3469
+ [
3470
+ "documentsLoaded",
3471
+ trace6.documentsLoaded
3472
+ ],
3473
+ [
3474
+ "index hits",
3475
+ trace6.indexHits
3476
+ ],
3477
+ [
3478
+ "indexQueryTime",
3479
+ trace6.indexQueryTime
3480
+ ],
3481
+ [
3482
+ "documentLoadTime",
3483
+ trace6.documentLoadTime
3484
+ ]
3485
+ ],
3486
+ tooltipText: trace6.details
3487
+ }
3488
+ }
3489
+ });
3490
+ for (const child of trace6.children) {
3491
+ ExecutionTrace.putOnPerformanceTimeline(child);
3492
+ }
3493
+ },
3491
3494
  format: (trace6) => {
3492
3495
  const go = (trace7, indent) => {
3493
3496
  return [
@@ -3502,6 +3505,30 @@ var ExecutionTrace = Object.freeze({
3502
3505
  });
3503
3506
  var TRACE_QUERY_EXECUTION = false;
3504
3507
  var QueryExecutor = class extends Resource6 {
3508
+ _indexer;
3509
+ _automergeHost;
3510
+ _spaceStateManager;
3511
+ /**
3512
+ * Id of this query.
3513
+ */
3514
+ _id;
3515
+ _query;
3516
+ // TODO(dmaretskyi): Might be used in the future.
3517
+ _reactivity;
3518
+ _plan;
3519
+ _trace = ExecutionTrace.makeEmpty();
3520
+ _lastResultSet = [];
3521
+ constructor(options) {
3522
+ super();
3523
+ this._indexer = options.indexer;
3524
+ this._automergeHost = options.automergeHost;
3525
+ this._spaceStateManager = options.spaceStateManager;
3526
+ this._id = options.queryId;
3527
+ this._query = options.query;
3528
+ this._reactivity = options.reactivity;
3529
+ const queryPlanner = new QueryPlanner();
3530
+ this._plan = queryPlanner.createPlan(this._query);
3531
+ }
3505
3532
  get query() {
3506
3533
  return this._query;
3507
3534
  }
@@ -3527,7 +3554,7 @@ var QueryExecutor = class extends Resource6 {
3527
3554
  async execQuery() {
3528
3555
  invariant10(this._lifecycleState === LifecycleState3.OPEN, void 0, {
3529
3556
  F: __dxlog_file11,
3530
- L: 176,
3557
+ L: 211,
3531
3558
  S: this,
3532
3559
  A: [
3533
3560
  "this._lifecycleState === LifecycleState.OPEN",
@@ -3562,7 +3589,7 @@ var QueryExecutor = class extends Resource6 {
3562
3589
  trace6.children.push(result.trace);
3563
3590
  }
3564
3591
  trace6.objectCount = workingSet.length;
3565
- trace6.executionTime = performance.now() - begin;
3592
+ ExecutionTrace.markEnd(trace6);
3566
3593
  return {
3567
3594
  workingSet,
3568
3595
  trace: trace6
@@ -3606,7 +3633,8 @@ var QueryExecutor = class extends Resource6 {
3606
3633
  default:
3607
3634
  throw new Error(`Unknown step type: ${step._tag}`);
3608
3635
  }
3609
- trace6.executionTime = performance.now() - begin;
3636
+ trace6.beginTs = begin;
3637
+ ExecutionTrace.markEnd(trace6);
3610
3638
  return {
3611
3639
  workingSet: newWorkingSet,
3612
3640
  trace: trace6
@@ -3619,7 +3647,8 @@ var QueryExecutor = class extends Resource6 {
3619
3647
  const trace6 = {
3620
3648
  ...ExecutionTrace.makeEmpty(),
3621
3649
  name: "Select",
3622
- details: JSON.stringify(step.selector)
3650
+ details: JSON.stringify(step.selector),
3651
+ beginTs: performance.now()
3623
3652
  };
3624
3653
  switch (step.selector._tag) {
3625
3654
  case "WildcardSelector": {
@@ -3640,7 +3669,7 @@ var QueryExecutor = class extends Resource6 {
3640
3669
  const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3641
3670
  trace6.documentsLoaded += results.length;
3642
3671
  trace6.documentLoadTime += performance.now() - documentLoadStart;
3643
- workingSet.push(...results.filter(isNonNullable2).filter((item) => step.spaces.includes(item.spaceId)));
3672
+ workingSet.push(...results.filter(isNonNullable3).filter((item) => step.spaces.includes(item.spaceId)));
3644
3673
  trace6.objectCount = workingSet.length;
3645
3674
  break;
3646
3675
  }
@@ -3650,7 +3679,7 @@ var QueryExecutor = class extends Resource6 {
3650
3679
  sourceSpaceId: step.spaces[0]
3651
3680
  })));
3652
3681
  trace6.documentLoadTime += performance.now() - beginLoad;
3653
- workingSet.push(...items.filter(isNonNullable2));
3682
+ workingSet.push(...items.filter(isNonNullable3));
3654
3683
  trace6.objectCount = workingSet.length;
3655
3684
  break;
3656
3685
  }
@@ -3672,7 +3701,7 @@ var QueryExecutor = class extends Resource6 {
3672
3701
  const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3673
3702
  trace6.documentsLoaded += results.length;
3674
3703
  trace6.documentLoadTime += performance.now() - documentLoadStart;
3675
- workingSet.push(...results.filter(isNonNullable2).filter((item) => step.spaces.includes(item.spaceId)));
3704
+ workingSet.push(...results.filter(isNonNullable3).filter((item) => step.spaces.includes(item.spaceId)));
3676
3705
  trace6.objectCount = workingSet.length;
3677
3706
  break;
3678
3707
  }
@@ -3697,7 +3726,7 @@ var QueryExecutor = class extends Resource6 {
3697
3726
  const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3698
3727
  trace6.documentsLoaded += results.length;
3699
3728
  trace6.documentLoadTime += performance.now() - documentLoadStart;
3700
- workingSet.push(...results.filter(isNonNullable2).filter((item) => step.spaces.includes(item.spaceId)));
3729
+ workingSet.push(...results.filter(isNonNullable3).filter((item) => step.spaces.includes(item.spaceId)));
3701
3730
  trace6.objectCount = workingSet.length;
3702
3731
  break;
3703
3732
  }
@@ -3767,20 +3796,20 @@ var QueryExecutor = class extends Resource6 {
3767
3796
  ref: ref2["/"]
3768
3797
  }, {
3769
3798
  F: __dxlog_file11,
3770
- L: 432,
3799
+ L: 477,
3771
3800
  S: this,
3772
3801
  C: (f, a) => f(...a)
3773
3802
  });
3774
3803
  return null;
3775
3804
  }
3776
3805
  });
3777
- }).filter(isNonNullable2);
3806
+ }).filter(isNonNullable3);
3778
3807
  const beginLoad = performance.now();
3779
3808
  const items = await Promise.all(refs.map(({ ref, spaceId }) => this._loadFromDXN(ref, {
3780
3809
  sourceSpaceId: spaceId
3781
3810
  })));
3782
3811
  trace6.documentLoadTime += performance.now() - beginLoad;
3783
- newWorkingSet.push(...items.filter(isNonNullable2));
3812
+ newWorkingSet.push(...items.filter(isNonNullable3));
3784
3813
  trace6.objectCount = newWorkingSet.length;
3785
3814
  break;
3786
3815
  }
@@ -3799,7 +3828,7 @@ var QueryExecutor = class extends Resource6 {
3799
3828
  const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3800
3829
  trace6.documentsLoaded += results.length;
3801
3830
  trace6.documentLoadTime += performance.now() - documentLoadStart;
3802
- newWorkingSet.push(...results.filter(isNonNullable2));
3831
+ newWorkingSet.push(...results.filter(isNonNullable3));
3803
3832
  trace6.objectCount = newWorkingSet.length;
3804
3833
  break;
3805
3834
  }
@@ -3825,19 +3854,19 @@ var QueryExecutor = class extends Resource6 {
3825
3854
  ref: ref["/"]
3826
3855
  }, {
3827
3856
  F: __dxlog_file11,
3828
- L: 495,
3857
+ L: 540,
3829
3858
  S: this,
3830
3859
  C: (f, a) => f(...a)
3831
3860
  });
3832
3861
  return null;
3833
3862
  }
3834
- }).filter(isNonNullable2);
3863
+ }).filter(isNonNullable3);
3835
3864
  const beginLoad = performance.now();
3836
3865
  const items = await Promise.all(refs.map(({ ref, spaceId }) => this._loadFromDXN(ref, {
3837
3866
  sourceSpaceId: spaceId
3838
3867
  })));
3839
3868
  trace6.documentLoadTime += performance.now() - beginLoad;
3840
- newWorkingSet.push(...items.filter(isNonNullable2));
3869
+ newWorkingSet.push(...items.filter(isNonNullable3));
3841
3870
  trace6.objectCount = newWorkingSet.length;
3842
3871
  break;
3843
3872
  }
@@ -3857,7 +3886,7 @@ var QueryExecutor = class extends Resource6 {
3857
3886
  const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3858
3887
  trace6.documentsLoaded += results.length;
3859
3888
  trace6.documentLoadTime += performance.now() - documentLoadStart;
3860
- newWorkingSet.push(...results.filter(isNonNullable2));
3889
+ newWorkingSet.push(...results.filter(isNonNullable3));
3861
3890
  trace6.objectCount = newWorkingSet.length;
3862
3891
  break;
3863
3892
  }
@@ -3915,15 +3944,9 @@ var QueryExecutor = class extends Resource6 {
3915
3944
  };
3916
3945
  }
3917
3946
  async _execOrderStep(step, workingSet) {
3918
- const compareItems = (a, b) => step.order.reduce((comparison, order) => {
3919
- if (comparison !== 0) {
3920
- return comparison;
3921
- }
3922
- return this._compareByOrder(a, b, order);
3923
- }, 0);
3924
3947
  const sortedWorkingSet = [
3925
3948
  ...workingSet
3926
- ].sort(compareItems);
3949
+ ].sort((a, b) => this._compareMultiOrder(a, b, step.order));
3927
3950
  return {
3928
3951
  workingSet: sortedWorkingSet,
3929
3952
  trace: {
@@ -3934,64 +3957,69 @@ var QueryExecutor = class extends Resource6 {
3934
3957
  }
3935
3958
  };
3936
3959
  }
3960
+ _compareMultiOrder(a, b, orders) {
3961
+ if (orders.length === 0) {
3962
+ return 0;
3963
+ } else if (orders.length === 1) {
3964
+ return this._compareByOrder(a, b, orders[0]);
3965
+ }
3966
+ for (const order of orders) {
3967
+ const comparison = this._compareByOrder(a, b, order);
3968
+ if (comparison !== 0) {
3969
+ return comparison;
3970
+ }
3971
+ }
3972
+ return 0;
3973
+ }
3937
3974
  _compareByOrder(a, b, order) {
3938
- return Match.type().pipe(Match.withReturnType(), Match.when({
3939
- kind: "natural"
3940
- }, () => a.objectId.localeCompare(b.objectId)), Match.when({
3941
- kind: "property"
3942
- }, ({ property, direction }) => {
3943
- const comparison = this._compareByProperty(a, b, property);
3944
- return direction === "desc" ? -comparison : comparison;
3945
- }), Match.exhaustive)(order);
3975
+ switch (order.kind) {
3976
+ case "natural":
3977
+ return a.objectId.localeCompare(b.objectId);
3978
+ case "property": {
3979
+ const comparison = this._compareByProperty(a, b, order.property);
3980
+ return order.direction === "desc" ? -comparison : comparison;
3981
+ }
3982
+ default:
3983
+ return 0;
3984
+ }
3946
3985
  }
3947
3986
  _compareByProperty(a, b, property) {
3948
3987
  const aValue = a.doc.data[property];
3949
3988
  const bValue = b.doc.data[property];
3950
- return Match.type().pipe(
3951
- Match.withReturnType(),
3952
- Match.when({
3953
- a: isNullable,
3954
- b: isNullable
3955
- }, () => 0),
3956
- Match.when({
3957
- a: isNullable
3958
- }, () => 1),
3959
- Match.when({
3960
- b: isNullable
3961
- }, () => -1),
3962
- Match.when({
3963
- a: Match.string,
3964
- b: Match.string
3965
- }, ({ a: a2, b: b2 }) => a2.localeCompare(b2)),
3966
- Match.when({
3967
- a: Match.number,
3968
- b: Match.number
3969
- }, ({ a: a2, b: b2 }) => a2 - b2),
3970
- Match.when({
3971
- a: Match.boolean,
3972
- b: Match.boolean
3973
- }, ({ a: a2, b: b2 }) => a2 === b2 ? 0 : a2 ? 1 : -1),
3974
- Match.when({
3975
- a: Match.defined,
3976
- b: Match.defined
3977
- }, ({ a: a2, b: b2 }) => String(a2).localeCompare(String(b2))),
3978
- // TODO(wittjosiah): Why does Match.exhaustive fail here?
3979
- Match.orElse(() => 0)
3980
- )({
3981
- a: aValue,
3982
- b: bValue
3983
- });
3989
+ if (aValue == null && bValue == null) {
3990
+ return 0;
3991
+ }
3992
+ if (aValue == null) {
3993
+ return 1;
3994
+ }
3995
+ if (bValue == null) {
3996
+ return -1;
3997
+ }
3998
+ if (typeof aValue === "string" && typeof bValue === "string") {
3999
+ return aValue.localeCompare(bValue);
4000
+ }
4001
+ if (typeof aValue === "number" && typeof bValue === "number") {
4002
+ return aValue - bValue;
4003
+ }
4004
+ if (typeof aValue === "boolean" && typeof bValue === "boolean") {
4005
+ return aValue === bValue ? 0 : aValue ? 1 : -1;
4006
+ }
4007
+ return String(aValue).localeCompare(String(bValue));
3984
4008
  }
3985
4009
  async _loadDocumentsAfterIndexQuery(indexHits) {
3986
4010
  return Promise.all(indexHits.map(async (hit) => {
3987
4011
  return this._loadFromIndexHit(hit);
3988
4012
  }));
3989
4013
  }
4014
+ /**
4015
+ * Space key hex -> SpaceId.
4016
+ */
4017
+ _spaceIdCache = /* @__PURE__ */ new Map();
3990
4018
  async _loadFromIndexHit(hit) {
3991
4019
  const { objectId, documentId, spaceKey: spaceKeyInIndex } = objectPointerCodec3.decode(hit.id);
3992
4020
  const handle = await this._automergeHost.loadDoc(Context3.default(void 0, {
3993
4021
  F: __dxlog_file11,
3994
- L: 659
4022
+ L: 738
3995
4023
  }), documentId);
3996
4024
  const doc = handle.doc();
3997
4025
  if (!doc) {
@@ -4001,6 +4029,11 @@ var QueryExecutor = class extends Resource6 {
4001
4029
  if (!spaceKey) {
4002
4030
  return null;
4003
4031
  }
4032
+ let spaceId = this._spaceIdCache.get(spaceKey);
4033
+ if (!spaceId) {
4034
+ spaceId = await createIdFromSpaceKey(PublicKey3.from(spaceKey));
4035
+ this._spaceIdCache.set(spaceKey, spaceId);
4036
+ }
4004
4037
  const object = DatabaseDirectory3.getInlineObject(doc, objectId);
4005
4038
  if (!object) {
4006
4039
  return null;
@@ -4008,7 +4041,7 @@ var QueryExecutor = class extends Resource6 {
4008
4041
  return {
4009
4042
  objectId,
4010
4043
  documentId,
4011
- spaceId: await createIdFromSpaceKey(PublicKey3.from(spaceKey)),
4044
+ spaceId,
4012
4045
  doc: object
4013
4046
  };
4014
4047
  }
@@ -4019,7 +4052,7 @@ var QueryExecutor = class extends Resource6 {
4019
4052
  dxn
4020
4053
  }, {
4021
4054
  F: __dxlog_file11,
4022
- L: 686,
4055
+ L: 771,
4023
4056
  S: this,
4024
4057
  C: (f, a) => f(...a)
4025
4058
  });
@@ -4032,7 +4065,7 @@ var QueryExecutor = class extends Resource6 {
4032
4065
  spaceId
4033
4066
  }, {
4034
4067
  F: __dxlog_file11,
4035
- L: 694,
4068
+ L: 779,
4036
4069
  S: this,
4037
4070
  C: (f, a) => f(...a)
4038
4071
  });
@@ -4044,7 +4077,7 @@ var QueryExecutor = class extends Resource6 {
4044
4077
  spaceId
4045
4078
  }, {
4046
4079
  F: __dxlog_file11,
4047
- L: 699,
4080
+ L: 784,
4048
4081
  S: this,
4049
4082
  C: (f, a) => f(...a)
4050
4083
  });
@@ -4065,7 +4098,7 @@ var QueryExecutor = class extends Resource6 {
4065
4098
  }
4066
4099
  const handle = await this._automergeHost.loadDoc(Context3.default(void 0, {
4067
4100
  F: __dxlog_file11,
4068
- L: 718
4101
+ L: 803
4069
4102
  }), link);
4070
4103
  const doc = handle.doc();
4071
4104
  if (!doc) {
@@ -4082,37 +4115,9 @@ var QueryExecutor = class extends Resource6 {
4082
4115
  doc: object
4083
4116
  };
4084
4117
  }
4085
- constructor(options) {
4086
- super(), _define_property12(this, "_indexer", void 0), _define_property12(this, "_automergeHost", void 0), _define_property12(this, "_spaceStateManager", void 0), /**
4087
- * Id of this query.
4088
- */
4089
- _define_property12(this, "_id", void 0), _define_property12(this, "_query", void 0), // TODO(dmaretskyi): Might be used in the future.
4090
- _define_property12(this, "_reactivity", void 0), _define_property12(this, "_plan", void 0), _define_property12(this, "_trace", ExecutionTrace.makeEmpty()), _define_property12(this, "_lastResultSet", []);
4091
- this._indexer = options.indexer;
4092
- this._automergeHost = options.automergeHost;
4093
- this._spaceStateManager = options.spaceStateManager;
4094
- this._id = options.queryId;
4095
- this._query = options.query;
4096
- this._reactivity = options.reactivity;
4097
- const queryPlanner = new QueryPlanner();
4098
- this._plan = queryPlanner.createPlan(this._query);
4099
- }
4100
4118
  };
4101
4119
 
4102
4120
  // src/db-host/query-service.ts
4103
- function _define_property13(obj, key, value) {
4104
- if (key in obj) {
4105
- Object.defineProperty(obj, key, {
4106
- value,
4107
- enumerable: true,
4108
- configurable: true,
4109
- writable: true
4110
- });
4111
- } else {
4112
- obj[key] = value;
4113
- }
4114
- return obj;
4115
- }
4116
4121
  function _ts_decorate5(decorators, target, key, desc) {
4117
4122
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4118
4123
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -4121,6 +4126,27 @@ function _ts_decorate5(decorators, target, key, desc) {
4121
4126
  }
4122
4127
  var __dxlog_file12 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/query-service.ts";
4123
4128
  var QueryServiceImpl = class extends Resource7 {
4129
+ _params;
4130
+ // TODO(dmaretskyi): We need to implement query deduping. Idle composer has 80 queries with only 10 being unique.
4131
+ _queries = /* @__PURE__ */ new Set();
4132
+ _updateQueries;
4133
+ // TODO(burdon): OK for options, but not params. Pass separately and type readonly here.
4134
+ constructor(_params) {
4135
+ super(), this._params = _params;
4136
+ trace4.diagnostic({
4137
+ id: "active-queries",
4138
+ name: "Active Queries",
4139
+ fetch: () => {
4140
+ return Array.from(this._queries).map((query) => {
4141
+ return {
4142
+ query: JSON.stringify(query.executor.query),
4143
+ plan: JSON.stringify(query.executor.plan),
4144
+ trace: JSON.stringify(query.executor.trace)
4145
+ };
4146
+ });
4147
+ }
4148
+ });
4149
+ }
4124
4150
  async _open() {
4125
4151
  this._params.indexer.updated.on(this._ctx, () => this.invalidateQueries());
4126
4152
  this._updateQueries = new DeferredTask2(this._ctx, this._executeQueries.bind(this));
@@ -4139,7 +4165,7 @@ var QueryServiceImpl = class extends Resource7 {
4139
4165
  config: this._params.indexer.config
4140
4166
  }, {
4141
4167
  F: __dxlog_file12,
4142
- L: 101,
4168
+ L: 102,
4143
4169
  S: this,
4144
4170
  C: (f, a) => f(...a)
4145
4171
  });
@@ -4161,7 +4187,7 @@ var QueryServiceImpl = class extends Resource7 {
4161
4187
  async reindex() {
4162
4188
  log10("Reindexing all documents...", void 0, {
4163
4189
  F: __dxlog_file12,
4164
- L: 120,
4190
+ L: 121,
4165
4191
  S: this,
4166
4192
  C: (f, a) => f(...a)
4167
4193
  });
@@ -4176,7 +4202,7 @@ var QueryServiceImpl = class extends Resource7 {
4176
4202
  count: ids.size
4177
4203
  }, {
4178
4204
  F: __dxlog_file12,
4179
- L: 128,
4205
+ L: 129,
4180
4206
  S: this,
4181
4207
  C: (f, a) => f(...a)
4182
4208
  });
@@ -4186,7 +4212,7 @@ var QueryServiceImpl = class extends Resource7 {
4186
4212
  count: ids.size
4187
4213
  }, {
4188
4214
  F: __dxlog_file12,
4189
- L: 132,
4215
+ L: 133,
4190
4216
  S: this,
4191
4217
  C: (f, a) => f(...a)
4192
4218
  });
@@ -4252,7 +4278,7 @@ var QueryServiceImpl = class extends Resource7 {
4252
4278
  } catch (err) {
4253
4279
  log10.catch(err, void 0, {
4254
4280
  F: __dxlog_file12,
4255
- L: 203,
4281
+ L: 204,
4256
4282
  S: this,
4257
4283
  C: (f, a) => f(...a)
4258
4284
  });
@@ -4263,28 +4289,11 @@ var QueryServiceImpl = class extends Resource7 {
4263
4289
  duration: performance.now() - begin
4264
4290
  }, {
4265
4291
  F: __dxlog_file12,
4266
- L: 207,
4292
+ L: 208,
4267
4293
  S: this,
4268
4294
  C: (f, a) => f(...a)
4269
4295
  });
4270
4296
  }
4271
- // TODO(burdon): OK for options, but not params. Pass separately and type readonly here.
4272
- constructor(_params) {
4273
- super(), _define_property13(this, "_params", void 0), _define_property13(this, "_queries", void 0), _define_property13(this, "_updateQueries", void 0), this._params = _params, this._queries = /* @__PURE__ */ new Set();
4274
- trace4.diagnostic({
4275
- id: "active-queries",
4276
- name: "Active Queries",
4277
- fetch: () => {
4278
- return Array.from(this._queries).map((query) => {
4279
- return {
4280
- query: JSON.stringify(query.executor.query),
4281
- plan: JSON.stringify(query.executor.plan),
4282
- trace: JSON.stringify(query.executor.trace)
4283
- };
4284
- });
4285
- }
4286
- });
4287
- }
4288
4297
  };
4289
4298
  _ts_decorate5([
4290
4299
  synchronized2
@@ -4331,7 +4340,7 @@ var createDocumentsIterator = (automergeHost) => (
4331
4340
  }
4332
4341
  const linkHandle = await automergeHost.loadDoc(Context4.default(void 0, {
4333
4342
  F: __dxlog_file12,
4334
- L: 247
4343
+ L: 248
4335
4344
  }), urlString);
4336
4345
  for await (const result of getObjectsFromHandle(linkHandle)) {
4337
4346
  yield result;
@@ -4365,17 +4374,17 @@ import { DatabaseDirectory as DatabaseDirectory5, SpaceDocVersion as SpaceDocVer
4365
4374
  import { invariant as invariant11 } from "@dxos/invariant";
4366
4375
 
4367
4376
  // src/db-host/automerge-metrics.ts
4368
- import * as A4 from "@automerge/automerge";
4377
+ import * as A5 from "@automerge/automerge";
4369
4378
  import { log as log11 } from "@dxos/log";
4370
4379
  var __dxlog_file13 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/automerge-metrics.ts";
4371
4380
  var measureDocMetrics = (doc) => {
4372
- const snapshot = A4.save(doc);
4381
+ const snapshot = A5.save(doc);
4373
4382
  const start = Date.now();
4374
- const temp = A4.load(snapshot);
4383
+ const temp = A5.load(snapshot);
4375
4384
  const end = Date.now();
4376
- A4.free(temp);
4385
+ A5.free(temp);
4377
4386
  const getAllChangesStart = Date.now();
4378
- const mutationCount = A4.getAllChanges(doc).length;
4387
+ const mutationCount = A5.getAllChanges(doc).length;
4379
4388
  const getAllChangesEnd = Date.now();
4380
4389
  if (getAllChangesEnd - getAllChangesStart > 300) {
4381
4390
  log11.warn("getAllChanges took too long", {
@@ -4395,21 +4404,9 @@ var measureDocMetrics = (doc) => {
4395
4404
  };
4396
4405
 
4397
4406
  // src/db-host/database-root.ts
4398
- function _define_property14(obj, key, value) {
4399
- if (key in obj) {
4400
- Object.defineProperty(obj, key, {
4401
- value,
4402
- enumerable: true,
4403
- configurable: true,
4404
- writable: true
4405
- });
4406
- } else {
4407
- obj[key] = value;
4408
- }
4409
- return obj;
4410
- }
4411
4407
  var __dxlog_file14 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/database-root.ts";
4412
4408
  var DatabaseRoot = class {
4409
+ _rootHandle;
4413
4410
  static mapLinks(doc, mapping) {
4414
4411
  doc.change((d) => {
4415
4412
  if (!d.links) {
@@ -4423,6 +4420,9 @@ var DatabaseRoot = class {
4423
4420
  }
4424
4421
  });
4425
4422
  }
4423
+ constructor(_rootHandle) {
4424
+ this._rootHandle = _rootHandle;
4425
+ }
4426
4426
  get documentId() {
4427
4427
  return this._rootHandle.documentId;
4428
4428
  }
@@ -4486,28 +4486,16 @@ var DatabaseRoot = class {
4486
4486
  }
4487
4487
  return measureDocMetrics(doc);
4488
4488
  }
4489
- constructor(_rootHandle) {
4490
- _define_property14(this, "_rootHandle", void 0);
4491
- this._rootHandle = _rootHandle;
4492
- }
4493
4489
  };
4494
4490
 
4495
4491
  // src/db-host/space-state-manager.ts
4496
- function _define_property15(obj, key, value) {
4497
- if (key in obj) {
4498
- Object.defineProperty(obj, key, {
4499
- value,
4500
- enumerable: true,
4501
- configurable: true,
4502
- writable: true
4503
- });
4504
- } else {
4505
- obj[key] = value;
4506
- }
4507
- return obj;
4508
- }
4509
4492
  var __dxlog_file15 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/space-state-manager.ts";
4510
4493
  var SpaceStateManager = class extends Resource8 {
4494
+ _roots = /* @__PURE__ */ new Map();
4495
+ _rootBySpace = /* @__PURE__ */ new Map();
4496
+ _perRootContext = /* @__PURE__ */ new Map();
4497
+ _lastSpaceDocumentList = /* @__PURE__ */ new Map();
4498
+ spaceDocumentListUpdated = new Event3();
4511
4499
  async _close(ctx) {
4512
4500
  for (const [_, rootCtx] of this._perRootContext) {
4513
4501
  await rootCtx.dispose();
@@ -4580,16 +4568,13 @@ var SpaceStateManager = class extends Resource8 {
4580
4568
  documentListCheckScheduler.trigger();
4581
4569
  return root;
4582
4570
  }
4583
- constructor(...args) {
4584
- super(...args), _define_property15(this, "_roots", /* @__PURE__ */ new Map()), _define_property15(this, "_rootBySpace", /* @__PURE__ */ new Map()), _define_property15(this, "_perRootContext", /* @__PURE__ */ new Map()), _define_property15(this, "_lastSpaceDocumentList", /* @__PURE__ */ new Map()), _define_property15(this, "spaceDocumentListUpdated", new Event3());
4585
- }
4586
4571
  };
4587
4572
  var SpaceDocumentListUpdatedEvent = class {
4573
+ spaceId;
4574
+ spaceRootId;
4575
+ previousRootId;
4576
+ documentIds;
4588
4577
  constructor(spaceId, spaceRootId, previousRootId, documentIds) {
4589
- _define_property15(this, "spaceId", void 0);
4590
- _define_property15(this, "spaceRootId", void 0);
4591
- _define_property15(this, "previousRootId", void 0);
4592
- _define_property15(this, "documentIds", void 0);
4593
4578
  this.spaceId = spaceId;
4594
4579
  this.spaceRootId = spaceRootId;
4595
4580
  this.previousRootId = previousRootId;
@@ -4598,19 +4583,6 @@ var SpaceDocumentListUpdatedEvent = class {
4598
4583
  };
4599
4584
 
4600
4585
  // src/db-host/echo-host.ts
4601
- function _define_property16(obj, key, value) {
4602
- if (key in obj) {
4603
- Object.defineProperty(obj, key, {
4604
- value,
4605
- enumerable: true,
4606
- configurable: true,
4607
- writable: true
4608
- });
4609
- } else {
4610
- obj[key] = value;
4611
- }
4612
- return obj;
4613
- }
4614
4586
  var __dxlog_file16 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/echo-host.ts";
4615
4587
  var DEFAULT_INDEXING_CONFIG = {
4616
4588
  // TODO(dmaretskyi): Disabled by default since embedding generation is expensive.
@@ -4618,6 +4590,111 @@ var DEFAULT_INDEXING_CONFIG = {
4618
4590
  vector: false
4619
4591
  };
4620
4592
  var EchoHost = class extends Resource9 {
4593
+ _indexMetadataStore;
4594
+ _indexer;
4595
+ _automergeHost;
4596
+ _queryService;
4597
+ _dataService;
4598
+ _spaceStateManager = new SpaceStateManager();
4599
+ _echoDataMonitor;
4600
+ constructor({ kv, indexing = {}, peerIdProvider, getSpaceKeyByRootDocumentId }) {
4601
+ super();
4602
+ const indexingConfig = {
4603
+ ...DEFAULT_INDEXING_CONFIG,
4604
+ ...indexing
4605
+ };
4606
+ this._indexMetadataStore = new IndexMetadataStore({
4607
+ db: kv.sublevel("index-metadata")
4608
+ });
4609
+ this._echoDataMonitor = new EchoDataMonitor();
4610
+ this._automergeHost = new AutomergeHost({
4611
+ db: kv,
4612
+ dataMonitor: this._echoDataMonitor,
4613
+ indexMetadataStore: this._indexMetadataStore,
4614
+ peerIdProvider,
4615
+ getSpaceKeyByRootDocumentId
4616
+ });
4617
+ this._indexer = new Indexer({
4618
+ db: kv,
4619
+ indexStore: new IndexStore({
4620
+ db: kv.sublevel("index-storage")
4621
+ }),
4622
+ metadataStore: this._indexMetadataStore,
4623
+ loadDocuments: createSelectedDocumentsIterator(this._automergeHost),
4624
+ indexCooldownTime: false ? 0 : void 0
4625
+ });
4626
+ void this._indexer.setConfig({
4627
+ enabled: true,
4628
+ indexes: [
4629
+ //
4630
+ {
4631
+ kind: IndexKind.Kind.SCHEMA_MATCH
4632
+ },
4633
+ {
4634
+ kind: IndexKind.Kind.GRAPH
4635
+ },
4636
+ ...indexingConfig.fullText ? [
4637
+ {
4638
+ kind: IndexKind.Kind.FULL_TEXT
4639
+ }
4640
+ ] : [],
4641
+ ...indexingConfig.vector ? [
4642
+ {
4643
+ kind: IndexKind.Kind.VECTOR
4644
+ }
4645
+ ] : []
4646
+ ]
4647
+ });
4648
+ this._queryService = new QueryServiceImpl({
4649
+ automergeHost: this._automergeHost,
4650
+ indexer: this._indexer,
4651
+ spaceStateManager: this._spaceStateManager
4652
+ });
4653
+ this._dataService = new DataServiceImpl({
4654
+ automergeHost: this._automergeHost,
4655
+ spaceStateManager: this._spaceStateManager,
4656
+ updateIndexes: async () => {
4657
+ await this._indexer.updateIndexes();
4658
+ }
4659
+ });
4660
+ trace5.diagnostic({
4661
+ id: "echo-stats",
4662
+ name: "Echo Stats",
4663
+ fetch: async () => {
4664
+ return {
4665
+ dataStats: this._echoDataMonitor.computeStats(),
4666
+ loadedDocsCount: this._automergeHost.loadedDocsCount
4667
+ };
4668
+ }
4669
+ });
4670
+ trace5.diagnostic({
4671
+ id: "database-roots",
4672
+ name: "Database Roots",
4673
+ fetch: async () => {
4674
+ return Array.from(this._spaceStateManager.roots.values()).map((root) => ({
4675
+ url: root.url,
4676
+ isLoaded: root.isLoaded,
4677
+ spaceKey: root.getSpaceKey(),
4678
+ inlineObjects: root.getInlineObjectCount(),
4679
+ linkedObjects: root.getLinkedObjectCount()
4680
+ }));
4681
+ }
4682
+ });
4683
+ trace5.diagnostic({
4684
+ id: "database-root-metrics",
4685
+ name: "Database Roots (with metrics)",
4686
+ fetch: async () => {
4687
+ return Array.from(this._spaceStateManager.roots.values()).map((root) => ({
4688
+ url: root.url,
4689
+ isLoaded: root.isLoaded,
4690
+ spaceKey: root.getSpaceKey(),
4691
+ inlineObjects: root.getInlineObjectCount(),
4692
+ linkedObjects: root.getLinkedObjectCount(),
4693
+ ...root.measureMetrics() ?? {}
4694
+ }));
4695
+ }
4696
+ });
4697
+ }
4621
4698
  get queryService() {
4622
4699
  return this._queryService;
4623
4700
  }
@@ -4658,7 +4735,7 @@ var EchoHost = class extends Resource9 {
4658
4735
  * Flush all pending writes to the underlying storage.
4659
4736
  */
4660
4737
  async flush() {
4661
- await this._automergeHost.repo.flush();
4738
+ await this._automergeHost.flush();
4662
4739
  }
4663
4740
  /**
4664
4741
  * Perform any pending index updates.
@@ -4742,107 +4819,10 @@ var EchoHost = class extends Resource9 {
4742
4819
  async removeReplicator(replicator) {
4743
4820
  await this._automergeHost.removeReplicator(replicator);
4744
4821
  }
4745
- constructor({ kv, indexing = {}, peerIdProvider, getSpaceKeyByRootDocumentId }) {
4746
- super(), _define_property16(this, "_indexMetadataStore", void 0), _define_property16(this, "_indexer", void 0), _define_property16(this, "_automergeHost", void 0), _define_property16(this, "_queryService", void 0), _define_property16(this, "_dataService", void 0), _define_property16(this, "_spaceStateManager", new SpaceStateManager()), _define_property16(this, "_echoDataMonitor", void 0);
4747
- const indexingConfig = {
4748
- ...DEFAULT_INDEXING_CONFIG,
4749
- ...indexing
4750
- };
4751
- this._indexMetadataStore = new IndexMetadataStore({
4752
- db: kv.sublevel("index-metadata")
4753
- });
4754
- this._echoDataMonitor = new EchoDataMonitor();
4755
- this._automergeHost = new AutomergeHost({
4756
- db: kv,
4757
- dataMonitor: this._echoDataMonitor,
4758
- indexMetadataStore: this._indexMetadataStore,
4759
- peerIdProvider,
4760
- getSpaceKeyByRootDocumentId
4761
- });
4762
- this._indexer = new Indexer({
4763
- db: kv,
4764
- indexStore: new IndexStore({
4765
- db: kv.sublevel("index-storage")
4766
- }),
4767
- metadataStore: this._indexMetadataStore,
4768
- loadDocuments: createSelectedDocumentsIterator(this._automergeHost),
4769
- indexCooldownTime: false ? 0 : void 0
4770
- });
4771
- void this._indexer.setConfig({
4772
- enabled: true,
4773
- indexes: [
4774
- //
4775
- {
4776
- kind: IndexKind.Kind.SCHEMA_MATCH
4777
- },
4778
- {
4779
- kind: IndexKind.Kind.GRAPH
4780
- },
4781
- ...indexingConfig.fullText ? [
4782
- {
4783
- kind: IndexKind.Kind.FULL_TEXT
4784
- }
4785
- ] : [],
4786
- ...indexingConfig.vector ? [
4787
- {
4788
- kind: IndexKind.Kind.VECTOR
4789
- }
4790
- ] : []
4791
- ]
4792
- });
4793
- this._queryService = new QueryServiceImpl({
4794
- automergeHost: this._automergeHost,
4795
- indexer: this._indexer,
4796
- spaceStateManager: this._spaceStateManager
4797
- });
4798
- this._dataService = new DataServiceImpl({
4799
- automergeHost: this._automergeHost,
4800
- spaceStateManager: this._spaceStateManager,
4801
- updateIndexes: async () => {
4802
- await this._indexer.updateIndexes();
4803
- }
4804
- });
4805
- trace5.diagnostic({
4806
- id: "echo-stats",
4807
- name: "Echo Stats",
4808
- fetch: async () => {
4809
- return {
4810
- dataStats: this._echoDataMonitor.computeStats(),
4811
- loadedDocsCount: this._automergeHost.loadedDocsCount
4812
- };
4813
- }
4814
- });
4815
- trace5.diagnostic({
4816
- id: "database-roots",
4817
- name: "Database Roots",
4818
- fetch: async () => {
4819
- return Array.from(this._spaceStateManager.roots.values()).map((root) => ({
4820
- url: root.url,
4821
- isLoaded: root.isLoaded,
4822
- spaceKey: root.getSpaceKey(),
4823
- inlineObjects: root.getInlineObjectCount(),
4824
- linkedObjects: root.getLinkedObjectCount()
4825
- }));
4826
- }
4827
- });
4828
- trace5.diagnostic({
4829
- id: "database-root-metrics",
4830
- name: "Database Roots (with metrics)",
4831
- fetch: async () => {
4832
- return Array.from(this._spaceStateManager.roots.values()).map((root) => ({
4833
- url: root.url,
4834
- isLoaded: root.isLoaded,
4835
- spaceKey: root.getSpaceKey(),
4836
- inlineObjects: root.getInlineObjectCount(),
4837
- linkedObjects: root.getLinkedObjectCount(),
4838
- ...root.measureMetrics() ?? {}
4839
- }));
4840
- }
4841
- });
4842
- }
4843
4822
  };
4844
4823
 
4845
4824
  // src/edge/echo-edge-replicator.ts
4825
+ import * as Automerge from "@automerge/automerge";
4846
4826
  import { cbor as cbor2 } from "@automerge/automerge-repo";
4847
4827
  import { Mutex, scheduleMicroTask as scheduleMicroTask2, scheduleTask as scheduleTask2 } from "@dxos/async";
4848
4828
  import { Context as Context6, Resource as Resource11 } from "@dxos/context";
@@ -4852,27 +4832,26 @@ import { log as log13 } from "@dxos/log";
4852
4832
  import { DocumentCodec, EdgeService } from "@dxos/protocols";
4853
4833
  import { buf } from "@dxos/protocols/buf";
4854
4834
  import { MessageSchema as RouterMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
4855
- import { bufferToArray as bufferToArray2 } from "@dxos/util";
4835
+ import { bufferToArray as bufferToArray2, setDeep } from "@dxos/util";
4856
4836
 
4857
4837
  // src/edge/inflight-request-limiter.ts
4858
4838
  import { Trigger as Trigger2 } from "@dxos/async";
4859
4839
  import { Resource as Resource10 } from "@dxos/context";
4860
4840
  import { log as log12 } from "@dxos/log";
4861
- function _define_property17(obj, key, value) {
4862
- if (key in obj) {
4863
- Object.defineProperty(obj, key, {
4864
- value,
4865
- enumerable: true,
4866
- configurable: true,
4867
- writable: true
4868
- });
4869
- } else {
4870
- obj[key] = value;
4871
- }
4872
- return obj;
4873
- }
4874
4841
  var __dxlog_file17 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/edge/inflight-request-limiter.ts";
4875
4842
  var InflightRequestLimiter = class extends Resource10 {
4843
+ _config;
4844
+ /**
4845
+ * Decrement when we receive a sync message, increment when we send one.
4846
+ * Can't exceed _config.maxInflightRequests.
4847
+ * Resets after timeout to avoid replicator being stuck.
4848
+ */
4849
+ _inflightRequestBalance = 0;
4850
+ _requestBarrier = new Trigger2();
4851
+ _resetBalanceTimeout;
4852
+ constructor(_config) {
4853
+ super(), this._config = _config;
4854
+ }
4876
4855
  async _open() {
4877
4856
  this._inflightRequestBalance = 0;
4878
4857
  this._requestBarrier.reset();
@@ -4915,30 +4894,9 @@ var InflightRequestLimiter = class extends Resource10 {
4915
4894
  clearInterval(this._resetBalanceTimeout);
4916
4895
  }
4917
4896
  }
4918
- constructor(_config) {
4919
- super(), _define_property17(this, "_config", void 0), /**
4920
- * Decrement when we receive a sync message, increment when we send one.
4921
- * Can't exceed _config.maxInflightRequests.
4922
- * Resets after timeout to avoid replicator being stuck.
4923
- */
4924
- _define_property17(this, "_inflightRequestBalance", void 0), _define_property17(this, "_requestBarrier", void 0), _define_property17(this, "_resetBalanceTimeout", void 0), this._config = _config, this._inflightRequestBalance = 0, this._requestBarrier = new Trigger2();
4925
- }
4926
4897
  };
4927
4898
 
4928
4899
  // src/edge/echo-edge-replicator.ts
4929
- function _define_property18(obj, key, value) {
4930
- if (key in obj) {
4931
- Object.defineProperty(obj, key, {
4932
- value,
4933
- enumerable: true,
4934
- configurable: true,
4935
- writable: true
4936
- });
4937
- } else {
4938
- obj[key] = value;
4939
- }
4940
- return obj;
4941
- }
4942
4900
  function _ts_add_disposable_resource(env, value, async) {
4943
4901
  if (value !== null && value !== void 0) {
4944
4902
  if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
@@ -5009,20 +4967,33 @@ var INITIAL_RESTART_DELAY = 500;
5009
4967
  var RESTART_DELAY_JITTER = 250;
5010
4968
  var MAX_RESTART_DELAY = 5e3;
5011
4969
  var EchoEdgeReplicator = class {
4970
+ _edgeConnection;
4971
+ _edgeHttpClient;
4972
+ _mutex = new Mutex();
4973
+ _ctx = void 0;
4974
+ _context = null;
4975
+ _connectedSpaces = /* @__PURE__ */ new Set();
4976
+ _connections = /* @__PURE__ */ new Map();
4977
+ _sharePolicyEnabled = true;
4978
+ constructor({ edgeConnection, edgeHttpClient, disableSharePolicy }) {
4979
+ this._edgeConnection = edgeConnection;
4980
+ this._edgeHttpClient = edgeHttpClient;
4981
+ this._sharePolicyEnabled = !disableSharePolicy;
4982
+ }
5012
4983
  async connect(context) {
5013
4984
  log13("connecting...", {
5014
4985
  peerId: context.peerId,
5015
4986
  connectedSpaces: this._connectedSpaces.size
5016
4987
  }, {
5017
4988
  F: __dxlog_file18,
5018
- L: 72,
4989
+ L: 73,
5019
4990
  S: this,
5020
4991
  C: (f, a) => f(...a)
5021
4992
  });
5022
4993
  this._context = context;
5023
4994
  this._ctx = Context6.default(void 0, {
5024
4995
  F: __dxlog_file18,
5025
- L: 74
4996
+ L: 75
5026
4997
  });
5027
4998
  this._ctx.onDispose(this._edgeConnection.onReconnected(() => {
5028
4999
  this._ctx && scheduleMicroTask2(this._ctx, () => this._handleReconnect());
@@ -5121,7 +5092,7 @@ var EchoEdgeReplicator = class {
5121
5092
  async _openConnection(spaceId, reconnects = 0) {
5122
5093
  invariant14(this._context, void 0, {
5123
5094
  F: __dxlog_file18,
5124
- L: 135,
5095
+ L: 136,
5125
5096
  S: this,
5126
5097
  A: [
5127
5098
  "this._context",
@@ -5130,7 +5101,7 @@ var EchoEdgeReplicator = class {
5130
5101
  });
5131
5102
  invariant14(!this._connections.has(spaceId), void 0, {
5132
5103
  F: __dxlog_file18,
5133
- L: 136,
5104
+ L: 137,
5134
5105
  S: this,
5135
5106
  A: [
5136
5107
  "!this._connections.has(spaceId)",
@@ -5149,7 +5120,7 @@ var EchoEdgeReplicator = class {
5149
5120
  spaceId
5150
5121
  }, {
5151
5122
  F: __dxlog_file18,
5152
- L: 147,
5123
+ L: 148,
5153
5124
  S: this,
5154
5125
  C: (f, a) => f(...a)
5155
5126
  });
@@ -5160,7 +5131,7 @@ var EchoEdgeReplicator = class {
5160
5131
  spaceId
5161
5132
  }, {
5162
5133
  F: __dxlog_file18,
5163
- L: 151,
5134
+ L: 152,
5164
5135
  S: this,
5165
5136
  C: (f, a) => f(...a)
5166
5137
  });
@@ -5177,7 +5148,7 @@ var EchoEdgeReplicator = class {
5177
5148
  restartDelay
5178
5149
  }, {
5179
5150
  F: __dxlog_file18,
5180
- L: 162,
5151
+ L: 163,
5181
5152
  S: this,
5182
5153
  C: (f, a) => f(...a)
5183
5154
  });
@@ -5205,7 +5176,7 @@ var EchoEdgeReplicator = class {
5205
5176
  restartDelay
5206
5177
  }, {
5207
5178
  F: __dxlog_file18,
5208
- L: 179,
5179
+ L: 180,
5209
5180
  S: this,
5210
5181
  C: (f, a) => f(...a)
5211
5182
  });
@@ -5222,27 +5193,57 @@ var EchoEdgeReplicator = class {
5222
5193
  this._connections.set(spaceId, connection);
5223
5194
  await connection.open();
5224
5195
  }
5225
- constructor({ edgeConnection, edgeHttpClient, disableSharePolicy }) {
5226
- _define_property18(this, "_edgeConnection", void 0);
5227
- _define_property18(this, "_edgeHttpClient", void 0);
5228
- _define_property18(this, "_mutex", new Mutex());
5229
- _define_property18(this, "_ctx", void 0);
5230
- _define_property18(this, "_context", null);
5231
- _define_property18(this, "_connectedSpaces", /* @__PURE__ */ new Set());
5232
- _define_property18(this, "_connections", /* @__PURE__ */ new Map());
5233
- _define_property18(this, "_sharePolicyEnabled", true);
5234
- this._edgeConnection = edgeConnection;
5235
- this._edgeHttpClient = edgeHttpClient;
5236
- this._sharePolicyEnabled = !disableSharePolicy;
5237
- }
5238
5196
  };
5239
5197
  var MAX_INFLIGHT_REQUESTS = 5;
5240
5198
  var MAX_RATE_LIMIT_WAIT_TIME_MS = 3e3;
5241
5199
  var EdgeReplicatorConnection = class extends Resource11 {
5200
+ _connectionId = randomUUID();
5201
+ _edgeConnection;
5202
+ _edgeHttpClient;
5203
+ _remotePeerId = null;
5204
+ _targetServiceId;
5205
+ _spaceId;
5206
+ _context;
5207
+ _sharedPolicyEnabled;
5208
+ _onRemoteConnected;
5209
+ _onRemoteDisconnected;
5210
+ _onRestartRequested;
5211
+ _sequence = 0;
5212
+ _requestLimiter = new InflightRequestLimiter({
5213
+ maxInflightRequests: MAX_INFLIGHT_REQUESTS,
5214
+ resetBalanceTimeoutMs: MAX_RATE_LIMIT_WAIT_TIME_MS
5215
+ });
5216
+ _readableStreamController;
5217
+ readable;
5218
+ writable;
5219
+ constructor({ edgeConnection, edgeHttpClient, spaceId, context, sharedPolicyEnabled, onRemoteConnected, onRemoteDisconnected, onRestartRequested }) {
5220
+ super();
5221
+ this._edgeConnection = edgeConnection;
5222
+ this._edgeHttpClient = edgeHttpClient;
5223
+ this._spaceId = spaceId;
5224
+ this._context = context;
5225
+ this._remotePeerId = `${EdgeService.AUTOMERGE_REPLICATOR}:${spaceId}-${this._connectionId}`;
5226
+ this._targetServiceId = `${EdgeService.AUTOMERGE_REPLICATOR}:${spaceId}`;
5227
+ this._sharedPolicyEnabled = sharedPolicyEnabled;
5228
+ this._onRemoteConnected = onRemoteConnected;
5229
+ this._onRemoteDisconnected = onRemoteDisconnected;
5230
+ this._onRestartRequested = onRestartRequested;
5231
+ this.readable = new ReadableStream({
5232
+ start: (controller) => {
5233
+ this._readableStreamController = controller;
5234
+ }
5235
+ });
5236
+ this.writable = new WritableStream({
5237
+ write: async (message, controller) => {
5238
+ await this._requestLimiter.rateLimit(message);
5239
+ await this._sendMessage(message);
5240
+ }
5241
+ });
5242
+ }
5242
5243
  async _open(ctx) {
5243
5244
  log13("opening...", void 0, {
5244
5245
  F: __dxlog_file18,
5245
- L: 270,
5246
+ L: 273,
5246
5247
  S: this,
5247
5248
  C: (f, a) => f(...a)
5248
5249
  });
@@ -5257,7 +5258,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
5257
5258
  if (firstReconnect) {
5258
5259
  log13.verbose("first reconnect skipped", void 0, {
5259
5260
  F: __dxlog_file18,
5260
- L: 285,
5261
+ L: 288,
5261
5262
  S: this,
5262
5263
  C: (f, a) => f(...a)
5263
5264
  });
@@ -5272,7 +5273,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
5272
5273
  async _close() {
5273
5274
  log13("closing...", void 0, {
5274
5275
  F: __dxlog_file18,
5275
- L: 298,
5276
+ L: 301,
5276
5277
  S: this,
5277
5278
  C: (f, a) => f(...a)
5278
5279
  });
@@ -5283,7 +5284,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
5283
5284
  get peerId() {
5284
5285
  invariant14(this._remotePeerId, "Not connected", {
5285
5286
  F: __dxlog_file18,
5286
- L: 307,
5287
+ L: 310,
5287
5288
  S: this,
5288
5289
  A: [
5289
5290
  "this._remotePeerId",
@@ -5308,7 +5309,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
5308
5309
  remoteId: this._remotePeerId
5309
5310
  }, {
5310
5311
  F: __dxlog_file18,
5311
- L: 322,
5312
+ L: 325,
5312
5313
  S: this,
5313
5314
  C: (f, a) => f(...a)
5314
5315
  });
@@ -5329,12 +5330,11 @@ var EdgeReplicatorConnection = class extends Resource11 {
5329
5330
  }
5330
5331
  const payload = cbor2.decode(message.payload.value);
5331
5332
  log13.verbose("received", {
5332
- type: payload.type,
5333
- documentId: payload.type === "sync" && payload.documentId,
5333
+ ...getMessageInfo(payload),
5334
5334
  remoteId: this._remotePeerId
5335
5335
  }, {
5336
5336
  F: __dxlog_file18,
5337
- L: 351,
5337
+ L: 354,
5338
5338
  S: this,
5339
5339
  C: (f, a) => f(...a)
5340
5340
  });
@@ -5365,7 +5365,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
5365
5365
  ]));
5366
5366
  }
5367
5367
  _processMessage(message) {
5368
- if (isForbiddenErrorMessage(message)) {
5368
+ if (isErrorMessage(message)) {
5369
5369
  this._onRestartRequested();
5370
5370
  return;
5371
5371
  }
@@ -5374,13 +5374,20 @@ var EdgeReplicatorConnection = class extends Resource11 {
5374
5374
  }
5375
5375
  async _sendMessage(message) {
5376
5376
  message.targetId = this._targetServiceId;
5377
+ setDeep(message, [
5378
+ "metadata",
5379
+ "dxos_sequence"
5380
+ ], this._getSequence());
5381
+ setDeep(message, [
5382
+ "metadata",
5383
+ "dxos_connectionId"
5384
+ ], this._connectionId);
5377
5385
  log13.verbose("sending...", {
5378
- type: message.type,
5379
- documentId: message.type === "sync" && message.documentId,
5386
+ ...getMessageInfo(message),
5380
5387
  remoteId: this._remotePeerId
5381
5388
  }, {
5382
5389
  F: __dxlog_file18,
5383
- L: 401,
5390
+ L: 407,
5384
5391
  S: this,
5385
5392
  C: (f, a) => f(...a)
5386
5393
  });
@@ -5401,41 +5408,29 @@ var EdgeReplicatorConnection = class extends Resource11 {
5401
5408
  err
5402
5409
  }, {
5403
5410
  F: __dxlog_file18,
5404
- L: 421,
5411
+ L: 426,
5405
5412
  S: this,
5406
5413
  C: (f, a) => f(...a)
5407
5414
  });
5408
5415
  }
5409
5416
  }
5410
- constructor({ edgeConnection, edgeHttpClient, spaceId, context, sharedPolicyEnabled, onRemoteConnected, onRemoteDisconnected, onRestartRequested }) {
5411
- super(), _define_property18(this, "_edgeConnection", void 0), _define_property18(this, "_edgeHttpClient", void 0), _define_property18(this, "_remotePeerId", null), _define_property18(this, "_targetServiceId", void 0), _define_property18(this, "_spaceId", void 0), _define_property18(this, "_context", void 0), _define_property18(this, "_sharedPolicyEnabled", void 0), _define_property18(this, "_onRemoteConnected", void 0), _define_property18(this, "_onRemoteDisconnected", void 0), _define_property18(this, "_onRestartRequested", void 0), _define_property18(this, "_requestLimiter", new InflightRequestLimiter({
5412
- maxInflightRequests: MAX_INFLIGHT_REQUESTS,
5413
- resetBalanceTimeoutMs: MAX_RATE_LIMIT_WAIT_TIME_MS
5414
- })), _define_property18(this, "_readableStreamController", void 0), _define_property18(this, "readable", void 0), _define_property18(this, "writable", void 0);
5415
- this._edgeConnection = edgeConnection;
5416
- this._edgeHttpClient = edgeHttpClient;
5417
- this._spaceId = spaceId;
5418
- this._context = context;
5419
- this._remotePeerId = `${EdgeService.AUTOMERGE_REPLICATOR}:${spaceId}-${randomUUID()}`;
5420
- this._targetServiceId = `${EdgeService.AUTOMERGE_REPLICATOR}:${spaceId}`;
5421
- this._sharedPolicyEnabled = sharedPolicyEnabled;
5422
- this._onRemoteConnected = onRemoteConnected;
5423
- this._onRemoteDisconnected = onRemoteDisconnected;
5424
- this._onRestartRequested = onRestartRequested;
5425
- this.readable = new ReadableStream({
5426
- start: (controller) => {
5427
- this._readableStreamController = controller;
5428
- }
5429
- });
5430
- this.writable = new WritableStream({
5431
- write: async (message, controller) => {
5432
- await this._requestLimiter.rateLimit(message);
5433
- await this._sendMessage(message);
5434
- }
5435
- });
5417
+ _getSequence() {
5418
+ return this._sequence++;
5436
5419
  }
5437
5420
  };
5438
- var isForbiddenErrorMessage = (message) => message.type === "error" && message.message === "Forbidden";
5421
+ var isErrorMessage = (message) => message.type === "error";
5422
+ var getMessageInfo = (msg) => {
5423
+ const { have, heads, need, changes } = msg.type === "sync" ? Automerge.decodeSyncMessage(msg.data) : {};
5424
+ return {
5425
+ type: msg.type,
5426
+ documentId: "documentId" in msg ? msg.documentId : void 0,
5427
+ have,
5428
+ heads,
5429
+ need,
5430
+ changes: changes?.length,
5431
+ sequence: msg.metadata?.dxos_sequence
5432
+ };
5433
+ };
5439
5434
 
5440
5435
  // src/util.ts
5441
5436
  import { ObjectStructure as ObjectStructure2, decodeReference } from "@dxos/echo-protocol";