@dxos/echo-pipeline 0.8.3 → 0.8.4-main.1da679c

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 (146) hide show
  1. package/dist/lib/browser/{chunk-TQJTKNMS.mjs → chunk-KQYT6ADL.mjs} +109 -3
  2. package/dist/lib/browser/chunk-KQYT6ADL.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-35I6ERLG.mjs → chunk-XGG76KKU.mjs} +513 -350
  4. package/dist/lib/browser/chunk-XGG76KKU.mjs.map +7 -0
  5. package/dist/lib/browser/filter/index.mjs +3 -1
  6. package/dist/lib/browser/index.mjs +1371 -601
  7. package/dist/lib/browser/index.mjs.map +4 -4
  8. package/dist/lib/browser/meta.json +1 -1
  9. package/dist/lib/browser/testing/index.mjs +119 -56
  10. package/dist/lib/browser/testing/index.mjs.map +3 -3
  11. package/dist/lib/node-esm/{chunk-5BHLPT24.mjs → chunk-CHMJJ4DG.mjs} +513 -350
  12. package/dist/lib/node-esm/chunk-CHMJJ4DG.mjs.map +7 -0
  13. package/dist/lib/node-esm/{chunk-RVK35BS7.mjs → chunk-W4ACY3YC.mjs} +109 -3
  14. package/dist/lib/node-esm/chunk-W4ACY3YC.mjs.map +7 -0
  15. package/dist/lib/node-esm/filter/index.mjs +3 -1
  16. package/dist/lib/node-esm/index.mjs +1371 -601
  17. package/dist/lib/node-esm/index.mjs.map +4 -4
  18. package/dist/lib/node-esm/meta.json +1 -1
  19. package/dist/lib/node-esm/testing/index.mjs +119 -56
  20. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  21. package/dist/types/src/automerge/automerge-host.d.ts +15 -28
  22. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  23. package/dist/types/src/automerge/collection-synchronizer.d.ts +1 -1
  24. package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
  25. package/dist/types/src/automerge/echo-network-adapter.d.ts +8 -1
  26. package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
  27. package/dist/types/src/automerge/echo-replicator.d.ts +21 -2
  28. package/dist/types/src/automerge/echo-replicator.d.ts.map +1 -1
  29. package/dist/types/src/automerge/index.d.ts +1 -1
  30. package/dist/types/src/automerge/index.d.ts.map +1 -1
  31. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +1 -1
  32. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -1
  33. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts +1 -0
  34. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
  35. package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
  36. package/dist/types/src/common/codec.d.ts +1 -1
  37. package/dist/types/src/common/codec.d.ts.map +1 -1
  38. package/dist/types/src/db-host/data-service.d.ts +2 -2
  39. package/dist/types/src/db-host/data-service.d.ts.map +1 -1
  40. package/dist/types/src/db-host/database-root.d.ts.map +1 -1
  41. package/dist/types/src/db-host/documents-synchronizer.d.ts +2 -2
  42. package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
  43. package/dist/types/src/db-host/echo-host.d.ts +2 -2
  44. package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
  45. package/dist/types/src/db-host/query-service.d.ts +1 -1
  46. package/dist/types/src/db-host/query-service.d.ts.map +1 -1
  47. package/dist/types/src/db-host/space-state-manager.d.ts +1 -1
  48. package/dist/types/src/db-host/space-state-manager.d.ts.map +1 -1
  49. package/dist/types/src/edge/echo-edge-replicator.d.ts +4 -2
  50. package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
  51. package/dist/types/src/filter/filter-match.d.ts +4 -1
  52. package/dist/types/src/filter/filter-match.d.ts.map +1 -1
  53. package/dist/types/src/metadata/metadata-store.d.ts +1 -1
  54. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  55. package/dist/types/src/pipeline/pipeline.d.ts +1 -1
  56. package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
  57. package/dist/types/src/query/errors.d.ts +24 -8
  58. package/dist/types/src/query/errors.d.ts.map +1 -1
  59. package/dist/types/src/query/plan.d.ts +8 -1
  60. package/dist/types/src/query/plan.d.ts.map +1 -1
  61. package/dist/types/src/query/query-executor.d.ts +4 -1
  62. package/dist/types/src/query/query-executor.d.ts.map +1 -1
  63. package/dist/types/src/query/query-planner.d.ts +2 -0
  64. package/dist/types/src/query/query-planner.d.ts.map +1 -1
  65. package/dist/types/src/space/admission-discovery-extension.d.ts.map +1 -1
  66. package/dist/types/src/space/control-pipeline.d.ts +1 -1
  67. package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
  68. package/dist/types/src/space/space-manager.d.ts +1 -1
  69. package/dist/types/src/space/space-manager.d.ts.map +1 -1
  70. package/dist/types/src/space/space-protocol.d.ts +1 -1
  71. package/dist/types/src/space/space-protocol.d.ts.map +1 -1
  72. package/dist/types/src/space/space.d.ts +1 -1
  73. package/dist/types/src/space/space.d.ts.map +1 -1
  74. package/dist/types/src/testing/test-agent-builder.d.ts +2 -2
  75. package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
  76. package/dist/types/src/testing/test-replicator.d.ts +1 -0
  77. package/dist/types/src/testing/test-replicator.d.ts.map +1 -1
  78. package/dist/types/src/util.d.ts +1 -1
  79. package/dist/types/src/util.d.ts.map +1 -1
  80. package/dist/types/tsconfig.tsbuildinfo +1 -1
  81. package/package.json +42 -38
  82. package/src/automerge/automerge-host.test.ts +18 -8
  83. package/src/automerge/automerge-host.ts +251 -65
  84. package/src/automerge/automerge-repo.test.ts +67 -16
  85. package/src/automerge/collection-synchronizer.test.ts +2 -2
  86. package/src/automerge/collection-synchronizer.ts +4 -4
  87. package/src/automerge/echo-data-monitor.ts +1 -1
  88. package/src/automerge/echo-network-adapter.test.ts +3 -3
  89. package/src/automerge/echo-network-adapter.ts +40 -7
  90. package/src/automerge/echo-replicator.ts +23 -2
  91. package/src/automerge/index.ts +1 -1
  92. package/src/automerge/leveldb-storage-adapter.ts +7 -7
  93. package/src/automerge/mesh-echo-replicator-connection.ts +4 -0
  94. package/src/automerge/mesh-echo-replicator.ts +2 -1
  95. package/src/automerge/storage-adapter.test.ts +1 -1
  96. package/src/common/space-id.ts +1 -1
  97. package/src/db-host/data-service.ts +9 -17
  98. package/src/db-host/database-root.ts +2 -2
  99. package/src/db-host/documents-synchronizer.test.ts +1 -1
  100. package/src/db-host/documents-synchronizer.ts +39 -26
  101. package/src/db-host/echo-host.ts +13 -14
  102. package/src/db-host/query-service.ts +8 -1
  103. package/src/db-host/space-state-manager.ts +2 -2
  104. package/src/edge/echo-edge-replicator.test.ts +5 -3
  105. package/src/edge/echo-edge-replicator.ts +75 -18
  106. package/src/filter/filter-match.test.ts +23 -3
  107. package/src/filter/filter-match.ts +148 -3
  108. package/src/metadata/metadata-store.ts +3 -3
  109. package/src/pipeline/pipeline-stress.test.ts +4 -2
  110. package/src/pipeline/pipeline.test.ts +3 -2
  111. package/src/pipeline/pipeline.ts +8 -5
  112. package/src/query/errors.ts +2 -0
  113. package/src/query/plan.ts +12 -1
  114. package/src/query/query-executor.ts +66 -11
  115. package/src/query/query-planner.test.ts +146 -2
  116. package/src/query/query-planner.ts +52 -8
  117. package/src/space/admission-discovery-extension.ts +2 -2
  118. package/src/space/control-pipeline.test.ts +4 -3
  119. package/src/space/control-pipeline.ts +9 -6
  120. package/src/space/space-manager.browser.test.ts +1 -1
  121. package/src/space/space-manager.ts +5 -4
  122. package/src/space/space-protocol.browser.test.ts +2 -2
  123. package/src/space/space-protocol.test.ts +3 -2
  124. package/src/space/space-protocol.ts +6 -3
  125. package/src/space/space.test.ts +1 -1
  126. package/src/space/space.ts +3 -2
  127. package/src/testing/test-agent-builder.ts +4 -3
  128. package/src/testing/test-replicator.ts +4 -0
  129. package/src/util.ts +1 -1
  130. package/dist/lib/browser/chunk-35I6ERLG.mjs.map +0 -7
  131. package/dist/lib/browser/chunk-TQJTKNMS.mjs.map +0 -7
  132. package/dist/lib/node/chunk-HOPOFWAL.cjs +0 -147
  133. package/dist/lib/node/chunk-HOPOFWAL.cjs.map +0 -7
  134. package/dist/lib/node/chunk-JXX6LF5U.cjs +0 -2084
  135. package/dist/lib/node/chunk-JXX6LF5U.cjs.map +0 -7
  136. package/dist/lib/node/chunk-Q7SFCCGT.cjs +0 -33
  137. package/dist/lib/node/chunk-Q7SFCCGT.cjs.map +0 -7
  138. package/dist/lib/node/filter/index.cjs +0 -32
  139. package/dist/lib/node/filter/index.cjs.map +0 -7
  140. package/dist/lib/node/index.cjs +0 -4699
  141. package/dist/lib/node/index.cjs.map +0 -7
  142. package/dist/lib/node/meta.json +0 -1
  143. package/dist/lib/node/testing/index.cjs +0 -753
  144. package/dist/lib/node/testing/index.cjs.map +0 -7
  145. package/dist/lib/node-esm/chunk-5BHLPT24.mjs.map +0 -7
  146. package/dist/lib/node-esm/chunk-RVK35BS7.mjs.map +0 -7
@@ -1,8 +1,9 @@
1
1
  import "@dxos/node-std/globals";
2
2
  import {
3
3
  filterMatchObject,
4
+ filterMatchObjectJSON,
4
5
  filterMatchValue
5
- } from "./chunk-TQJTKNMS.mjs";
6
+ } from "./chunk-KQYT6ADL.mjs";
6
7
  import {
7
8
  AuthExtension,
8
9
  AuthStatus,
@@ -25,27 +26,21 @@ import {
25
26
  mapTimeframeToFeedIndexes,
26
27
  startAfter,
27
28
  valueEncoding
28
- } from "./chunk-35I6ERLG.mjs";
29
+ } from "./chunk-XGG76KKU.mjs";
29
30
  import "./chunk-CGS2ULMK.mjs";
30
31
 
31
- // packages/core/echo/echo-pipeline/src/db-host/data-service.ts
32
+ // src/db-host/data-service.ts
32
33
  import { UpdateScheduler as UpdateScheduler2 } from "@dxos/async";
33
34
  import { Stream } from "@dxos/codec-protobuf/stream";
34
35
  import { invariant as invariant7 } from "@dxos/invariant";
35
36
  import { SpaceId as SpaceId2 } from "@dxos/keys";
36
37
  import { log as log7 } from "@dxos/log";
37
38
 
38
- // packages/core/echo/echo-pipeline/src/db-host/documents-synchronizer.ts
39
- import { next as A2 } from "@automerge/automerge";
40
- import { UpdateScheduler } from "@dxos/async";
41
- import { Resource as Resource5 } from "@dxos/context";
42
- import { invariant as invariant6 } from "@dxos/invariant";
43
- import { log as log6 } from "@dxos/log";
44
-
45
- // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
46
- import { getBackend, getHeads, isAutomerge, equals as headsEquals, save } from "@automerge/automerge";
39
+ // src/automerge/automerge-host.ts
40
+ import { getBackend, getHeads, equals as headsEquals, isAutomerge, save } from "@automerge/automerge";
47
41
  import { Repo, interpretAsDocumentId } from "@automerge/automerge-repo";
48
- import { Event as Event2, asyncTimeout } from "@dxos/async";
42
+ import { exportBundle } from "@automerge/automerge-repo-bundles";
43
+ import { DeferredTask, Event as Event2, asyncTimeout } from "@dxos/async";
49
44
  import { Context, Resource as Resource3, cancelWithContext } from "@dxos/context";
50
45
  import { DatabaseDirectory } from "@dxos/echo-protocol";
51
46
  import { invariant as invariant2 } from "@dxos/invariant";
@@ -53,38 +48,38 @@ import { PublicKey } from "@dxos/keys";
53
48
  import { log as log3 } from "@dxos/log";
54
49
  import { objectPointerCodec } from "@dxos/protocols";
55
50
  import { trace as trace2 } from "@dxos/tracing";
56
- import { bufferToArray } from "@dxos/util";
51
+ import { ComplexSet, bufferToArray, range } from "@dxos/util";
57
52
 
58
- // packages/core/echo/echo-pipeline/src/automerge/collection-synchronizer.ts
53
+ // src/automerge/collection-synchronizer.ts
59
54
  import { next as am } from "@automerge/automerge";
60
- import { asyncReturn, Event, scheduleTask, scheduleTaskInterval } from "@dxos/async";
55
+ import { Event, asyncReturn, scheduleTask, scheduleTaskInterval } from "@dxos/async";
61
56
  import { Resource } from "@dxos/context";
62
57
  import { log } from "@dxos/log";
63
58
  import { trace } from "@dxos/tracing";
64
59
  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
+ }
65
73
  function _ts_decorate(decorators, target, key, desc) {
66
74
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
67
75
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
68
76
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
69
77
  return c > 3 && r && Object.defineProperty(target, key, r), r;
70
78
  }
71
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/collection-synchronizer.ts";
79
+ var __dxlog_file = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/collection-synchronizer.ts";
72
80
  var MIN_QUERY_INTERVAL = 5e3;
73
81
  var POLL_INTERVAL = 3e4;
74
82
  var CollectionSynchronizer = class extends Resource {
75
- constructor(params) {
76
- super();
77
- /**
78
- * CollectionId -> State.
79
- */
80
- this._perCollectionStates = /* @__PURE__ */ new Map();
81
- this._activeCollections = /* @__PURE__ */ new Set();
82
- this._connectedPeers = /* @__PURE__ */ new Set();
83
- this.remoteStateUpdated = new Event();
84
- this._sendCollectionState = params.sendCollectionState;
85
- this._queryCollectionState = params.queryCollectionState;
86
- this._shouldSyncCollection = params.shouldSyncCollection;
87
- }
88
83
  async _open(ctx) {
89
84
  scheduleTaskInterval(this._ctx, async () => {
90
85
  for (const collectionId of this._perCollectionStates.keys()) {
@@ -263,6 +258,15 @@ var CollectionSynchronizer = class extends Resource {
263
258
  }
264
259
  }
265
260
  }
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
+ }
266
270
  };
267
271
  CollectionSynchronizer = _ts_decorate([
268
272
  trace.resource()
@@ -276,9 +280,9 @@ var diffCollectionState = (local, remote) => {
276
280
  const missingOnLocal = [];
277
281
  const different = [];
278
282
  for (const documentId of allDocuments) {
279
- if (!local.documents[documentId]) {
283
+ if (!local.documents[documentId] || local.documents[documentId].length === 0) {
280
284
  missingOnLocal.push(documentId);
281
- } else if (!remote.documents[documentId]) {
285
+ } else if (!remote.documents[documentId] || remote.documents[documentId].length === 0) {
282
286
  missingOnRemote.push(documentId);
283
287
  } else if (!am.equals(local.documents[documentId], remote.documents[documentId])) {
284
288
  different.push(documentId);
@@ -307,31 +311,41 @@ var getSpanName = (peerId) => {
307
311
  return `collection-sync-${peerId}`;
308
312
  };
309
313
 
310
- // packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts
314
+ // src/automerge/echo-network-adapter.ts
311
315
  import { NetworkAdapter } from "@automerge/automerge-repo";
312
- import { synchronized, Trigger } from "@dxos/async";
316
+ import { Trigger, synchronized } from "@dxos/async";
313
317
  import { LifecycleState } from "@dxos/context";
314
318
  import { invariant } from "@dxos/invariant";
315
319
  import { log as log2 } from "@dxos/log";
316
320
  import { isNonNullable } from "@dxos/util";
317
321
 
318
- // packages/core/echo/echo-pipeline/src/automerge/network-protocol.ts
322
+ // src/automerge/network-protocol.ts
319
323
  import { MESSAGE_TYPE_COLLECTION_QUERY, MESSAGE_TYPE_COLLECTION_STATE } from "@dxos/protocols";
320
324
  var isCollectionQueryMessage = (message) => message.type === MESSAGE_TYPE_COLLECTION_QUERY;
321
325
  var isCollectionStateMessage = (message) => message.type === MESSAGE_TYPE_COLLECTION_STATE;
322
326
 
323
- // packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts
327
+ // 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
+ }
324
341
  function _ts_decorate2(decorators, target, key, desc) {
325
342
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
326
343
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
327
344
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
328
345
  return c > 3 && r && Object.defineProperty(target, key, r), r;
329
346
  }
330
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts";
347
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts";
331
348
  var EchoNetworkAdapter = class extends NetworkAdapter {
332
- constructor(_params) {
333
- super(), 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();
334
- }
335
349
  isReady() {
336
350
  return this._lifecycleState === LifecycleState.OPEN;
337
351
  }
@@ -380,7 +394,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
380
394
  async addReplicator(replicator) {
381
395
  invariant(this._lifecycleState === LifecycleState.OPEN, void 0, {
382
396
  F: __dxlog_file2,
383
- L: 129,
397
+ L: 137,
384
398
  S: this,
385
399
  A: [
386
400
  "this._lifecycleState === LifecycleState.OPEN",
@@ -389,7 +403,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
389
403
  });
390
404
  invariant(this.peerId, void 0, {
391
405
  F: __dxlog_file2,
392
- L: 130,
406
+ L: 138,
393
407
  S: this,
394
408
  A: [
395
409
  "this.peerId",
@@ -398,7 +412,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
398
412
  });
399
413
  invariant(!this._replicators.has(replicator), void 0, {
400
414
  F: __dxlog_file2,
401
- L: 131,
415
+ L: 139,
402
416
  S: this,
403
417
  A: [
404
418
  "!this._replicators.has(replicator)",
@@ -422,7 +436,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
422
436
  async removeReplicator(replicator) {
423
437
  invariant(this._lifecycleState === LifecycleState.OPEN, void 0, {
424
438
  F: __dxlog_file2,
425
- L: 150,
439
+ L: 158,
426
440
  S: this,
427
441
  A: [
428
442
  "this._lifecycleState === LifecycleState.OPEN",
@@ -431,7 +445,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
431
445
  });
432
446
  invariant(this._replicators.has(replicator), void 0, {
433
447
  F: __dxlog_file2,
434
- L: 151,
448
+ L: 159,
435
449
  S: this,
436
450
  A: [
437
451
  "this._replicators.has(replicator)",
@@ -482,6 +496,27 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
482
496
  }) ? connection.connection.peerId : null;
483
497
  }).filter(isNonNullable);
484
498
  }
499
+ bundleSyncEnabledForPeer(peerId) {
500
+ const connection = this._connections.get(peerId);
501
+ if (!connection) {
502
+ return false;
503
+ }
504
+ return connection.connection.bundleSyncEnabled;
505
+ }
506
+ async pushBundle(peerId, bundle) {
507
+ const connection = this._connections.get(peerId);
508
+ if (!connection) {
509
+ throw new Error("Connection not found.");
510
+ }
511
+ return connection.connection.pushBundle(bundle);
512
+ }
513
+ async pullBundle(peerId, docHeads) {
514
+ const connection = this._connections.get(peerId);
515
+ if (!connection) {
516
+ throw new Error("Connection not found.");
517
+ }
518
+ return connection.connection.pullBundle(docHeads);
519
+ }
485
520
  _send(message) {
486
521
  const connectionEntry = this._connections.get(message.targetId);
487
522
  if (!connectionEntry) {
@@ -494,7 +529,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
494
529
  if (connectionEntry.isOpen) {
495
530
  log2.catch(err, void 0, {
496
531
  F: __dxlog_file2,
497
- L: 221,
532
+ L: 253,
498
533
  S: this,
499
534
  C: (f, a) => f(...a)
500
535
  });
@@ -507,13 +542,13 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
507
542
  peerId: connection.peerId
508
543
  }, {
509
544
  F: __dxlog_file2,
510
- L: 229,
545
+ L: 261,
511
546
  S: this,
512
547
  C: (f, a) => f(...a)
513
548
  });
514
549
  invariant(!this._connections.has(connection.peerId), void 0, {
515
550
  F: __dxlog_file2,
516
- L: 230,
551
+ L: 262,
517
552
  S: this,
518
553
  A: [
519
554
  "!this._connections.has(connection.peerId as PeerId)",
@@ -540,7 +575,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
540
575
  if (connectionEntry.isOpen) {
541
576
  log2.catch(err, void 0, {
542
577
  F: __dxlog_file2,
543
- L: 254,
578
+ L: 286,
544
579
  S: this,
545
580
  C: (f, a) => f(...a)
546
581
  });
@@ -551,7 +586,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
551
586
  peerId: connection.peerId
552
587
  }, {
553
588
  F: __dxlog_file2,
554
- L: 259,
589
+ L: 291,
555
590
  S: this,
556
591
  C: (f, a) => f(...a)
557
592
  });
@@ -573,14 +608,14 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
573
608
  peerId: connection.peerId
574
609
  }, {
575
610
  F: __dxlog_file2,
576
- L: 276,
611
+ L: 308,
577
612
  S: this,
578
613
  C: (f, a) => f(...a)
579
614
  });
580
615
  const entry = this._connections.get(connection.peerId);
581
616
  invariant(entry, void 0, {
582
617
  F: __dxlog_file2,
583
- L: 278,
618
+ L: 310,
584
619
  S: this,
585
620
  A: [
586
621
  "entry",
@@ -592,15 +627,15 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
592
627
  peerId: connection.peerId
593
628
  });
594
629
  this._params.monitor?.recordPeerDisconnected(connection.peerId);
595
- void entry.reader.cancel().catch((err) => log2.catch(err, void 0, {
630
+ void entry.writer.abort().catch((err) => log2.catch(err, void 0, {
596
631
  F: __dxlog_file2,
597
- L: 284,
632
+ L: 316,
598
633
  S: this,
599
634
  C: (f, a) => f(...a)
600
635
  }));
601
- void entry.writer.abort().catch((err) => log2.catch(err, void 0, {
636
+ void entry.reader.cancel().catch((err) => log2.catch(err, void 0, {
602
637
  F: __dxlog_file2,
603
- L: 285,
638
+ L: 317,
604
639
  S: this,
605
640
  C: (f, a) => f(...a)
606
641
  }));
@@ -615,14 +650,14 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
615
650
  peerId: connection.peerId
616
651
  }, {
617
652
  F: __dxlog_file2,
618
- L: 294,
653
+ L: 327,
619
654
  S: this,
620
655
  C: (f, a) => f(...a)
621
656
  });
622
657
  const entry = this._connections.get(connection.peerId);
623
658
  invariant(entry, void 0, {
624
659
  F: __dxlog_file2,
625
- L: 296,
660
+ L: 329,
626
661
  S: this,
627
662
  A: [
628
663
  "entry",
@@ -640,6 +675,12 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
640
675
  peerMetadata: createEchoPeerMetadata()
641
676
  });
642
677
  }
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
+ }
643
684
  };
644
685
  _ts_decorate2([
645
686
  synchronized
@@ -659,12 +700,22 @@ var createEchoPeerMetadata = () => ({
659
700
  });
660
701
  var isEchoPeerMetadata = (metadata) => metadata?.dxos_peerSource === "EchoNetworkAdapter";
661
702
 
662
- // packages/core/echo/echo-pipeline/src/automerge/heads-store.ts
703
+ // src/automerge/heads-store.ts
663
704
  import { headsEncoding } from "@dxos/indexing";
664
- var HeadsStore = class {
665
- constructor({ db }) {
666
- this._db = db;
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;
667
715
  }
716
+ return obj;
717
+ }
718
+ var HeadsStore = class {
668
719
  setHeads(documentId, heads, batch) {
669
720
  batch.put(documentId, heads, {
670
721
  sublevel: this._db,
@@ -679,17 +730,31 @@ var HeadsStore = class {
679
730
  valueEncoding: headsEncoding
680
731
  });
681
732
  }
733
+ constructor({ db }) {
734
+ _define_property3(this, "_db", void 0);
735
+ this._db = db;
736
+ }
682
737
  };
683
738
 
684
- // packages/core/echo/echo-pipeline/src/automerge/leveldb-storage-adapter.ts
685
- import { LifecycleState as LifecycleState2, Resource as Resource2 } from "@dxos/context";
686
- var LevelDBStorageAdapter = class extends Resource2 {
687
- constructor(_params) {
688
- super(), this._params = _params;
739
+ // src/automerge/leveldb-storage-adapter.ts
740
+ 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;
689
751
  }
752
+ return obj;
753
+ }
754
+ var LevelDBStorageAdapter = class extends Resource2 {
690
755
  async load(keyArray) {
691
756
  try {
692
- if (this._lifecycleState !== LifecycleState2.OPEN) {
757
+ if (!this.isOpen) {
693
758
  return void 0;
694
759
  }
695
760
  const startMs = Date.now();
@@ -707,7 +772,7 @@ var LevelDBStorageAdapter = class extends Resource2 {
707
772
  }
708
773
  }
709
774
  async save(keyArray, binary) {
710
- if (this._lifecycleState !== LifecycleState2.OPEN) {
775
+ if (!this.isOpen) {
711
776
  return void 0;
712
777
  }
713
778
  const startMs = Date.now();
@@ -725,7 +790,7 @@ var LevelDBStorageAdapter = class extends Resource2 {
725
790
  this._params.monitor?.recordStoreDuration(Date.now() - startMs);
726
791
  }
727
792
  async remove(keyArray) {
728
- if (this._lifecycleState !== LifecycleState2.OPEN) {
793
+ if (!this.isOpen) {
729
794
  return void 0;
730
795
  }
731
796
  await this._params.db.del(keyArray, {
@@ -733,7 +798,7 @@ var LevelDBStorageAdapter = class extends Resource2 {
733
798
  });
734
799
  }
735
800
  async loadRange(keyPrefix) {
736
- if (this._lifecycleState !== LifecycleState2.OPEN) {
801
+ if (!this.isOpen) {
737
802
  return [];
738
803
  }
739
804
  const startMs = Date.now();
@@ -756,7 +821,7 @@ var LevelDBStorageAdapter = class extends Resource2 {
756
821
  return result;
757
822
  }
758
823
  async removeRange(keyPrefix) {
759
- if (this._lifecycleState !== LifecycleState2.OPEN) {
824
+ if (!this.isOpen) {
760
825
  return void 0;
761
826
  }
762
827
  const batch = this._params.db.batch();
@@ -774,6 +839,9 @@ var LevelDBStorageAdapter = class extends Resource2 {
774
839
  }
775
840
  await batch.write();
776
841
  }
842
+ constructor(_params) {
843
+ super(), _define_property4(this, "_params", void 0), this._params = _params;
844
+ }
777
845
  };
778
846
  var keyEncoder = {
779
847
  encode: (key) => Buffer.from(key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-")),
@@ -786,58 +854,44 @@ var encodingOptions = {
786
854
  };
787
855
  var isLevelDbNotFoundError = (err) => err.code === "LEVEL_NOT_FOUND";
788
856
 
789
- // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
857
+ // 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
+ }
790
871
  function _ts_decorate3(decorators, target, key, desc) {
791
872
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
792
873
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
793
874
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
794
875
  return c > 3 && r && Object.defineProperty(target, key, r), r;
795
876
  }
796
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
877
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
797
878
  var FIND_PARAMS = {
798
879
  allowableStates: [
799
880
  "ready",
800
881
  "requesting"
801
882
  ]
802
883
  };
884
+ var BUNDLE_SIZE = 100;
885
+ var BUNDLE_SYNC_CONCURRENCY = 2;
886
+ var BUNDLE_SYNC_THRESHOLD = 50;
803
887
  var AutomergeHost = class extends Resource3 {
804
- constructor({ db, indexMetadataStore, dataMonitor, peerIdProvider, getSpaceKeyByRootDocumentId }) {
805
- super();
806
- this._collectionSynchronizer = new CollectionSynchronizer({
807
- queryCollectionState: this._queryCollectionState.bind(this),
808
- sendCollectionState: this._sendCollectionState.bind(this),
809
- shouldSyncCollection: this._shouldSyncCollection.bind(this)
810
- });
811
- this.collectionStateUpdated = new Event2();
812
- /**
813
- * Fired after a batch of documents was saved to disk.
814
- */
815
- this.documentsSaved = new Event2();
816
- this._db = db;
817
- this._storage = new LevelDBStorageAdapter({
818
- db: db.sublevel("automerge"),
819
- callbacks: {
820
- beforeSave: async (params) => this._beforeSave(params),
821
- afterSave: async (key) => this._afterSave(key)
822
- },
823
- monitor: dataMonitor
824
- });
825
- this._echoNetworkAdapter = new EchoNetworkAdapter({
826
- getContainingSpaceForDocument: this._getContainingSpaceForDocument.bind(this),
827
- isDocumentInRemoteCollection: this._isDocumentInRemoteCollection.bind(this),
828
- onCollectionStateQueried: this._onCollectionStateQueried.bind(this),
829
- onCollectionStateReceived: this._onCollectionStateReceived.bind(this),
830
- monitor: dataMonitor
831
- });
832
- this._headsStore = new HeadsStore({
833
- db: db.sublevel("heads")
834
- });
835
- this._indexMetadataStore = indexMetadataStore;
836
- this._peerIdProvider = peerIdProvider;
837
- this._getSpaceKeyByRootDocumentId = getSpaceKeyByRootDocumentId;
838
- }
839
888
  async _open() {
840
889
  this._peerId = `host-${this._peerIdProvider?.() ?? PublicKey.random().toHex()}`;
890
+ this._onHeadsChangedTask = new DeferredTask(this._ctx, async () => {
891
+ const docHeads = Array.from(this._headsUpdates.entries());
892
+ this._headsUpdates.clear();
893
+ this._onHeadsChanged(docHeads);
894
+ });
841
895
  await this._storage.open?.();
842
896
  this._repo = new Repo({
843
897
  peerId: this._peerId,
@@ -865,6 +919,28 @@ var AutomergeHost = class extends Resource3 {
865
919
  }
866
920
  }
867
921
  });
922
+ this._syncTask = new DeferredTask(this._ctx, async () => {
923
+ const collectionToSync = Array.from(this._collectionsToSync.values());
924
+ if (collectionToSync.length === 0) {
925
+ return;
926
+ }
927
+ await Promise.all(collectionToSync.map(async ({ collectionId, peerId }) => {
928
+ try {
929
+ await this._handleCollectionSync(collectionId, peerId);
930
+ } catch (err) {
931
+ log3.error("failed to sync collection", {
932
+ collectionId,
933
+ peerId,
934
+ err
935
+ }, {
936
+ F: __dxlog_file3,
937
+ L: 224,
938
+ S: this,
939
+ C: (f, a) => f(...a)
940
+ });
941
+ }
942
+ }));
943
+ });
868
944
  await this._echoNetworkAdapter.open();
869
945
  await this._collectionSynchronizer.open();
870
946
  await this._echoNetworkAdapter.open();
@@ -874,7 +950,8 @@ var AutomergeHost = class extends Resource3 {
874
950
  await this._collectionSynchronizer.close();
875
951
  await this._storage.close?.();
876
952
  await this._echoNetworkAdapter.close();
877
- await this._ctx.dispose();
953
+ this._syncTask = void 0;
954
+ this._onHeadsChangedTask = void 0;
878
955
  }
879
956
  /**
880
957
  * @deprecated To be abstracted away.
@@ -889,15 +966,42 @@ var AutomergeHost = class extends Resource3 {
889
966
  return Object.keys(this._repo.handles).length;
890
967
  }
891
968
  async addReplicator(replicator) {
969
+ invariant2(this.isOpen, "AutomergeHost is not open", {
970
+ F: __dxlog_file3,
971
+ L: 260,
972
+ S: this,
973
+ A: [
974
+ "this.isOpen",
975
+ "'AutomergeHost is not open'"
976
+ ]
977
+ });
892
978
  await this._echoNetworkAdapter.addReplicator(replicator);
893
979
  }
894
980
  async removeReplicator(replicator) {
981
+ invariant2(this.isOpen, "AutomergeHost is not open", {
982
+ F: __dxlog_file3,
983
+ L: 265,
984
+ S: this,
985
+ A: [
986
+ "this.isOpen",
987
+ "'AutomergeHost is not open'"
988
+ ]
989
+ });
895
990
  await this._echoNetworkAdapter.removeReplicator(replicator);
896
991
  }
897
992
  /**
898
993
  * Loads the document handle from the repo and waits for it to be ready.
899
994
  */
900
995
  async loadDoc(ctx, documentId, opts) {
996
+ invariant2(this.isOpen, "AutomergeHost is not open", {
997
+ F: __dxlog_file3,
998
+ L: 273,
999
+ S: this,
1000
+ A: [
1001
+ "this.isOpen",
1002
+ "'AutomergeHost is not open'"
1003
+ ]
1004
+ });
901
1005
  let handle;
902
1006
  if (typeof documentId === "string") {
903
1007
  handle = this._repo.handles[documentId];
@@ -915,6 +1019,15 @@ var AutomergeHost = class extends Resource3 {
915
1019
  return handle;
916
1020
  }
917
1021
  async exportDoc(ctx, id) {
1022
+ invariant2(this.isOpen, "AutomergeHost is not open", {
1023
+ F: __dxlog_file3,
1024
+ L: 296,
1025
+ S: this,
1026
+ A: [
1027
+ "this.isOpen",
1028
+ "'AutomergeHost is not open'"
1029
+ ]
1030
+ });
918
1031
  const documentId = interpretAsDocumentId(id);
919
1032
  const chunks = await this._storage.loadRange([
920
1033
  documentId
@@ -925,6 +1038,15 @@ var AutomergeHost = class extends Resource3 {
925
1038
  * Create new persisted document.
926
1039
  */
927
1040
  createDoc(initialValue, opts) {
1041
+ invariant2(this.isOpen, "AutomergeHost is not open", {
1042
+ F: __dxlog_file3,
1043
+ L: 307,
1044
+ S: this,
1045
+ A: [
1046
+ "this.isOpen",
1047
+ "'AutomergeHost is not open'"
1048
+ ]
1049
+ });
928
1050
  if (opts?.preserveHistory) {
929
1051
  if (initialValue instanceof Uint8Array) {
930
1052
  return this._repo.import(initialValue);
@@ -941,6 +1063,15 @@ var AutomergeHost = class extends Resource3 {
941
1063
  }
942
1064
  }
943
1065
  async waitUntilHeadsReplicated(heads) {
1066
+ invariant2(this.isOpen, "AutomergeHost is not open", {
1067
+ F: __dxlog_file3,
1068
+ L: 329,
1069
+ S: this,
1070
+ A: [
1071
+ "this.isOpen",
1072
+ "'AutomergeHost is not open'"
1073
+ ]
1074
+ });
944
1075
  const entries = heads.entries;
945
1076
  if (!entries?.length) {
946
1077
  return;
@@ -959,7 +1090,7 @@ var AutomergeHost = class extends Resource3 {
959
1090
  await Promise.all(headsToWait.map(async (entry, index) => {
960
1091
  const handle = await this.loadDoc(Context.default(void 0, {
961
1092
  F: __dxlog_file3,
962
- L: 293
1093
+ L: 347
963
1094
  }), entry.documentId);
964
1095
  await waitForHeads(handle, entry.heads);
965
1096
  }));
@@ -967,12 +1098,21 @@ var AutomergeHost = class extends Resource3 {
967
1098
  await this._repo.flush(documentIds.filter((documentId) => this._repo.handles[documentId] && this._repo.handles[documentId].isReady()));
968
1099
  }
969
1100
  async reIndexHeads(documentIds) {
1101
+ invariant2(this.isOpen, "AutomergeHost is not open", {
1102
+ F: __dxlog_file3,
1103
+ L: 360,
1104
+ S: this,
1105
+ A: [
1106
+ "this.isOpen",
1107
+ "'AutomergeHost is not open'"
1108
+ ]
1109
+ });
970
1110
  for (const documentId of documentIds) {
971
1111
  log3("re-indexing heads for document", {
972
1112
  documentId
973
1113
  }, {
974
1114
  F: __dxlog_file3,
975
- L: 307,
1115
+ L: 362,
976
1116
  S: this,
977
1117
  C: (f, a) => f(...a)
978
1118
  });
@@ -982,7 +1122,7 @@ var AutomergeHost = class extends Resource3 {
982
1122
  documentId
983
1123
  }, {
984
1124
  F: __dxlog_file3,
985
- L: 310,
1125
+ L: 365,
986
1126
  S: this,
987
1127
  C: (f, a) => f(...a)
988
1128
  });
@@ -995,7 +1135,7 @@ var AutomergeHost = class extends Resource3 {
995
1135
  }
996
1136
  log3("done re-indexing heads", void 0, {
997
1137
  F: __dxlog_file3,
998
- L: 319,
1138
+ L: 374,
999
1139
  S: this,
1000
1140
  C: (f, a) => f(...a)
1001
1141
  });
@@ -1056,13 +1196,31 @@ var AutomergeHost = class extends Resource3 {
1056
1196
  * Called by AutomergeStorageAdapter after levelDB batch commit.
1057
1197
  */
1058
1198
  async _afterSave(path) {
1199
+ if (!this.isOpen) {
1200
+ return void 0;
1201
+ }
1059
1202
  this._indexMetadataStore.notifyMarkedDirty();
1060
1203
  const documentId = path[0];
1061
- const document = this._repo.handles[documentId]?.doc();
1062
- if (document) {
1063
- const heads = getHeads(document);
1064
- this._onHeadsChanged(documentId, heads);
1204
+ const handle = this._repo.handles[documentId];
1205
+ if (!handle || !handle.isReady()) {
1206
+ return;
1207
+ }
1208
+ const document = handle.doc();
1209
+ if (!document) {
1210
+ return;
1065
1211
  }
1212
+ const heads = getHeads(document);
1213
+ this._headsUpdates.set(documentId, heads);
1214
+ invariant2(this._onHeadsChangedTask, "onHeadsChangedTask is not initialized", {
1215
+ F: __dxlog_file3,
1216
+ L: 450,
1217
+ S: this,
1218
+ A: [
1219
+ "this._onHeadsChangedTask",
1220
+ "'onHeadsChangedTask is not initialized'"
1221
+ ]
1222
+ });
1223
+ this._onHeadsChangedTask.schedule();
1066
1224
  this.documentsSaved.emit();
1067
1225
  }
1068
1226
  _automergePeers() {
@@ -1155,8 +1313,17 @@ var AutomergeHost = class extends Resource3 {
1155
1313
  missingOnRemote: diff.missingOnRemote.length,
1156
1314
  missingOnLocal: diff.missingOnLocal.length,
1157
1315
  differentDocuments: diff.different.length,
1158
- localDocumentCount: Object.keys(localState.documents).length,
1159
- remoteDocumentCount: Object.keys(state.documents).length
1316
+ localDocumentCount: Object.entries(localState.documents).filter(([_, heads]) => heads.length > 0).length,
1317
+ remoteDocumentCount: Object.entries(state.documents).filter(([_, heads]) => heads.length > 0).length,
1318
+ totalDocumentCount: (/* @__PURE__ */ new Set([
1319
+ ...Object.keys(localState.documents),
1320
+ ...Object.keys(state.documents)
1321
+ ])).size,
1322
+ unsyncedDocumentCount: (/* @__PURE__ */ new Set([
1323
+ ...diff.missingOnLocal,
1324
+ ...diff.missingOnRemote,
1325
+ ...diff.different
1326
+ ])).size
1160
1327
  });
1161
1328
  }
1162
1329
  return result;
@@ -1173,6 +1340,14 @@ var AutomergeHost = class extends Resource3 {
1173
1340
  this._collectionSynchronizer.setLocalCollectionState(collectionId, {
1174
1341
  documents
1175
1342
  });
1343
+ const interestedPeers = this._echoNetworkAdapter.getPeersInterestedInCollection(collectionId);
1344
+ if (interestedPeers.length > 0) {
1345
+ for (const peerId of interestedPeers) {
1346
+ this._sendCollectionState(collectionId, peerId, {
1347
+ documents
1348
+ });
1349
+ }
1350
+ }
1176
1351
  }
1177
1352
  async clearLocalCollectionState(collectionId) {
1178
1353
  this._collectionSynchronizer.clearLocalCollectionState(collectionId);
@@ -1196,42 +1371,203 @@ var AutomergeHost = class extends Resource3 {
1196
1371
  this._collectionSynchronizer.onConnectionClosed(peerId);
1197
1372
  }
1198
1373
  _onRemoteCollectionStateUpdated(collectionId, peerId) {
1374
+ this._collectionsToSync.add({
1375
+ collectionId,
1376
+ peerId
1377
+ });
1378
+ this._syncTask?.schedule();
1379
+ }
1380
+ async _handleCollectionSync(collectionId, peerId) {
1199
1381
  const localState = this._collectionSynchronizer.getLocalCollectionState(collectionId);
1200
1382
  const remoteState = this._collectionSynchronizer.getRemoteCollectionStates(collectionId).get(peerId);
1201
1383
  if (!localState || !remoteState) {
1202
1384
  return;
1203
1385
  }
1204
1386
  const { different, missingOnLocal, missingOnRemote } = diffCollectionState(localState, remoteState);
1205
- const toReplicate = [
1206
- ...missingOnLocal,
1207
- ...missingOnRemote,
1387
+ if (different.length === 0 && missingOnLocal.length === 0 && missingOnRemote.length === 0) {
1388
+ return;
1389
+ }
1390
+ const toReplicateWithoutBatching = [
1208
1391
  ...different
1209
1392
  ];
1210
- if (toReplicate.length === 0) {
1393
+ const bundleSyncEnabled = this._echoNetworkAdapter.bundleSyncEnabledForPeer(peerId);
1394
+ if (bundleSyncEnabled && missingOnRemote.length >= BUNDLE_SYNC_THRESHOLD) {
1395
+ log3("pushing bundle", {
1396
+ amount: missingOnRemote.length
1397
+ }, {
1398
+ F: __dxlog_file3,
1399
+ L: 649,
1400
+ S: this,
1401
+ C: (f, a) => f(...a)
1402
+ });
1403
+ const { syncInteractively } = await this._pushInBundles(peerId, missingOnRemote);
1404
+ toReplicateWithoutBatching.push(...syncInteractively);
1405
+ } else {
1406
+ log3.verbose("failed to push bundle, replicating interactively", {
1407
+ collectionId,
1408
+ peerId,
1409
+ amount: missingOnRemote.length
1410
+ }, {
1411
+ F: __dxlog_file3,
1412
+ L: 653,
1413
+ S: this,
1414
+ C: (f, a) => f(...a)
1415
+ });
1416
+ toReplicateWithoutBatching.push(...missingOnRemote);
1417
+ }
1418
+ if (bundleSyncEnabled && missingOnLocal.length >= BUNDLE_SYNC_THRESHOLD) {
1419
+ log3("pulling bundle", {
1420
+ amount: missingOnLocal.length
1421
+ }, {
1422
+ F: __dxlog_file3,
1423
+ L: 661,
1424
+ S: this,
1425
+ C: (f, a) => f(...a)
1426
+ });
1427
+ const { syncInteractively } = await this._pullInBundles(peerId, missingOnLocal);
1428
+ toReplicateWithoutBatching.push(...syncInteractively);
1429
+ } else {
1430
+ log3.verbose("failed to pull bundle, replicating interactively", {
1431
+ collectionId,
1432
+ peerId,
1433
+ amount: missingOnLocal.length
1434
+ }, {
1435
+ F: __dxlog_file3,
1436
+ L: 665,
1437
+ S: this,
1438
+ C: (f, a) => f(...a)
1439
+ });
1440
+ toReplicateWithoutBatching.push(...missingOnLocal);
1441
+ }
1442
+ if (toReplicateWithoutBatching.length === 0) {
1211
1443
  return;
1212
1444
  }
1213
1445
  log3("replicating documents after collection sync", {
1214
1446
  collectionId,
1215
1447
  peerId,
1216
- toReplicate,
1217
- count: toReplicate.length
1448
+ toReplicateWithoutBatching,
1449
+ count: toReplicateWithoutBatching.length
1218
1450
  }, {
1219
1451
  F: __dxlog_file3,
1220
- L: 563,
1452
+ L: 677,
1221
1453
  S: this,
1222
1454
  C: (f, a) => f(...a)
1223
1455
  });
1224
- for (const documentId of toReplicate) {
1456
+ for (const documentId of toReplicateWithoutBatching) {
1225
1457
  this._repo.findWithProgress(documentId);
1226
1458
  }
1227
1459
  }
1228
- _onHeadsChanged(documentId, heads) {
1460
+ // TODO(mykola): Add retries of batches https://gist.github.com/mykola-vrmchk/fde270259e9209fcbf1331e5abbf12cf
1461
+ // TODO(mykola): Use effect to retry batches.
1462
+ async _pushInBundles(peerId, documentIds) {
1463
+ const documentsToPush = [
1464
+ ...documentIds
1465
+ ];
1466
+ const syncInteractively = [];
1467
+ while (documentsToPush.length > 0) {
1468
+ await Promise.all(range(BUNDLE_SYNC_CONCURRENCY).map(async () => {
1469
+ const bundle = documentsToPush.splice(0, BUNDLE_SIZE);
1470
+ if (bundle.length === 0) {
1471
+ return;
1472
+ }
1473
+ await this._pushBundle(peerId, bundle).catch((err) => {
1474
+ log3.warn("failed to push bundle, replicating interactively", {
1475
+ peerId,
1476
+ bundle,
1477
+ err
1478
+ }, {
1479
+ F: __dxlog_file3,
1480
+ L: 708,
1481
+ S: this,
1482
+ C: (f, a) => f(...a)
1483
+ });
1484
+ syncInteractively.push(...bundle);
1485
+ });
1486
+ }));
1487
+ }
1488
+ return {
1489
+ syncInteractively
1490
+ };
1491
+ }
1492
+ async _pushBundle(peerId, documentIds) {
1493
+ if (this._ctx.disposed) {
1494
+ return;
1495
+ }
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
+ })));
1503
+ }
1504
+ async _pullInBundles(peerId, documentIds) {
1505
+ const documentsToPull = [
1506
+ ...documentIds
1507
+ ];
1508
+ const syncInteractively = [];
1509
+ const docsToImport = {};
1510
+ while (documentsToPull.length > 0) {
1511
+ await Promise.all(range(BUNDLE_SYNC_CONCURRENCY).map(async () => {
1512
+ const bundle = documentsToPull.splice(0, BUNDLE_SIZE);
1513
+ if (bundle.length === 0) {
1514
+ return;
1515
+ }
1516
+ const result = await this._pullBundle(peerId, bundle).catch((err) => {
1517
+ log3.warn("failed to pull bundle, replicating interactively", {
1518
+ peerId,
1519
+ bundle,
1520
+ err
1521
+ }, {
1522
+ F: __dxlog_file3,
1523
+ L: 752,
1524
+ S: this,
1525
+ C: (f, a) => f(...a)
1526
+ });
1527
+ syncInteractively.push(...bundle);
1528
+ });
1529
+ if (result) {
1530
+ Object.assign(docsToImport, result.docsToImport);
1531
+ }
1532
+ }));
1533
+ }
1534
+ for (const [documentId, data] of Object.entries(docsToImport)) {
1535
+ this._repo.import(data, {
1536
+ docId: documentId
1537
+ });
1538
+ }
1539
+ await this._repo.flush(Object.keys(docsToImport));
1540
+ return {
1541
+ syncInteractively
1542
+ };
1543
+ }
1544
+ async _pullBundle(peerId, documentIds) {
1545
+ if (this._ctx.disposed) {
1546
+ return;
1547
+ }
1548
+ const docHeads = Object.fromEntries(documentIds.map((documentId) => [
1549
+ documentId,
1550
+ []
1551
+ ]));
1552
+ const bundle = await this._echoNetworkAdapter.pullBundle(peerId, docHeads);
1553
+ return {
1554
+ docsToImport: bundle
1555
+ };
1556
+ }
1557
+ _onHeadsChanged(docHeads) {
1229
1558
  const collectionsChanged = /* @__PURE__ */ new Set();
1230
1559
  for (const collectionId of this._collectionSynchronizer.getRegisteredCollectionIds()) {
1231
1560
  const state = this._collectionSynchronizer.getLocalCollectionState(collectionId);
1232
- if (state?.documents[documentId]) {
1233
- const newState = structuredClone(state);
1234
- newState.documents[documentId] = heads;
1561
+ let newState;
1562
+ for (const [documentId, heads] of docHeads) {
1563
+ if (state?.documents[documentId]) {
1564
+ if (!newState) {
1565
+ newState = structuredClone(state);
1566
+ }
1567
+ newState.documents[documentId] = heads;
1568
+ }
1569
+ }
1570
+ if (newState) {
1235
1571
  this._collectionSynchronizer.setLocalCollectionState(collectionId, newState);
1236
1572
  collectionsChanged.add(collectionId);
1237
1573
  }
@@ -1242,16 +1578,51 @@ var AutomergeHost = class extends Resource3 {
1242
1578
  });
1243
1579
  }
1244
1580
  }
1245
- };
1246
- _ts_decorate3([
1247
- trace2.info()
1248
- ], AutomergeHost.prototype, "_peerId", void 0);
1249
- _ts_decorate3([
1250
- trace2.info({
1251
- depth: null
1252
- })
1253
- ], AutomergeHost.prototype, "_automergePeers", null);
1254
- _ts_decorate3([
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
+ };
1617
+ _ts_decorate3([
1618
+ trace2.info()
1619
+ ], AutomergeHost.prototype, "_peerId", void 0);
1620
+ _ts_decorate3([
1621
+ trace2.info({
1622
+ depth: null
1623
+ })
1624
+ ], AutomergeHost.prototype, "_automergePeers", null);
1625
+ _ts_decorate3([
1255
1626
  trace2.span({
1256
1627
  showInBrowserTimeline: true
1257
1628
  })
@@ -1277,7 +1648,7 @@ var changeIsPresentInDoc = (doc, changeHash) => {
1277
1648
  var decodeCollectionState = (state) => {
1278
1649
  invariant2(typeof state === "object" && state !== null, "Invalid state", {
1279
1650
  F: __dxlog_file3,
1280
- L: 614,
1651
+ L: 832,
1281
1652
  S: void 0,
1282
1653
  A: [
1283
1654
  "typeof state === 'object' && state !== null",
@@ -1290,24 +1661,88 @@ var encodeCollectionState = (state) => {
1290
1661
  return state;
1291
1662
  };
1292
1663
 
1293
- // packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts
1664
+ // src/automerge/mesh-echo-replicator.ts
1294
1665
  import { invariant as invariant5 } from "@dxos/invariant";
1295
1666
  import { PublicKey as PublicKey2 } from "@dxos/keys";
1296
1667
  import { log as log5 } from "@dxos/log";
1297
- import { ComplexSet, defaultMap as defaultMap2 } from "@dxos/util";
1668
+ import { ComplexSet as ComplexSet2, defaultMap as defaultMap2 } from "@dxos/util";
1298
1669
 
1299
- // packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts
1670
+ // src/automerge/mesh-echo-replicator-connection.ts
1300
1671
  import * as A from "@automerge/automerge";
1301
1672
  import { cbor } from "@automerge/automerge-repo";
1302
1673
  import { Resource as Resource4 } from "@dxos/context";
1303
1674
  import { invariant as invariant3 } from "@dxos/invariant";
1304
1675
  import { log as log4 } from "@dxos/log";
1305
1676
  import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
1306
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts";
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
+ var __dxlog_file4 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts";
1307
1691
  var DEFAULT_FACTORY = (params) => new AutomergeReplicator(...params);
1308
1692
  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
+ }
1309
1744
  constructor(_params) {
1310
- super(), this._params = _params, this.remoteDeviceKey = null, this._remotePeerId = null, this._isEnabled = false;
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;
1311
1746
  let readableStreamController;
1312
1747
  this.readable = new ReadableStream({
1313
1748
  start: (controller) => {
@@ -1371,54 +1806,6 @@ var MeshReplicatorConnection = class extends Resource4 {
1371
1806
  }
1372
1807
  ]);
1373
1808
  }
1374
- _disconnectIfEnabled() {
1375
- if (this._isEnabled) {
1376
- this._params.onRemoteDisconnected();
1377
- }
1378
- }
1379
- get peerId() {
1380
- invariant3(this._remotePeerId != null, "Remote peer has not connected yet.", {
1381
- F: __dxlog_file4,
1382
- L: 106,
1383
- S: this,
1384
- A: [
1385
- "this._remotePeerId != null",
1386
- "'Remote peer has not connected yet.'"
1387
- ]
1388
- });
1389
- return this._remotePeerId;
1390
- }
1391
- get isEnabled() {
1392
- return this._isEnabled;
1393
- }
1394
- async shouldAdvertise(params) {
1395
- return this._params.shouldAdvertise(params);
1396
- }
1397
- shouldSyncCollection(params) {
1398
- return this._params.shouldSyncCollection(params);
1399
- }
1400
- /**
1401
- * Start exchanging messages with the remote peer.
1402
- * Call after the remote peer has connected.
1403
- */
1404
- enable() {
1405
- invariant3(this._remotePeerId != null, "Remote peer has not connected yet.", {
1406
- F: __dxlog_file4,
1407
- L: 127,
1408
- S: this,
1409
- A: [
1410
- "this._remotePeerId != null",
1411
- "'Remote peer has not connected yet.'"
1412
- ]
1413
- });
1414
- this._isEnabled = true;
1415
- }
1416
- /**
1417
- * Stop exchanging messages with the remote peer.
1418
- */
1419
- disable() {
1420
- this._isEnabled = false;
1421
- }
1422
1809
  };
1423
1810
  var logSendSync = (message) => {
1424
1811
  log4("sendSyncMessage", () => {
@@ -1435,16 +1822,16 @@ var logSendSync = (message) => {
1435
1822
  };
1436
1823
  }, {
1437
1824
  F: __dxlog_file4,
1438
- L: 140,
1825
+ L: 144,
1439
1826
  S: void 0,
1440
1827
  C: (f, a) => f(...a)
1441
1828
  });
1442
1829
  };
1443
1830
 
1444
- // packages/core/echo/echo-pipeline/src/automerge/space-collection.ts
1831
+ // src/automerge/space-collection.ts
1445
1832
  import { invariant as invariant4 } from "@dxos/invariant";
1446
1833
  import { SpaceId } from "@dxos/keys";
1447
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/space-collection.ts";
1834
+ var __dxlog_file5 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/space-collection.ts";
1448
1835
  var deriveCollectionIdFromSpaceId = (spaceId, rootDocumentId) => rootDocumentId ? `space:${spaceId}:${rootDocumentId}` : `space:${spaceId}`;
1449
1836
  var getSpaceIdFromCollectionId = (collectionId) => {
1450
1837
  const spaceId = collectionId.split(":")[1];
@@ -1460,27 +1847,22 @@ var getSpaceIdFromCollectionId = (collectionId) => {
1460
1847
  return spaceId;
1461
1848
  };
1462
1849
 
1463
- // packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts
1464
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts";
1465
- var MeshEchoReplicator = class {
1466
- constructor() {
1467
- /**
1468
- * We might have multiple connections open with a peer (one per space), but there'll be only one enabled
1469
- * connection at any given moment, because there's a single repo for all the spaces.
1470
- * When a connection closes (space was closed) it gets removed from the list and the next connection
1471
- * in the line gets enabled.
1472
- */
1473
- this._connectionsPerPeer = /* @__PURE__ */ new Map();
1474
- /**
1475
- * A set of all connections (enabled and disabled).
1476
- */
1477
- this._connections = /* @__PURE__ */ new Set();
1478
- /**
1479
- * spaceId -> deviceKey[]
1480
- */
1481
- this._authorizedDevices = /* @__PURE__ */ new Map();
1482
- this._context = null;
1850
+ // 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;
1483
1861
  }
1862
+ return obj;
1863
+ }
1864
+ var __dxlog_file6 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts";
1865
+ var MeshEchoReplicator = class {
1484
1866
  async connect(context) {
1485
1867
  this._context = context;
1486
1868
  }
@@ -1500,7 +1882,7 @@ var MeshEchoReplicator = class {
1500
1882
  createExtension(extensionFactory) {
1501
1883
  invariant5(this._context, void 0, {
1502
1884
  F: __dxlog_file6,
1503
- L: 67,
1885
+ L: 68,
1504
1886
  S: this,
1505
1887
  A: [
1506
1888
  "this._context",
@@ -1515,13 +1897,13 @@ var MeshEchoReplicator = class {
1515
1897
  peerId: connection.peerId
1516
1898
  }, {
1517
1899
  F: __dxlog_file6,
1518
- L: 73,
1900
+ L: 74,
1519
1901
  S: this,
1520
1902
  C: (f, a) => f(...a)
1521
1903
  });
1522
1904
  invariant5(this._context, void 0, {
1523
1905
  F: __dxlog_file6,
1524
- L: 74,
1906
+ L: 75,
1525
1907
  S: this,
1526
1908
  A: [
1527
1909
  "this._context",
@@ -1546,7 +1928,7 @@ var MeshEchoReplicator = class {
1546
1928
  peerId: connection.peerId
1547
1929
  }, {
1548
1930
  F: __dxlog_file6,
1549
- L: 88,
1931
+ L: 89,
1550
1932
  S: this,
1551
1933
  C: (f, a) => f(...a)
1552
1934
  });
@@ -1558,7 +1940,7 @@ var MeshEchoReplicator = class {
1558
1940
  peerId: connection.peerId
1559
1941
  }, {
1560
1942
  F: __dxlog_file6,
1561
- L: 96,
1943
+ L: 97,
1562
1944
  S: this,
1563
1945
  C: (f, a) => f(...a)
1564
1946
  });
@@ -1580,13 +1962,13 @@ var MeshEchoReplicator = class {
1580
1962
  documentId: params.documentId
1581
1963
  }, {
1582
1964
  F: __dxlog_file6,
1583
- L: 114,
1965
+ L: 115,
1584
1966
  S: this,
1585
1967
  C: (f, a) => f(...a)
1586
1968
  });
1587
1969
  invariant5(this._context, void 0, {
1588
1970
  F: __dxlog_file6,
1589
- L: 115,
1971
+ L: 116,
1590
1972
  S: this,
1591
1973
  A: [
1592
1974
  "this._context",
@@ -1606,7 +1988,7 @@ var MeshEchoReplicator = class {
1606
1988
  acceptDocument: remoteDocumentExists
1607
1989
  }, {
1608
1990
  F: __dxlog_file6,
1609
- L: 123,
1991
+ L: 124,
1610
1992
  S: this,
1611
1993
  C: (f, a) => f(...a)
1612
1994
  });
@@ -1620,7 +2002,7 @@ var MeshEchoReplicator = class {
1620
2002
  documentId: params.documentId
1621
2003
  }, {
1622
2004
  F: __dxlog_file6,
1623
- L: 140,
2005
+ L: 141,
1624
2006
  S: this,
1625
2007
  C: (f, a) => f(...a)
1626
2008
  });
@@ -1636,7 +2018,7 @@ var MeshEchoReplicator = class {
1636
2018
  isAuthorized
1637
2019
  }, {
1638
2020
  F: __dxlog_file6,
1639
- L: 148,
2021
+ L: 149,
1640
2022
  S: this,
1641
2023
  C: (f, a) => f(...a)
1642
2024
  });
@@ -1644,7 +2026,7 @@ var MeshEchoReplicator = class {
1644
2026
  } catch (err) {
1645
2027
  log5.catch(err, void 0, {
1646
2028
  F: __dxlog_file6,
1647
- L: 158,
2029
+ L: 159,
1648
2030
  S: this,
1649
2031
  C: (f, a) => f(...a)
1650
2032
  });
@@ -1660,7 +2042,7 @@ var MeshEchoReplicator = class {
1660
2042
  collectionId
1661
2043
  }, {
1662
2044
  F: __dxlog_file6,
1663
- L: 168,
2045
+ L: 169,
1664
2046
  S: this,
1665
2047
  C: (f, a) => f(...a)
1666
2048
  });
@@ -1679,12 +2061,12 @@ var MeshEchoReplicator = class {
1679
2061
  deviceKey
1680
2062
  }, {
1681
2063
  F: __dxlog_file6,
1682
- L: 185,
2064
+ L: 186,
1683
2065
  S: this,
1684
2066
  C: (f, a) => f(...a)
1685
2067
  });
1686
2068
  const spaceId = await createIdFromSpaceKey(spaceKey);
1687
- defaultMap2(this._authorizedDevices, spaceId, () => new ComplexSet(PublicKey2.hash)).add(deviceKey);
2069
+ defaultMap2(this._authorizedDevices, spaceId, () => new ComplexSet2(PublicKey2.hash)).add(deviceKey);
1688
2070
  for (const connection of this._connections) {
1689
2071
  if (connection.isEnabled && connection.remoteDeviceKey && connection.remoteDeviceKey.equals(deviceKey)) {
1690
2072
  if (this._connectionsPerPeer.has(connection.peerId)) {
@@ -1693,11 +2075,30 @@ var MeshEchoReplicator = class {
1693
2075
  }
1694
2076
  }
1695
2077
  }
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
+ }
1696
2084
  };
1697
2085
 
1698
- // packages/core/echo/echo-pipeline/src/automerge/echo-data-monitor.ts
2086
+ // src/automerge/echo-data-monitor.ts
1699
2087
  import { trace as trace3 } from "@dxos/tracing";
1700
- import { CircularBuffer, mapValues, SlidingWindowSummary } from "@dxos/util";
2088
+ 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
+ }
1701
2102
  function _ts_decorate4(decorators, target, key, desc) {
1702
2103
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1703
2104
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -1707,20 +2108,6 @@ function _ts_decorate4(decorators, target, key, desc) {
1707
2108
  var PER_SECOND_RATE_AVG_WINDOW_SIZE = 5;
1708
2109
  var DEFAULT_AVG_WINDOW_SIZE = 25;
1709
2110
  var EchoDataMonitor = class {
1710
- constructor(_params = {
1711
- timeSeriesLength: 30
1712
- }) {
1713
- this._params = _params;
1714
- this._lastTick = 0;
1715
- this._activeCounters = createLocalCounters();
1716
- this._localTimeSeries = createLocalTimeSeries();
1717
- this._storageAverages = createStorageAverages();
1718
- this._replicationAverages = createNetworkAverages();
1719
- this._sizeByMessage = {};
1720
- this._lastReceivedMessages = new CircularBuffer(100);
1721
- this._lastSentMessages = new CircularBuffer(100);
1722
- this._connectionsCount = 0;
1723
- }
1724
2111
  tick(timeMs) {
1725
2112
  this._advanceTimeWindow(timeMs - this._lastTick);
1726
2113
  this._lastTick = timeMs;
@@ -1960,8 +2347,9 @@ var EchoDataMonitor = class {
1960
2347
  messageCounts.failed++;
1961
2348
  }
1962
2349
  _getStatsForType(message) {
1963
- const messageSize = this._sizeByMessage[message.type] ??= createSlidingWindow();
1964
- const messageCounts = this._activeCounters.byType[message.type] ??= createMessageCounter();
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());
1965
2353
  return {
1966
2354
  messageCounts,
1967
2355
  messageSize
@@ -1970,21 +2358,48 @@ var EchoDataMonitor = class {
1970
2358
  _computeMessageHistogram(groupKey) {
1971
2359
  const result = {};
1972
2360
  for (const receivedMessage of this._lastReceivedMessages) {
1973
- const counters = result[receivedMessage[groupKey]] ??= {
2361
+ var _result, _receivedMessage_groupKey;
2362
+ const counters = (_result = result)[_receivedMessage_groupKey = receivedMessage[groupKey]] ?? (_result[_receivedMessage_groupKey] = {
1974
2363
  received: 0,
1975
2364
  sent: 0
1976
- };
2365
+ });
1977
2366
  counters.received++;
1978
2367
  }
1979
2368
  for (const receivedMessage of this._lastSentMessages) {
1980
- const counters = result[receivedMessage[groupKey]] ??= {
2369
+ var _result1, _receivedMessage_groupKey1;
2370
+ const counters = (_result1 = result)[_receivedMessage_groupKey1 = receivedMessage[groupKey]] ?? (_result1[_receivedMessage_groupKey1] = {
1981
2371
  received: 0,
1982
2372
  sent: 0
1983
- };
2373
+ });
1984
2374
  counters.sent++;
1985
2375
  }
1986
2376
  return result;
1987
2377
  }
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
+ }
1988
2403
  };
1989
2404
  EchoDataMonitor = _ts_decorate4([
1990
2405
  trace3.resource()
@@ -2056,20 +2471,37 @@ var getByteCount = (message) => {
2056
2471
  return message.type.length + message.senderId.length + message.targetId.length + (message.data?.byteLength ?? 0) + (message.documentId?.length ?? 0);
2057
2472
  };
2058
2473
 
2059
- // packages/core/echo/echo-pipeline/src/db-host/documents-synchronizer.ts
2060
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/documents-synchronizer.ts";
2474
+ // src/db-host/documents-synchronizer.ts
2475
+ import { next as A2 } from "@automerge/automerge";
2476
+ import { UpdateScheduler, sleep } from "@dxos/async";
2477
+ import { LifecycleState as LifecycleState2, Resource as Resource5, cancelWithContext as cancelWithContext2 } from "@dxos/context";
2478
+ import { invariant as invariant6 } from "@dxos/invariant";
2479
+ 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
+ var __dxlog_file7 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/documents-synchronizer.ts";
2061
2494
  var MAX_UPDATE_FREQ = 10;
2495
+ var WRAP_AROUND_RETRY_LIMIT = 3;
2496
+ var WRAP_AROUND_RETRY_INITIAL_DELAY = 100;
2062
2497
  var DocumentsSynchronizer = class extends Resource5 {
2063
- constructor(_params) {
2064
- super(), this._params = _params, this._syncStates = /* @__PURE__ */ new Map(), this._pendingUpdates = /* @__PURE__ */ new Set(), this._sendUpdatesJob = void 0;
2065
- }
2066
- addDocuments(documentIds, retryCounter = 0) {
2067
- if (retryCounter > 3) {
2498
+ addDocuments(documentIds, retryCounter = 0, wrapAroundRetryDelay = WRAP_AROUND_RETRY_INITIAL_DELAY) {
2499
+ if (retryCounter > WRAP_AROUND_RETRY_LIMIT) {
2068
2500
  log6.warn("Failed to load document, retry limit reached", {
2069
2501
  documentIds
2070
2502
  }, {
2071
2503
  F: __dxlog_file7,
2072
- L: 52,
2504
+ L: 57,
2073
2505
  S: this,
2074
2506
  C: (f, a) => f(...a)
2075
2507
  });
@@ -2087,13 +2519,13 @@ var DocumentsSynchronizer = class extends Resource5 {
2087
2519
  error
2088
2520
  }, {
2089
2521
  F: __dxlog_file7,
2090
- L: 66,
2522
+ L: 71,
2091
2523
  S: this,
2092
2524
  C: (f, a) => f(...a)
2093
2525
  });
2094
- this.addDocuments([
2526
+ void cancelWithContext2(this._ctx, sleep(wrapAroundRetryDelay)).then(() => this.addDocuments([
2095
2527
  documentId
2096
- ], retryCounter + 1);
2528
+ ], retryCounter + 1, wrapAroundRetryDelay * 2));
2097
2529
  });
2098
2530
  }
2099
2531
  }
@@ -2115,14 +2547,9 @@ var DocumentsSynchronizer = class extends Resource5 {
2115
2547
  }
2116
2548
  async update(updates) {
2117
2549
  for (const { documentId, mutation, isNew } of updates) {
2118
- if (isNew) {
2119
- const doc = await this._params.repo.find(documentId, FIND_PARAMS);
2120
- doc.update((doc2) => A2.loadIncremental(doc2, mutation));
2121
- this._startSync(doc);
2122
- } else {
2123
- this._writeMutation(documentId, mutation);
2124
- }
2550
+ this._writeMutation(documentId, mutation, isNew);
2125
2551
  }
2552
+ await this._params.repo.flush(updates.map(({ documentId }) => documentId));
2126
2553
  }
2127
2554
  _startSync(doc) {
2128
2555
  if (this._syncStates.has(doc.documentId)) {
@@ -2130,7 +2557,7 @@ var DocumentsSynchronizer = class extends Resource5 {
2130
2557
  documentId: doc.documentId
2131
2558
  }, {
2132
2559
  F: __dxlog_file7,
2133
- L: 105,
2560
+ L: 108,
2134
2561
  S: this,
2135
2562
  C: (f, a) => f(...a)
2136
2563
  });
@@ -2141,6 +2568,7 @@ var DocumentsSynchronizer = class extends Resource5 {
2141
2568
  };
2142
2569
  this._subscribeForChanges(syncState);
2143
2570
  this._syncStates.set(doc.documentId, syncState);
2571
+ return syncState;
2144
2572
  }
2145
2573
  _subscribeForChanges(syncState) {
2146
2574
  const handler = () => {
@@ -2173,7 +2601,7 @@ var DocumentsSynchronizer = class extends Resource5 {
2173
2601
  const syncState = this._syncStates.get(documentId);
2174
2602
  invariant6(syncState, "Sync state for document not found", {
2175
2603
  F: __dxlog_file7,
2176
- L: 146,
2604
+ L: 150,
2177
2605
  S: this,
2178
2606
  A: [
2179
2607
  "syncState",
@@ -2192,41 +2620,64 @@ var DocumentsSynchronizer = class extends Resource5 {
2192
2620
  syncState.lastSentHead = A2.getHeads(doc);
2193
2621
  return mutation;
2194
2622
  }
2195
- _writeMutation(documentId, mutation) {
2196
- const syncState = this._syncStates.get(documentId);
2197
- invariant6(syncState, "Sync state for document not found", {
2198
- F: __dxlog_file7,
2199
- L: 162,
2200
- S: this,
2201
- A: [
2202
- "syncState",
2203
- "'Sync state for document not found'"
2204
- ]
2205
- });
2206
- syncState.handle.update((doc) => {
2207
- const headsBefore = A2.getHeads(doc);
2208
- const newDoc = A2.loadIncremental(doc, mutation);
2623
+ _writeMutation(documentId, mutation, isNew) {
2624
+ if (this._lifecycleState === LifecycleState2.CLOSED) {
2625
+ return;
2626
+ }
2627
+ if (isNew) {
2628
+ const newHandle = this._params.repo.import(mutation, {
2629
+ docId: documentId
2630
+ });
2631
+ const syncState = this._startSync(newHandle);
2632
+ syncState.lastSentHead = A2.getHeads(newHandle.doc());
2633
+ } else {
2634
+ const syncState = this._syncStates.get(documentId);
2635
+ invariant6(syncState, "Sync state for document not found", {
2636
+ F: __dxlog_file7,
2637
+ L: 174,
2638
+ S: this,
2639
+ A: [
2640
+ "syncState",
2641
+ "'Sync state for document not found'"
2642
+ ]
2643
+ });
2644
+ const headsBefore = A2.getHeads(syncState.handle.doc());
2645
+ this._params.repo.import(mutation, {
2646
+ docId: documentId
2647
+ });
2209
2648
  if (A2.equals(headsBefore, syncState.lastSentHead)) {
2210
- syncState.lastSentHead = A2.getHeads(newDoc);
2649
+ syncState.lastSentHead = A2.getHeads(syncState.handle.doc());
2211
2650
  }
2212
- return newDoc;
2213
- });
2651
+ }
2652
+ }
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;
2214
2662
  }
2215
2663
  };
2216
2664
 
2217
- // packages/core/echo/echo-pipeline/src/db-host/data-service.ts
2218
- var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/data-service.ts";
2219
- var DataServiceImpl = class {
2220
- constructor(params) {
2221
- /**
2222
- * Map of subscriptions.
2223
- * subscriptionId -> DocumentsSynchronizer
2224
- */
2225
- this._subscriptions = /* @__PURE__ */ new Map();
2226
- this._automergeHost = params.automergeHost;
2227
- this._spaceStateManager = params.spaceStateManager;
2228
- this._updateIndexes = params.updateIndexes;
2665
+ // 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;
2229
2676
  }
2677
+ return obj;
2678
+ }
2679
+ var __dxlog_file8 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/data-service.ts";
2680
+ var DataServiceImpl = class {
2230
2681
  subscribe(request) {
2231
2682
  return new Stream(({ next, ready }) => {
2232
2683
  const synchronizer = new DocumentsSynchronizer({
@@ -2238,7 +2689,7 @@ var DataServiceImpl = class {
2238
2689
  ready();
2239
2690
  }).catch((err) => log7.catch(err, void 0, {
2240
2691
  F: __dxlog_file8,
2241
- L: 71,
2692
+ L: 72,
2242
2693
  S: this,
2243
2694
  C: (f, a) => f(...a)
2244
2695
  }));
@@ -2249,7 +2700,7 @@ var DataServiceImpl = class {
2249
2700
  const synchronizer = this._subscriptions.get(request.subscriptionId);
2250
2701
  invariant7(synchronizer, "Subscription not found", {
2251
2702
  F: __dxlog_file8,
2252
- L: 78,
2703
+ L: 79,
2253
2704
  S: this,
2254
2705
  A: [
2255
2706
  "synchronizer",
@@ -2270,7 +2721,7 @@ var DataServiceImpl = class {
2270
2721
  const synchronizer = this._subscriptions.get(request.subscriptionId);
2271
2722
  invariant7(synchronizer, "Subscription not found", {
2272
2723
  F: __dxlog_file8,
2273
- L: 93,
2724
+ L: 94,
2274
2725
  S: this,
2275
2726
  A: [
2276
2727
  "synchronizer",
@@ -2315,7 +2766,7 @@ var DataServiceImpl = class {
2315
2766
  const spaceId = request.spaceId;
2316
2767
  invariant7(SpaceId2.isValid(spaceId), void 0, {
2317
2768
  F: __dxlog_file8,
2318
- L: 133,
2769
+ L: 134,
2319
2770
  S: this,
2320
2771
  A: [
2321
2772
  "SpaceId.isValid(spaceId)",
@@ -2336,14 +2787,7 @@ var DataServiceImpl = class {
2336
2787
  peers: []
2337
2788
  };
2338
2789
  next({
2339
- peers: state.peers.map((peer) => ({
2340
- peerId: peer.peerId,
2341
- missingOnRemote: peer.missingOnRemote,
2342
- missingOnLocal: peer.missingOnLocal,
2343
- differentDocuments: peer.differentDocuments,
2344
- localDocumentCount: peer.localDocumentCount,
2345
- remoteDocumentCount: peer.remoteDocumentCount
2346
- }))
2790
+ peers: state.peers
2347
2791
  });
2348
2792
  });
2349
2793
  this._automergeHost.collectionStateUpdated.on(ctx, (e) => {
@@ -2354,25 +2798,34 @@ var DataServiceImpl = class {
2354
2798
  scheduler.trigger();
2355
2799
  });
2356
2800
  }
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
+ }
2357
2810
  };
2358
2811
 
2359
- // packages/core/echo/echo-pipeline/src/db-host/echo-host.ts
2812
+ // src/db-host/echo-host.ts
2360
2813
  import { LifecycleState as LifecycleState5, Resource as Resource9 } from "@dxos/context";
2361
2814
  import { todo } from "@dxos/debug";
2362
- import { createIdFromSpaceKey as createIdFromSpaceKey2, SpaceDocVersion as SpaceDocVersion3 } from "@dxos/echo-protocol";
2815
+ import { SpaceDocVersion as SpaceDocVersion3, createIdFromSpaceKey as createIdFromSpaceKey2 } from "@dxos/echo-protocol";
2363
2816
  import { IndexMetadataStore, IndexStore, Indexer } from "@dxos/indexing";
2364
2817
  import { invariant as invariant13 } from "@dxos/invariant";
2365
2818
  import { IndexKind } from "@dxos/protocols/proto/dxos/echo/indexing";
2366
2819
  import { trace as trace5 } from "@dxos/tracing";
2367
2820
 
2368
- // packages/core/echo/echo-pipeline/src/db-host/documents-iterator.ts
2821
+ // src/db-host/documents-iterator.ts
2369
2822
  import * as A3 from "@automerge/automerge";
2370
2823
  import { Context as Context2 } from "@dxos/context";
2371
2824
  import { DatabaseDirectory as DatabaseDirectory2, SpaceDocVersion } from "@dxos/echo-protocol";
2372
2825
  import { invariant as invariant8 } from "@dxos/invariant";
2373
2826
  import { log as log8 } from "@dxos/log";
2374
2827
  import { ObjectPointerVersion, objectPointerCodec as objectPointerCodec2 } from "@dxos/protocols";
2375
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/documents-iterator.ts";
2828
+ var __dxlog_file9 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/documents-iterator.ts";
2376
2829
  var LOG_VIEW_OPERATION_THRESHOLD = 300;
2377
2830
  var createSelectedDocumentsIterator = (automergeHost) => (
2378
2831
  /**
@@ -2453,10 +2906,10 @@ var createSelectedDocumentsIterator = (automergeHost) => (
2453
2906
  }
2454
2907
  );
2455
2908
 
2456
- // packages/core/echo/echo-pipeline/src/db-host/query-service.ts
2909
+ // src/db-host/query-service.ts
2457
2910
  import { getHeads as getHeads3 } from "@automerge/automerge";
2458
2911
  import { Schema } from "effect";
2459
- import { DeferredTask, scheduleMicroTask, synchronized as synchronized2 } from "@dxos/async";
2912
+ import { DeferredTask as DeferredTask2, scheduleMicroTask, synchronized as synchronized2 } from "@dxos/async";
2460
2913
  import { Stream as Stream2 } from "@dxos/codec-protobuf/stream";
2461
2914
  import { Context as Context4, Resource as Resource7 } from "@dxos/context";
2462
2915
  import { raise } from "@dxos/debug";
@@ -2465,10 +2918,10 @@ import { log as log10 } from "@dxos/log";
2465
2918
  import { objectPointerCodec as objectPointerCodec4 } from "@dxos/protocols";
2466
2919
  import { trace as trace4 } from "@dxos/tracing";
2467
2920
 
2468
- // packages/core/echo/echo-pipeline/src/query/query-executor.ts
2469
- import { Match } from "effect";
2921
+ // src/query/query-executor.ts
2922
+ import { Match, Predicate } from "effect";
2470
2923
  import { Context as Context3, ContextDisposedError, LifecycleState as LifecycleState3, Resource as Resource6 } from "@dxos/context";
2471
- import { DatabaseDirectory as DatabaseDirectory3, isEncodedReference, ObjectStructure } from "@dxos/echo-protocol";
2924
+ import { DatabaseDirectory as DatabaseDirectory3, ObjectStructure, isEncodedReference } from "@dxos/echo-protocol";
2472
2925
  import { EscapedPropPath } from "@dxos/indexing";
2473
2926
  import { invariant as invariant10 } from "@dxos/invariant";
2474
2927
  import { DXN, PublicKey as PublicKey3 } from "@dxos/keys";
@@ -2476,15 +2929,18 @@ import { log as log9 } from "@dxos/log";
2476
2929
  import { objectPointerCodec as objectPointerCodec3 } from "@dxos/protocols";
2477
2930
  import { getDeep, isNonNullable as isNonNullable2 } from "@dxos/util";
2478
2931
 
2479
- // packages/core/echo/echo-pipeline/src/query/query-planner.ts
2932
+ // src/query/query-planner.ts
2933
+ import { Order } from "@dxos/echo";
2480
2934
  import { invariant as invariant9 } from "@dxos/invariant";
2481
2935
 
2482
- // packages/core/echo/echo-pipeline/src/query/errors.ts
2936
+ // src/query/errors.ts
2483
2937
  import { BaseError } from "@dxos/errors";
2484
2938
  var QueryError = class extends BaseError.extend("QUERY_ERROR") {
2485
2939
  };
2940
+ var InvalidQueryError = class extends QueryError.extend("INVALID_QUERY") {
2941
+ };
2486
2942
 
2487
- // packages/core/echo/echo-pipeline/src/query/plan.ts
2943
+ // src/query/plan.ts
2488
2944
  (function(QueryPlan2) {
2489
2945
  QueryPlan2.Plan = Object.freeze({
2490
2946
  make: (steps) => ({
@@ -2505,18 +2961,25 @@ var QueryError = class extends BaseError.extend("QUERY_ERROR") {
2505
2961
  })(QueryPlan || (QueryPlan = {}));
2506
2962
  var QueryPlan;
2507
2963
 
2508
- // packages/core/echo/echo-pipeline/src/query/query-planner.ts
2509
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-planner.ts";
2964
+ // src/query/query-planner.ts
2965
+ function _define_property11(obj, key, value) {
2966
+ if (key in obj) {
2967
+ Object.defineProperty(obj, key, {
2968
+ value,
2969
+ enumerable: true,
2970
+ configurable: true,
2971
+ writable: true
2972
+ });
2973
+ } else {
2974
+ obj[key] = value;
2975
+ }
2976
+ return obj;
2977
+ }
2978
+ var __dxlog_file10 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-planner.ts";
2510
2979
  var DEFAULT_OPTIONS = {
2511
2980
  defaultTextSearchKind: "full-text"
2512
2981
  };
2513
2982
  var QueryPlanner = class {
2514
- constructor(options) {
2515
- this._options = {
2516
- ...DEFAULT_OPTIONS,
2517
- ...options
2518
- };
2519
- }
2520
2983
  createPlan(query) {
2521
2984
  let plan = this._generate(query, {
2522
2985
  ...DEFAULT_CONTEXT,
@@ -2524,6 +2987,7 @@ var QueryPlanner = class {
2524
2987
  });
2525
2988
  plan = this._optimizeEmptyFilters(plan);
2526
2989
  plan = this._optimizeSoloUnions(plan);
2990
+ plan = this._ensureOrderStep(plan);
2527
2991
  return plan;
2528
2992
  }
2529
2993
  _generate(query, context) {
@@ -2546,8 +3010,11 @@ var QueryPlanner = class {
2546
3010
  return this._generateUnionClause(query, context);
2547
3011
  case "set-difference":
2548
3012
  return this._generateSetDifferenceClause(query, context);
3013
+ case "order":
3014
+ return this._generateOrderClause(query, context);
2549
3015
  default:
2550
- throw new QueryError(`Unsupported query type: ${query.type}`, {
3016
+ throw new QueryError({
3017
+ message: `Unsupported query type: ${query.type}`,
2551
3018
  context: {
2552
3019
  query: context.originalQuery
2553
3020
  }
@@ -2583,7 +3050,8 @@ var QueryPlanner = class {
2583
3050
  ]);
2584
3051
  }
2585
3052
  if (context.selectionInverted) {
2586
- throw new QueryError("Query too complex", {
3053
+ throw new QueryError({
3054
+ message: "Query too complex",
2587
3055
  context: {
2588
3056
  query: context.originalQuery
2589
3057
  }
@@ -2664,19 +3132,22 @@ var QueryPlanner = class {
2664
3132
  ]);
2665
3133
  }
2666
3134
  case "compare":
2667
- throw new QueryError("Query too complex", {
3135
+ throw new QueryError({
3136
+ message: "Query too complex",
2668
3137
  context: {
2669
3138
  query: context.originalQuery
2670
3139
  }
2671
3140
  });
2672
3141
  case "in":
2673
- throw new QueryError("Query too complex", {
3142
+ throw new QueryError({
3143
+ message: "Query too complex",
2674
3144
  context: {
2675
3145
  query: context.originalQuery
2676
3146
  }
2677
3147
  });
2678
3148
  case "range":
2679
- throw new QueryError("Query too complex", {
3149
+ throw new QueryError({
3150
+ message: "Query too complex",
2680
3151
  context: {
2681
3152
  query: context.originalQuery
2682
3153
  }
@@ -2687,7 +3158,8 @@ var QueryPlanner = class {
2687
3158
  selectionInverted: !context.selectionInverted
2688
3159
  });
2689
3160
  case "and":
2690
- throw new QueryError("Query too complex", {
3161
+ throw new QueryError({
3162
+ message: "Query too complex",
2691
3163
  context: {
2692
3164
  query: context.originalQuery
2693
3165
  }
@@ -2697,7 +3169,7 @@ var QueryPlanner = class {
2697
3169
  const typenames = filter.filters.map((f) => {
2698
3170
  invariant9(f.type === "object" && f.typename !== null, void 0, {
2699
3171
  F: __dxlog_file10,
2700
- L: 191,
3172
+ L: 199,
2701
3173
  S: this,
2702
3174
  A: [
2703
3175
  "f.type === 'object' && f.typename !== null",
@@ -2719,14 +3191,16 @@ var QueryPlanner = class {
2719
3191
  ...this._generateDeletedHandlingSteps(context)
2720
3192
  ]);
2721
3193
  } else {
2722
- throw new QueryError("Query too complex", {
3194
+ throw new QueryError({
3195
+ message: "Query too complex",
2723
3196
  context: {
2724
3197
  query: context.originalQuery
2725
3198
  }
2726
3199
  });
2727
3200
  }
2728
3201
  default:
2729
- throw new QueryError(`Unsupported filter type: ${filter.type}`, {
3202
+ throw new QueryError({
3203
+ message: `Unsupported filter type: ${filter.type}`,
2730
3204
  context: {
2731
3205
  query: context.originalQuery
2732
3206
  }
@@ -2926,6 +3400,52 @@ var QueryPlanner = class {
2926
3400
  _optimizeSoloUnions(plan) {
2927
3401
  return plan;
2928
3402
  }
3403
+ _generateOrderClause(query, context) {
3404
+ return QueryPlan.Plan.make([
3405
+ ...this._generate(query.query, context).steps,
3406
+ {
3407
+ _tag: "OrderStep",
3408
+ order: query.order
3409
+ }
3410
+ ]);
3411
+ }
3412
+ // After complete plan is built, inspect it from the end:
3413
+ // - Walk backwards until hitting an object set changer.
3414
+ // - If an order step is found, skip.
3415
+ // - Otherwise append natural order to the end.
3416
+ _ensureOrderStep(plan) {
3417
+ const OBJECT_SET_CHANGERS = /* @__PURE__ */ new Set([
3418
+ "SelectStep",
3419
+ "TraverseStep",
3420
+ "UnionStep",
3421
+ "SetDifferenceStep"
3422
+ ]);
3423
+ for (let i = plan.steps.length - 1; i >= 0; i--) {
3424
+ const step = plan.steps[i];
3425
+ if (step._tag === "OrderStep") {
3426
+ return plan;
3427
+ }
3428
+ if (OBJECT_SET_CHANGERS.has(step._tag)) {
3429
+ break;
3430
+ }
3431
+ }
3432
+ return QueryPlan.Plan.make([
3433
+ ...plan.steps,
3434
+ {
3435
+ _tag: "OrderStep",
3436
+ order: [
3437
+ Order.natural.ast
3438
+ ]
3439
+ }
3440
+ ]);
3441
+ }
3442
+ constructor(options) {
3443
+ _define_property11(this, "_options", void 0);
3444
+ this._options = {
3445
+ ...DEFAULT_OPTIONS,
3446
+ ...options
3447
+ };
3448
+ }
2929
3449
  };
2930
3450
  var DEFAULT_CONTEXT = {
2931
3451
  originalQuery: null,
@@ -2950,8 +3470,22 @@ var isTrivialTypenameFilter = (filter) => {
2950
3470
  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);
2951
3471
  };
2952
3472
 
2953
- // packages/core/echo/echo-pipeline/src/query/query-executor.ts
2954
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-executor.ts";
3473
+ // src/query/query-executor.ts
3474
+ function _define_property12(obj, key, value) {
3475
+ if (key in obj) {
3476
+ Object.defineProperty(obj, key, {
3477
+ value,
3478
+ enumerable: true,
3479
+ configurable: true,
3480
+ writable: true
3481
+ });
3482
+ } else {
3483
+ obj[key] = value;
3484
+ }
3485
+ return obj;
3486
+ }
3487
+ var __dxlog_file11 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-executor.ts";
3488
+ var isNullable = Predicate.isNullable;
2955
3489
  var ExecutionTrace = Object.freeze({
2956
3490
  makeEmpty: () => ({
2957
3491
  name: "Empty",
@@ -2978,19 +3512,6 @@ var ExecutionTrace = Object.freeze({
2978
3512
  });
2979
3513
  var TRACE_QUERY_EXECUTION = false;
2980
3514
  var QueryExecutor = class extends Resource6 {
2981
- constructor(options) {
2982
- super();
2983
- this._trace = ExecutionTrace.makeEmpty();
2984
- this._lastResultSet = [];
2985
- this._indexer = options.indexer;
2986
- this._automergeHost = options.automergeHost;
2987
- this._spaceStateManager = options.spaceStateManager;
2988
- this._id = options.queryId;
2989
- this._query = options.query;
2990
- this._reactivity = options.reactivity;
2991
- const queryPlanner = new QueryPlanner();
2992
- this._plan = queryPlanner.createPlan(this._query);
2993
- }
2994
3515
  get query() {
2995
3516
  return this._query;
2996
3517
  }
@@ -3016,7 +3537,7 @@ var QueryExecutor = class extends Resource6 {
3016
3537
  async execQuery() {
3017
3538
  invariant10(this._lifecycleState === LifecycleState3.OPEN, void 0, {
3018
3539
  F: __dxlog_file11,
3019
- L: 173,
3540
+ L: 176,
3020
3541
  S: this,
3021
3542
  A: [
3022
3543
  "this._lifecycleState === LifecycleState.OPEN",
@@ -3089,6 +3610,9 @@ var QueryExecutor = class extends Resource6 {
3089
3610
  case "TraverseStep":
3090
3611
  ({ workingSet: newWorkingSet, trace: trace6 } = await this._execTraverseStep(step, workingSet));
3091
3612
  break;
3613
+ case "OrderStep":
3614
+ ({ workingSet: newWorkingSet, trace: trace6 } = await this._execOrderStep(step, workingSet));
3615
+ break;
3092
3616
  default:
3093
3617
  throw new Error(`Unknown step type: ${step._tag}`);
3094
3618
  }
@@ -3212,17 +3736,6 @@ var QueryExecutor = class extends Resource6 {
3212
3736
  };
3213
3737
  }
3214
3738
  async _execFilterDeletedStep(step, workingSet) {
3215
- if (workingSet.length === 6) {
3216
- log9.info("FilterDeletedStep", {
3217
- step,
3218
- workingSet
3219
- }, {
3220
- F: __dxlog_file11,
3221
- L: 386,
3222
- S: this,
3223
- C: (f, a) => f(...a)
3224
- });
3225
- }
3226
3739
  const expected = step.mode === "only-deleted";
3227
3740
  const result = workingSet.filter((item) => ObjectStructure.isDeleted(item.doc) === expected);
3228
3741
  return {
@@ -3260,11 +3773,11 @@ var QueryExecutor = class extends Resource6 {
3260
3773
  spaceId: item.spaceId
3261
3774
  } : null;
3262
3775
  } catch {
3263
- log9.warn("Invalid reference", {
3776
+ log9.warn("invalid reference", {
3264
3777
  ref: ref2["/"]
3265
3778
  }, {
3266
3779
  F: __dxlog_file11,
3267
- L: 431,
3780
+ L: 432,
3268
3781
  S: this,
3269
3782
  C: (f, a) => f(...a)
3270
3783
  });
@@ -3318,11 +3831,11 @@ var QueryExecutor = class extends Resource6 {
3318
3831
  spaceId: item.spaceId
3319
3832
  };
3320
3833
  } catch {
3321
- log9.warn("Invalid reference", {
3834
+ log9.warn("invalid reference", {
3322
3835
  ref: ref["/"]
3323
3836
  }, {
3324
3837
  F: __dxlog_file11,
3325
- L: 494,
3838
+ L: 495,
3326
3839
  S: this,
3327
3840
  C: (f, a) => f(...a)
3328
3841
  });
@@ -3411,6 +3924,74 @@ var QueryExecutor = class extends Resource6 {
3411
3924
  trace: trace6
3412
3925
  };
3413
3926
  }
3927
+ async _execOrderStep(step, workingSet) {
3928
+ const compareItems = (a, b) => step.order.reduce((comparison, order) => {
3929
+ if (comparison !== 0) {
3930
+ return comparison;
3931
+ }
3932
+ return this._compareByOrder(a, b, order);
3933
+ }, 0);
3934
+ const sortedWorkingSet = [
3935
+ ...workingSet
3936
+ ].sort(compareItems);
3937
+ return {
3938
+ workingSet: sortedWorkingSet,
3939
+ trace: {
3940
+ ...ExecutionTrace.makeEmpty(),
3941
+ name: "Order",
3942
+ details: JSON.stringify(step.order),
3943
+ objectCount: sortedWorkingSet.length
3944
+ }
3945
+ };
3946
+ }
3947
+ _compareByOrder(a, b, order) {
3948
+ return Match.type().pipe(Match.withReturnType(), Match.when({
3949
+ kind: "natural"
3950
+ }, () => a.objectId.localeCompare(b.objectId)), Match.when({
3951
+ kind: "property"
3952
+ }, ({ property, direction }) => {
3953
+ const comparison = this._compareByProperty(a, b, property);
3954
+ return direction === "desc" ? -comparison : comparison;
3955
+ }), Match.exhaustive)(order);
3956
+ }
3957
+ _compareByProperty(a, b, property) {
3958
+ const aValue = a.doc.data[property];
3959
+ const bValue = b.doc.data[property];
3960
+ return Match.type().pipe(
3961
+ Match.withReturnType(),
3962
+ Match.when({
3963
+ a: isNullable,
3964
+ b: isNullable
3965
+ }, () => 0),
3966
+ Match.when({
3967
+ a: isNullable
3968
+ }, () => 1),
3969
+ Match.when({
3970
+ b: isNullable
3971
+ }, () => -1),
3972
+ Match.when({
3973
+ a: Match.string,
3974
+ b: Match.string
3975
+ }, ({ a: a2, b: b2 }) => a2.localeCompare(b2)),
3976
+ Match.when({
3977
+ a: Match.number,
3978
+ b: Match.number
3979
+ }, ({ a: a2, b: b2 }) => a2 - b2),
3980
+ Match.when({
3981
+ a: Match.boolean,
3982
+ b: Match.boolean
3983
+ }, ({ a: a2, b: b2 }) => a2 === b2 ? 0 : a2 ? 1 : -1),
3984
+ Match.when({
3985
+ a: Match.defined,
3986
+ b: Match.defined
3987
+ }, ({ a: a2, b: b2 }) => String(a2).localeCompare(String(b2))),
3988
+ // TODO(wittjosiah): Why does Match.exhaustive fail here?
3989
+ Match.orElse(() => 0)
3990
+ )({
3991
+ a: aValue,
3992
+ b: bValue
3993
+ });
3994
+ }
3414
3995
  async _loadDocumentsAfterIndexQuery(indexHits) {
3415
3996
  return Promise.all(indexHits.map(async (hit) => {
3416
3997
  return this._loadFromIndexHit(hit);
@@ -3420,7 +4001,7 @@ var QueryExecutor = class extends Resource6 {
3420
4001
  const { objectId, documentId, spaceKey: spaceKeyInIndex } = objectPointerCodec3.decode(hit.id);
3421
4002
  const handle = await this._automergeHost.loadDoc(Context3.default(void 0, {
3422
4003
  F: __dxlog_file11,
3423
- L: 604
4004
+ L: 659
3424
4005
  }), documentId);
3425
4006
  const doc = handle.doc();
3426
4007
  if (!doc) {
@@ -3448,7 +4029,7 @@ var QueryExecutor = class extends Resource6 {
3448
4029
  dxn
3449
4030
  }, {
3450
4031
  F: __dxlog_file11,
3451
- L: 631,
4032
+ L: 686,
3452
4033
  S: this,
3453
4034
  C: (f, a) => f(...a)
3454
4035
  });
@@ -3461,7 +4042,7 @@ var QueryExecutor = class extends Resource6 {
3461
4042
  spaceId
3462
4043
  }, {
3463
4044
  F: __dxlog_file11,
3464
- L: 639,
4045
+ L: 694,
3465
4046
  S: this,
3466
4047
  C: (f, a) => f(...a)
3467
4048
  });
@@ -3473,7 +4054,7 @@ var QueryExecutor = class extends Resource6 {
3473
4054
  spaceId
3474
4055
  }, {
3475
4056
  F: __dxlog_file11,
3476
- L: 644,
4057
+ L: 699,
3477
4058
  S: this,
3478
4059
  C: (f, a) => f(...a)
3479
4060
  });
@@ -3494,7 +4075,7 @@ var QueryExecutor = class extends Resource6 {
3494
4075
  }
3495
4076
  const handle = await this._automergeHost.loadDoc(Context3.default(void 0, {
3496
4077
  F: __dxlog_file11,
3497
- L: 663
4078
+ L: 718
3498
4079
  }), link);
3499
4080
  const doc = handle.doc();
3500
4081
  if (!doc) {
@@ -3511,37 +4092,48 @@ var QueryExecutor = class extends Resource6 {
3511
4092
  doc: object
3512
4093
  };
3513
4094
  }
4095
+ constructor(options) {
4096
+ super(), _define_property12(this, "_indexer", void 0), _define_property12(this, "_automergeHost", void 0), _define_property12(this, "_spaceStateManager", void 0), /**
4097
+ * Id of this query.
4098
+ */
4099
+ _define_property12(this, "_id", void 0), _define_property12(this, "_query", void 0), // TODO(dmaretskyi): Might be used in the future.
4100
+ _define_property12(this, "_reactivity", void 0), _define_property12(this, "_plan", void 0), _define_property12(this, "_trace", ExecutionTrace.makeEmpty()), _define_property12(this, "_lastResultSet", []);
4101
+ this._indexer = options.indexer;
4102
+ this._automergeHost = options.automergeHost;
4103
+ this._spaceStateManager = options.spaceStateManager;
4104
+ this._id = options.queryId;
4105
+ this._query = options.query;
4106
+ this._reactivity = options.reactivity;
4107
+ const queryPlanner = new QueryPlanner();
4108
+ this._plan = queryPlanner.createPlan(this._query);
4109
+ }
3514
4110
  };
3515
4111
 
3516
- // packages/core/echo/echo-pipeline/src/db-host/query-service.ts
4112
+ // src/db-host/query-service.ts
4113
+ function _define_property13(obj, key, value) {
4114
+ if (key in obj) {
4115
+ Object.defineProperty(obj, key, {
4116
+ value,
4117
+ enumerable: true,
4118
+ configurable: true,
4119
+ writable: true
4120
+ });
4121
+ } else {
4122
+ obj[key] = value;
4123
+ }
4124
+ return obj;
4125
+ }
3517
4126
  function _ts_decorate5(decorators, target, key, desc) {
3518
4127
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3519
4128
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3520
4129
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3521
4130
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3522
4131
  }
3523
- var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/query-service.ts";
4132
+ var __dxlog_file12 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/query-service.ts";
3524
4133
  var QueryServiceImpl = class extends Resource7 {
3525
- // TODO(burdon): OK for options, but not params. Pass separately and type readonly here.
3526
- constructor(_params) {
3527
- super(), this._params = _params, this._queries = /* @__PURE__ */ new Set();
3528
- trace4.diagnostic({
3529
- id: "active-queries",
3530
- name: "Active Queries",
3531
- fetch: () => {
3532
- return Array.from(this._queries).map((query) => {
3533
- return {
3534
- query: JSON.stringify(query.executor.query),
3535
- plan: JSON.stringify(query.executor.plan),
3536
- trace: JSON.stringify(query.executor.trace)
3537
- };
3538
- });
3539
- }
3540
- });
3541
- }
3542
4134
  async _open() {
3543
4135
  this._params.indexer.updated.on(this._ctx, () => this.invalidateQueries());
3544
- this._updateQueries = new DeferredTask(this._ctx, this._executeQueries.bind(this));
4136
+ this._updateQueries = new DeferredTask2(this._ctx, this._executeQueries.bind(this));
3545
4137
  }
3546
4138
  async _close() {
3547
4139
  await this._updateQueries.join();
@@ -3552,6 +4144,18 @@ var QueryServiceImpl = class extends Resource7 {
3552
4144
  }
3553
4145
  execQuery(request) {
3554
4146
  return new Stream2(({ next, close, ctx }) => {
4147
+ if (this._params.indexer.config?.enabled !== true) {
4148
+ log10.error("indexer is disabled", {
4149
+ config: this._params.indexer.config
4150
+ }, {
4151
+ F: __dxlog_file12,
4152
+ L: 101,
4153
+ S: this,
4154
+ C: (f, a) => f(...a)
4155
+ });
4156
+ close();
4157
+ return;
4158
+ }
3555
4159
  const queryEntry = this._createQuery(ctx, request, next, close, close);
3556
4160
  scheduleMicroTask(ctx, async () => {
3557
4161
  await queryEntry.executor.open();
@@ -3567,7 +4171,7 @@ var QueryServiceImpl = class extends Resource7 {
3567
4171
  async reindex() {
3568
4172
  log10("Reindexing all documents...", void 0, {
3569
4173
  F: __dxlog_file12,
3570
- L: 113,
4174
+ L: 120,
3571
4175
  S: this,
3572
4176
  C: (f, a) => f(...a)
3573
4177
  });
@@ -3582,7 +4186,7 @@ var QueryServiceImpl = class extends Resource7 {
3582
4186
  count: ids.size
3583
4187
  }, {
3584
4188
  F: __dxlog_file12,
3585
- L: 121,
4189
+ L: 128,
3586
4190
  S: this,
3587
4191
  C: (f, a) => f(...a)
3588
4192
  });
@@ -3592,7 +4196,7 @@ var QueryServiceImpl = class extends Resource7 {
3592
4196
  count: ids.size
3593
4197
  }, {
3594
4198
  F: __dxlog_file12,
3595
- L: 125,
4199
+ L: 132,
3596
4200
  S: this,
3597
4201
  C: (f, a) => f(...a)
3598
4202
  });
@@ -3658,7 +4262,7 @@ var QueryServiceImpl = class extends Resource7 {
3658
4262
  } catch (err) {
3659
4263
  log10.catch(err, void 0, {
3660
4264
  F: __dxlog_file12,
3661
- L: 196,
4265
+ L: 203,
3662
4266
  S: this,
3663
4267
  C: (f, a) => f(...a)
3664
4268
  });
@@ -3669,11 +4273,28 @@ var QueryServiceImpl = class extends Resource7 {
3669
4273
  duration: performance.now() - begin
3670
4274
  }, {
3671
4275
  F: __dxlog_file12,
3672
- L: 200,
4276
+ L: 207,
3673
4277
  S: this,
3674
4278
  C: (f, a) => f(...a)
3675
4279
  });
3676
4280
  }
4281
+ // TODO(burdon): OK for options, but not params. Pass separately and type readonly here.
4282
+ constructor(_params) {
4283
+ 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();
4284
+ trace4.diagnostic({
4285
+ id: "active-queries",
4286
+ name: "Active Queries",
4287
+ fetch: () => {
4288
+ return Array.from(this._queries).map((query) => {
4289
+ return {
4290
+ query: JSON.stringify(query.executor.query),
4291
+ plan: JSON.stringify(query.executor.plan),
4292
+ trace: JSON.stringify(query.executor.trace)
4293
+ };
4294
+ });
4295
+ }
4296
+ });
4297
+ }
3677
4298
  };
3678
4299
  _ts_decorate5([
3679
4300
  synchronized2
@@ -3720,7 +4341,7 @@ var createDocumentsIterator = (automergeHost) => (
3720
4341
  }
3721
4342
  const linkHandle = await automergeHost.loadDoc(Context4.default(void 0, {
3722
4343
  F: __dxlog_file12,
3723
- L: 240
4344
+ L: 247
3724
4345
  }), urlString);
3725
4346
  for await (const result of getObjectsFromHandle(linkHandle)) {
3726
4347
  yield result;
@@ -3741,22 +4362,22 @@ var createDocumentsIterator = (automergeHost) => (
3741
4362
  }
3742
4363
  );
3743
4364
 
3744
- // packages/core/echo/echo-pipeline/src/db-host/space-state-manager.ts
4365
+ // src/db-host/space-state-manager.ts
3745
4366
  import { interpretAsDocumentId as interpretAsDocumentId3 } from "@automerge/automerge-repo";
3746
4367
  import isEqual from "lodash.isequal";
3747
4368
  import { Event as Event3, UpdateScheduler as UpdateScheduler3 } from "@dxos/async";
3748
- import { Resource as Resource8, Context as Context5, LifecycleState as LifecycleState4 } from "@dxos/context";
4369
+ import { Context as Context5, LifecycleState as LifecycleState4, Resource as Resource8 } from "@dxos/context";
3749
4370
  import { invariant as invariant12 } from "@dxos/invariant";
3750
4371
 
3751
- // packages/core/echo/echo-pipeline/src/db-host/database-root.ts
4372
+ // src/db-host/database-root.ts
3752
4373
  import { interpretAsDocumentId as interpretAsDocumentId2 } from "@automerge/automerge-repo";
3753
4374
  import { DatabaseDirectory as DatabaseDirectory5, SpaceDocVersion as SpaceDocVersion2 } from "@dxos/echo-protocol";
3754
4375
  import { invariant as invariant11 } from "@dxos/invariant";
3755
4376
 
3756
- // packages/core/echo/echo-pipeline/src/db-host/automerge-metrics.ts
4377
+ // src/db-host/automerge-metrics.ts
3757
4378
  import * as A4 from "@automerge/automerge";
3758
4379
  import { log as log11 } from "@dxos/log";
3759
- var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/automerge-metrics.ts";
4380
+ var __dxlog_file13 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/automerge-metrics.ts";
3760
4381
  var measureDocMetrics = (doc) => {
3761
4382
  const snapshot = A4.save(doc);
3762
4383
  const start = Date.now();
@@ -3783,8 +4404,21 @@ var measureDocMetrics = (doc) => {
3783
4404
  };
3784
4405
  };
3785
4406
 
3786
- // packages/core/echo/echo-pipeline/src/db-host/database-root.ts
3787
- var __dxlog_file14 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/database-root.ts";
4407
+ // src/db-host/database-root.ts
4408
+ function _define_property14(obj, key, value) {
4409
+ if (key in obj) {
4410
+ Object.defineProperty(obj, key, {
4411
+ value,
4412
+ enumerable: true,
4413
+ configurable: true,
4414
+ writable: true
4415
+ });
4416
+ } else {
4417
+ obj[key] = value;
4418
+ }
4419
+ return obj;
4420
+ }
4421
+ var __dxlog_file14 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/database-root.ts";
3788
4422
  var DatabaseRoot = class {
3789
4423
  static mapLinks(doc, mapping) {
3790
4424
  doc.change((d) => {
@@ -3799,9 +4433,6 @@ var DatabaseRoot = class {
3799
4433
  }
3800
4434
  });
3801
4435
  }
3802
- constructor(_rootHandle) {
3803
- this._rootHandle = _rootHandle;
3804
- }
3805
4436
  get documentId() {
3806
4437
  return this._rootHandle.documentId;
3807
4438
  }
@@ -3865,19 +4496,28 @@ var DatabaseRoot = class {
3865
4496
  }
3866
4497
  return measureDocMetrics(doc);
3867
4498
  }
4499
+ constructor(_rootHandle) {
4500
+ _define_property14(this, "_rootHandle", void 0);
4501
+ this._rootHandle = _rootHandle;
4502
+ }
3868
4503
  };
3869
4504
 
3870
- // packages/core/echo/echo-pipeline/src/db-host/space-state-manager.ts
3871
- var __dxlog_file15 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/space-state-manager.ts";
3872
- var SpaceStateManager = class extends Resource8 {
3873
- constructor() {
3874
- super(...arguments);
3875
- this._roots = /* @__PURE__ */ new Map();
3876
- this._rootBySpace = /* @__PURE__ */ new Map();
3877
- this._perRootContext = /* @__PURE__ */ new Map();
3878
- this._lastSpaceDocumentList = /* @__PURE__ */ new Map();
3879
- this.spaceDocumentListUpdated = new Event3();
4505
+ // src/db-host/space-state-manager.ts
4506
+ function _define_property15(obj, key, value) {
4507
+ if (key in obj) {
4508
+ Object.defineProperty(obj, key, {
4509
+ value,
4510
+ enumerable: true,
4511
+ configurable: true,
4512
+ writable: true
4513
+ });
4514
+ } else {
4515
+ obj[key] = value;
3880
4516
  }
4517
+ return obj;
4518
+ }
4519
+ var __dxlog_file15 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/space-state-manager.ts";
4520
+ var SpaceStateManager = class extends Resource8 {
3881
4521
  async _close(ctx) {
3882
4522
  for (const [_, rootCtx] of this._perRootContext) {
3883
4523
  await rootCtx.dispose();
@@ -3950,9 +4590,16 @@ var SpaceStateManager = class extends Resource8 {
3950
4590
  documentListCheckScheduler.trigger();
3951
4591
  return root;
3952
4592
  }
4593
+ constructor(...args) {
4594
+ 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());
4595
+ }
3953
4596
  };
3954
4597
  var SpaceDocumentListUpdatedEvent = class {
3955
4598
  constructor(spaceId, spaceRootId, previousRootId, documentIds) {
4599
+ _define_property15(this, "spaceId", void 0);
4600
+ _define_property15(this, "spaceRootId", void 0);
4601
+ _define_property15(this, "previousRootId", void 0);
4602
+ _define_property15(this, "documentIds", void 0);
3956
4603
  this.spaceId = spaceId;
3957
4604
  this.spaceRootId = spaceRootId;
3958
4605
  this.previousRootId = previousRootId;
@@ -3960,113 +4607,27 @@ var SpaceDocumentListUpdatedEvent = class {
3960
4607
  }
3961
4608
  };
3962
4609
 
3963
- // packages/core/echo/echo-pipeline/src/db-host/echo-host.ts
3964
- var __dxlog_file16 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/echo-host.ts";
4610
+ // src/db-host/echo-host.ts
4611
+ function _define_property16(obj, key, value) {
4612
+ if (key in obj) {
4613
+ Object.defineProperty(obj, key, {
4614
+ value,
4615
+ enumerable: true,
4616
+ configurable: true,
4617
+ writable: true
4618
+ });
4619
+ } else {
4620
+ obj[key] = value;
4621
+ }
4622
+ return obj;
4623
+ }
4624
+ var __dxlog_file16 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/echo-host.ts";
3965
4625
  var DEFAULT_INDEXING_CONFIG = {
3966
4626
  // TODO(dmaretskyi): Disabled by default since embedding generation is expensive.
3967
4627
  fullText: false,
3968
4628
  vector: false
3969
4629
  };
3970
4630
  var EchoHost = class extends Resource9 {
3971
- constructor({ kv, indexing = {}, peerIdProvider, getSpaceKeyByRootDocumentId }) {
3972
- super();
3973
- this._spaceStateManager = new SpaceStateManager();
3974
- const indexingConfig = {
3975
- ...DEFAULT_INDEXING_CONFIG,
3976
- ...indexing
3977
- };
3978
- this._indexMetadataStore = new IndexMetadataStore({
3979
- db: kv.sublevel("index-metadata")
3980
- });
3981
- this._echoDataMonitor = new EchoDataMonitor();
3982
- this._automergeHost = new AutomergeHost({
3983
- db: kv,
3984
- dataMonitor: this._echoDataMonitor,
3985
- indexMetadataStore: this._indexMetadataStore,
3986
- peerIdProvider,
3987
- getSpaceKeyByRootDocumentId
3988
- });
3989
- this._indexer = new Indexer({
3990
- db: kv,
3991
- indexStore: new IndexStore({
3992
- db: kv.sublevel("index-storage")
3993
- }),
3994
- metadataStore: this._indexMetadataStore,
3995
- loadDocuments: createSelectedDocumentsIterator(this._automergeHost),
3996
- indexCooldownTime: false ? 0 : void 0
3997
- });
3998
- void this._indexer.setConfig({
3999
- enabled: true,
4000
- indexes: [
4001
- //
4002
- {
4003
- kind: IndexKind.Kind.SCHEMA_MATCH
4004
- },
4005
- {
4006
- kind: IndexKind.Kind.GRAPH
4007
- },
4008
- ...indexingConfig.fullText ? [
4009
- {
4010
- kind: IndexKind.Kind.FULL_TEXT
4011
- }
4012
- ] : [],
4013
- ...indexingConfig.vector ? [
4014
- {
4015
- kind: IndexKind.Kind.VECTOR
4016
- }
4017
- ] : []
4018
- ]
4019
- });
4020
- this._queryService = new QueryServiceImpl({
4021
- automergeHost: this._automergeHost,
4022
- indexer: this._indexer,
4023
- spaceStateManager: this._spaceStateManager
4024
- });
4025
- this._dataService = new DataServiceImpl({
4026
- automergeHost: this._automergeHost,
4027
- spaceStateManager: this._spaceStateManager,
4028
- updateIndexes: async () => {
4029
- await this._indexer.updateIndexes();
4030
- }
4031
- });
4032
- trace5.diagnostic({
4033
- id: "echo-stats",
4034
- name: "Echo Stats",
4035
- fetch: async () => {
4036
- return {
4037
- dataStats: this._echoDataMonitor.computeStats(),
4038
- loadedDocsCount: this._automergeHost.loadedDocsCount
4039
- };
4040
- }
4041
- });
4042
- trace5.diagnostic({
4043
- id: "database-roots",
4044
- name: "Database Roots",
4045
- fetch: async () => {
4046
- return Array.from(this._spaceStateManager.roots.values()).map((root) => ({
4047
- url: root.url,
4048
- isLoaded: root.isLoaded,
4049
- spaceKey: root.getSpaceKey(),
4050
- inlineObjects: root.getInlineObjectCount(),
4051
- linkedObjects: root.getLinkedObjectCount()
4052
- }));
4053
- }
4054
- });
4055
- trace5.diagnostic({
4056
- id: "database-root-metrics",
4057
- name: "Database Roots (with metrics)",
4058
- fetch: async () => {
4059
- return Array.from(this._spaceStateManager.roots.values()).map((root) => ({
4060
- url: root.url,
4061
- isLoaded: root.isLoaded,
4062
- spaceKey: root.getSpaceKey(),
4063
- inlineObjects: root.getInlineObjectCount(),
4064
- linkedObjects: root.getLinkedObjectCount(),
4065
- ...root.measureMetrics() ?? {}
4066
- }));
4067
- }
4068
- });
4069
- }
4070
4631
  get queryService() {
4071
4632
  return this._queryService;
4072
4633
  }
@@ -4091,7 +4652,6 @@ var EchoHost = class extends Resource9 {
4091
4652
  if (e.previousRootId) {
4092
4653
  void this._automergeHost.clearLocalCollectionState(deriveCollectionIdFromSpaceId(e.spaceId, e.previousRootId));
4093
4654
  }
4094
- void this._automergeHost.updateLocalCollectionState(deriveCollectionIdFromSpaceId(e.spaceId), e.documentIds);
4095
4655
  void this._automergeHost.updateLocalCollectionState(deriveCollectionIdFromSpaceId(e.spaceId, e.spaceRootId), e.documentIds);
4096
4656
  });
4097
4657
  this._automergeHost.documentsSaved.on(this._ctx, () => {
@@ -4137,7 +4697,7 @@ var EchoHost = class extends Resource9 {
4137
4697
  async createSpaceRoot(spaceKey) {
4138
4698
  invariant13(this._lifecycleState === LifecycleState5.OPEN, void 0, {
4139
4699
  F: __dxlog_file16,
4140
- L: 255,
4700
+ L: 254,
4141
4701
  S: this,
4142
4702
  A: [
4143
4703
  "this._lifecycleState === LifecycleState.OPEN",
@@ -4165,7 +4725,7 @@ var EchoHost = class extends Resource9 {
4165
4725
  async openSpaceRoot(spaceId, automergeUrl) {
4166
4726
  invariant13(this._lifecycleState === LifecycleState5.OPEN, void 0, {
4167
4727
  F: __dxlog_file16,
4168
- L: 274,
4728
+ L: 273,
4169
4729
  S: this,
4170
4730
  A: [
4171
4731
  "this._lifecycleState === LifecycleState.OPEN",
@@ -4192,29 +4752,137 @@ var EchoHost = class extends Resource9 {
4192
4752
  async removeReplicator(replicator) {
4193
4753
  await this._automergeHost.removeReplicator(replicator);
4194
4754
  }
4755
+ constructor({ kv, indexing = {}, peerIdProvider, getSpaceKeyByRootDocumentId }) {
4756
+ 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);
4757
+ const indexingConfig = {
4758
+ ...DEFAULT_INDEXING_CONFIG,
4759
+ ...indexing
4760
+ };
4761
+ this._indexMetadataStore = new IndexMetadataStore({
4762
+ db: kv.sublevel("index-metadata")
4763
+ });
4764
+ this._echoDataMonitor = new EchoDataMonitor();
4765
+ this._automergeHost = new AutomergeHost({
4766
+ db: kv,
4767
+ dataMonitor: this._echoDataMonitor,
4768
+ indexMetadataStore: this._indexMetadataStore,
4769
+ peerIdProvider,
4770
+ getSpaceKeyByRootDocumentId
4771
+ });
4772
+ this._indexer = new Indexer({
4773
+ db: kv,
4774
+ indexStore: new IndexStore({
4775
+ db: kv.sublevel("index-storage")
4776
+ }),
4777
+ metadataStore: this._indexMetadataStore,
4778
+ loadDocuments: createSelectedDocumentsIterator(this._automergeHost),
4779
+ indexCooldownTime: false ? 0 : void 0
4780
+ });
4781
+ void this._indexer.setConfig({
4782
+ enabled: true,
4783
+ indexes: [
4784
+ //
4785
+ {
4786
+ kind: IndexKind.Kind.SCHEMA_MATCH
4787
+ },
4788
+ {
4789
+ kind: IndexKind.Kind.GRAPH
4790
+ },
4791
+ ...indexingConfig.fullText ? [
4792
+ {
4793
+ kind: IndexKind.Kind.FULL_TEXT
4794
+ }
4795
+ ] : [],
4796
+ ...indexingConfig.vector ? [
4797
+ {
4798
+ kind: IndexKind.Kind.VECTOR
4799
+ }
4800
+ ] : []
4801
+ ]
4802
+ });
4803
+ this._queryService = new QueryServiceImpl({
4804
+ automergeHost: this._automergeHost,
4805
+ indexer: this._indexer,
4806
+ spaceStateManager: this._spaceStateManager
4807
+ });
4808
+ this._dataService = new DataServiceImpl({
4809
+ automergeHost: this._automergeHost,
4810
+ spaceStateManager: this._spaceStateManager,
4811
+ updateIndexes: async () => {
4812
+ await this._indexer.updateIndexes();
4813
+ }
4814
+ });
4815
+ trace5.diagnostic({
4816
+ id: "echo-stats",
4817
+ name: "Echo Stats",
4818
+ fetch: async () => {
4819
+ return {
4820
+ dataStats: this._echoDataMonitor.computeStats(),
4821
+ loadedDocsCount: this._automergeHost.loadedDocsCount
4822
+ };
4823
+ }
4824
+ });
4825
+ trace5.diagnostic({
4826
+ id: "database-roots",
4827
+ name: "Database Roots",
4828
+ fetch: async () => {
4829
+ return Array.from(this._spaceStateManager.roots.values()).map((root) => ({
4830
+ url: root.url,
4831
+ isLoaded: root.isLoaded,
4832
+ spaceKey: root.getSpaceKey(),
4833
+ inlineObjects: root.getInlineObjectCount(),
4834
+ linkedObjects: root.getLinkedObjectCount()
4835
+ }));
4836
+ }
4837
+ });
4838
+ trace5.diagnostic({
4839
+ id: "database-root-metrics",
4840
+ name: "Database Roots (with metrics)",
4841
+ fetch: async () => {
4842
+ return Array.from(this._spaceStateManager.roots.values()).map((root) => ({
4843
+ url: root.url,
4844
+ isLoaded: root.isLoaded,
4845
+ spaceKey: root.getSpaceKey(),
4846
+ inlineObjects: root.getInlineObjectCount(),
4847
+ linkedObjects: root.getLinkedObjectCount(),
4848
+ ...root.measureMetrics() ?? {}
4849
+ }));
4850
+ }
4851
+ });
4852
+ }
4195
4853
  };
4196
4854
 
4197
- // packages/core/echo/echo-pipeline/src/edge/echo-edge-replicator.ts
4855
+ // src/edge/echo-edge-replicator.ts
4198
4856
  import { cbor as cbor2 } from "@automerge/automerge-repo";
4199
- import { Mutex, scheduleTask as scheduleTask2, scheduleMicroTask as scheduleMicroTask2 } from "@dxos/async";
4857
+ import { Mutex, scheduleMicroTask as scheduleMicroTask2, scheduleTask as scheduleTask2 } from "@dxos/async";
4200
4858
  import { Context as Context6, Resource as Resource11 } from "@dxos/context";
4201
4859
  import { randomUUID } from "@dxos/crypto";
4202
4860
  import { invariant as invariant14 } from "@dxos/invariant";
4203
4861
  import { log as log13 } from "@dxos/log";
4204
- import { EdgeService } from "@dxos/protocols";
4862
+ import { DocumentCodec, EdgeService } from "@dxos/protocols";
4205
4863
  import { buf } from "@dxos/protocols/buf";
4206
4864
  import { MessageSchema as RouterMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
4207
4865
  import { bufferToArray as bufferToArray2 } from "@dxos/util";
4208
4866
 
4209
- // packages/core/echo/echo-pipeline/src/edge/inflight-request-limiter.ts
4867
+ // src/edge/inflight-request-limiter.ts
4210
4868
  import { Trigger as Trigger2 } from "@dxos/async";
4211
4869
  import { Resource as Resource10 } from "@dxos/context";
4212
4870
  import { log as log12 } from "@dxos/log";
4213
- var __dxlog_file17 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/edge/inflight-request-limiter.ts";
4214
- var InflightRequestLimiter = class extends Resource10 {
4215
- constructor(_config) {
4216
- super(), this._config = _config, this._inflightRequestBalance = 0, this._requestBarrier = new Trigger2();
4871
+ function _define_property17(obj, key, value) {
4872
+ if (key in obj) {
4873
+ Object.defineProperty(obj, key, {
4874
+ value,
4875
+ enumerable: true,
4876
+ configurable: true,
4877
+ writable: true
4878
+ });
4879
+ } else {
4880
+ obj[key] = value;
4217
4881
  }
4882
+ return obj;
4883
+ }
4884
+ var __dxlog_file17 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/edge/inflight-request-limiter.ts";
4885
+ var InflightRequestLimiter = class extends Resource10 {
4218
4886
  async _open() {
4219
4887
  this._inflightRequestBalance = 0;
4220
4888
  this._requestBarrier.reset();
@@ -4257,9 +4925,30 @@ var InflightRequestLimiter = class extends Resource10 {
4257
4925
  clearInterval(this._resetBalanceTimeout);
4258
4926
  }
4259
4927
  }
4928
+ constructor(_config) {
4929
+ super(), _define_property17(this, "_config", void 0), /**
4930
+ * Decrement when we receive a sync message, increment when we send one.
4931
+ * Can't exceed _config.maxInflightRequests.
4932
+ * Resets after timeout to avoid replicator being stuck.
4933
+ */
4934
+ _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();
4935
+ }
4260
4936
  };
4261
4937
 
4262
- // packages/core/echo/echo-pipeline/src/edge/echo-edge-replicator.ts
4938
+ // src/edge/echo-edge-replicator.ts
4939
+ function _define_property18(obj, key, value) {
4940
+ if (key in obj) {
4941
+ Object.defineProperty(obj, key, {
4942
+ value,
4943
+ enumerable: true,
4944
+ configurable: true,
4945
+ writable: true
4946
+ });
4947
+ } else {
4948
+ obj[key] = value;
4949
+ }
4950
+ return obj;
4951
+ }
4263
4952
  function _ts_add_disposable_resource(env, value, async) {
4264
4953
  if (value !== null && value !== void 0) {
4265
4954
  if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
@@ -4325,35 +5014,25 @@ function _ts_dispose_resources(env) {
4325
5014
  return next();
4326
5015
  })(env);
4327
5016
  }
4328
- var __dxlog_file18 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/edge/echo-edge-replicator.ts";
5017
+ var __dxlog_file18 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/edge/echo-edge-replicator.ts";
4329
5018
  var INITIAL_RESTART_DELAY = 500;
4330
5019
  var RESTART_DELAY_JITTER = 250;
4331
5020
  var MAX_RESTART_DELAY = 5e3;
4332
5021
  var EchoEdgeReplicator = class {
4333
- constructor({ edgeConnection, disableSharePolicy }) {
4334
- this._mutex = new Mutex();
4335
- this._ctx = void 0;
4336
- this._context = null;
4337
- this._connectedSpaces = /* @__PURE__ */ new Set();
4338
- this._connections = /* @__PURE__ */ new Map();
4339
- this._sharePolicyEnabled = true;
4340
- this._edgeConnection = edgeConnection;
4341
- this._sharePolicyEnabled = !disableSharePolicy;
4342
- }
4343
5022
  async connect(context) {
4344
5023
  log13("connecting...", {
4345
5024
  peerId: context.peerId,
4346
5025
  connectedSpaces: this._connectedSpaces.size
4347
5026
  }, {
4348
5027
  F: __dxlog_file18,
4349
- L: 61,
5028
+ L: 72,
4350
5029
  S: this,
4351
5030
  C: (f, a) => f(...a)
4352
5031
  });
4353
5032
  this._context = context;
4354
5033
  this._ctx = Context6.default(void 0, {
4355
5034
  F: __dxlog_file18,
4356
- L: 63
5035
+ L: 74
4357
5036
  });
4358
5037
  this._ctx.onDispose(this._edgeConnection.onReconnected(() => {
4359
5038
  this._ctx && scheduleMicroTask2(this._ctx, () => this._handleReconnect());
@@ -4452,7 +5131,7 @@ var EchoEdgeReplicator = class {
4452
5131
  async _openConnection(spaceId, reconnects = 0) {
4453
5132
  invariant14(this._context, void 0, {
4454
5133
  F: __dxlog_file18,
4455
- L: 124,
5134
+ L: 135,
4456
5135
  S: this,
4457
5136
  A: [
4458
5137
  "this._context",
@@ -4461,7 +5140,7 @@ var EchoEdgeReplicator = class {
4461
5140
  });
4462
5141
  invariant14(!this._connections.has(spaceId), void 0, {
4463
5142
  F: __dxlog_file18,
4464
- L: 125,
5143
+ L: 136,
4465
5144
  S: this,
4466
5145
  A: [
4467
5146
  "!this._connections.has(spaceId)",
@@ -4470,14 +5149,31 @@ var EchoEdgeReplicator = class {
4470
5149
  });
4471
5150
  let restartScheduled = false;
4472
5151
  const connection = new EdgeReplicatorConnection({
5152
+ edgeHttpClient: this._edgeHttpClient,
4473
5153
  edgeConnection: this._edgeConnection,
4474
5154
  spaceId,
4475
5155
  context: this._context,
4476
5156
  sharedPolicyEnabled: this._sharePolicyEnabled,
4477
5157
  onRemoteConnected: async () => {
5158
+ log13.trace("dxos.echo.edge.replicator.onRemoteConnected", {
5159
+ spaceId
5160
+ }, {
5161
+ F: __dxlog_file18,
5162
+ L: 147,
5163
+ S: this,
5164
+ C: (f, a) => f(...a)
5165
+ });
4478
5166
  this._context?.onConnectionOpen(connection);
4479
5167
  },
4480
5168
  onRemoteDisconnected: async () => {
5169
+ log13.trace("dxos.echo.edge.replicator.onRemoteDisconnected", {
5170
+ spaceId
5171
+ }, {
5172
+ F: __dxlog_file18,
5173
+ L: 151,
5174
+ S: this,
5175
+ C: (f, a) => f(...a)
5176
+ });
4481
5177
  this._context?.onConnectionClosed(connection);
4482
5178
  },
4483
5179
  onRestartRequested: async () => {
@@ -4491,7 +5187,7 @@ var EchoEdgeReplicator = class {
4491
5187
  restartDelay
4492
5188
  }, {
4493
5189
  F: __dxlog_file18,
4494
- L: 148,
5190
+ L: 162,
4495
5191
  S: this,
4496
5192
  C: (f, a) => f(...a)
4497
5193
  });
@@ -4513,6 +5209,16 @@ var EchoEdgeReplicator = class {
4513
5209
  if (ctx?.disposed) {
4514
5210
  return;
4515
5211
  }
5212
+ log13.trace("dxos.echo.edge.replicator.restart", {
5213
+ spaceId,
5214
+ reconnects,
5215
+ restartDelay
5216
+ }, {
5217
+ F: __dxlog_file18,
5218
+ L: 179,
5219
+ S: this,
5220
+ C: (f, a) => f(...a)
5221
+ });
4516
5222
  await this._openConnection(spaceId, reconnects + 1);
4517
5223
  } catch (e) {
4518
5224
  env.error = e;
@@ -4526,42 +5232,27 @@ var EchoEdgeReplicator = class {
4526
5232
  this._connections.set(spaceId, connection);
4527
5233
  await connection.open();
4528
5234
  }
5235
+ constructor({ edgeConnection, edgeHttpClient, disableSharePolicy }) {
5236
+ _define_property18(this, "_edgeConnection", void 0);
5237
+ _define_property18(this, "_edgeHttpClient", void 0);
5238
+ _define_property18(this, "_mutex", new Mutex());
5239
+ _define_property18(this, "_ctx", void 0);
5240
+ _define_property18(this, "_context", null);
5241
+ _define_property18(this, "_connectedSpaces", /* @__PURE__ */ new Set());
5242
+ _define_property18(this, "_connections", /* @__PURE__ */ new Map());
5243
+ _define_property18(this, "_sharePolicyEnabled", true);
5244
+ this._edgeConnection = edgeConnection;
5245
+ this._edgeHttpClient = edgeHttpClient;
5246
+ this._sharePolicyEnabled = !disableSharePolicy;
5247
+ }
4529
5248
  };
4530
5249
  var MAX_INFLIGHT_REQUESTS = 5;
4531
5250
  var MAX_RATE_LIMIT_WAIT_TIME_MS = 3e3;
4532
5251
  var EdgeReplicatorConnection = class extends Resource11 {
4533
- constructor({ edgeConnection, spaceId, context, sharedPolicyEnabled, onRemoteConnected, onRemoteDisconnected, onRestartRequested }) {
4534
- super();
4535
- this._remotePeerId = null;
4536
- this._requestLimiter = new InflightRequestLimiter({
4537
- maxInflightRequests: MAX_INFLIGHT_REQUESTS,
4538
- resetBalanceTimeoutMs: MAX_RATE_LIMIT_WAIT_TIME_MS
4539
- });
4540
- this._edgeConnection = edgeConnection;
4541
- this._spaceId = spaceId;
4542
- this._context = context;
4543
- this._remotePeerId = `${EdgeService.AUTOMERGE_REPLICATOR}:${spaceId}-${randomUUID()}`;
4544
- this._targetServiceId = `${EdgeService.AUTOMERGE_REPLICATOR}:${spaceId}`;
4545
- this._sharedPolicyEnabled = sharedPolicyEnabled;
4546
- this._onRemoteConnected = onRemoteConnected;
4547
- this._onRemoteDisconnected = onRemoteDisconnected;
4548
- this._onRestartRequested = onRestartRequested;
4549
- this.readable = new ReadableStream({
4550
- start: (controller) => {
4551
- this._readableStreamController = controller;
4552
- }
4553
- });
4554
- this.writable = new WritableStream({
4555
- write: async (message, controller) => {
4556
- await this._requestLimiter.rateLimit(message);
4557
- await this._sendMessage(message);
4558
- }
4559
- });
4560
- }
4561
5252
  async _open(ctx) {
4562
5253
  log13("opening...", void 0, {
4563
5254
  F: __dxlog_file18,
4564
- L: 251,
5255
+ L: 270,
4565
5256
  S: this,
4566
5257
  C: (f, a) => f(...a)
4567
5258
  });
@@ -4569,12 +5260,29 @@ var EdgeReplicatorConnection = class extends Resource11 {
4569
5260
  this._ctx.onDispose(this._edgeConnection.onMessage((msg) => {
4570
5261
  this._onMessage(msg);
4571
5262
  }));
5263
+ let firstReconnect = true;
5264
+ this._ctx.onDispose(
5265
+ // NOTE: This will fire immediately if the connection is already open.
5266
+ this._edgeConnection.onReconnected(async () => {
5267
+ if (firstReconnect) {
5268
+ log13.verbose("first reconnect skipped", void 0, {
5269
+ F: __dxlog_file18,
5270
+ L: 285,
5271
+ S: this,
5272
+ C: (f, a) => f(...a)
5273
+ });
5274
+ firstReconnect = false;
5275
+ return;
5276
+ }
5277
+ this._onRestartRequested();
5278
+ })
5279
+ );
4572
5280
  await this._onRemoteConnected();
4573
5281
  }
4574
5282
  async _close() {
4575
5283
  log13("closing...", void 0, {
4576
5284
  F: __dxlog_file18,
4577
- L: 266,
5285
+ L: 298,
4578
5286
  S: this,
4579
5287
  C: (f, a) => f(...a)
4580
5288
  });
@@ -4585,7 +5293,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
4585
5293
  get peerId() {
4586
5294
  invariant14(this._remotePeerId, "Not connected", {
4587
5295
  F: __dxlog_file18,
4588
- L: 275,
5296
+ L: 307,
4589
5297
  S: this,
4590
5298
  A: [
4591
5299
  "this._remotePeerId",
@@ -4610,7 +5318,7 @@ var EdgeReplicatorConnection = class extends Resource11 {
4610
5318
  remoteId: this._remotePeerId
4611
5319
  }, {
4612
5320
  F: __dxlog_file18,
4613
- L: 290,
5321
+ L: 322,
4614
5322
  S: this,
4615
5323
  C: (f, a) => f(...a)
4616
5324
  });
@@ -4636,13 +5344,36 @@ var EdgeReplicatorConnection = class extends Resource11 {
4636
5344
  remoteId: this._remotePeerId
4637
5345
  }, {
4638
5346
  F: __dxlog_file18,
4639
- L: 319,
5347
+ L: 351,
4640
5348
  S: this,
4641
5349
  C: (f, a) => f(...a)
4642
5350
  });
4643
5351
  payload.senderId = this._remotePeerId;
4644
5352
  this._processMessage(payload);
4645
5353
  }
5354
+ get bundleSyncEnabled() {
5355
+ return true;
5356
+ }
5357
+ async pushBundle(bundle) {
5358
+ const request = {
5359
+ bundle: bundle.map(({ documentId, data, heads }) => ({
5360
+ documentId,
5361
+ mutation: DocumentCodec.encode(data),
5362
+ heads
5363
+ }))
5364
+ };
5365
+ await this._edgeHttpClient.importBundle(this._spaceId, request);
5366
+ }
5367
+ async pullBundle(docHeads) {
5368
+ const request = {
5369
+ docHeads
5370
+ };
5371
+ const response = await this._edgeHttpClient.exportBundle(this._spaceId, request);
5372
+ return Object.fromEntries(response.bundle.map((doc) => [
5373
+ doc.documentId,
5374
+ DocumentCodec.decode(doc.mutation)
5375
+ ]));
5376
+ }
4646
5377
  _processMessage(message) {
4647
5378
  if (isForbiddenErrorMessage(message)) {
4648
5379
  this._onRestartRequested();
@@ -4659,27 +5390,65 @@ var EdgeReplicatorConnection = class extends Resource11 {
4659
5390
  remoteId: this._remotePeerId
4660
5391
  }, {
4661
5392
  F: __dxlog_file18,
4662
- L: 348,
5393
+ L: 401,
4663
5394
  S: this,
4664
5395
  C: (f, a) => f(...a)
4665
5396
  });
4666
5397
  const encoded = cbor2.encode(message);
4667
- await this._edgeConnection.send(buf.create(RouterMessageSchema, {
4668
- serviceId: this._targetServiceId,
4669
- source: {
4670
- identityKey: this._edgeConnection.identityKey,
4671
- peerKey: this._edgeConnection.peerKey
4672
- },
4673
- payload: {
4674
- value: bufferToArray2(encoded)
5398
+ try {
5399
+ await this._edgeConnection.send(buf.create(RouterMessageSchema, {
5400
+ serviceId: this._targetServiceId,
5401
+ source: {
5402
+ identityKey: this._edgeConnection.identityKey,
5403
+ peerKey: this._edgeConnection.peerKey
5404
+ },
5405
+ payload: {
5406
+ value: bufferToArray2(encoded)
5407
+ }
5408
+ }));
5409
+ } catch (err) {
5410
+ log13.error("failed to send message", {
5411
+ err
5412
+ }, {
5413
+ F: __dxlog_file18,
5414
+ L: 421,
5415
+ S: this,
5416
+ C: (f, a) => f(...a)
5417
+ });
5418
+ }
5419
+ }
5420
+ constructor({ edgeConnection, edgeHttpClient, spaceId, context, sharedPolicyEnabled, onRemoteConnected, onRemoteDisconnected, onRestartRequested }) {
5421
+ 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({
5422
+ maxInflightRequests: MAX_INFLIGHT_REQUESTS,
5423
+ resetBalanceTimeoutMs: MAX_RATE_LIMIT_WAIT_TIME_MS
5424
+ })), _define_property18(this, "_readableStreamController", void 0), _define_property18(this, "readable", void 0), _define_property18(this, "writable", void 0);
5425
+ this._edgeConnection = edgeConnection;
5426
+ this._edgeHttpClient = edgeHttpClient;
5427
+ this._spaceId = spaceId;
5428
+ this._context = context;
5429
+ this._remotePeerId = `${EdgeService.AUTOMERGE_REPLICATOR}:${spaceId}-${randomUUID()}`;
5430
+ this._targetServiceId = `${EdgeService.AUTOMERGE_REPLICATOR}:${spaceId}`;
5431
+ this._sharedPolicyEnabled = sharedPolicyEnabled;
5432
+ this._onRemoteConnected = onRemoteConnected;
5433
+ this._onRemoteDisconnected = onRemoteDisconnected;
5434
+ this._onRestartRequested = onRestartRequested;
5435
+ this.readable = new ReadableStream({
5436
+ start: (controller) => {
5437
+ this._readableStreamController = controller;
4675
5438
  }
4676
- }));
5439
+ });
5440
+ this.writable = new WritableStream({
5441
+ write: async (message, controller) => {
5442
+ await this._requestLimiter.rateLimit(message);
5443
+ await this._sendMessage(message);
5444
+ }
5445
+ });
4677
5446
  }
4678
5447
  };
4679
5448
  var isForbiddenErrorMessage = (message) => message.type === "error" && message.message === "Forbidden";
4680
5449
 
4681
- // packages/core/echo/echo-pipeline/src/util.ts
4682
- import { decodeReference, ObjectStructure as ObjectStructure2 } from "@dxos/echo-protocol";
5450
+ // src/util.ts
5451
+ import { ObjectStructure as ObjectStructure2, decodeReference } from "@dxos/echo-protocol";
4683
5452
  var findInlineObjectOfType = (spaceDoc, typename) => {
4684
5453
  for (const id in spaceDoc.objects ?? {}) {
4685
5454
  const obj = spaceDoc.objects[id];
@@ -4731,6 +5500,7 @@ export {
4731
5500
  diffCollectionState,
4732
5501
  encodingOptions,
4733
5502
  filterMatchObject,
5503
+ filterMatchObjectJSON,
4734
5504
  filterMatchValue,
4735
5505
  findInlineObjectOfType,
4736
5506
  getSpaceIdFromCollectionId,