@dxos/echo-pipeline 0.8.4-main.ae835ea → 0.8.4-main.bc674ce

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 (154) hide show
  1. package/dist/lib/browser/{chunk-WJJXJTNS.mjs → chunk-FJPXA75J.mjs} +7 -12
  2. package/dist/lib/browser/chunk-FJPXA75J.mjs.map +7 -0
  3. package/dist/lib/browser/{chunk-FR6GJ4S4.mjs → chunk-WIQUYO7H.mjs} +39 -29
  4. package/dist/lib/browser/chunk-WIQUYO7H.mjs.map +7 -0
  5. package/dist/lib/browser/filter/index.mjs +1 -2
  6. package/dist/lib/browser/index.mjs +1933 -620
  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 +28 -201
  10. package/dist/lib/browser/testing/index.mjs.map +4 -4
  11. package/dist/lib/node-esm/{chunk-JQCCVDLT.mjs → chunk-7PL6UK4B.mjs} +39 -29
  12. package/dist/lib/node-esm/chunk-7PL6UK4B.mjs.map +7 -0
  13. package/dist/lib/node-esm/{chunk-LEQ77KAT.mjs → chunk-S5KGVQFZ.mjs} +7 -12
  14. package/dist/lib/node-esm/chunk-S5KGVQFZ.mjs.map +7 -0
  15. package/dist/lib/node-esm/filter/index.mjs +1 -2
  16. package/dist/lib/node-esm/index.mjs +1933 -620
  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 +28 -201
  20. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  21. package/dist/types/src/automerge/automerge-host.d.ts +36 -9
  22. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  23. package/dist/types/src/automerge/automerge-repo.test.d.ts +1 -1
  24. package/dist/types/src/automerge/automerge-repo.test.d.ts.map +1 -1
  25. package/dist/types/src/automerge/collection-synchronizer.d.ts +3 -2
  26. package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
  27. package/dist/types/src/automerge/echo-network-adapter.d.ts +11 -6
  28. package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
  29. package/dist/types/src/automerge/echo-replicator.d.ts +9 -6
  30. package/dist/types/src/automerge/echo-replicator.d.ts.map +1 -1
  31. package/dist/types/src/automerge/heads-store.d.ts +9 -2
  32. package/dist/types/src/automerge/heads-store.d.ts.map +1 -1
  33. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +4 -4
  34. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -1
  35. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts +7 -7
  36. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
  37. package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
  38. package/dist/types/src/db-host/automerge-data-source.d.ts +34 -0
  39. package/dist/types/src/db-host/automerge-data-source.d.ts.map +1 -0
  40. package/dist/types/src/db-host/automerge-data-source.test.d.ts +2 -0
  41. package/dist/types/src/db-host/automerge-data-source.test.d.ts.map +1 -0
  42. package/dist/types/src/db-host/data-service.d.ts +4 -3
  43. package/dist/types/src/db-host/data-service.d.ts.map +1 -1
  44. package/dist/types/src/db-host/documents-iterator.d.ts.map +1 -1
  45. package/dist/types/src/db-host/documents-synchronizer.d.ts +6 -5
  46. package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
  47. package/dist/types/src/db-host/echo-host.d.ts +43 -11
  48. package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
  49. package/dist/types/src/db-host/index.d.ts +1 -0
  50. package/dist/types/src/db-host/index.d.ts.map +1 -1
  51. package/dist/types/src/db-host/local-queue-service.d.ts +15 -0
  52. package/dist/types/src/db-host/local-queue-service.d.ts.map +1 -0
  53. package/dist/types/src/db-host/query-service.d.ts +7 -2
  54. package/dist/types/src/db-host/query-service.d.ts.map +1 -1
  55. package/dist/types/src/db-host/queue-data-source.d.ts +28 -0
  56. package/dist/types/src/db-host/queue-data-source.d.ts.map +1 -0
  57. package/dist/types/src/db-host/queue-service.test.d.ts +2 -0
  58. package/dist/types/src/db-host/queue-service.test.d.ts.map +1 -0
  59. package/dist/types/src/db-host/space-state-manager.d.ts +1 -0
  60. package/dist/types/src/db-host/space-state-manager.d.ts.map +1 -1
  61. package/dist/types/src/db-host/stub.d.ts +10 -0
  62. package/dist/types/src/db-host/stub.d.ts.map +1 -0
  63. package/dist/types/src/edge/echo-edge-replicator.d.ts +2 -2
  64. package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
  65. package/dist/types/src/filter/filter-match.d.ts.map +1 -1
  66. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  67. package/dist/types/src/pipeline/pipeline.d.ts +2 -2
  68. package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
  69. package/dist/types/src/query/errors.d.ts +11 -15
  70. package/dist/types/src/query/errors.d.ts.map +1 -1
  71. package/dist/types/src/query/plan.d.ts +37 -3
  72. package/dist/types/src/query/plan.d.ts.map +1 -1
  73. package/dist/types/src/query/query-executor.d.ts +39 -3
  74. package/dist/types/src/query/query-executor.d.ts.map +1 -1
  75. package/dist/types/src/query/query-planner.d.ts +6 -0
  76. package/dist/types/src/query/query-planner.d.ts.map +1 -1
  77. package/dist/types/src/space/auth.d.ts +3 -3
  78. package/dist/types/src/space/auth.d.ts.map +1 -1
  79. package/dist/types/src/space/control-pipeline.d.ts +2 -2
  80. package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
  81. package/dist/types/src/space/space-manager.d.ts +6 -6
  82. package/dist/types/src/space/space-manager.d.ts.map +1 -1
  83. package/dist/types/src/space/space-protocol.d.ts +5 -5
  84. package/dist/types/src/space/space-protocol.d.ts.map +1 -1
  85. package/dist/types/src/space/space.d.ts +3 -3
  86. package/dist/types/src/space/space.d.ts.map +1 -1
  87. package/dist/types/src/testing/index.d.ts +0 -2
  88. package/dist/types/src/testing/index.d.ts.map +1 -1
  89. package/dist/types/src/testing/test-network-adapter.d.ts +1 -1
  90. package/dist/types/src/testing/test-network-adapter.d.ts.map +1 -1
  91. package/dist/types/src/testing/test-replicator.d.ts +6 -6
  92. package/dist/types/src/testing/test-replicator.d.ts.map +1 -1
  93. package/dist/types/src/util.d.ts.map +1 -1
  94. package/dist/types/tsconfig.tsbuildinfo +1 -1
  95. package/package.json +48 -38
  96. package/src/automerge/automerge-host.test.ts +37 -14
  97. package/src/automerge/automerge-host.ts +130 -36
  98. package/src/automerge/automerge-repo.test.ts +147 -30
  99. package/src/automerge/collection-synchronizer.test.ts +16 -10
  100. package/src/automerge/collection-synchronizer.ts +41 -11
  101. package/src/automerge/echo-network-adapter.ts +23 -11
  102. package/src/automerge/echo-replicator.ts +10 -6
  103. package/src/automerge/heads-store.ts +14 -2
  104. package/src/automerge/leveldb-storage-adapter.ts +4 -4
  105. package/src/automerge/mesh-echo-replicator-connection.ts +7 -7
  106. package/src/automerge/mesh-echo-replicator.ts +2 -2
  107. package/src/db-host/automerge-data-source.test.ts +294 -0
  108. package/src/db-host/automerge-data-source.ts +144 -0
  109. package/src/db-host/data-service.ts +10 -3
  110. package/src/db-host/documents-iterator.ts +3 -1
  111. package/src/db-host/documents-synchronizer.test.ts +77 -13
  112. package/src/db-host/documents-synchronizer.ts +51 -50
  113. package/src/db-host/echo-host.ts +191 -28
  114. package/src/db-host/index.ts +1 -0
  115. package/src/db-host/local-queue-service.ts +127 -0
  116. package/src/db-host/query-service.ts +17 -4
  117. package/src/db-host/queue-data-source.ts +132 -0
  118. package/src/db-host/queue-service.test.ts +141 -0
  119. package/src/db-host/space-state-manager.ts +4 -0
  120. package/src/db-host/stub.ts +28 -0
  121. package/src/edge/echo-edge-replicator.ts +12 -8
  122. package/src/filter/filter-match.test.ts +31 -25
  123. package/src/filter/filter-match.ts +8 -14
  124. package/src/metadata/metadata-store.ts +5 -2
  125. package/src/pipeline/pipeline.ts +2 -2
  126. package/src/query/errors.ts +2 -2
  127. package/src/query/plan.ts +48 -3
  128. package/src/query/query-executor.ts +612 -131
  129. package/src/query/query-planner.test.ts +509 -35
  130. package/src/query/query-planner.ts +187 -13
  131. package/src/space/admission-discovery-extension.ts +1 -1
  132. package/src/space/auth.ts +6 -6
  133. package/src/space/control-pipeline.ts +2 -2
  134. package/src/space/space-manager.ts +6 -6
  135. package/src/space/space-protocol.ts +11 -11
  136. package/src/space/space.ts +3 -3
  137. package/src/testing/index.ts +0 -2
  138. package/src/testing/test-network-adapter.ts +16 -3
  139. package/src/testing/test-replicator.ts +8 -7
  140. package/src/util.ts +7 -3
  141. package/dist/lib/browser/chunk-CGS2ULMK.mjs +0 -11
  142. package/dist/lib/browser/chunk-CGS2ULMK.mjs.map +0 -7
  143. package/dist/lib/browser/chunk-FR6GJ4S4.mjs.map +0 -7
  144. package/dist/lib/browser/chunk-WJJXJTNS.mjs.map +0 -7
  145. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  146. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
  147. package/dist/lib/node-esm/chunk-JQCCVDLT.mjs.map +0 -7
  148. package/dist/lib/node-esm/chunk-LEQ77KAT.mjs.map +0 -7
  149. package/dist/types/src/testing/test-data.d.ts +0 -18
  150. package/dist/types/src/testing/test-data.d.ts.map +0 -1
  151. package/dist/types/src/testing/test-schema.d.ts +0 -37
  152. package/dist/types/src/testing/test-schema.d.ts.map +0 -1
  153. package/src/testing/test-data.ts +0 -127
  154. package/src/testing/test-schema.ts +0 -53
@@ -3,7 +3,7 @@ import {
3
3
  filterMatchObject,
4
4
  filterMatchObjectJSON,
5
5
  filterMatchValue
6
- } from "./chunk-WJJXJTNS.mjs";
6
+ } from "./chunk-FJPXA75J.mjs";
7
7
  import {
8
8
  AuthExtension,
9
9
  AuthStatus,
@@ -26,28 +26,142 @@ import {
26
26
  mapTimeframeToFeedIndexes,
27
27
  startAfter,
28
28
  valueEncoding
29
- } from "./chunk-FR6GJ4S4.mjs";
30
- import "./chunk-CGS2ULMK.mjs";
29
+ } from "./chunk-WIQUYO7H.mjs";
30
+
31
+ // src/db-host/automerge-data-source.ts
32
+ import * as Effect from "effect/Effect";
33
+ import { Context } from "@dxos/context";
34
+ import { objectStructureToJson } from "@dxos/echo/internal";
35
+ import { DatabaseDirectory, SpaceDocVersion } from "@dxos/echo-protocol";
36
+ import { PublicKey } from "@dxos/keys";
37
+ import { log } from "@dxos/log";
38
+ var __dxlog_file = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/automerge-data-source.ts";
39
+ var HEADS_DELIMITER = "|";
40
+ var headsCodec = {
41
+ /**
42
+ * Serialize automerge heads to a cursor string.
43
+ * Heads are sorted to ensure consistent comparison.
44
+ */
45
+ encode: (heads) => [
46
+ ...heads
47
+ ].sort().join(HEADS_DELIMITER),
48
+ /**
49
+ * Deserialize a cursor string back to heads array.
50
+ */
51
+ decode: (cursor) => cursor ? cursor.split(HEADS_DELIMITER) : []
52
+ };
53
+ var hasChanged = (cursor, currentHeads) => {
54
+ if (!cursor) {
55
+ return true;
56
+ }
57
+ return cursor !== headsCodec.encode(currentHeads);
58
+ };
59
+ var AutomergeDataSource = class {
60
+ sourceName = "automerge";
61
+ #automergeHost;
62
+ constructor(automergeHost) {
63
+ this.#automergeHost = automergeHost;
64
+ }
65
+ getChangedObjects(cursors, opts) {
66
+ return Effect.gen(this, function* () {
67
+ const cursorMap = /* @__PURE__ */ new Map();
68
+ for (const cursor of cursors) {
69
+ if (cursor.resourceId) {
70
+ cursorMap.set(cursor.resourceId, String(cursor.cursor));
71
+ }
72
+ }
73
+ const changedDocuments = yield* Effect.promise(async () => {
74
+ const result = [];
75
+ const limit = opts?.limit ?? Infinity;
76
+ for await (const { documentId, heads } of this.#automergeHost.listDocumentHeads()) {
77
+ const existingCursor = cursorMap.get(documentId);
78
+ if (hasChanged(existingCursor, heads)) {
79
+ result.push({
80
+ documentId,
81
+ heads
82
+ });
83
+ if (result.length >= limit) {
84
+ break;
85
+ }
86
+ }
87
+ }
88
+ return result;
89
+ });
90
+ const objects = [];
91
+ const updatedCursors = [];
92
+ for (const { documentId, heads: docHeads } of changedDocuments) {
93
+ try {
94
+ const handle = yield* Effect.promise(() => this.#automergeHost.loadDoc(Context.default(void 0, {
95
+ F: __dxlog_file,
96
+ L: 97
97
+ }), documentId));
98
+ const doc = handle.doc();
99
+ if (!doc) {
100
+ continue;
101
+ }
102
+ if (doc.version !== SpaceDocVersion.CURRENT) {
103
+ continue;
104
+ }
105
+ const spaceKeyHex = DatabaseDirectory.getSpaceKey(doc);
106
+ if (!spaceKeyHex) {
107
+ continue;
108
+ }
109
+ const spaceKey = PublicKey.fromHex(spaceKeyHex);
110
+ const spaceId = yield* Effect.promise(() => createIdFromSpaceKey(spaceKey));
111
+ const docObjects = doc.objects ?? {};
112
+ for (const [objectId, structure] of Object.entries(docObjects)) {
113
+ objects.push({
114
+ spaceId,
115
+ documentId,
116
+ queueId: null,
117
+ recordId: null,
118
+ data: objectStructureToJson(objectId, structure)
119
+ });
120
+ }
121
+ updatedCursors.push({
122
+ spaceId,
123
+ resourceId: documentId,
124
+ cursor: headsCodec.encode(docHeads)
125
+ });
126
+ } catch (error) {
127
+ log.error("Error loading document for indexing", {
128
+ documentId,
129
+ error
130
+ }, {
131
+ F: __dxlog_file,
132
+ L: 137,
133
+ S: this,
134
+ C: (f, a) => f(...a)
135
+ });
136
+ }
137
+ }
138
+ return {
139
+ objects,
140
+ cursors: updatedCursors
141
+ };
142
+ });
143
+ }
144
+ };
31
145
 
32
146
  // src/db-host/data-service.ts
33
147
  import { UpdateScheduler as UpdateScheduler2 } from "@dxos/async";
34
148
  import { Stream } from "@dxos/codec-protobuf/stream";
35
149
  import { invariant as invariant7 } from "@dxos/invariant";
36
150
  import { SpaceId as SpaceId2 } from "@dxos/keys";
37
- import { log as log7 } from "@dxos/log";
151
+ import { log as log8 } from "@dxos/log";
38
152
 
39
153
  // src/automerge/automerge-host.ts
40
154
  import { getBackend, getHeads, equals as headsEquals, isAutomerge, save } from "@automerge/automerge";
41
155
  import { Repo, interpretAsDocumentId } from "@automerge/automerge-repo";
42
- import { DeferredTask, Event as Event2, asyncTimeout } from "@dxos/async";
43
- import { Context, Resource as Resource3, cancelWithContext } from "@dxos/context";
44
- import { DatabaseDirectory } from "@dxos/echo-protocol";
156
+ import { DeferredTask, Event as Event3, asyncTimeout } from "@dxos/async";
157
+ import { Context as Context2, Resource as Resource3, cancelWithContext } from "@dxos/context";
158
+ import { DatabaseDirectory as DatabaseDirectory2 } from "@dxos/echo-protocol";
45
159
  import { invariant as invariant2 } from "@dxos/invariant";
46
- import { PublicKey } from "@dxos/keys";
47
- import { log as log3 } from "@dxos/log";
160
+ import { PublicKey as PublicKey2 } from "@dxos/keys";
161
+ import { log as log4 } from "@dxos/log";
48
162
  import { objectPointerCodec } from "@dxos/protocols";
49
163
  import { trace as trace2 } from "@dxos/tracing";
50
- import { ComplexSet, bufferToArray, isNonNullable as isNonNullable2, range } from "@dxos/util";
164
+ import { ComplexSet, bufferToArray, defaultMap as defaultMap2, isNonNullable as isNonNullable2, range } from "@dxos/util";
51
165
 
52
166
  // src/automerge/collection-synchronizer.ts
53
167
  import { next as A } from "@automerge/automerge";
@@ -55,7 +169,7 @@ import * as Array2 from "effect/Array";
55
169
  import * as Record from "effect/Record";
56
170
  import { Event, asyncReturn, scheduleTask, scheduleTaskInterval } from "@dxos/async";
57
171
  import { Resource } from "@dxos/context";
58
- import { log } from "@dxos/log";
172
+ import { log as log2 } from "@dxos/log";
59
173
  import { trace } from "@dxos/tracing";
60
174
  import { defaultMap } from "@dxos/util";
61
175
  function _ts_decorate(decorators, target, key, desc) {
@@ -64,9 +178,9 @@ function _ts_decorate(decorators, target, key, desc) {
64
178
  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;
65
179
  return c > 3 && r && Object.defineProperty(target, key, r), r;
66
180
  }
67
- var __dxlog_file = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/collection-synchronizer.ts";
181
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/collection-synchronizer.ts";
68
182
  var MIN_QUERY_INTERVAL = 5e3;
69
- var POLL_INTERVAL = 3e4;
183
+ var POLL_INTERVAL = 1e4;
70
184
  var CollectionSynchronizer = class extends Resource {
71
185
  _sendCollectionState;
72
186
  _queryCollectionState;
@@ -104,16 +218,19 @@ var CollectionSynchronizer = class extends Resource {
104
218
  }
105
219
  setLocalCollectionState(collectionId, state) {
106
220
  this._activeCollections.add(collectionId);
107
- log("setLocalCollectionState", {
221
+ log2("setLocalCollectionState", {
108
222
  collectionId,
109
223
  state
110
224
  }, {
111
- F: __dxlog_file,
225
+ F: __dxlog_file2,
112
226
  L: 78,
113
227
  S: this,
114
228
  C: (f, a) => f(...a)
115
229
  });
116
230
  this._getOrCreatePerCollectionState(collectionId).localState = state;
231
+ for (const peerId of this._connectedPeers) {
232
+ this._diffCollectionState(collectionId, peerId);
233
+ }
117
234
  queueMicrotask(async () => {
118
235
  if (!this._ctx.disposed && this._activeCollections.has(collectionId)) {
119
236
  this._refreshInterestedPeers(collectionId);
@@ -124,11 +241,11 @@ var CollectionSynchronizer = class extends Resource {
124
241
  clearLocalCollectionState(collectionId) {
125
242
  this._activeCollections.delete(collectionId);
126
243
  this._perCollectionStates.delete(collectionId);
127
- log("clearLocalCollectionState", {
244
+ log2("clearLocalCollectionState", {
128
245
  collectionId
129
246
  }, {
130
- F: __dxlog_file,
131
- L: 92,
247
+ F: __dxlog_file2,
248
+ L: 96,
132
249
  S: this,
133
250
  C: (f, a) => f(...a)
134
251
  });
@@ -158,6 +275,14 @@ var CollectionSynchronizer = class extends Resource {
158
275
  * Callback when a connection to a peer is established.
159
276
  */
160
277
  onConnectionOpen(peerId) {
278
+ log2("onConnectionOpen", {
279
+ peerId
280
+ }, {
281
+ F: __dxlog_file2,
282
+ L: 126,
283
+ S: this,
284
+ C: (f, a) => f(...a)
285
+ });
161
286
  const spanId = getSpanName(peerId);
162
287
  trace.spanStart({
163
288
  id: spanId,
@@ -187,6 +312,14 @@ var CollectionSynchronizer = class extends Resource {
187
312
  * Callback when a connection to a peer is closed.
188
313
  */
189
314
  onConnectionClosed(peerId) {
315
+ log2("onConnectionClosed", {
316
+ peerId
317
+ }, {
318
+ F: __dxlog_file2,
319
+ L: 156,
320
+ S: this,
321
+ C: (f, a) => f(...a)
322
+ });
190
323
  this._connectedPeers.delete(peerId);
191
324
  for (const perCollectionState of this._perCollectionStates.values()) {
192
325
  perCollectionState.remoteStates.delete(peerId);
@@ -205,22 +338,40 @@ var CollectionSynchronizer = class extends Resource {
205
338
  * Callback when a peer sends the state of a collection.
206
339
  */
207
340
  onRemoteStateReceived(collectionId, peerId, state) {
208
- log("onRemoteStateReceived", {
341
+ log2("onRemoteStateReceived", {
209
342
  collectionId,
210
343
  peerId,
211
344
  state
212
345
  }, {
213
- F: __dxlog_file,
214
- L: 173,
346
+ F: __dxlog_file2,
347
+ L: 180,
215
348
  S: this,
216
349
  C: (f, a) => f(...a)
217
350
  });
218
351
  validateCollectionState(state);
219
352
  const perCollectionState = this._getOrCreatePerCollectionState(collectionId);
220
- const existingState = perCollectionState.remoteStates.get(peerId) ?? {
353
+ perCollectionState.remoteStates.set(peerId, state);
354
+ this._diffCollectionState(collectionId, peerId);
355
+ }
356
+ _diffCollectionState(collectionId, peerId) {
357
+ const perCollectionState = this._getOrCreatePerCollectionState(collectionId);
358
+ const remoteState = perCollectionState.remoteStates.get(peerId);
359
+ if (!remoteState) {
360
+ return;
361
+ }
362
+ log2("diffCollectionState", {
363
+ collectionId,
364
+ peerId
365
+ }, {
366
+ F: __dxlog_file2,
367
+ L: 194,
368
+ S: this,
369
+ C: (f, a) => f(...a)
370
+ });
371
+ const localState = perCollectionState.localState ?? {
221
372
  documents: {}
222
373
  };
223
- const diff = diffCollectionState(existingState, state);
374
+ const diff = diffCollectionState(localState, remoteState);
224
375
  const spanId = getSpanName(peerId);
225
376
  if (diff.different.length === 0) {
226
377
  trace.spanEnd(spanId);
@@ -236,8 +387,25 @@ var CollectionSynchronizer = class extends Resource {
236
387
  }
237
388
  });
238
389
  }
239
- if (diff.missingOnLocal.length > 0 || diff.different.length > 0) {
240
- perCollectionState.remoteStates.set(peerId, state);
390
+ log2("diff", {
391
+ localState: localState.documents,
392
+ remoteState: remoteState.documents,
393
+ missingOnLocal: diff.missingOnLocal,
394
+ missingOnRemote: diff.missingOnRemote,
395
+ different: diff.different
396
+ }, {
397
+ F: __dxlog_file2,
398
+ L: 210,
399
+ S: this,
400
+ C: (f, a) => f(...a)
401
+ });
402
+ if (diff.missingOnLocal.length > 0 || diff.different.length > 0 || diff.missingOnRemote.length > 0) {
403
+ log2("emit remote state update", void 0, {
404
+ F: __dxlog_file2,
405
+ L: 218,
406
+ S: this,
407
+ C: (f, a) => f(...a)
408
+ });
241
409
  this.remoteStateUpdated.emit({
242
410
  peerId,
243
411
  collectionId,
@@ -312,10 +480,10 @@ var getSpanName = (peerId) => {
312
480
 
313
481
  // src/automerge/echo-network-adapter.ts
314
482
  import { NetworkAdapter } from "@automerge/automerge-repo";
315
- import { Trigger, synchronized } from "@dxos/async";
483
+ import { Event as Event2, Trigger, synchronized } from "@dxos/async";
316
484
  import { LifecycleState } from "@dxos/context";
317
485
  import { invariant } from "@dxos/invariant";
318
- import { log as log2 } from "@dxos/log";
486
+ import { log as log3 } from "@dxos/log";
319
487
  import { isNonNullable } from "@dxos/util";
320
488
 
321
489
  // src/automerge/network-protocol.ts
@@ -330,7 +498,7 @@ function _ts_decorate2(decorators, target, key, desc) {
330
498
  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;
331
499
  return c > 3 && r && Object.defineProperty(target, key, r), r;
332
500
  }
333
- var __dxlog_file2 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts";
501
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/echo-network-adapter.ts";
334
502
  var EchoNetworkAdapter = class extends NetworkAdapter {
335
503
  _params;
336
504
  _replicators = /* @__PURE__ */ new Set();
@@ -341,6 +509,7 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
341
509
  _lifecycleState = LifecycleState.CLOSED;
342
510
  _connected = new Trigger();
343
511
  _ready = new Trigger();
512
+ documentRequested = new Event2();
344
513
  constructor(_params) {
345
514
  super(), this._params = _params;
346
515
  }
@@ -391,8 +560,8 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
391
560
  }
392
561
  async addReplicator(replicator) {
393
562
  invariant(this._lifecycleState === LifecycleState.OPEN, void 0, {
394
- F: __dxlog_file2,
395
- L: 137,
563
+ F: __dxlog_file3,
564
+ L: 140,
396
565
  S: this,
397
566
  A: [
398
567
  "this._lifecycleState === LifecycleState.OPEN",
@@ -400,8 +569,8 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
400
569
  ]
401
570
  });
402
571
  invariant(this.peerId, void 0, {
403
- F: __dxlog_file2,
404
- L: 138,
572
+ F: __dxlog_file3,
573
+ L: 141,
405
574
  S: this,
406
575
  A: [
407
576
  "this.peerId",
@@ -409,8 +578,8 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
409
578
  ]
410
579
  });
411
580
  invariant(!this._replicators.has(replicator), void 0, {
412
- F: __dxlog_file2,
413
- L: 139,
581
+ F: __dxlog_file3,
582
+ L: 142,
414
583
  S: this,
415
584
  A: [
416
585
  "!this._replicators.has(replicator)",
@@ -433,8 +602,8 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
433
602
  }
434
603
  async removeReplicator(replicator) {
435
604
  invariant(this._lifecycleState === LifecycleState.OPEN, void 0, {
436
- F: __dxlog_file2,
437
- L: 158,
605
+ F: __dxlog_file3,
606
+ L: 161,
438
607
  S: this,
439
608
  A: [
440
609
  "this._lifecycleState === LifecycleState.OPEN",
@@ -442,8 +611,8 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
442
611
  ]
443
612
  });
444
613
  invariant(this._replicators.has(replicator), void 0, {
445
- F: __dxlog_file2,
446
- L: 159,
614
+ F: __dxlog_file3,
615
+ L: 162,
447
616
  S: this,
448
617
  A: [
449
618
  "this._replicators.has(replicator)",
@@ -525,9 +694,9 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
525
694
  this._params.monitor?.recordMessageSent(message, Date.now() - start);
526
695
  }).catch((err) => {
527
696
  if (connectionEntry.isOpen) {
528
- log2.catch(err, void 0, {
529
- F: __dxlog_file2,
530
- L: 253,
697
+ log3.catch(err, void 0, {
698
+ F: __dxlog_file3,
699
+ L: 256,
531
700
  S: this,
532
701
  C: (f, a) => f(...a)
533
702
  });
@@ -536,17 +705,17 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
536
705
  });
537
706
  }
538
707
  _onConnectionOpen(connection) {
539
- log2("connection opened", {
708
+ log3("connection opened", {
540
709
  peerId: connection.peerId
541
710
  }, {
542
- F: __dxlog_file2,
543
- L: 261,
711
+ F: __dxlog_file3,
712
+ L: 264,
544
713
  S: this,
545
714
  C: (f, a) => f(...a)
546
715
  });
547
716
  invariant(!this._connections.has(connection.peerId), void 0, {
548
- F: __dxlog_file2,
549
- L: 262,
717
+ F: __dxlog_file3,
718
+ L: 265,
550
719
  S: this,
551
720
  A: [
552
721
  "!this._connections.has(connection.peerId as PeerId)",
@@ -557,7 +726,8 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
557
726
  isOpen: true,
558
727
  connection,
559
728
  reader: connection.readable.getReader(),
560
- writer: connection.writable.getWriter()
729
+ writer: connection.writable.getWriter(),
730
+ requestedDocuments: /* @__PURE__ */ new Set()
561
731
  };
562
732
  this._connections.set(connection.peerId, connectionEntry);
563
733
  queueMicrotask(async () => {
@@ -567,31 +737,38 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
567
737
  if (done) {
568
738
  break;
569
739
  }
570
- this._onMessage(value);
740
+ this._onMessage(connectionEntry, value);
571
741
  }
572
742
  } catch (err) {
573
743
  if (connectionEntry.isOpen) {
574
- log2.catch(err, void 0, {
575
- F: __dxlog_file2,
576
- L: 286,
744
+ log3.catch(err, void 0, {
745
+ F: __dxlog_file3,
746
+ L: 290,
577
747
  S: this,
578
748
  C: (f, a) => f(...a)
579
749
  });
580
750
  }
581
751
  }
582
752
  });
583
- log2("emit peer-candidate", {
753
+ log3("emit peer-candidate", {
584
754
  peerId: connection.peerId
585
755
  }, {
586
- F: __dxlog_file2,
587
- L: 291,
756
+ F: __dxlog_file3,
757
+ L: 295,
588
758
  S: this,
589
759
  C: (f, a) => f(...a)
590
760
  });
591
761
  this._emitPeerCandidate(connection);
592
762
  this._params.monitor?.recordPeerConnected(connection.peerId);
593
763
  }
594
- _onMessage(message) {
764
+ _onMessage(connectionEntry, message) {
765
+ const amMessage = message;
766
+ if (amMessage.type === "request") {
767
+ this.documentRequested.emit({
768
+ documentId: amMessage.documentId,
769
+ peerId: connectionEntry.connection.peerId
770
+ });
771
+ }
595
772
  if (isCollectionQueryMessage(message)) {
596
773
  this._params.onCollectionStateQueried(message.collectionId, message.senderId);
597
774
  } else if (isCollectionStateMessage(message)) {
@@ -602,18 +779,18 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
602
779
  this._params.monitor?.recordMessageReceived(message);
603
780
  }
604
781
  _onConnectionClosed(connection) {
605
- log2("connection closed", {
782
+ log3("connection closed", {
606
783
  peerId: connection.peerId
607
784
  }, {
608
- F: __dxlog_file2,
609
- L: 308,
785
+ F: __dxlog_file3,
786
+ L: 320,
610
787
  S: this,
611
788
  C: (f, a) => f(...a)
612
789
  });
613
790
  const entry = this._connections.get(connection.peerId);
614
791
  invariant(entry, void 0, {
615
- F: __dxlog_file2,
616
- L: 310,
792
+ F: __dxlog_file3,
793
+ L: 322,
617
794
  S: this,
618
795
  A: [
619
796
  "entry",
@@ -625,15 +802,15 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
625
802
  peerId: connection.peerId
626
803
  });
627
804
  this._params.monitor?.recordPeerDisconnected(connection.peerId);
628
- void entry.writer.abort().catch((err) => log2.catch(err, void 0, {
629
- F: __dxlog_file2,
630
- L: 316,
805
+ void entry.writer.abort().catch((err) => log3.catch(err, void 0, {
806
+ F: __dxlog_file3,
807
+ L: 328,
631
808
  S: this,
632
809
  C: (f, a) => f(...a)
633
810
  }));
634
- void entry.reader.cancel().catch((err) => log2.catch(err, void 0, {
635
- F: __dxlog_file2,
636
- L: 317,
811
+ void entry.reader.cancel().catch((err) => log3.catch(err, void 0, {
812
+ F: __dxlog_file3,
813
+ L: 329,
637
814
  S: this,
638
815
  C: (f, a) => f(...a)
639
816
  }));
@@ -644,18 +821,18 @@ var EchoNetworkAdapter = class extends NetworkAdapter {
644
821
  * TODO(y): replace with a proper API call when sharePolicy update becomes supported by automerge-repo
645
822
  */
646
823
  _onConnectionAuthScopeChanged(connection) {
647
- log2("Connection auth scope changed", {
824
+ log3("Connection auth scope changed", {
648
825
  peerId: connection.peerId
649
826
  }, {
650
- F: __dxlog_file2,
651
- L: 327,
827
+ F: __dxlog_file3,
828
+ L: 339,
652
829
  S: this,
653
830
  C: (f, a) => f(...a)
654
831
  });
655
832
  const entry = this._connections.get(connection.peerId);
656
833
  invariant(entry, void 0, {
657
- F: __dxlog_file2,
658
- L: 329,
834
+ F: __dxlog_file3,
835
+ L: 341,
659
836
  S: this,
660
837
  A: [
661
838
  "entry",
@@ -713,6 +890,20 @@ var HeadsStore = class {
713
890
  valueEncoding: headsEncoding
714
891
  });
715
892
  }
893
+ /**
894
+ * Iterate over all document IDs and their heads.
895
+ */
896
+ async *iterateAll() {
897
+ for await (const [documentId, heads] of this._db.iterator({
898
+ keyEncoding: "utf8",
899
+ valueEncoding: headsEncoding
900
+ })) {
901
+ yield {
902
+ documentId,
903
+ heads
904
+ };
905
+ }
906
+ }
716
907
  };
717
908
 
718
909
  // src/automerge/leveldb-storage-adapter.ts
@@ -828,7 +1019,7 @@ function _ts_decorate3(decorators, target, key, desc) {
828
1019
  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;
829
1020
  return c > 3 && r && Object.defineProperty(target, key, r), r;
830
1021
  }
831
- var __dxlog_file3 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
1022
+ var __dxlog_file4 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
832
1023
  var FIND_PARAMS = {
833
1024
  allowableStates: [
834
1025
  "ready",
@@ -838,6 +1029,7 @@ var FIND_PARAMS = {
838
1029
  var BUNDLE_SIZE = 100;
839
1030
  var BUNDLE_SYNC_CONCURRENCY = 2;
840
1031
  var BUNDLE_SYNC_THRESHOLD = 50;
1032
+ var OPTIMIZED_SHARE_POLICY = true;
841
1033
  var AutomergeHost = class extends Resource3 {
842
1034
  _db;
843
1035
  _indexMetadataStore;
@@ -858,13 +1050,30 @@ var AutomergeHost = class extends Resource3 {
858
1050
  _peerId;
859
1051
  _peerIdProvider;
860
1052
  _getSpaceKeyByRootDocumentId;
861
- collectionStateUpdated = new Event2();
1053
+ collectionStateUpdated = new Event3();
862
1054
  /**
863
1055
  * Fired after a batch of documents was saved to disk.
864
1056
  */
865
- documentsSaved = new Event2();
1057
+ documentsSaved = new Event3();
866
1058
  _headsUpdates = /* @__PURE__ */ new Map();
867
1059
  _onHeadsChangedTask;
1060
+ /**
1061
+ * Documents created in this session.
1062
+ */
1063
+ _createdDocuments = /* @__PURE__ */ new Set();
1064
+ /**
1065
+ * Documents that need to be synced based on the result of collection-sync.
1066
+ */
1067
+ _documentsToSync = /* @__PURE__ */ new Set();
1068
+ /**
1069
+ * Documents that are not avaiale locally that should be requested.
1070
+ */
1071
+ _documentsToRequest = /* @__PURE__ */ new Set();
1072
+ /**
1073
+ * Documents requested by remote peers.
1074
+ */
1075
+ _documentsRequested = /* @__PURE__ */ new Map();
1076
+ _sharePolicyChangedTask;
868
1077
  constructor({ db, indexMetadataStore, dataMonitor, peerIdProvider, getSpaceKeyByRootDocumentId }) {
869
1078
  super();
870
1079
  this._db = db;
@@ -883,6 +1092,10 @@ var AutomergeHost = class extends Resource3 {
883
1092
  onCollectionStateReceived: this._onCollectionStateReceived.bind(this),
884
1093
  monitor: dataMonitor
885
1094
  });
1095
+ this._echoNetworkAdapter.documentRequested.on(({ peerId, documentId }) => {
1096
+ defaultMap2(this._documentsRequested, peerId, () => /* @__PURE__ */ new Set()).add(documentId);
1097
+ this._sharePolicyChangedTask.schedule();
1098
+ });
886
1099
  this._headsStore = new HeadsStore({
887
1100
  db: db.sublevel("heads")
888
1101
  });
@@ -891,7 +1104,7 @@ var AutomergeHost = class extends Resource3 {
891
1104
  this._getSpaceKeyByRootDocumentId = getSpaceKeyByRootDocumentId;
892
1105
  }
893
1106
  async _open() {
894
- this._peerId = `host-${this._peerIdProvider?.() ?? PublicKey.random().toHex()}`;
1107
+ this._peerId = `host-${this._peerIdProvider?.() ?? PublicKey2.random().toHex()}`;
895
1108
  this._onHeadsChangedTask = new DeferredTask(this._ctx, async () => {
896
1109
  const docHeads = Array.from(this._headsUpdates.entries());
897
1110
  this._headsUpdates.clear();
@@ -900,7 +1113,7 @@ var AutomergeHost = class extends Resource3 {
900
1113
  await this._storage.open?.();
901
1114
  this._repo = new Repo({
902
1115
  peerId: this._peerId,
903
- sharePolicy: this._sharePolicy.bind(this),
1116
+ shareConfig: this._shareConfig,
904
1117
  storage: this._storage,
905
1118
  network: [
906
1119
  // Upstream swarm.
@@ -908,8 +1121,8 @@ var AutomergeHost = class extends Resource3 {
908
1121
  ]
909
1122
  });
910
1123
  let updatingAuthScope = false;
911
- Event2.wrap(this._echoNetworkAdapter, "peer-candidate").on(this._ctx, (e) => !updatingAuthScope && this._onPeerConnected(e.peerId));
912
- Event2.wrap(this._echoNetworkAdapter, "peer-disconnected").on(this._ctx, (e) => !updatingAuthScope && this._onPeerDisconnected(e.peerId));
1124
+ Event3.wrap(this._echoNetworkAdapter, "peer-candidate").on(this._ctx, (e) => !updatingAuthScope && this._onPeerConnected(e.peerId));
1125
+ Event3.wrap(this._echoNetworkAdapter, "peer-disconnected").on(this._ctx, (e) => !updatingAuthScope && this._onPeerDisconnected(e.peerId));
913
1126
  this._collectionSynchronizer.remoteStateUpdated.on(this._ctx, ({ collectionId, peerId, newDocsAppeared }) => {
914
1127
  this._onRemoteCollectionStateUpdated(collectionId, peerId);
915
1128
  this.collectionStateUpdated.emit({
@@ -933,19 +1146,28 @@ var AutomergeHost = class extends Resource3 {
933
1146
  try {
934
1147
  await this._handleCollectionSync(collectionId, peerId);
935
1148
  } catch (err) {
936
- log3.error("failed to sync collection", {
1149
+ log4.error("failed to sync collection", {
937
1150
  collectionId,
938
1151
  peerId,
939
1152
  err
940
1153
  }, {
941
- F: __dxlog_file3,
942
- L: 223,
1154
+ F: __dxlog_file4,
1155
+ L: 263,
943
1156
  S: this,
944
1157
  C: (f, a) => f(...a)
945
1158
  });
946
1159
  }
947
1160
  }));
948
1161
  });
1162
+ this._sharePolicyChangedTask = new DeferredTask(this._ctx, async () => {
1163
+ log4("share policy changed", void 0, {
1164
+ F: __dxlog_file4,
1165
+ L: 270,
1166
+ S: this,
1167
+ C: (f, a) => f(...a)
1168
+ });
1169
+ this._repo.shareConfigChanged();
1170
+ });
949
1171
  await this._echoNetworkAdapter.open();
950
1172
  await this._collectionSynchronizer.open();
951
1173
  await this._echoNetworkAdapter.open();
@@ -957,12 +1179,7 @@ var AutomergeHost = class extends Resource3 {
957
1179
  await this._echoNetworkAdapter.close();
958
1180
  this._syncTask = void 0;
959
1181
  this._onHeadsChangedTask = void 0;
960
- }
961
- /**
962
- * @deprecated To be abstracted away.
963
- */
964
- get repo() {
965
- return this._repo;
1182
+ this._sharePolicyChangedTask = void 0;
966
1183
  }
967
1184
  get peerId() {
968
1185
  return this._peerId;
@@ -970,10 +1187,13 @@ var AutomergeHost = class extends Resource3 {
970
1187
  get loadedDocsCount() {
971
1188
  return Object.keys(this._repo.handles).length;
972
1189
  }
1190
+ get handles() {
1191
+ return this._repo.handles;
1192
+ }
973
1193
  async addReplicator(replicator) {
974
1194
  invariant2(this.isOpen, "AutomergeHost is not open", {
975
- F: __dxlog_file3,
976
- L: 259,
1195
+ F: __dxlog_file4,
1196
+ L: 302,
977
1197
  S: this,
978
1198
  A: [
979
1199
  "this.isOpen",
@@ -984,8 +1204,8 @@ var AutomergeHost = class extends Resource3 {
984
1204
  }
985
1205
  async removeReplicator(replicator) {
986
1206
  invariant2(this.isOpen, "AutomergeHost is not open", {
987
- F: __dxlog_file3,
988
- L: 264,
1207
+ F: __dxlog_file4,
1208
+ L: 307,
989
1209
  S: this,
990
1210
  A: [
991
1211
  "this.isOpen",
@@ -999,8 +1219,8 @@ var AutomergeHost = class extends Resource3 {
999
1219
  */
1000
1220
  async loadDoc(ctx, documentId, opts) {
1001
1221
  invariant2(this.isOpen, "AutomergeHost is not open", {
1002
- F: __dxlog_file3,
1003
- L: 272,
1222
+ F: __dxlog_file4,
1223
+ L: 315,
1004
1224
  S: this,
1005
1225
  A: [
1006
1226
  "this.isOpen",
@@ -1012,7 +1232,34 @@ var AutomergeHost = class extends Resource3 {
1012
1232
  handle = this._repo.handles[documentId];
1013
1233
  }
1014
1234
  if (!handle) {
1015
- handle = await this._repo.find(documentId, FIND_PARAMS);
1235
+ if (!opts?.fetchFromNetwork) {
1236
+ handle = await this._repo.find(documentId, FIND_PARAMS);
1237
+ } else {
1238
+ try {
1239
+ handle = await this._repo.find(documentId, {
1240
+ allowableStates: [
1241
+ "ready",
1242
+ "requesting",
1243
+ "unavailable"
1244
+ ]
1245
+ });
1246
+ if (handle.state === "requesting" || handle.state === "unavailable") {
1247
+ this._documentsToRequest.add(handle.documentId);
1248
+ this._sharePolicyChangedTask.schedule();
1249
+ }
1250
+ } catch (err) {
1251
+ log4.error("failed to load document", {
1252
+ documentId,
1253
+ err
1254
+ }, {
1255
+ F: __dxlog_file4,
1256
+ L: 334,
1257
+ S: this,
1258
+ C: (f, a) => f(...a)
1259
+ });
1260
+ throw err;
1261
+ }
1262
+ }
1016
1263
  }
1017
1264
  if (!handle.isReady()) {
1018
1265
  if (!opts?.timeout) {
@@ -1025,8 +1272,8 @@ var AutomergeHost = class extends Resource3 {
1025
1272
  }
1026
1273
  async exportDoc(ctx, id) {
1027
1274
  invariant2(this.isOpen, "AutomergeHost is not open", {
1028
- F: __dxlog_file3,
1029
- L: 295,
1275
+ F: __dxlog_file4,
1276
+ L: 353,
1030
1277
  S: this,
1031
1278
  A: [
1032
1279
  "this.isOpen",
@@ -1042,10 +1289,10 @@ var AutomergeHost = class extends Resource3 {
1042
1289
  /**
1043
1290
  * Create new persisted document.
1044
1291
  */
1045
- createDoc(initialValue, opts) {
1292
+ async createDoc(initialValue, opts) {
1046
1293
  invariant2(this.isOpen, "AutomergeHost is not open", {
1047
- F: __dxlog_file3,
1048
- L: 306,
1294
+ F: __dxlog_file4,
1295
+ L: 364,
1049
1296
  S: this,
1050
1297
  A: [
1051
1298
  "this.isOpen",
@@ -1054,23 +1301,36 @@ var AutomergeHost = class extends Resource3 {
1054
1301
  });
1055
1302
  if (opts?.preserveHistory) {
1056
1303
  if (initialValue instanceof Uint8Array) {
1057
- return this._repo.import(initialValue);
1304
+ return this._repo.import(initialValue, {
1305
+ docId: opts?.documentId
1306
+ });
1058
1307
  }
1059
1308
  if (!isAutomerge(initialValue)) {
1060
1309
  throw new TypeError("Initial value must be an Automerge document");
1061
1310
  }
1062
- return this._repo.import(save(initialValue));
1311
+ const handle = this._repo.import(save(initialValue), {
1312
+ docId: opts?.documentId
1313
+ });
1314
+ this._createdDocuments.add(handle.documentId);
1315
+ this._sharePolicyChangedTask.schedule();
1316
+ return handle;
1063
1317
  } else {
1064
1318
  if (initialValue instanceof Uint8Array) {
1065
1319
  throw new Error("Cannot create document from Uint8Array without preserving history");
1066
1320
  }
1067
- return this._repo.create(initialValue);
1321
+ if (opts?.documentId) {
1322
+ throw new Error("Cannot prefil document id when not importing an existing doc");
1323
+ }
1324
+ const handle = await this._repo.create2(initialValue);
1325
+ this._createdDocuments.add(handle.documentId);
1326
+ this._sharePolicyChangedTask.schedule();
1327
+ return handle;
1068
1328
  }
1069
1329
  }
1070
1330
  async waitUntilHeadsReplicated(heads) {
1071
1331
  invariant2(this.isOpen, "AutomergeHost is not open", {
1072
- F: __dxlog_file3,
1073
- L: 328,
1332
+ F: __dxlog_file4,
1333
+ L: 395,
1074
1334
  S: this,
1075
1335
  A: [
1076
1336
  "this.isOpen",
@@ -1093,9 +1353,9 @@ var AutomergeHost = class extends Resource3 {
1093
1353
  });
1094
1354
  if (headsToWait.length > 0) {
1095
1355
  await Promise.all(headsToWait.map(async (entry) => {
1096
- const handle = await this.loadDoc(Context.default(void 0, {
1097
- F: __dxlog_file3,
1098
- L: 346
1356
+ const handle = await this.loadDoc(Context2.default(void 0, {
1357
+ F: __dxlog_file4,
1358
+ L: 413
1099
1359
  }), entry.documentId);
1100
1360
  await waitForHeads(handle, entry.heads);
1101
1361
  }));
@@ -1104,8 +1364,8 @@ var AutomergeHost = class extends Resource3 {
1104
1364
  }
1105
1365
  async reIndexHeads(documentIds) {
1106
1366
  invariant2(this.isOpen, "AutomergeHost is not open", {
1107
- F: __dxlog_file3,
1108
- L: 359,
1367
+ F: __dxlog_file4,
1368
+ L: 426,
1109
1369
  S: this,
1110
1370
  A: [
1111
1371
  "this.isOpen",
@@ -1113,21 +1373,21 @@ var AutomergeHost = class extends Resource3 {
1113
1373
  ]
1114
1374
  });
1115
1375
  for (const documentId of documentIds) {
1116
- log3("re-indexing heads for document", {
1376
+ log4("re-indexing heads for document", {
1117
1377
  documentId
1118
1378
  }, {
1119
- F: __dxlog_file3,
1120
- L: 361,
1379
+ F: __dxlog_file4,
1380
+ L: 428,
1121
1381
  S: this,
1122
1382
  C: (f, a) => f(...a)
1123
1383
  });
1124
1384
  const handle = await this._repo.find(documentId, FIND_PARAMS);
1125
1385
  if (!handle.isReady()) {
1126
- log3.warn("document is not available locally, skipping", {
1386
+ log4.warn("document is not available locally, skipping", {
1127
1387
  documentId
1128
1388
  }, {
1129
- F: __dxlog_file3,
1130
- L: 364,
1389
+ F: __dxlog_file4,
1390
+ L: 431,
1131
1391
  S: this,
1132
1392
  C: (f, a) => f(...a)
1133
1393
  });
@@ -1138,29 +1398,40 @@ var AutomergeHost = class extends Resource3 {
1138
1398
  this._headsStore.setHeads(documentId, heads, batch);
1139
1399
  await batch.write();
1140
1400
  }
1141
- log3("done re-indexing heads", void 0, {
1142
- F: __dxlog_file3,
1143
- L: 373,
1401
+ log4("done re-indexing heads", void 0, {
1402
+ F: __dxlog_file4,
1403
+ L: 440,
1144
1404
  S: this,
1145
1405
  C: (f, a) => f(...a)
1146
1406
  });
1147
1407
  }
1148
- // TODO(dmaretskyi): Share based on HALO permissions and space affinity.
1149
- // Hosts, running in the worker, don't share documents unless requested by other peers.
1150
- // NOTE: If both peers return sharePolicy=false the replication will not happen
1151
- // https://github.com/automerge/automerge-repo/pull/292
1152
- async _sharePolicy(peerId, documentId) {
1153
- if (!documentId) {
1408
+ _shareConfig = {
1409
+ access: async (peerId, documentId) => {
1410
+ return true;
1411
+ },
1412
+ // TODO(dmaretskyi): Share based on HALO permissions and space affinity.
1413
+ // Hosts, running in the worker, don't share documents unless requested by other peers.
1414
+ // NOTE: If both peers return sharePolicy=false the replication will not happen
1415
+ // https://github.com/automerge/automerge-repo/pull/292
1416
+ // Called for all loaded documents so they could be advertised to the sync server.
1417
+ announce: async (peerId, documentId) => {
1418
+ if (!documentId) {
1419
+ return false;
1420
+ }
1421
+ if (OPTIMIZED_SHARE_POLICY) {
1422
+ if (!this._createdDocuments.has(documentId) && !this._documentsToSync.has(documentId) && !this._documentsToRequest.has(documentId)) {
1423
+ return false;
1424
+ }
1425
+ }
1426
+ const peerMetadata = this._repo.peerMetadataByPeerId[peerId];
1427
+ if (isEchoPeerMetadata(peerMetadata)) {
1428
+ return this._echoNetworkAdapter.shouldAdvertise(peerId, {
1429
+ documentId
1430
+ });
1431
+ }
1154
1432
  return false;
1155
1433
  }
1156
- const peerMetadata = this.repo.peerMetadataByPeerId[peerId];
1157
- if (isEchoPeerMetadata(peerMetadata)) {
1158
- return this._echoNetworkAdapter.shouldAdvertise(peerId, {
1159
- documentId
1160
- });
1161
- }
1162
- return false;
1163
- }
1434
+ };
1164
1435
  async _beforeSave({ path, batch }) {
1165
1436
  const handle = this._repo.handles[path[0]];
1166
1437
  if (!handle || !handle.isReady()) {
@@ -1172,7 +1443,7 @@ var AutomergeHost = class extends Resource3 {
1172
1443
  }
1173
1444
  const heads = getHeads(doc);
1174
1445
  this._headsStore.setHeads(handle.documentId, heads, batch);
1175
- const spaceKey = DatabaseDirectory.getSpaceKey(doc) ?? void 0;
1446
+ const spaceKey = DatabaseDirectory2.getSpaceKey(doc) ?? void 0;
1176
1447
  const objectIds = Object.keys(doc.objects ?? {});
1177
1448
  const encodedIds = objectIds.map((objectId) => objectPointerCodec.encode({
1178
1449
  documentId: handle.documentId,
@@ -1214,8 +1485,8 @@ var AutomergeHost = class extends Resource3 {
1214
1485
  const heads = getHeads(document);
1215
1486
  this._headsUpdates.set(documentId, heads);
1216
1487
  invariant2(this._onHeadsChangedTask, "onHeadsChangedTask is not initialized", {
1217
- F: __dxlog_file3,
1218
- L: 445,
1488
+ F: __dxlog_file4,
1489
+ L: 530,
1219
1490
  S: this,
1220
1491
  A: [
1221
1492
  "this._onHeadsChangedTask",
@@ -1244,9 +1515,9 @@ var AutomergeHost = class extends Resource3 {
1244
1515
  await handle.whenReady();
1245
1516
  }
1246
1517
  if (handle && handle.isReady() && handle.doc()) {
1247
- const spaceKeyHex = DatabaseDirectory.getSpaceKey(handle.doc());
1518
+ const spaceKeyHex = DatabaseDirectory2.getSpaceKey(handle.doc());
1248
1519
  if (spaceKeyHex) {
1249
- return PublicKey.from(spaceKeyHex);
1520
+ return PublicKey2.from(spaceKeyHex);
1250
1521
  }
1251
1522
  }
1252
1523
  const rootDocSpaceKey = this._getSpaceKeyByRootDocumentId?.(documentId);
@@ -1288,6 +1559,12 @@ var AutomergeHost = class extends Resource3 {
1288
1559
  }
1289
1560
  return result;
1290
1561
  }
1562
+ /**
1563
+ * Iterate over all document heads stored on disk.
1564
+ */
1565
+ listDocumentHeads() {
1566
+ return this._headsStore.iterateAll();
1567
+ }
1291
1568
  //
1292
1569
  // Collection sync.
1293
1570
  //
@@ -1395,48 +1672,48 @@ var AutomergeHost = class extends Resource3 {
1395
1672
  ];
1396
1673
  const bundleSyncEnabled = this._echoNetworkAdapter.bundleSyncEnabledForPeer(peerId);
1397
1674
  if (bundleSyncEnabled && missingOnRemote.length >= BUNDLE_SYNC_THRESHOLD) {
1398
- log3("pushing bundle", {
1675
+ log4("pushing bundle", {
1399
1676
  amount: missingOnRemote.length
1400
1677
  }, {
1401
- F: __dxlog_file3,
1402
- L: 650,
1678
+ F: __dxlog_file4,
1679
+ L: 742,
1403
1680
  S: this,
1404
1681
  C: (f, a) => f(...a)
1405
1682
  });
1406
1683
  const { syncInteractively } = await this._pushInBundles(peerId, missingOnRemote);
1407
1684
  toReplicateWithoutBatching.push(...syncInteractively);
1408
1685
  } else {
1409
- log3.verbose("failed to push bundle, replicating interactively", {
1686
+ log4.verbose("failed to push bundle, replicating interactively", {
1410
1687
  collectionId,
1411
1688
  peerId,
1412
1689
  amount: missingOnRemote.length
1413
1690
  }, {
1414
- F: __dxlog_file3,
1415
- L: 654,
1691
+ F: __dxlog_file4,
1692
+ L: 746,
1416
1693
  S: this,
1417
1694
  C: (f, a) => f(...a)
1418
1695
  });
1419
1696
  toReplicateWithoutBatching.push(...missingOnRemote);
1420
1697
  }
1421
1698
  if (bundleSyncEnabled && missingOnLocal.length >= BUNDLE_SYNC_THRESHOLD) {
1422
- log3("pulling bundle", {
1699
+ log4("pulling bundle", {
1423
1700
  amount: missingOnLocal.length
1424
1701
  }, {
1425
- F: __dxlog_file3,
1426
- L: 662,
1702
+ F: __dxlog_file4,
1703
+ L: 754,
1427
1704
  S: this,
1428
1705
  C: (f, a) => f(...a)
1429
1706
  });
1430
1707
  const { syncInteractively } = await this._pullInBundles(peerId, missingOnLocal);
1431
1708
  toReplicateWithoutBatching.push(...syncInteractively);
1432
1709
  } else {
1433
- log3.verbose("failed to pull bundle, replicating interactively", {
1710
+ log4.verbose("failed to pull bundle, replicating interactively", {
1434
1711
  collectionId,
1435
1712
  peerId,
1436
1713
  amount: missingOnLocal.length
1437
1714
  }, {
1438
- F: __dxlog_file3,
1439
- L: 666,
1715
+ F: __dxlog_file4,
1716
+ L: 758,
1440
1717
  S: this,
1441
1718
  C: (f, a) => f(...a)
1442
1719
  });
@@ -1445,23 +1722,24 @@ var AutomergeHost = class extends Resource3 {
1445
1722
  if (toReplicateWithoutBatching.length === 0) {
1446
1723
  return;
1447
1724
  }
1448
- log3("replicating documents after collection sync", {
1725
+ log4("replicating documents after collection sync", {
1449
1726
  collectionId,
1450
1727
  peerId,
1451
1728
  toReplicateWithoutBatching,
1452
1729
  count: toReplicateWithoutBatching.length
1453
1730
  }, {
1454
- F: __dxlog_file3,
1455
- L: 678,
1731
+ F: __dxlog_file4,
1732
+ L: 770,
1456
1733
  S: this,
1457
1734
  C: (f, a) => f(...a)
1458
1735
  });
1459
1736
  for (const documentId of toReplicateWithoutBatching) {
1737
+ this._documentsToSync.add(documentId);
1460
1738
  this._repo.findWithProgress(documentId);
1461
1739
  }
1740
+ this._sharePolicyChangedTask.schedule();
1462
1741
  }
1463
1742
  // TODO(mykola): Add retries of batches https://gist.github.com/mykola-vrmchk/fde270259e9209fcbf1331e5abbf12cf
1464
- // TODO(mykola): Use effect to retry batches.
1465
1743
  async _pushInBundles(peerId, documentIds) {
1466
1744
  const documentsToPush = [
1467
1745
  ...documentIds
@@ -1474,13 +1752,13 @@ var AutomergeHost = class extends Resource3 {
1474
1752
  return;
1475
1753
  }
1476
1754
  await this._pushBundle(peerId, bundle).catch((err) => {
1477
- log3.warn("failed to push bundle, replicating interactively", {
1755
+ log4.warn("failed to push bundle, replicating interactively", {
1478
1756
  peerId,
1479
1757
  bundle,
1480
1758
  err
1481
1759
  }, {
1482
- F: __dxlog_file3,
1483
- L: 709,
1760
+ F: __dxlog_file4,
1761
+ L: 803,
1484
1762
  S: this,
1485
1763
  C: (f, a) => f(...a)
1486
1764
  });
@@ -1499,11 +1777,11 @@ var AutomergeHost = class extends Resource3 {
1499
1777
  const docs = documentIds.map((documentId) => {
1500
1778
  const handle = this._repo.handles[documentId];
1501
1779
  if (!handle || !handle.isReady()) {
1502
- log3.warn("document not ready, skipping", {
1780
+ log4.warn("document not ready, skipping", {
1503
1781
  documentId
1504
1782
  }, {
1505
- F: __dxlog_file3,
1506
- L: 727,
1783
+ F: __dxlog_file4,
1784
+ L: 821,
1507
1785
  S: this,
1508
1786
  C: (f, a) => f(...a)
1509
1787
  });
@@ -1511,11 +1789,11 @@ var AutomergeHost = class extends Resource3 {
1511
1789
  }
1512
1790
  const doc = handle.doc();
1513
1791
  if (!doc) {
1514
- log3.warn("document not available, skipping", {
1792
+ log4.warn("document not available, skipping", {
1515
1793
  documentId
1516
1794
  }, {
1517
- F: __dxlog_file3,
1518
- L: 732,
1795
+ F: __dxlog_file4,
1796
+ L: 826,
1519
1797
  S: this,
1520
1798
  C: (f, a) => f(...a)
1521
1799
  });
@@ -1542,13 +1820,13 @@ var AutomergeHost = class extends Resource3 {
1542
1820
  return;
1543
1821
  }
1544
1822
  const result = await this._pullBundle(peerId, bundle).catch((err) => {
1545
- log3.warn("failed to pull bundle, replicating interactively", {
1823
+ log4.warn("failed to pull bundle, replicating interactively", {
1546
1824
  peerId,
1547
1825
  bundle,
1548
1826
  err
1549
1827
  }, {
1550
- F: __dxlog_file3,
1551
- L: 762,
1828
+ F: __dxlog_file4,
1829
+ L: 856,
1552
1830
  S: this,
1553
1831
  C: (f, a) => f(...a)
1554
1832
  });
@@ -1629,7 +1907,7 @@ AutomergeHost = _ts_decorate3([
1629
1907
  var waitForHeads = async (handle, heads) => {
1630
1908
  const unavailableHeads = new Set(heads);
1631
1909
  await handle.whenReady();
1632
- await Event2.wrap(handle, "change").waitForCondition(() => {
1910
+ await Event3.wrap(handle, "change").waitForCondition(() => {
1633
1911
  for (const changeHash of unavailableHeads.values()) {
1634
1912
  if (changeIsPresentInDoc(handle.doc(), changeHash)) {
1635
1913
  unavailableHeads.delete(changeHash);
@@ -1643,8 +1921,8 @@ var changeIsPresentInDoc = (doc, changeHash) => {
1643
1921
  };
1644
1922
  var decodeCollectionState = (state) => {
1645
1923
  invariant2(typeof state === "object" && state !== null, "Invalid state", {
1646
- F: __dxlog_file3,
1647
- L: 845,
1924
+ F: __dxlog_file4,
1925
+ L: 939,
1648
1926
  S: void 0,
1649
1927
  A: [
1650
1928
  "typeof state === 'object' && state !== null",
@@ -1659,18 +1937,18 @@ var encodeCollectionState = (state) => {
1659
1937
 
1660
1938
  // src/automerge/mesh-echo-replicator.ts
1661
1939
  import { invariant as invariant5 } from "@dxos/invariant";
1662
- import { PublicKey as PublicKey2 } from "@dxos/keys";
1663
- import { log as log5 } from "@dxos/log";
1664
- import { ComplexSet as ComplexSet2, defaultMap as defaultMap2 } from "@dxos/util";
1940
+ import { PublicKey as PublicKey3 } from "@dxos/keys";
1941
+ import { log as log6 } from "@dxos/log";
1942
+ import { ComplexSet as ComplexSet2, defaultMap as defaultMap3 } from "@dxos/util";
1665
1943
 
1666
1944
  // src/automerge/mesh-echo-replicator-connection.ts
1667
1945
  import * as A2 from "@automerge/automerge";
1668
1946
  import { cbor } from "@automerge/automerge-repo";
1669
1947
  import { Resource as Resource4 } from "@dxos/context";
1670
1948
  import { invariant as invariant3 } from "@dxos/invariant";
1671
- import { log as log4 } from "@dxos/log";
1949
+ import { log as log5 } from "@dxos/log";
1672
1950
  import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
1673
- var __dxlog_file4 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts";
1951
+ var __dxlog_file5 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator-connection.ts";
1674
1952
  var DEFAULT_FACTORY = (params) => new AutomergeReplicator(...params);
1675
1953
  var MeshReplicatorConnection = class extends Resource4 {
1676
1954
  _params;
@@ -1692,7 +1970,7 @@ var MeshReplicatorConnection = class extends Resource4 {
1692
1970
  this.writable = new WritableStream({
1693
1971
  write: async (message, controller) => {
1694
1972
  invariant3(this._isEnabled, "Writing to a disabled connection", {
1695
- F: __dxlog_file4,
1973
+ F: __dxlog_file5,
1696
1974
  L: 51,
1697
1975
  S: this,
1698
1976
  A: [
@@ -1720,12 +1998,12 @@ var MeshReplicatorConnection = class extends Resource4 {
1720
1998
  onStartReplication: async (info, remotePeerId) => {
1721
1999
  this.remoteDeviceKey = remotePeerId;
1722
2000
  this._remotePeerId = info.id;
1723
- log4("onStartReplication", {
2001
+ log5("onStartReplication", {
1724
2002
  id: info.id,
1725
2003
  thisPeerId: this.peerId,
1726
2004
  remotePeerId: remotePeerId.toHex()
1727
2005
  }, {
1728
- F: __dxlog_file4,
2006
+ F: __dxlog_file5,
1729
2007
  L: 80,
1730
2008
  S: this,
1731
2009
  C: (f, a) => f(...a)
@@ -1752,7 +2030,7 @@ var MeshReplicatorConnection = class extends Resource4 {
1752
2030
  }
1753
2031
  get peerId() {
1754
2032
  invariant3(this._remotePeerId != null, "Remote peer has not connected yet.", {
1755
- F: __dxlog_file4,
2033
+ F: __dxlog_file5,
1756
2034
  L: 106,
1757
2035
  S: this,
1758
2036
  A: [
@@ -1780,7 +2058,7 @@ var MeshReplicatorConnection = class extends Resource4 {
1780
2058
  */
1781
2059
  enable() {
1782
2060
  invariant3(this._remotePeerId != null, "Remote peer has not connected yet.", {
1783
- F: __dxlog_file4,
2061
+ F: __dxlog_file5,
1784
2062
  L: 131,
1785
2063
  S: this,
1786
2064
  A: [
@@ -1798,7 +2076,7 @@ var MeshReplicatorConnection = class extends Resource4 {
1798
2076
  }
1799
2077
  };
1800
2078
  var logSendSync = (message) => {
1801
- log4("sendSyncMessage", () => {
2079
+ log5("sendSyncMessage", () => {
1802
2080
  const decodedSyncMessage = message.type === "sync" && message.data ? A2.decodeSyncMessage(message.data) : void 0;
1803
2081
  return {
1804
2082
  sync: decodedSyncMessage && {
@@ -1811,7 +2089,7 @@ var logSendSync = (message) => {
1811
2089
  to: message.targetId
1812
2090
  };
1813
2091
  }, {
1814
- F: __dxlog_file4,
2092
+ F: __dxlog_file5,
1815
2093
  L: 144,
1816
2094
  S: void 0,
1817
2095
  C: (f, a) => f(...a)
@@ -1821,12 +2099,12 @@ var logSendSync = (message) => {
1821
2099
  // src/automerge/space-collection.ts
1822
2100
  import { invariant as invariant4 } from "@dxos/invariant";
1823
2101
  import { SpaceId } from "@dxos/keys";
1824
- var __dxlog_file5 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/space-collection.ts";
2102
+ var __dxlog_file6 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/space-collection.ts";
1825
2103
  var deriveCollectionIdFromSpaceId = (spaceId, rootDocumentId) => rootDocumentId ? `space:${spaceId}:${rootDocumentId}` : `space:${spaceId}`;
1826
2104
  var getSpaceIdFromCollectionId = (collectionId) => {
1827
2105
  const spaceId = collectionId.split(":")[1];
1828
2106
  invariant4(SpaceId.isValid(spaceId), void 0, {
1829
- F: __dxlog_file5,
2107
+ F: __dxlog_file6,
1830
2108
  L: 16,
1831
2109
  S: void 0,
1832
2110
  A: [
@@ -1838,7 +2116,7 @@ var getSpaceIdFromCollectionId = (collectionId) => {
1838
2116
  };
1839
2117
 
1840
2118
  // src/automerge/mesh-echo-replicator.ts
1841
- var __dxlog_file6 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts";
2119
+ var __dxlog_file7 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-echo-replicator.ts";
1842
2120
  var MeshEchoReplicator = class {
1843
2121
  /**
1844
2122
  * We might have multiple connections open with a peer (one per space), but there'll be only one enabled
@@ -1874,7 +2152,7 @@ var MeshEchoReplicator = class {
1874
2152
  }
1875
2153
  createExtension(extensionFactory) {
1876
2154
  invariant5(this._context, void 0, {
1877
- F: __dxlog_file6,
2155
+ F: __dxlog_file7,
1878
2156
  L: 68,
1879
2157
  S: this,
1880
2158
  A: [
@@ -1886,16 +2164,16 @@ var MeshEchoReplicator = class {
1886
2164
  ownPeerId: this._context.peerId,
1887
2165
  replicatorFactory: extensionFactory,
1888
2166
  onRemoteConnected: async () => {
1889
- log5("onRemoteConnected", {
2167
+ log6("onRemoteConnected", {
1890
2168
  peerId: connection.peerId
1891
2169
  }, {
1892
- F: __dxlog_file6,
2170
+ F: __dxlog_file7,
1893
2171
  L: 74,
1894
2172
  S: this,
1895
2173
  C: (f, a) => f(...a)
1896
2174
  });
1897
2175
  invariant5(this._context, void 0, {
1898
- F: __dxlog_file6,
2176
+ F: __dxlog_file7,
1899
2177
  L: 75,
1900
2178
  S: this,
1901
2179
  A: [
@@ -1917,10 +2195,10 @@ var MeshEchoReplicator = class {
1917
2195
  }
1918
2196
  },
1919
2197
  onRemoteDisconnected: async () => {
1920
- log5("onRemoteDisconnected", {
2198
+ log6("onRemoteDisconnected", {
1921
2199
  peerId: connection.peerId
1922
2200
  }, {
1923
- F: __dxlog_file6,
2201
+ F: __dxlog_file7,
1924
2202
  L: 89,
1925
2203
  S: this,
1926
2204
  C: (f, a) => f(...a)
@@ -1929,10 +2207,10 @@ var MeshEchoReplicator = class {
1929
2207
  const existingConnections = this._connectionsPerPeer.get(connection.peerId) ?? [];
1930
2208
  const index = existingConnections.indexOf(connection);
1931
2209
  if (index < 0) {
1932
- log5.warn("disconnected connection not found", {
2210
+ log6.warn("disconnected connection not found", {
1933
2211
  peerId: connection.peerId
1934
2212
  }, {
1935
- F: __dxlog_file6,
2213
+ F: __dxlog_file7,
1936
2214
  L: 97,
1937
2215
  S: this,
1938
2216
  C: (f, a) => f(...a)
@@ -1950,17 +2228,17 @@ var MeshEchoReplicator = class {
1950
2228
  }
1951
2229
  },
1952
2230
  shouldAdvertise: async (params) => {
1953
- log5("shouldAdvertise", {
2231
+ log6("shouldAdvertise", {
1954
2232
  peerId: connection.peerId,
1955
2233
  documentId: params.documentId
1956
2234
  }, {
1957
- F: __dxlog_file6,
2235
+ F: __dxlog_file7,
1958
2236
  L: 115,
1959
2237
  S: this,
1960
2238
  C: (f, a) => f(...a)
1961
2239
  });
1962
2240
  invariant5(this._context, void 0, {
1963
- F: __dxlog_file6,
2241
+ F: __dxlog_file7,
1964
2242
  L: 116,
1965
2243
  S: this,
1966
2244
  A: [
@@ -1975,12 +2253,12 @@ var MeshEchoReplicator = class {
1975
2253
  documentId: params.documentId,
1976
2254
  peerId: connection.peerId
1977
2255
  });
1978
- log5("document not found locally for share policy check", {
2256
+ log6("document not found locally for share policy check", {
1979
2257
  peerId: connection.peerId,
1980
2258
  documentId: params.documentId,
1981
2259
  acceptDocument: remoteDocumentExists
1982
2260
  }, {
1983
- F: __dxlog_file6,
2261
+ F: __dxlog_file7,
1984
2262
  L: 124,
1985
2263
  S: this,
1986
2264
  C: (f, a) => f(...a)
@@ -1990,11 +2268,11 @@ var MeshEchoReplicator = class {
1990
2268
  const spaceId = await createIdFromSpaceKey(spaceKey);
1991
2269
  const authorizedDevices = this._authorizedDevices.get(spaceId);
1992
2270
  if (!connection.remoteDeviceKey) {
1993
- log5("device key not found for share policy check", {
2271
+ log6("device key not found for share policy check", {
1994
2272
  peerId: connection.peerId,
1995
2273
  documentId: params.documentId
1996
2274
  }, {
1997
- F: __dxlog_file6,
2275
+ F: __dxlog_file7,
1998
2276
  L: 141,
1999
2277
  S: this,
2000
2278
  C: (f, a) => f(...a)
@@ -2002,7 +2280,7 @@ var MeshEchoReplicator = class {
2002
2280
  return false;
2003
2281
  }
2004
2282
  const isAuthorized = authorizedDevices?.has(connection.remoteDeviceKey) ?? false;
2005
- log5("share policy check", {
2283
+ log6("share policy check", {
2006
2284
  localPeer: this._context.peerId,
2007
2285
  remotePeer: connection.peerId,
2008
2286
  documentId: params.documentId,
@@ -2010,15 +2288,15 @@ var MeshEchoReplicator = class {
2010
2288
  spaceKey,
2011
2289
  isAuthorized
2012
2290
  }, {
2013
- F: __dxlog_file6,
2291
+ F: __dxlog_file7,
2014
2292
  L: 149,
2015
2293
  S: this,
2016
2294
  C: (f, a) => f(...a)
2017
2295
  });
2018
2296
  return isAuthorized;
2019
2297
  } catch (err) {
2020
- log5.catch(err, void 0, {
2021
- F: __dxlog_file6,
2298
+ log6.catch(err, void 0, {
2299
+ F: __dxlog_file7,
2022
2300
  L: 159,
2023
2301
  S: this,
2024
2302
  C: (f, a) => f(...a)
@@ -2030,11 +2308,11 @@ var MeshEchoReplicator = class {
2030
2308
  const spaceId = getSpaceIdFromCollectionId(collectionId);
2031
2309
  const authorizedDevices = this._authorizedDevices.get(spaceId);
2032
2310
  if (!connection.remoteDeviceKey) {
2033
- log5("device key not found for collection sync check", {
2311
+ log6("device key not found for collection sync check", {
2034
2312
  peerId: connection.peerId,
2035
2313
  collectionId
2036
2314
  }, {
2037
- F: __dxlog_file6,
2315
+ F: __dxlog_file7,
2038
2316
  L: 169,
2039
2317
  S: this,
2040
2318
  C: (f, a) => f(...a)
@@ -2049,17 +2327,17 @@ var MeshEchoReplicator = class {
2049
2327
  return connection.replicatorExtension;
2050
2328
  }
2051
2329
  async authorizeDevice(spaceKey, deviceKey) {
2052
- log5("authorizeDevice", {
2330
+ log6("authorizeDevice", {
2053
2331
  spaceKey,
2054
2332
  deviceKey
2055
2333
  }, {
2056
- F: __dxlog_file6,
2334
+ F: __dxlog_file7,
2057
2335
  L: 186,
2058
2336
  S: this,
2059
2337
  C: (f, a) => f(...a)
2060
2338
  });
2061
2339
  const spaceId = await createIdFromSpaceKey(spaceKey);
2062
- defaultMap2(this._authorizedDevices, spaceId, () => new ComplexSet2(PublicKey2.hash)).add(deviceKey);
2340
+ defaultMap3(this._authorizedDevices, spaceId, () => new ComplexSet2(PublicKey3.hash)).add(deviceKey);
2063
2341
  for (const connection of this._connections) {
2064
2342
  if (connection.isEnabled && connection.remoteDeviceKey && connection.remoteDeviceKey.equals(deviceKey)) {
2065
2343
  if (this._connectionsPerPeer.has(connection.peerId)) {
@@ -2435,11 +2713,12 @@ var getByteCount = (message) => {
2435
2713
 
2436
2714
  // src/db-host/documents-synchronizer.ts
2437
2715
  import { next as A3 } from "@automerge/automerge";
2438
- import { UpdateScheduler, sleep } from "@dxos/async";
2439
- import { LifecycleState as LifecycleState2, Resource as Resource5, cancelWithContext as cancelWithContext2 } from "@dxos/context";
2716
+ import { UpdateScheduler } from "@dxos/async";
2717
+ import { Context as Context3, LifecycleState as LifecycleState2, Resource as Resource5 } from "@dxos/context";
2440
2718
  import { invariant as invariant6 } from "@dxos/invariant";
2441
- import { log as log6 } from "@dxos/log";
2442
- var __dxlog_file7 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/documents-synchronizer.ts";
2719
+ import { log as log7 } from "@dxos/log";
2720
+ import { retry } from "@dxos/util";
2721
+ var __dxlog_file8 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/documents-synchronizer.ts";
2443
2722
  var MAX_UPDATE_FREQ = 10;
2444
2723
  var WRAP_AROUND_RETRY_LIMIT = 3;
2445
2724
  var WRAP_AROUND_RETRY_INITIAL_DELAY = 100;
@@ -2458,39 +2737,53 @@ var DocumentsSynchronizer = class extends Resource5 {
2458
2737
  constructor(_params) {
2459
2738
  super(), this._params = _params;
2460
2739
  }
2461
- addDocuments(documentIds, retryCounter = 0, wrapAroundRetryDelay = WRAP_AROUND_RETRY_INITIAL_DELAY) {
2462
- if (retryCounter > WRAP_AROUND_RETRY_LIMIT) {
2463
- log6.warn("Failed to load document, retry limit reached", {
2464
- documentIds
2465
- }, {
2466
- F: __dxlog_file7,
2467
- L: 57,
2468
- S: this,
2469
- C: (f, a) => f(...a)
2470
- });
2471
- return;
2472
- }
2473
- for (const documentId of documentIds) {
2474
- this._params.repo.find(documentId).then(async (doc) => {
2475
- await doc.whenReady();
2476
- this._startSync(doc);
2477
- this._pendingUpdates.add(doc.documentId);
2478
- this._sendUpdatesJob.trigger();
2479
- }).catch((error) => {
2480
- log6.warn("Failed to load document, wraparound", {
2481
- documentId,
2482
- error
2483
- }, {
2484
- F: __dxlog_file7,
2485
- L: 71,
2740
+ async addDocuments(documentIds) {
2741
+ await Promise.all(documentIds.map(async (documentId) => {
2742
+ try {
2743
+ await retry({
2744
+ count: WRAP_AROUND_RETRY_LIMIT,
2745
+ delayMs: WRAP_AROUND_RETRY_INITIAL_DELAY,
2746
+ exponent: 2
2747
+ }, async () => {
2748
+ try {
2749
+ log7("loading document", {
2750
+ documentId
2751
+ }, {
2752
+ F: __dxlog_file8,
2753
+ L: 62,
2754
+ S: this,
2755
+ C: (f, a) => f(...a)
2756
+ });
2757
+ const doc = await this._params.automergeHost.loadDoc(Context3.default(void 0, {
2758
+ F: __dxlog_file8,
2759
+ L: 64
2760
+ }), documentId, {
2761
+ fetchFromNetwork: true
2762
+ });
2763
+ this._startSync(doc);
2764
+ this._pendingUpdates.add(doc.documentId);
2765
+ this._sendUpdatesJob.trigger();
2766
+ } catch (err) {
2767
+ log7.warn("failed to load document", {
2768
+ err
2769
+ }, {
2770
+ F: __dxlog_file8,
2771
+ L: 72,
2772
+ S: this,
2773
+ C: (f, a) => f(...a)
2774
+ });
2775
+ throw err;
2776
+ }
2777
+ });
2778
+ } catch (err) {
2779
+ log7.catch(err, void 0, {
2780
+ F: __dxlog_file8,
2781
+ L: 78,
2486
2782
  S: this,
2487
2783
  C: (f, a) => f(...a)
2488
2784
  });
2489
- void cancelWithContext2(this._ctx, sleep(wrapAroundRetryDelay)).then(() => this.addDocuments([
2490
- documentId
2491
- ], retryCounter + 1, wrapAroundRetryDelay * 2));
2492
- });
2493
- }
2785
+ }
2786
+ }));
2494
2787
  }
2495
2788
  removeDocuments(documentIds) {
2496
2789
  for (const documentId of documentIds) {
@@ -2509,18 +2802,20 @@ var DocumentsSynchronizer = class extends Resource5 {
2509
2802
  this._syncStates.clear();
2510
2803
  }
2511
2804
  async update(updates) {
2512
- for (const { documentId, mutation, isNew } of updates) {
2513
- this._writeMutation(documentId, mutation, isNew);
2805
+ for (const { documentId, mutation } of updates) {
2806
+ await this._writeMutation(documentId, mutation);
2514
2807
  }
2515
- await this._params.repo.flush(updates.map(({ documentId }) => documentId));
2808
+ await this._params.automergeHost.flush({
2809
+ documentIds: updates.map(({ documentId }) => documentId)
2810
+ });
2516
2811
  }
2517
2812
  _startSync(doc) {
2518
2813
  if (this._syncStates.has(doc.documentId)) {
2519
- log6("Document already being synced", {
2814
+ log7("Document already being synced", {
2520
2815
  documentId: doc.documentId
2521
2816
  }, {
2522
- F: __dxlog_file7,
2523
- L: 108,
2817
+ F: __dxlog_file8,
2818
+ L: 113,
2524
2819
  S: this,
2525
2820
  C: (f, a) => f(...a)
2526
2821
  });
@@ -2563,8 +2858,8 @@ var DocumentsSynchronizer = class extends Resource5 {
2563
2858
  _getPendingChanges(documentId) {
2564
2859
  const syncState = this._syncStates.get(documentId);
2565
2860
  invariant6(syncState, "Sync state for document not found", {
2566
- F: __dxlog_file7,
2567
- L: 150,
2861
+ F: __dxlog_file8,
2862
+ L: 155,
2568
2863
  S: this,
2569
2864
  A: [
2570
2865
  "syncState",
@@ -2583,40 +2878,41 @@ var DocumentsSynchronizer = class extends Resource5 {
2583
2878
  syncState.lastSentHead = A3.getHeads(doc);
2584
2879
  return mutation;
2585
2880
  }
2586
- _writeMutation(documentId, mutation, isNew) {
2881
+ async _writeMutation(documentId, mutation) {
2587
2882
  if (this._lifecycleState === LifecycleState2.CLOSED) {
2588
2883
  return;
2589
2884
  }
2590
- if (isNew) {
2591
- const newHandle = this._params.repo.import(mutation, {
2592
- docId: documentId
2593
- });
2594
- const syncState = this._startSync(newHandle);
2595
- syncState.lastSentHead = A3.getHeads(newHandle.doc());
2596
- } else {
2597
- const syncState = this._syncStates.get(documentId);
2598
- invariant6(syncState, "Sync state for document not found", {
2599
- F: __dxlog_file7,
2600
- L: 174,
2601
- S: this,
2602
- A: [
2603
- "syncState",
2604
- "'Sync state for document not found'"
2605
- ]
2606
- });
2607
- const headsBefore = A3.getHeads(syncState.handle.doc());
2608
- this._params.repo.import(mutation, {
2609
- docId: documentId
2610
- });
2611
- if (A3.equals(headsBefore, syncState.lastSentHead)) {
2612
- syncState.lastSentHead = A3.getHeads(syncState.handle.doc());
2613
- }
2885
+ log7("write mutation", {
2886
+ documentId
2887
+ }, {
2888
+ F: __dxlog_file8,
2889
+ L: 173,
2890
+ S: this,
2891
+ C: (f, a) => f(...a)
2892
+ });
2893
+ const syncState = this._syncStates.get(documentId);
2894
+ invariant6(syncState, "Sync state for document not found", {
2895
+ F: __dxlog_file8,
2896
+ L: 176,
2897
+ S: this,
2898
+ A: [
2899
+ "syncState",
2900
+ "'Sync state for document not found'"
2901
+ ]
2902
+ });
2903
+ const headsBefore = A3.getHeads(syncState.handle.doc());
2904
+ await this._params.automergeHost.createDoc(mutation, {
2905
+ documentId,
2906
+ preserveHistory: true
2907
+ });
2908
+ if (A3.equals(headsBefore, syncState.lastSentHead)) {
2909
+ syncState.lastSentHead = A3.getHeads(syncState.handle.doc());
2614
2910
  }
2615
2911
  }
2616
2912
  };
2617
2913
 
2618
2914
  // src/db-host/data-service.ts
2619
- var __dxlog_file8 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/data-service.ts";
2915
+ var __dxlog_file9 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/data-service.ts";
2620
2916
  var DataServiceImpl = class {
2621
2917
  /**
2622
2918
  * Map of subscriptions.
@@ -2634,15 +2930,15 @@ var DataServiceImpl = class {
2634
2930
  subscribe(request) {
2635
2931
  return new Stream(({ next, ready }) => {
2636
2932
  const synchronizer = new DocumentsSynchronizer({
2637
- repo: this._automergeHost.repo,
2933
+ automergeHost: this._automergeHost,
2638
2934
  sendUpdates: (updates) => next(updates)
2639
2935
  });
2640
2936
  synchronizer.open().then(() => {
2641
2937
  this._subscriptions.set(request.subscriptionId, synchronizer);
2642
2938
  ready();
2643
- }).catch((err) => log7.catch(err, void 0, {
2644
- F: __dxlog_file8,
2645
- L: 72,
2939
+ }).catch((err) => log8.catch(err, void 0, {
2940
+ F: __dxlog_file9,
2941
+ L: 74,
2646
2942
  S: this,
2647
2943
  C: (f, a) => f(...a)
2648
2944
  }));
@@ -2652,8 +2948,8 @@ var DataServiceImpl = class {
2652
2948
  async updateSubscription(request) {
2653
2949
  const synchronizer = this._subscriptions.get(request.subscriptionId);
2654
2950
  invariant7(synchronizer, "Subscription not found", {
2655
- F: __dxlog_file8,
2656
- L: 79,
2951
+ F: __dxlog_file9,
2952
+ L: 81,
2657
2953
  S: this,
2658
2954
  A: [
2659
2955
  "synchronizer",
@@ -2667,14 +2963,20 @@ var DataServiceImpl = class {
2667
2963
  await synchronizer.removeDocuments(request.removeIds);
2668
2964
  }
2669
2965
  }
2966
+ async createDocument(request) {
2967
+ const handle = await this._automergeHost.createDoc(request.initialValue);
2968
+ return {
2969
+ documentId: handle.documentId
2970
+ };
2971
+ }
2670
2972
  async update(request) {
2671
2973
  if (!request.updates) {
2672
2974
  return;
2673
2975
  }
2674
2976
  const synchronizer = this._subscriptions.get(request.subscriptionId);
2675
2977
  invariant7(synchronizer, "Subscription not found", {
2676
- F: __dxlog_file8,
2677
- L: 94,
2978
+ F: __dxlog_file9,
2979
+ L: 101,
2678
2980
  S: this,
2679
2981
  A: [
2680
2982
  "synchronizer",
@@ -2718,8 +3020,8 @@ var DataServiceImpl = class {
2718
3020
  return new Stream(({ ctx, next, ready }) => {
2719
3021
  const spaceId = request.spaceId;
2720
3022
  invariant7(SpaceId2.isValid(spaceId), void 0, {
2721
- F: __dxlog_file8,
2722
- L: 134,
3023
+ F: __dxlog_file9,
3024
+ L: 141,
2723
3025
  S: this,
2724
3026
  A: [
2725
3027
  "SpaceId.isValid(spaceId)",
@@ -2754,22 +3056,27 @@ var DataServiceImpl = class {
2754
3056
  };
2755
3057
 
2756
3058
  // src/db-host/echo-host.ts
2757
- import { LifecycleState as LifecycleState5, Resource as Resource9 } from "@dxos/context";
3059
+ import { DeferredTask as DeferredTask3, sleep } from "@dxos/async";
3060
+ import { Context as Context8, LifecycleState as LifecycleState5, Resource as Resource9 } from "@dxos/context";
2758
3061
  import { todo } from "@dxos/debug";
2759
- import { SpaceDocVersion as SpaceDocVersion3, createIdFromSpaceKey as createIdFromSpaceKey2 } from "@dxos/echo-protocol";
3062
+ import { SpaceDocVersion as SpaceDocVersion4, createIdFromSpaceKey as createIdFromSpaceKey2 } from "@dxos/echo-protocol";
3063
+ import { RuntimeProvider as RuntimeProvider3 } from "@dxos/effect";
3064
+ import { FeedStore } from "@dxos/feed";
3065
+ import { IndexEngine } from "@dxos/index-core";
2760
3066
  import { IndexMetadataStore, IndexStore, Indexer } from "@dxos/indexing";
2761
- import { invariant as invariant13 } from "@dxos/invariant";
3067
+ import { invariant as invariant14 } from "@dxos/invariant";
3068
+ import { log as log14 } from "@dxos/log";
2762
3069
  import { IndexKind } from "@dxos/protocols/proto/dxos/echo/indexing";
2763
3070
  import { trace as trace5 } from "@dxos/tracing";
2764
3071
 
2765
3072
  // src/db-host/documents-iterator.ts
2766
3073
  import * as A4 from "@automerge/automerge";
2767
- import { Context as Context2 } from "@dxos/context";
2768
- import { DatabaseDirectory as DatabaseDirectory2, SpaceDocVersion } from "@dxos/echo-protocol";
3074
+ import { Context as Context4 } from "@dxos/context";
3075
+ import { DatabaseDirectory as DatabaseDirectory3, SpaceDocVersion as SpaceDocVersion2 } from "@dxos/echo-protocol";
2769
3076
  import { invariant as invariant8 } from "@dxos/invariant";
2770
- import { log as log8 } from "@dxos/log";
3077
+ import { log as log9 } from "@dxos/log";
2771
3078
  import { ObjectPointerVersion, objectPointerCodec as objectPointerCodec2 } from "@dxos/protocols";
2772
- var __dxlog_file9 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/documents-iterator.ts";
3079
+ var __dxlog_file10 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/documents-iterator.ts";
2773
3080
  var LOG_VIEW_OPERATION_THRESHOLD = 300;
2774
3081
  var createSelectedDocumentsIterator = (automergeHost) => (
2775
3082
  /**
@@ -2780,14 +3087,16 @@ var createSelectedDocumentsIterator = (automergeHost) => (
2780
3087
  for (const [id, heads] of objects.entries()) {
2781
3088
  try {
2782
3089
  const { documentId, objectId } = objectPointerCodec2.decode(id);
2783
- const handle = await automergeHost.loadDoc(Context2.default(void 0, {
2784
- F: __dxlog_file9,
3090
+ const handle = await automergeHost.loadDoc(Context4.default(void 0, {
3091
+ F: __dxlog_file10,
2785
3092
  L: 31
2786
- }), documentId);
3093
+ }), documentId, {
3094
+ fetchFromNetwork: true
3095
+ });
2787
3096
  let doc = handle.doc();
2788
3097
  invariant8(doc, void 0, {
2789
- F: __dxlog_file9,
2790
- L: 34,
3098
+ F: __dxlog_file10,
3099
+ L: 36,
2791
3100
  S: this,
2792
3101
  A: [
2793
3102
  "doc",
@@ -2800,19 +3109,19 @@ var createSelectedDocumentsIterator = (automergeHost) => (
2800
3109
  doc = A4.view(doc, heads);
2801
3110
  const end = Date.now();
2802
3111
  if (end - begin > LOG_VIEW_OPERATION_THRESHOLD) {
2803
- log8("Checking out document version is taking too long", {
3112
+ log9("Checking out document version is taking too long", {
2804
3113
  duration: end - begin,
2805
3114
  requestedHeads: heads,
2806
3115
  originalHeads: currentHeads
2807
3116
  }, {
2808
- F: __dxlog_file9,
2809
- L: 45,
3117
+ F: __dxlog_file10,
3118
+ L: 47,
2810
3119
  S: this,
2811
3120
  C: (f, a) => f(...a)
2812
3121
  });
2813
3122
  }
2814
3123
  }
2815
- if (doc.version !== SpaceDocVersion.CURRENT) {
3124
+ if (doc.version !== SpaceDocVersion2.CURRENT) {
2816
3125
  continue;
2817
3126
  }
2818
3127
  if (!doc.objects?.[objectId]) {
@@ -2820,7 +3129,7 @@ var createSelectedDocumentsIterator = (automergeHost) => (
2820
3129
  }
2821
3130
  let newId = id;
2822
3131
  if (objectPointerCodec2.getVersion(id) === ObjectPointerVersion.V0) {
2823
- const spaceKey = DatabaseDirectory2.getSpaceKey(doc) ?? void 0;
3132
+ const spaceKey = DatabaseDirectory3.getSpaceKey(doc) ?? void 0;
2824
3133
  newId = objectPointerCodec2.encode({
2825
3134
  documentId,
2826
3135
  objectId,
@@ -2835,13 +3144,13 @@ var createSelectedDocumentsIterator = (automergeHost) => (
2835
3144
  }
2836
3145
  ];
2837
3146
  } catch (error) {
2838
- log8.error("Error loading document", {
3147
+ log9.error("Error loading document", {
2839
3148
  heads,
2840
3149
  id,
2841
3150
  error
2842
3151
  }, {
2843
- F: __dxlog_file9,
2844
- L: 71,
3152
+ F: __dxlog_file10,
3153
+ L: 73,
2845
3154
  S: this,
2846
3155
  C: (f, a) => f(...a)
2847
3156
  });
@@ -2850,39 +3159,148 @@ var createSelectedDocumentsIterator = (automergeHost) => (
2850
3159
  }
2851
3160
  );
2852
3161
 
3162
+ // src/db-host/local-queue-service.ts
3163
+ import * as Effect2 from "effect/Effect";
3164
+ import * as Function from "effect/Function";
3165
+ import { ATTR_META } from "@dxos/echo/internal";
3166
+ import { RuntimeProvider } from "@dxos/effect";
3167
+ import { invariant as invariant9 } from "@dxos/invariant";
3168
+ import { KEY_QUEUE_POSITION } from "@dxos/protocols";
3169
+ var __dxlog_file11 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/local-queue-service.ts";
3170
+ var LocalQueueServiceImpl = class {
3171
+ #runtime;
3172
+ #feedStore;
3173
+ constructor(runtime, feedStore) {
3174
+ this.#runtime = runtime;
3175
+ this.#feedStore = feedStore;
3176
+ }
3177
+ queryQueue(request) {
3178
+ const { query } = request;
3179
+ invariant9(query, "query is required", {
3180
+ F: __dxlog_file11,
3181
+ L: 37,
3182
+ S: this,
3183
+ A: [
3184
+ "query",
3185
+ "'query is required'"
3186
+ ]
3187
+ });
3188
+ const { spaceId, queueIds } = query;
3189
+ return RuntimeProvider.runPromise(this.#runtime)(Effect2.gen(this, function* () {
3190
+ const cursor = query.after ? parseInt(query.after) : -1;
3191
+ const result = yield* this.#feedStore.query({
3192
+ requestId: crypto.randomUUID(),
3193
+ spaceId,
3194
+ query: {
3195
+ feedIds: queueIds ?? []
3196
+ },
3197
+ position: cursor,
3198
+ limit: query.limit
3199
+ });
3200
+ const objects = result.blocks.map((block) => {
3201
+ const data = JSON.parse(new TextDecoder().decode(block.data));
3202
+ if (block.position !== null) {
3203
+ setQueuePosition(data, block.position);
3204
+ }
3205
+ return data;
3206
+ });
3207
+ const lastBlock = result.blocks[result.blocks.length - 1];
3208
+ const nextCursor = lastBlock && lastBlock.position != null ? String(lastBlock.position) : null;
3209
+ return Function.identity({
3210
+ objects,
3211
+ // TODO(dmaretskyi): This is wrong, fix later - cursors should come directly from the feed.
3212
+ nextCursor: nextCursor?.toString() ?? "",
3213
+ prevCursor: ""
3214
+ });
3215
+ }));
3216
+ }
3217
+ insertIntoQueue(request) {
3218
+ const { subspaceTag, spaceId, queueId, objects } = request;
3219
+ return RuntimeProvider.runPromise(this.#runtime)(Effect2.gen(this, function* () {
3220
+ const messages = objects.map((obj) => {
3221
+ const data = structuredClone(obj);
3222
+ if (data[ATTR_META]?.keys?.find((key) => key.source === KEY_QUEUE_POSITION)) {
3223
+ data[ATTR_META].keys = data[ATTR_META].keys.filter((key) => key.source !== KEY_QUEUE_POSITION);
3224
+ }
3225
+ return {
3226
+ spaceId,
3227
+ feedId: queueId,
3228
+ feedNamespace: subspaceTag,
3229
+ data: new TextEncoder().encode(JSON.stringify(obj))
3230
+ };
3231
+ });
3232
+ yield* this.#feedStore.appendLocal(messages);
3233
+ }));
3234
+ }
3235
+ deleteFromQueue(request) {
3236
+ const { subspaceTag, spaceId, queueId, objectIds } = request;
3237
+ return RuntimeProvider.runPromise(this.#runtime)(Effect2.gen(this, function* () {
3238
+ const messages = objectIds.map((id) => ({
3239
+ spaceId,
3240
+ feedId: queueId,
3241
+ feedNamespace: subspaceTag,
3242
+ data: new TextEncoder().encode(JSON.stringify({
3243
+ id,
3244
+ "@deleted": true
3245
+ }))
3246
+ }));
3247
+ yield* this.#feedStore.appendLocal(messages);
3248
+ }));
3249
+ }
3250
+ };
3251
+ var setQueuePosition = (obj, position) => {
3252
+ obj[ATTR_META] ??= {
3253
+ keys: []
3254
+ };
3255
+ obj[ATTR_META].keys ??= [];
3256
+ for (let i = 0; i < obj[ATTR_META].keys.length; i++) {
3257
+ const key = obj[ATTR_META].keys[i];
3258
+ if (key.source === KEY_QUEUE_POSITION) {
3259
+ obj[ATTR_META].keys.splice(i, 1);
3260
+ i--;
3261
+ }
3262
+ }
3263
+ obj[ATTR_META].keys.push({
3264
+ source: KEY_QUEUE_POSITION,
3265
+ id: position.toString()
3266
+ });
3267
+ };
3268
+
2853
3269
  // src/db-host/query-service.ts
2854
3270
  import { getHeads as getHeads3 } from "@automerge/automerge";
2855
3271
  import * as Schema from "effect/Schema";
2856
3272
  import { DeferredTask as DeferredTask2, scheduleMicroTask, synchronized as synchronized2 } from "@dxos/async";
2857
3273
  import { Stream as Stream2 } from "@dxos/codec-protobuf/stream";
2858
- import { Context as Context4, Resource as Resource7 } from "@dxos/context";
3274
+ import { Context as Context6, Resource as Resource7 } from "@dxos/context";
2859
3275
  import { raise } from "@dxos/debug";
2860
- import { DatabaseDirectory as DatabaseDirectory4, QueryAST } from "@dxos/echo-protocol";
2861
- import { log as log10 } from "@dxos/log";
3276
+ import { DatabaseDirectory as DatabaseDirectory5, QueryAST } from "@dxos/echo-protocol";
3277
+ import { log as log11 } from "@dxos/log";
2862
3278
  import { objectPointerCodec as objectPointerCodec4 } from "@dxos/protocols";
2863
3279
  import { trace as trace4 } from "@dxos/tracing";
2864
3280
 
2865
3281
  // src/query/query-executor.ts
2866
3282
  import * as Match from "effect/Match";
2867
- import * as Predicate from "effect/Predicate";
2868
- import { Context as Context3, ContextDisposedError, LifecycleState as LifecycleState3, Resource as Resource6 } from "@dxos/context";
2869
- import { DatabaseDirectory as DatabaseDirectory3, ObjectStructure, isEncodedReference } from "@dxos/echo-protocol";
3283
+ import * as Runtime from "effect/Runtime";
3284
+ import { Context as Context5, ContextDisposedError, LifecycleState as LifecycleState3, Resource as Resource6 } from "@dxos/context";
3285
+ import { ATTR_RELATION_SOURCE, ATTR_RELATION_TARGET } from "@dxos/echo/internal";
3286
+ import { DatabaseDirectory as DatabaseDirectory4, ObjectStructure, isEncodedReference } from "@dxos/echo-protocol";
3287
+ import { runAndForwardErrors, unwrapExit } from "@dxos/effect";
2870
3288
  import { EscapedPropPath } from "@dxos/indexing";
2871
- import { invariant as invariant10 } from "@dxos/invariant";
2872
- import { DXN, PublicKey as PublicKey3 } from "@dxos/keys";
2873
- import { log as log9 } from "@dxos/log";
3289
+ import { invariant as invariant11 } from "@dxos/invariant";
3290
+ import { DXN, PublicKey as PublicKey4 } from "@dxos/keys";
3291
+ import { log as log10 } from "@dxos/log";
2874
3292
  import { objectPointerCodec as objectPointerCodec3 } from "@dxos/protocols";
2875
3293
  import { getDeep, isNonNullable as isNonNullable3 } from "@dxos/util";
2876
3294
 
2877
3295
  // src/query/query-planner.ts
2878
3296
  import { Order } from "@dxos/echo";
2879
- import { invariant as invariant9 } from "@dxos/invariant";
3297
+ import { invariant as invariant10 } from "@dxos/invariant";
2880
3298
 
2881
3299
  // src/query/errors.ts
2882
3300
  import { BaseError } from "@dxos/errors";
2883
- var QueryError = class extends BaseError.extend("QUERY_ERROR") {
3301
+ var QueryError = class extends BaseError.extend("QueryError") {
2884
3302
  };
2885
- var InvalidQueryError = class extends QueryError.extend("INVALID_QUERY") {
3303
+ var InvalidQueryError = class extends QueryError.extend("InvalidQueryError") {
2886
3304
  };
2887
3305
 
2888
3306
  // src/query/plan.ts
@@ -2907,7 +3325,7 @@ var InvalidQueryError = class extends QueryError.extend("INVALID_QUERY") {
2907
3325
  var QueryPlan;
2908
3326
 
2909
3327
  // src/query/query-planner.ts
2910
- var __dxlog_file10 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-planner.ts";
3328
+ var __dxlog_file12 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-planner.ts";
2911
3329
  var DEFAULT_OPTIONS = {
2912
3330
  defaultTextSearchKind: "full-text"
2913
3331
  };
@@ -2927,6 +3345,7 @@ var QueryPlanner = class {
2927
3345
  plan = this._optimizeEmptyFilters(plan);
2928
3346
  plan = this._optimizeSoloUnions(plan);
2929
3347
  plan = this._ensureOrderStep(plan);
3348
+ plan = this._optimizeLimits(plan);
2930
3349
  return plan;
2931
3350
  }
2932
3351
  _generate(query, context) {
@@ -2951,6 +3370,8 @@ var QueryPlanner = class {
2951
3370
  return this._generateSetDifferenceClause(query, context);
2952
3371
  case "order":
2953
3372
  return this._generateOrderClause(query, context);
3373
+ case "limit":
3374
+ return this._generateLimitClause(query, context);
2954
3375
  default:
2955
3376
  throw new QueryError({
2956
3377
  message: `Unsupported query type: ${query.type}`,
@@ -2967,6 +3388,12 @@ var QueryPlanner = class {
2967
3388
  if (query.options.spaceIds) {
2968
3389
  newContext.selectionSpaces = query.options.spaceIds;
2969
3390
  }
3391
+ if (query.options.allQueuesFromSpaces !== void 0) {
3392
+ newContext.selectionAllQueuesFromSpaces = query.options.allQueuesFromSpaces;
3393
+ }
3394
+ if (query.options.queues) {
3395
+ newContext.selectionQueues = query.options.queues;
3396
+ }
2970
3397
  if (query.options.deleted) {
2971
3398
  newContext.deletedHandling = query.options.deleted;
2972
3399
  }
@@ -3002,6 +3429,8 @@ var QueryPlanner = class {
3002
3429
  {
3003
3430
  _tag: "SelectStep",
3004
3431
  spaces: context.selectionSpaces,
3432
+ allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
3433
+ queues: context.selectionQueues,
3005
3434
  selector: {
3006
3435
  _tag: "IdSelector",
3007
3436
  objectIds: filter2.id
@@ -3021,6 +3450,8 @@ var QueryPlanner = class {
3021
3450
  {
3022
3451
  _tag: "SelectStep",
3023
3452
  spaces: context.selectionSpaces,
3453
+ allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
3454
+ queues: context.selectionQueues,
3024
3455
  selector: {
3025
3456
  _tag: "TypeSelector",
3026
3457
  typename: [
@@ -3030,11 +3461,11 @@ var QueryPlanner = class {
3030
3461
  }
3031
3462
  },
3032
3463
  ...this._generateDeletedHandlingSteps(context),
3464
+ // TODO(dmaretskyi): Normally we could skip filtering by typename here, but since the index does not separate schema versions, we need to do additional filter to only select the correct version.
3033
3465
  {
3034
3466
  _tag: "FilterStep",
3035
3467
  filter: {
3036
- ...filter2,
3037
- typename: null
3468
+ ...filter2
3038
3469
  }
3039
3470
  }
3040
3471
  ]);
@@ -3043,6 +3474,8 @@ var QueryPlanner = class {
3043
3474
  {
3044
3475
  _tag: "SelectStep",
3045
3476
  spaces: context.selectionSpaces,
3477
+ allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
3478
+ queues: context.selectionQueues,
3046
3479
  selector: {
3047
3480
  _tag: "WildcardSelector"
3048
3481
  }
@@ -3063,6 +3496,8 @@ var QueryPlanner = class {
3063
3496
  {
3064
3497
  _tag: "SelectStep",
3065
3498
  spaces: context.selectionSpaces,
3499
+ allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
3500
+ queues: context.selectionQueues,
3066
3501
  selector: {
3067
3502
  _tag: "WildcardSelector"
3068
3503
  }
@@ -3082,10 +3517,13 @@ var QueryPlanner = class {
3082
3517
  {
3083
3518
  _tag: "SelectStep",
3084
3519
  spaces: context.selectionSpaces,
3520
+ allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
3521
+ queues: context.selectionQueues,
3085
3522
  selector: {
3086
3523
  _tag: "TextSelector",
3087
3524
  text: filter2.text,
3088
- searchKind: filter2.searchKind ?? this._options.defaultTextSearchKind
3525
+ searchKind: filter2.searchKind ?? this._options.defaultTextSearchKind,
3526
+ typename: null
3089
3527
  }
3090
3528
  },
3091
3529
  ...this._generateDeletedHandlingSteps(context)
@@ -3129,9 +3567,9 @@ var QueryPlanner = class {
3129
3567
  case "or":
3130
3568
  if (filter2.filters.every(isTrivialTypenameFilter)) {
3131
3569
  const typenames = filter2.filters.map((filter3) => {
3132
- invariant9(filter3.type === "object" && filter3.typename !== null, void 0, {
3133
- F: __dxlog_file10,
3134
- L: 224,
3570
+ invariant10(filter3.type === "object" && filter3.typename !== null, void 0, {
3571
+ F: __dxlog_file12,
3572
+ L: 245,
3135
3573
  S: this,
3136
3574
  A: [
3137
3575
  "filter.type === 'object' && filter.typename !== null",
@@ -3144,13 +3582,21 @@ var QueryPlanner = class {
3144
3582
  {
3145
3583
  _tag: "SelectStep",
3146
3584
  spaces: context.selectionSpaces,
3585
+ allQueuesFromSpaces: context.selectionAllQueuesFromSpaces,
3586
+ queues: context.selectionQueues,
3147
3587
  selector: {
3148
3588
  _tag: "TypeSelector",
3149
3589
  typename: typenames,
3150
3590
  inverted: context.selectionInverted
3151
3591
  }
3152
3592
  },
3153
- ...this._generateDeletedHandlingSteps(context)
3593
+ ...this._generateDeletedHandlingSteps(context),
3594
+ {
3595
+ _tag: "FilterStep",
3596
+ filter: {
3597
+ ...filter2
3598
+ }
3599
+ }
3154
3600
  ]);
3155
3601
  } else {
3156
3602
  throw new QueryError({
@@ -3228,7 +3674,7 @@ var QueryPlanner = class {
3228
3674
  traversal: {
3229
3675
  _tag: "ReferenceTraversal",
3230
3676
  direction: "incoming",
3231
- property: query.property
3677
+ property: query.property ?? null
3232
3678
  }
3233
3679
  },
3234
3680
  ...this._generateDeletedHandlingSteps(context),
@@ -3371,40 +3817,156 @@ var QueryPlanner = class {
3371
3817
  }
3372
3818
  ]);
3373
3819
  }
3820
+ _generateLimitClause(query, context) {
3821
+ return QueryPlan.Plan.make([
3822
+ ...this._generate(query.query, context).steps,
3823
+ {
3824
+ _tag: "LimitStep",
3825
+ limit: query.limit
3826
+ }
3827
+ ]);
3828
+ }
3374
3829
  // After complete plan is built, inspect it from the end:
3375
3830
  // - Walk backwards until hitting an object set changer.
3376
3831
  // - If an order step is found, skip.
3377
- // - Otherwise append natural order to the end.
3832
+ // - Otherwise insert natural order before any limit steps (since limit should be applied after ordering).
3833
+ // This method is recursive and also processes sub-plans in unions and set differences.
3378
3834
  _ensureOrderStep(plan) {
3835
+ const processedSteps = plan.steps.map((step) => {
3836
+ if (step._tag === "UnionStep") {
3837
+ return {
3838
+ _tag: "UnionStep",
3839
+ plans: step.plans.map((subPlan) => this._ensureOrderStep(subPlan))
3840
+ };
3841
+ } else if (step._tag === "SetDifferenceStep") {
3842
+ return {
3843
+ _tag: "SetDifferenceStep",
3844
+ source: this._ensureOrderStep(step.source),
3845
+ exclude: this._ensureOrderStep(step.exclude)
3846
+ };
3847
+ }
3848
+ return step;
3849
+ });
3850
+ const processedPlan = QueryPlan.Plan.make(processedSteps);
3379
3851
  const OBJECT_SET_CHANGERS = /* @__PURE__ */ new Set([
3380
3852
  "SelectStep",
3381
3853
  "TraverseStep",
3382
3854
  "UnionStep",
3383
3855
  "SetDifferenceStep"
3384
3856
  ]);
3385
- for (let i = plan.steps.length - 1; i >= 0; i--) {
3386
- const step = plan.steps[i];
3857
+ for (let i = processedPlan.steps.length - 1; i >= 0; i--) {
3858
+ const step = processedPlan.steps[i];
3387
3859
  if (step._tag === "OrderStep") {
3388
- return plan;
3860
+ return processedPlan;
3389
3861
  }
3390
3862
  if (OBJECT_SET_CHANGERS.has(step._tag)) {
3391
3863
  break;
3392
3864
  }
3393
3865
  }
3394
- return QueryPlan.Plan.make([
3395
- ...plan.steps,
3396
- {
3397
- _tag: "OrderStep",
3398
- order: [
3399
- Order.natural.ast
3400
- ]
3866
+ let insertIndex = processedPlan.steps.length;
3867
+ for (let i = processedPlan.steps.length - 1; i >= 0; i--) {
3868
+ if (processedPlan.steps[i]._tag === "LimitStep") {
3869
+ insertIndex = i;
3870
+ } else {
3871
+ break;
3872
+ }
3873
+ }
3874
+ const newSteps = [
3875
+ ...processedPlan.steps
3876
+ ];
3877
+ newSteps.splice(insertIndex, 0, {
3878
+ _tag: "OrderStep",
3879
+ order: [
3880
+ Order.natural.ast
3881
+ ]
3882
+ });
3883
+ return QueryPlan.Plan.make(newSteps);
3884
+ }
3885
+ /**
3886
+ * Propagates limits from LimitStep to SelectStep and OrderStep when possible.
3887
+ * Limits can only be propagated if there are no unions or traversals between the LimitStep and SelectStep/OrderStep.
3888
+ */
3889
+ _optimizeLimits(plan) {
3890
+ const processedSteps = plan.steps.map((step) => {
3891
+ if (step._tag === "UnionStep") {
3892
+ return {
3893
+ _tag: "UnionStep",
3894
+ plans: step.plans.map((subPlan) => this._optimizeLimits(subPlan))
3895
+ };
3896
+ } else if (step._tag === "SetDifferenceStep") {
3897
+ return {
3898
+ _tag: "SetDifferenceStep",
3899
+ source: this._optimizeLimits(step.source),
3900
+ exclude: this._optimizeLimits(step.exclude)
3901
+ };
3902
+ }
3903
+ return step;
3904
+ });
3905
+ let limitStepIndex = -1;
3906
+ let limitValue;
3907
+ for (let i = processedSteps.length - 1; i >= 0; i--) {
3908
+ const step = processedSteps[i];
3909
+ if (step._tag === "LimitStep") {
3910
+ limitStepIndex = i;
3911
+ limitValue = step.limit;
3912
+ break;
3913
+ }
3914
+ if (step._tag !== "OrderStep") {
3915
+ break;
3401
3916
  }
3917
+ }
3918
+ if (limitStepIndex === -1 || limitValue === void 0) {
3919
+ return QueryPlan.Plan.make(processedSteps);
3920
+ }
3921
+ const BLOCKERS = /* @__PURE__ */ new Set([
3922
+ "UnionStep",
3923
+ "TraverseStep",
3924
+ "SetDifferenceStep"
3402
3925
  ]);
3926
+ let selectStepIndex = -1;
3927
+ let orderStepIndex = -1;
3928
+ for (let i = 0; i < limitStepIndex; i++) {
3929
+ const step = processedSteps[i];
3930
+ if (step._tag === "SelectStep") {
3931
+ selectStepIndex = i;
3932
+ }
3933
+ if (step._tag === "OrderStep") {
3934
+ orderStepIndex = i;
3935
+ }
3936
+ if (BLOCKERS.has(step._tag)) {
3937
+ selectStepIndex = -1;
3938
+ orderStepIndex = -1;
3939
+ }
3940
+ }
3941
+ if (selectStepIndex === -1 && orderStepIndex === -1) {
3942
+ return QueryPlan.Plan.make(processedSteps);
3943
+ }
3944
+ const newSteps = [
3945
+ ...processedSteps
3946
+ ];
3947
+ if (selectStepIndex !== -1) {
3948
+ const selectStep = newSteps[selectStepIndex];
3949
+ newSteps[selectStepIndex] = {
3950
+ ...selectStep,
3951
+ limit: limitValue
3952
+ };
3953
+ }
3954
+ if (orderStepIndex !== -1) {
3955
+ const orderStep = newSteps[orderStepIndex];
3956
+ newSteps[orderStepIndex] = {
3957
+ ...orderStep,
3958
+ limit: limitValue
3959
+ };
3960
+ }
3961
+ newSteps.splice(limitStepIndex, 1);
3962
+ return QueryPlan.Plan.make(newSteps);
3403
3963
  }
3404
3964
  };
3405
3965
  var DEFAULT_CONTEXT = {
3406
3966
  originalQuery: null,
3407
3967
  selectionSpaces: [],
3968
+ selectionAllQueuesFromSpaces: false,
3969
+ selectionQueues: [],
3408
3970
  deletedHandling: "exclude",
3409
3971
  selectionInverted: false
3410
3972
  };
@@ -3426,7 +3988,45 @@ var isTrivialTypenameFilter = (filter2) => {
3426
3988
  };
3427
3989
 
3428
3990
  // src/query/query-executor.ts
3429
- var __dxlog_file11 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-executor.ts";
3991
+ var __dxlog_file13 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/query/query-executor.ts";
3992
+ var QueryItem = Object.freeze({
3993
+ isDeleted: (item) => {
3994
+ if (item.doc) {
3995
+ return ObjectStructure.isDeleted(item.doc);
3996
+ } else if (item.data) {
3997
+ return item.data["@deleted"] === true;
3998
+ } else {
3999
+ throw new Error("Invalid query item");
4000
+ }
4001
+ },
4002
+ getProperty: (item, property) => {
4003
+ if (item.doc) {
4004
+ return getDeep(item.doc.data, property);
4005
+ } else if (item.data) {
4006
+ return getDeep(item.data, property);
4007
+ } else {
4008
+ throw new Error("Invalid query item");
4009
+ }
4010
+ },
4011
+ getRelationSource: (item) => {
4012
+ if (item.doc) {
4013
+ return ObjectStructure.getRelationSource(item.doc)?.["/"];
4014
+ } else if (item.data) {
4015
+ return item.data[ATTR_RELATION_SOURCE];
4016
+ } else {
4017
+ throw new Error("Invalid query item");
4018
+ }
4019
+ },
4020
+ getRelationTarget: (item) => {
4021
+ if (item.doc) {
4022
+ return ObjectStructure.getRelationTarget(item.doc)?.["/"];
4023
+ } else if (item.data) {
4024
+ return item.data[ATTR_RELATION_TARGET];
4025
+ } else {
4026
+ throw new Error("Invalid query item");
4027
+ }
4028
+ }
4029
+ });
3430
4030
  var ExecutionTrace = Object.freeze({
3431
4031
  makeEmpty: () => ({
3432
4032
  name: "Empty",
@@ -3498,8 +4098,10 @@ var ExecutionTrace = Object.freeze({
3498
4098
  }
3499
4099
  });
3500
4100
  var TRACE_QUERY_EXECUTION = false;
3501
- var QueryExecutor = class extends Resource6 {
4101
+ var QueryExecutor = class _QueryExecutor extends Resource6 {
3502
4102
  _indexer;
4103
+ _indexer2;
4104
+ _runtime;
3503
4105
  _automergeHost;
3504
4106
  _spaceStateManager;
3505
4107
  /**
@@ -3515,6 +4117,8 @@ var QueryExecutor = class extends Resource6 {
3515
4117
  constructor(options) {
3516
4118
  super();
3517
4119
  this._indexer = options.indexer;
4120
+ this._indexer2 = options.indexer2;
4121
+ this._runtime = options.runtime;
3518
4122
  this._automergeHost = options.automergeHost;
3519
4123
  this._spaceStateManager = options.spaceStateManager;
3520
4124
  this._id = options.queryId;
@@ -3532,23 +4136,21 @@ var QueryExecutor = class extends Resource6 {
3532
4136
  get trace() {
3533
4137
  return this._trace;
3534
4138
  }
3535
- async _open(ctx) {
3536
- }
3537
- async _close(ctx) {
3538
- }
3539
4139
  getResults() {
3540
4140
  return this._lastResultSet.map((item) => ({
3541
4141
  id: item.objectId,
3542
- documentId: item.documentId,
4142
+ documentId: item.documentId ?? void 0,
4143
+ queueId: item.queueId ?? void 0,
4144
+ queueNamespace: item.queueNamespace ?? void 0,
3543
4145
  spaceId: item.spaceId,
3544
- // TODO(dmaretskyi): Plumb through the rank.
3545
- rank: 0
4146
+ rank: item.rank,
4147
+ documentJson: item.doc ? JSON.stringify(item.doc) : item.data ? JSON.stringify(item.data) : void 0
3546
4148
  }));
3547
4149
  }
3548
4150
  async execQuery() {
3549
- invariant10(this._lifecycleState === LifecycleState3.OPEN, void 0, {
3550
- F: __dxlog_file11,
3551
- L: 211,
4151
+ invariant11(this._lifecycleState === LifecycleState3.OPEN, void 0, {
4152
+ F: __dxlog_file13,
4153
+ L: 285,
3552
4154
  S: this,
3553
4155
  A: [
3554
4156
  "this._lifecycleState === LifecycleState.OPEN",
@@ -3573,7 +4175,6 @@ var QueryExecutor = class extends Resource6 {
3573
4175
  }
3574
4176
  async _execPlan(plan, workingSet) {
3575
4177
  const trace6 = ExecutionTrace.makeEmpty();
3576
- const begin = performance.now();
3577
4178
  for (const step of plan.steps) {
3578
4179
  if (this._ctx.disposed) {
3579
4180
  throw new ContextDisposedError();
@@ -3624,6 +4225,9 @@ var QueryExecutor = class extends Resource6 {
3624
4225
  case "OrderStep":
3625
4226
  ({ workingSet: newWorkingSet, trace: trace6 } = await this._execOrderStep(step, workingSet));
3626
4227
  break;
4228
+ case "LimitStep":
4229
+ ({ workingSet: newWorkingSet, trace: trace6 } = await this._execLimitStep(step, workingSet));
4230
+ break;
3627
4231
  default:
3628
4232
  throw new Error(`Unknown step type: ${step._tag}`);
3629
4233
  }
@@ -3646,24 +4250,42 @@ var QueryExecutor = class extends Resource6 {
3646
4250
  };
3647
4251
  switch (step.selector._tag) {
3648
4252
  case "WildcardSelector": {
3649
- const beginIndexQuery = performance.now();
3650
- const indexHits = await this._indexer.execQuery({
3651
- typenames: [],
3652
- inverted: false
3653
- });
3654
- trace6.indexHits = +indexHits.length;
3655
- trace6.indexQueryTime += performance.now() - beginIndexQuery;
3656
- if (this._ctx.disposed) {
3657
- return {
3658
- workingSet,
3659
- trace: trace6
3660
- };
4253
+ if (this._supportsSqlIndexing()) {
4254
+ const beginIndexQuery = performance.now();
4255
+ const metas = await this._queryAllFromSqlIndex(step.spaces);
4256
+ trace6.indexHits = metas.length;
4257
+ trace6.indexQueryTime += performance.now() - beginIndexQuery;
4258
+ if (this._ctx.disposed) {
4259
+ return {
4260
+ workingSet,
4261
+ trace: trace6
4262
+ };
4263
+ }
4264
+ const documentLoadStart = performance.now();
4265
+ const results = await this._loadDocumentsAfterSqlQuery(metas);
4266
+ trace6.documentsLoaded += results.length;
4267
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4268
+ workingSet.push(...results.filter(isNonNullable3));
4269
+ } else {
4270
+ const beginIndexQuery = performance.now();
4271
+ const indexHits = await this._indexer.execQuery({
4272
+ typenames: [],
4273
+ inverted: false
4274
+ });
4275
+ trace6.indexHits = +indexHits.length;
4276
+ trace6.indexQueryTime += performance.now() - beginIndexQuery;
4277
+ if (this._ctx.disposed) {
4278
+ return {
4279
+ workingSet,
4280
+ trace: trace6
4281
+ };
4282
+ }
4283
+ const documentLoadStart = performance.now();
4284
+ const results = await this._loadDocumentsAfterIndexQuery(indexHits);
4285
+ trace6.documentsLoaded += results.length;
4286
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4287
+ workingSet.push(...results.filter(isNonNullable3).filter((item) => step.spaces.includes(item.spaceId)));
3661
4288
  }
3662
- const documentLoadStart = performance.now();
3663
- const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3664
- trace6.documentsLoaded += results.length;
3665
- trace6.documentLoadTime += performance.now() - documentLoadStart;
3666
- workingSet.push(...results.filter(isNonNullable3).filter((item) => step.spaces.includes(item.spaceId)));
3667
4289
  trace6.objectCount = workingSet.length;
3668
4290
  break;
3669
4291
  }
@@ -3678,66 +4300,182 @@ var QueryExecutor = class extends Resource6 {
3678
4300
  break;
3679
4301
  }
3680
4302
  case "TypeSelector": {
3681
- const beginIndexQuery = performance.now();
3682
- const indexHits = await this._indexer.execQuery({
3683
- typenames: step.selector.typename,
3684
- inverted: step.selector.inverted
3685
- });
3686
- trace6.indexHits = +indexHits.length;
3687
- trace6.indexQueryTime += performance.now() - beginIndexQuery;
3688
- if (this._ctx.disposed) {
3689
- return {
3690
- workingSet,
3691
- trace: trace6
3692
- };
4303
+ if (this._supportsSqlIndexing()) {
4304
+ const beginIndexQuery = performance.now();
4305
+ const metas = await this._queryTypesFromSqlIndex(step.spaces, step.selector.typename, step.selector.inverted);
4306
+ trace6.indexHits = metas.length;
4307
+ trace6.indexQueryTime += performance.now() - beginIndexQuery;
4308
+ if (this._ctx.disposed) {
4309
+ return {
4310
+ workingSet,
4311
+ trace: trace6
4312
+ };
4313
+ }
4314
+ const documentLoadStart = performance.now();
4315
+ const results = await this._loadDocumentsAfterSqlQuery(metas);
4316
+ trace6.documentsLoaded += results.length;
4317
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4318
+ workingSet.push(...results.filter(isNonNullable3));
4319
+ } else {
4320
+ const beginIndexQuery = performance.now();
4321
+ const indexHits = await this._indexer.execQuery({
4322
+ typenames: step.selector.typename,
4323
+ inverted: step.selector.inverted
4324
+ });
4325
+ trace6.indexHits = +indexHits.length;
4326
+ trace6.indexQueryTime += performance.now() - beginIndexQuery;
4327
+ if (this._ctx.disposed) {
4328
+ return {
4329
+ workingSet,
4330
+ trace: trace6
4331
+ };
4332
+ }
4333
+ const documentLoadStart = performance.now();
4334
+ const results = await this._loadDocumentsAfterIndexQuery(indexHits);
4335
+ trace6.documentsLoaded += results.length;
4336
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4337
+ workingSet.push(...results.filter(isNonNullable3).filter((item) => step.spaces.includes(item.spaceId)));
3693
4338
  }
3694
- const documentLoadStart = performance.now();
3695
- const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3696
- trace6.documentsLoaded += results.length;
3697
- trace6.documentLoadTime += performance.now() - documentLoadStart;
3698
- workingSet.push(...results.filter(isNonNullable3).filter((item) => step.spaces.includes(item.spaceId)));
3699
4339
  trace6.objectCount = workingSet.length;
3700
4340
  break;
3701
4341
  }
3702
4342
  case "TextSelector": {
3703
- const beginIndexQuery = performance.now();
3704
- const indexHits = await this._indexer.execQuery({
3705
- typenames: [],
3706
- text: {
4343
+ if (step.selector.searchKind === "full-text" && this._supportsSqlIndexing()) {
4344
+ const beginIndexQuery = performance.now();
4345
+ invariant11(this._indexer2, "SQL indexer is required.", {
4346
+ F: __dxlog_file13,
4347
+ L: 492,
4348
+ S: this,
4349
+ A: [
4350
+ "this._indexer2",
4351
+ "'SQL indexer is required.'"
4352
+ ]
4353
+ });
4354
+ invariant11(step.spaces.length <= 1, "Multiple spaces are not supported for full-text search", {
4355
+ F: __dxlog_file13,
4356
+ L: 493,
4357
+ S: this,
4358
+ A: [
4359
+ "step.spaces.length <= 1",
4360
+ "'Multiple spaces are not supported for full-text search'"
4361
+ ]
4362
+ });
4363
+ const queueIds = step.queues.length > 0 ? step.queues.map((dxnStr) => DXN.parse(dxnStr).asQueueDXN()?.queueId).filter(Boolean) : null;
4364
+ const textResults = await this._runInRuntime(this._indexer2.queryText({
3707
4365
  query: step.selector.text,
3708
- kind: Match.type().pipe(Match.withReturnType(), Match.when("full-text", () => "text"), Match.when("vector", () => "vector"), Match.orElseAbsurd)(step.selector.searchKind)
4366
+ spaceId: step.spaces,
4367
+ includeAllQueues: step.allQueuesFromSpaces,
4368
+ queueIds
4369
+ }));
4370
+ trace6.indexHits = textResults.length;
4371
+ trace6.indexQueryTime += performance.now() - beginIndexQuery;
4372
+ if (this._ctx.disposed) {
4373
+ return {
4374
+ workingSet,
4375
+ trace: trace6
4376
+ };
3709
4377
  }
3710
- });
3711
- trace6.indexHits = +indexHits.length;
3712
- trace6.indexQueryTime += performance.now() - beginIndexQuery;
3713
- if (this._ctx.disposed) {
3714
- return {
3715
- workingSet,
3716
- trace: trace6
3717
- };
4378
+ const documentLoadStart = performance.now();
4379
+ const queueResults = textResults.filter((r) => r.queueId);
4380
+ const spaceResults = textResults.filter((r) => !r.queueId);
4381
+ const rankMap = new Map(textResults.map((r) => [
4382
+ r.recordId,
4383
+ r.rank
4384
+ ]));
4385
+ let queueItems = [];
4386
+ if (queueResults.length > 0) {
4387
+ const snapshots = await this._runInRuntime(this._indexer2.querySnapshotsJSON(queueResults.map((r) => r.recordId)));
4388
+ const snapshotMap = new Map(snapshots.map((s) => [
4389
+ s.recordId,
4390
+ s.snapshot
4391
+ ]));
4392
+ queueItems = queueResults.map((result) => {
4393
+ const snapshot = snapshotMap.get(result.recordId);
4394
+ if (!snapshot || typeof snapshot !== "object") {
4395
+ return null;
4396
+ }
4397
+ return {
4398
+ objectId: result.objectId,
4399
+ spaceId: result.spaceId,
4400
+ queueId: result.queueId,
4401
+ queueNamespace: "data",
4402
+ documentId: null,
4403
+ doc: null,
4404
+ data: snapshot,
4405
+ rank: rankMap.get(result.recordId) ?? 1
4406
+ };
4407
+ }).filter(isNonNullable3);
4408
+ }
4409
+ const spaceItems = await Promise.all(spaceResults.map(async (result) => {
4410
+ const dxn = DXN.fromLocalObjectId(result.objectId);
4411
+ const item = await this._loadFromDXN(dxn, {
4412
+ sourceSpaceId: result.spaceId
4413
+ });
4414
+ if (item) {
4415
+ item.rank = rankMap.get(result.recordId) ?? 1;
4416
+ }
4417
+ return item;
4418
+ }));
4419
+ const items = [
4420
+ ...queueItems,
4421
+ ...spaceItems.filter(isNonNullable3)
4422
+ ];
4423
+ trace6.documentsLoaded += items.length;
4424
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4425
+ workingSet.push(...items.filter((item) => step.spaces.includes(item.spaceId)));
4426
+ trace6.objectCount = workingSet.length;
4427
+ } else {
4428
+ const beginIndexQuery = performance.now();
4429
+ const indexHits = await this._indexer.execQuery({
4430
+ typenames: [],
4431
+ text: {
4432
+ query: step.selector.text,
4433
+ kind: Match.type().pipe(Match.withReturnType(), Match.when("full-text", () => "text"), Match.when("vector", () => "vector"), Match.orElseAbsurd)(step.selector.searchKind)
4434
+ }
4435
+ });
4436
+ trace6.indexHits = +indexHits.length;
4437
+ trace6.indexQueryTime += performance.now() - beginIndexQuery;
4438
+ if (this._ctx.disposed) {
4439
+ return {
4440
+ workingSet,
4441
+ trace: trace6
4442
+ };
4443
+ }
4444
+ const documentLoadStart = performance.now();
4445
+ const results = await this._loadDocumentsAfterIndexQuery(indexHits);
4446
+ trace6.documentsLoaded += results.length;
4447
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4448
+ workingSet.push(...results.filter(isNonNullable3).filter((item) => step.spaces.includes(item.spaceId)));
4449
+ trace6.objectCount = workingSet.length;
3718
4450
  }
3719
- const documentLoadStart = performance.now();
3720
- const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3721
- trace6.documentsLoaded += results.length;
3722
- trace6.documentLoadTime += performance.now() - documentLoadStart;
3723
- workingSet.push(...results.filter(isNonNullable3).filter((item) => step.spaces.includes(item.spaceId)));
3724
- trace6.objectCount = workingSet.length;
3725
4451
  break;
3726
4452
  }
3727
4453
  default:
3728
4454
  throw new Error(`Unknown selector type: ${step.selector._tag}`);
3729
4455
  }
4456
+ if (step.limit !== void 0 && workingSet.length > step.limit) {
4457
+ workingSet = workingSet.slice(0, step.limit);
4458
+ trace6.objectCount = workingSet.length;
4459
+ }
3730
4460
  return {
3731
4461
  workingSet,
3732
4462
  trace: trace6
3733
4463
  };
3734
4464
  }
3735
4465
  async _execFilterStep(step, workingSet) {
3736
- const result = workingSet.filter((item) => filterMatchObject(step.filter, {
3737
- id: item.objectId,
3738
- spaceId: item.spaceId,
3739
- doc: item.doc
3740
- }));
4466
+ const result = workingSet.filter((item) => {
4467
+ if (item.doc) {
4468
+ return filterMatchObject(step.filter, {
4469
+ id: item.objectId,
4470
+ spaceId: item.spaceId,
4471
+ doc: item.doc
4472
+ });
4473
+ } else if (item.data) {
4474
+ return filterMatchObjectJSON(step.filter, item.data);
4475
+ } else {
4476
+ return false;
4477
+ }
4478
+ });
3741
4479
  return {
3742
4480
  workingSet: result,
3743
4481
  trace: {
@@ -3750,7 +4488,7 @@ var QueryExecutor = class extends Resource6 {
3750
4488
  }
3751
4489
  async _execFilterDeletedStep(step, workingSet) {
3752
4490
  const expected = step.mode === "only-deleted";
3753
- const result = workingSet.filter((item) => ObjectStructure.isDeleted(item.doc) === expected);
4491
+ const result = workingSet.filter((item) => QueryItem.isDeleted(item) === expected);
3754
4492
  return {
3755
4493
  workingSet: result,
3756
4494
  trace: {
@@ -3773,9 +4511,18 @@ var QueryExecutor = class extends Resource6 {
3773
4511
  case "ReferenceTraversal": {
3774
4512
  switch (step.traversal.direction) {
3775
4513
  case "outgoing": {
4514
+ invariant11(step.traversal.property !== null, "Outgoing reference traversal requires a property", {
4515
+ F: __dxlog_file13,
4516
+ L: 674,
4517
+ S: this,
4518
+ A: [
4519
+ "step.traversal.property !== null",
4520
+ "'Outgoing reference traversal requires a property'"
4521
+ ]
4522
+ });
3776
4523
  const property = EscapedPropPath.unescape(step.traversal.property);
3777
4524
  const refs = workingSet.flatMap((item) => {
3778
- const ref = getDeep(item.doc.data, property);
4525
+ const ref = QueryItem.getProperty(item, property);
3779
4526
  const refs2 = Array.isArray(ref) ? ref : [
3780
4527
  ref
3781
4528
  ];
@@ -3786,11 +4533,11 @@ var QueryExecutor = class extends Resource6 {
3786
4533
  spaceId: item.spaceId
3787
4534
  } : null;
3788
4535
  } catch {
3789
- log9.warn("invalid reference", {
4536
+ log10.warn("invalid reference", {
3790
4537
  ref: ref2["/"]
3791
4538
  }, {
3792
- F: __dxlog_file11,
3793
- L: 477,
4539
+ F: __dxlog_file13,
4540
+ L: 690,
3794
4541
  S: this,
3795
4542
  C: (f, a) => f(...a)
3796
4543
  });
@@ -3808,22 +4555,35 @@ var QueryExecutor = class extends Resource6 {
3808
4555
  break;
3809
4556
  }
3810
4557
  case "incoming": {
3811
- const indexHits = await this._indexer.execQuery({
3812
- typenames: [],
3813
- inverted: false,
3814
- graph: {
3815
- kind: "inbound-reference",
3816
- property: step.traversal.property,
3817
- anchors: workingSet.map((item) => item.objectId)
3818
- }
3819
- });
3820
- trace6.indexHits += indexHits.length;
3821
- const documentLoadStart = performance.now();
3822
- const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3823
- trace6.documentsLoaded += results.length;
3824
- trace6.documentLoadTime += performance.now() - documentLoadStart;
3825
- newWorkingSet.push(...results.filter(isNonNullable3));
3826
- trace6.objectCount = newWorkingSet.length;
4558
+ if (this._supportsSqlIndexing()) {
4559
+ const beginIndexQuery = performance.now();
4560
+ const metas = await this._queryIncomingReferencesFromSqlIndex(workingSet, step.traversal.property);
4561
+ trace6.indexHits += metas.length;
4562
+ trace6.indexQueryTime += performance.now() - beginIndexQuery;
4563
+ const documentLoadStart = performance.now();
4564
+ const results = await this._loadDocumentsAfterSqlQuery(metas);
4565
+ trace6.documentsLoaded += results.length;
4566
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4567
+ newWorkingSet.push(...results.filter(isNonNullable3));
4568
+ trace6.objectCount = newWorkingSet.length;
4569
+ } else {
4570
+ const indexHits = await this._indexer.execQuery({
4571
+ typenames: [],
4572
+ inverted: false,
4573
+ graph: {
4574
+ kind: "inbound-reference",
4575
+ property: step.traversal.property,
4576
+ anchors: workingSet.map((item) => item.objectId)
4577
+ }
4578
+ });
4579
+ trace6.indexHits += indexHits.length;
4580
+ const documentLoadStart = performance.now();
4581
+ const results = await this._loadDocumentsAfterIndexQuery(indexHits);
4582
+ trace6.documentsLoaded += results.length;
4583
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4584
+ newWorkingSet.push(...results.filter(isNonNullable3));
4585
+ trace6.objectCount = newWorkingSet.length;
4586
+ }
3827
4587
  break;
3828
4588
  }
3829
4589
  }
@@ -3834,21 +4594,18 @@ var QueryExecutor = class extends Resource6 {
3834
4594
  case "relation-to-source":
3835
4595
  case "relation-to-target": {
3836
4596
  const refs = workingSet.map((item) => {
3837
- const ref = step.traversal.direction === "relation-to-source" ? ObjectStructure.getRelationSource(item.doc) : ObjectStructure.getRelationTarget(item.doc);
3838
- if (!isEncodedReference(ref)) {
3839
- return null;
3840
- }
4597
+ const dxn = step.traversal.direction === "relation-to-source" ? QueryItem.getRelationSource(item) : QueryItem.getRelationTarget(item);
3841
4598
  try {
3842
4599
  return {
3843
- ref: DXN.parse(ref["/"]),
4600
+ ref: DXN.parse(dxn),
3844
4601
  spaceId: item.spaceId
3845
4602
  };
3846
4603
  } catch {
3847
- log9.warn("invalid reference", {
3848
- ref: ref["/"]
4604
+ log10.warn("invalid reference", {
4605
+ ref: dxn
3849
4606
  }, {
3850
- F: __dxlog_file11,
3851
- L: 540,
4607
+ F: __dxlog_file13,
4608
+ L: 764,
3852
4609
  S: this,
3853
4610
  C: (f, a) => f(...a)
3854
4611
  });
@@ -3866,22 +4623,35 @@ var QueryExecutor = class extends Resource6 {
3866
4623
  }
3867
4624
  case "source-to-relation":
3868
4625
  case "target-to-relation": {
3869
- const indexHits = await this._indexer.execQuery({
3870
- typenames: [],
3871
- inverted: false,
3872
- graph: {
3873
- kind: step.traversal.direction === "source-to-relation" ? "relation-source" : "relation-target",
3874
- anchors: workingSet.map((item) => item.objectId),
3875
- property: null
3876
- }
3877
- });
3878
- trace6.indexHits += indexHits.length;
3879
- const documentLoadStart = performance.now();
3880
- const results = await this._loadDocumentsAfterIndexQuery(indexHits);
3881
- trace6.documentsLoaded += results.length;
3882
- trace6.documentLoadTime += performance.now() - documentLoadStart;
3883
- newWorkingSet.push(...results.filter(isNonNullable3));
3884
- trace6.objectCount = newWorkingSet.length;
4626
+ if (this._supportsSqlIndexing()) {
4627
+ const beginIndexQuery = performance.now();
4628
+ const metas = await this._queryRelationsFromSqlIndex(workingSet, step.traversal.direction === "source-to-relation" ? "source" : "target");
4629
+ trace6.indexHits += metas.length;
4630
+ trace6.indexQueryTime += performance.now() - beginIndexQuery;
4631
+ const documentLoadStart = performance.now();
4632
+ const results = await this._loadDocumentsAfterSqlQuery(metas);
4633
+ trace6.documentsLoaded += results.length;
4634
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4635
+ newWorkingSet.push(...results.filter(isNonNullable3));
4636
+ trace6.objectCount = newWorkingSet.length;
4637
+ } else {
4638
+ const indexHits = await this._indexer.execQuery({
4639
+ typenames: [],
4640
+ inverted: false,
4641
+ graph: {
4642
+ kind: step.traversal.direction === "source-to-relation" ? "relation-source" : "relation-target",
4643
+ anchors: workingSet.map((item) => item.objectId),
4644
+ property: null
4645
+ }
4646
+ });
4647
+ trace6.indexHits += indexHits.length;
4648
+ const documentLoadStart = performance.now();
4649
+ const results = await this._loadDocumentsAfterIndexQuery(indexHits);
4650
+ trace6.documentsLoaded += results.length;
4651
+ trace6.documentLoadTime += performance.now() - documentLoadStart;
4652
+ newWorkingSet.push(...results.filter(isNonNullable3));
4653
+ trace6.objectCount = newWorkingSet.length;
4654
+ }
3885
4655
  break;
3886
4656
  }
3887
4657
  }
@@ -3938,19 +4708,39 @@ var QueryExecutor = class extends Resource6 {
3938
4708
  };
3939
4709
  }
3940
4710
  async _execOrderStep(step, workingSet) {
3941
- const sortedWorkingSet = [
4711
+ let sortedWorkingSet = [
3942
4712
  ...workingSet
3943
4713
  ].sort((a, b) => this._compareMultiOrder(a, b, step.order));
4714
+ if (step.limit !== void 0 && sortedWorkingSet.length > step.limit) {
4715
+ sortedWorkingSet = sortedWorkingSet.slice(0, step.limit);
4716
+ }
3944
4717
  return {
3945
4718
  workingSet: sortedWorkingSet,
3946
4719
  trace: {
3947
4720
  ...ExecutionTrace.makeEmpty(),
3948
4721
  name: "Order",
3949
- details: JSON.stringify(step.order),
4722
+ details: JSON.stringify({
4723
+ order: step.order,
4724
+ limit: step.limit
4725
+ }),
3950
4726
  objectCount: sortedWorkingSet.length
3951
4727
  }
3952
4728
  };
3953
4729
  }
4730
+ async _execLimitStep(step, workingSet) {
4731
+ const limitedWorkingSet = workingSet.slice(0, step.limit);
4732
+ return {
4733
+ workingSet: limitedWorkingSet,
4734
+ trace: {
4735
+ ...ExecutionTrace.makeEmpty(),
4736
+ name: "Limit",
4737
+ details: JSON.stringify({
4738
+ limit: step.limit
4739
+ }),
4740
+ objectCount: limitedWorkingSet.length
4741
+ }
4742
+ };
4743
+ }
3954
4744
  _compareMultiOrder(a, b, orders) {
3955
4745
  if (orders.length === 0) {
3956
4746
  return 0;
@@ -3973,13 +4763,21 @@ var QueryExecutor = class extends Resource6 {
3973
4763
  const comparison = this._compareByProperty(a, b, order.property);
3974
4764
  return order.direction === "desc" ? -comparison : comparison;
3975
4765
  }
4766
+ case "rank": {
4767
+ const comparison = a.rank - b.rank;
4768
+ return order.direction === "desc" ? -comparison : comparison;
4769
+ }
3976
4770
  default:
3977
4771
  return 0;
3978
4772
  }
3979
4773
  }
3980
4774
  _compareByProperty(a, b, property) {
3981
- const aValue = a.doc.data[property];
3982
- const bValue = b.doc.data[property];
4775
+ const aValue = QueryItem.getProperty(a, [
4776
+ property
4777
+ ]);
4778
+ const bValue = QueryItem.getProperty(b, [
4779
+ property
4780
+ ]);
3983
4781
  if (aValue == null && bValue == null) {
3984
4782
  return 0;
3985
4783
  }
@@ -4005,30 +4803,242 @@ var QueryExecutor = class extends Resource6 {
4005
4803
  return this._loadFromIndexHit(hit);
4006
4804
  }));
4007
4805
  }
4806
+ _supportsSqlIndexing() {
4807
+ return !!this._indexer2 && !!this._runtime;
4808
+ }
4809
+ async _runInRuntime(effect) {
4810
+ const runtimeProvider = this._runtime;
4811
+ invariant11(runtimeProvider, "SQL runtime is required.", {
4812
+ F: __dxlog_file13,
4813
+ L: 1002,
4814
+ S: this,
4815
+ A: [
4816
+ "runtimeProvider",
4817
+ "'SQL runtime is required.'"
4818
+ ]
4819
+ });
4820
+ const runtime = await runAndForwardErrors(runtimeProvider);
4821
+ return await unwrapExit(await effect.pipe(Runtime.runPromiseExit(runtime)));
4822
+ }
4823
+ async _queryAllFromSqlIndex(spaceIds) {
4824
+ invariant11(this._indexer2, "SQL indexer is required.", {
4825
+ F: __dxlog_file13,
4826
+ L: 1008,
4827
+ S: this,
4828
+ A: [
4829
+ "this._indexer2",
4830
+ "'SQL indexer is required.'"
4831
+ ]
4832
+ });
4833
+ return await this._runInRuntime(this._indexer2.queryAll({
4834
+ spaceIds
4835
+ }));
4836
+ }
4837
+ async _queryTypesFromSqlIndex(spaceIds, typeDxns, inverted) {
4838
+ invariant11(this._indexer2, "SQL indexer is required.", {
4839
+ F: __dxlog_file13,
4840
+ L: 1017,
4841
+ S: this,
4842
+ A: [
4843
+ "this._indexer2",
4844
+ "'SQL indexer is required.'"
4845
+ ]
4846
+ });
4847
+ return await this._runInRuntime(this._indexer2.queryTypes({
4848
+ spaceIds,
4849
+ typeDxns,
4850
+ inverted
4851
+ }));
4852
+ }
4853
+ async _queryIncomingReferencesFromSqlIndex(workingSet, property) {
4854
+ const anchorDxns = workingSet.map((item) => DXN.fromLocalObjectId(item.objectId).toString());
4855
+ invariant11(this._indexer2, "SQL indexer is required.", {
4856
+ F: __dxlog_file13,
4857
+ L: 1026,
4858
+ S: this,
4859
+ A: [
4860
+ "this._indexer2",
4861
+ "'SQL indexer is required.'"
4862
+ ]
4863
+ });
4864
+ const rows = (await Promise.all(anchorDxns.map((targetDxn) => this._runInRuntime(this._indexer2.queryReverseRef({
4865
+ targetDxn
4866
+ }))))).flat();
4867
+ const recordIds = rows.filter((row) => {
4868
+ if (property === null) {
4869
+ return true;
4870
+ }
4871
+ const queryPath = EscapedPropPath.unescape(property);
4872
+ const rowPath = EscapedPropPath.unescape(row.propPath);
4873
+ return _QueryExecutor._matchesReferencePropertyPath(rowPath, queryPath);
4874
+ }).map((row) => row.recordId);
4875
+ const uniqueRecordIds = Array.from(new Set(recordIds));
4876
+ return await this._runInRuntime(this._indexer2.lookupByRecordIds(uniqueRecordIds));
4877
+ }
4878
+ /**
4879
+ * Matches a reverse-reference row path against a query property path.
4880
+ * Allows numeric segments in the row path (array indices) that are not present in the query.
4881
+ *
4882
+ * Examples:
4883
+ * - query: ['assignee'] matches row: ['assignee'] and ['assignee', '0'].
4884
+ * - query: ['items', 'assignee'] matches row: ['items', '0', 'assignee'].
4885
+ * - query: ['a', 'b'] does NOT match row: ['a'].
4886
+ * - query: ['a'] does NOT match row: ['a', 'b'].
4887
+ */
4888
+ static _matchesReferencePropertyPath(rowPath, queryPath) {
4889
+ const isNumericSegment = (segment) => /^[0-9]+$/.test(segment);
4890
+ let i = 0;
4891
+ let j = 0;
4892
+ while (i < queryPath.length && j < rowPath.length) {
4893
+ if (rowPath[j] === queryPath[i]) {
4894
+ i++;
4895
+ j++;
4896
+ continue;
4897
+ }
4898
+ if (isNumericSegment(rowPath[j])) {
4899
+ j++;
4900
+ continue;
4901
+ }
4902
+ return false;
4903
+ }
4904
+ if (i !== queryPath.length) {
4905
+ return false;
4906
+ }
4907
+ for (; j < rowPath.length; j++) {
4908
+ if (!isNumericSegment(rowPath[j])) {
4909
+ return false;
4910
+ }
4911
+ }
4912
+ return true;
4913
+ }
4914
+ async _queryRelationsFromSqlIndex(workingSet, endpoint) {
4915
+ invariant11(this._indexer2, "SQL indexer is required.", {
4916
+ F: __dxlog_file13,
4917
+ L: 1100,
4918
+ S: this,
4919
+ A: [
4920
+ "this._indexer2",
4921
+ "'SQL indexer is required.'"
4922
+ ]
4923
+ });
4924
+ const anchorDxns = workingSet.map((item) => DXN.fromLocalObjectId(item.objectId).toString());
4925
+ return await this._runInRuntime(this._indexer2.queryRelations({
4926
+ endpoint,
4927
+ anchorDxns
4928
+ }));
4929
+ }
4930
+ async _loadDocumentsAfterSqlQuery(metas) {
4931
+ const snapshotMap = await this._loadQueueSnapshotMap(metas);
4932
+ return await Promise.all(metas.map(async (meta) => {
4933
+ if (meta.documentId) {
4934
+ return this._loadFromAutomerge(meta);
4935
+ }
4936
+ if (meta.queueId) {
4937
+ return this._loadFromQueue(meta, snapshotMap);
4938
+ }
4939
+ return null;
4940
+ }));
4941
+ }
4942
+ async _loadQueueSnapshotMap(metas) {
4943
+ const queueMetas = metas.filter((meta) => !meta.documentId && !!meta.queueId);
4944
+ if (queueMetas.length === 0) {
4945
+ return /* @__PURE__ */ new Map();
4946
+ }
4947
+ invariant11(this._indexer2, "SQL indexer is required.", {
4948
+ F: __dxlog_file13,
4949
+ L: 1130,
4950
+ S: this,
4951
+ A: [
4952
+ "this._indexer2",
4953
+ "'SQL indexer is required.'"
4954
+ ]
4955
+ });
4956
+ const snapshots = await this._runInRuntime(this._indexer2.querySnapshotsJSON(queueMetas.map((meta) => meta.recordId)));
4957
+ return new Map(snapshots.map((s) => [
4958
+ s.recordId,
4959
+ s.snapshot
4960
+ ]));
4961
+ }
4962
+ /**
4963
+ * Loads a queue-backed object from an indexed snapshot (by `recordId`).
4964
+ * Returns `null` when the snapshot is missing or is not a JSON object.
4965
+ */
4966
+ _loadFromQueue(meta, snapshotMap) {
4967
+ const snapshot = snapshotMap.get(meta.recordId);
4968
+ if (!snapshot || typeof snapshot !== "object") {
4969
+ return null;
4970
+ }
4971
+ return {
4972
+ objectId: meta.objectId,
4973
+ spaceId: meta.spaceId,
4974
+ queueId: meta.queueId,
4975
+ queueNamespace: "data",
4976
+ documentId: null,
4977
+ doc: null,
4978
+ data: snapshot,
4979
+ rank: 1
4980
+ };
4981
+ }
4982
+ /**
4983
+ * Loads a document-backed object from an Automerge `DatabaseDirectory`.
4984
+ * Returns `null` if the document can't be loaded, the inline object isn't present, or if the meta does not have a
4985
+ * document id (e.g. queue-backed objects).
4986
+ */
4987
+ async _loadFromAutomerge(meta) {
4988
+ if (!meta.documentId) {
4989
+ return null;
4990
+ }
4991
+ const handle = await this._automergeHost.loadDoc(Context5.default(void 0, {
4992
+ F: __dxlog_file13,
4993
+ L: 1169
4994
+ }), meta.documentId, {
4995
+ fetchFromNetwork: true
4996
+ });
4997
+ const doc = handle.doc();
4998
+ if (!doc) {
4999
+ return null;
5000
+ }
5001
+ const object = DatabaseDirectory4.getInlineObject(doc, meta.objectId);
5002
+ if (!object) {
5003
+ return null;
5004
+ }
5005
+ return {
5006
+ objectId: meta.objectId,
5007
+ documentId: meta.documentId,
5008
+ spaceId: meta.spaceId,
5009
+ queueId: null,
5010
+ queueNamespace: null,
5011
+ doc: object,
5012
+ data: null,
5013
+ rank: 1
5014
+ };
5015
+ }
4008
5016
  /**
4009
5017
  * Space key hex -> SpaceId.
4010
5018
  */
4011
5019
  _spaceIdCache = /* @__PURE__ */ new Map();
4012
5020
  async _loadFromIndexHit(hit) {
4013
5021
  const { objectId, documentId, spaceKey: spaceKeyInIndex } = objectPointerCodec3.decode(hit.id);
4014
- const handle = await this._automergeHost.loadDoc(Context3.default(void 0, {
4015
- F: __dxlog_file11,
4016
- L: 738
4017
- }), documentId);
5022
+ const handle = await this._automergeHost.loadDoc(Context5.default(void 0, {
5023
+ F: __dxlog_file13,
5024
+ L: 1203
5025
+ }), documentId, {
5026
+ fetchFromNetwork: true
5027
+ });
4018
5028
  const doc = handle.doc();
4019
5029
  if (!doc) {
4020
5030
  return null;
4021
5031
  }
4022
- const spaceKey = spaceKeyInIndex ?? DatabaseDirectory3.getSpaceKey(doc);
5032
+ const spaceKey = spaceKeyInIndex ?? DatabaseDirectory4.getSpaceKey(doc);
4023
5033
  if (!spaceKey) {
4024
5034
  return null;
4025
5035
  }
4026
5036
  let spaceId = this._spaceIdCache.get(spaceKey);
4027
5037
  if (!spaceId) {
4028
- spaceId = await createIdFromSpaceKey(PublicKey3.from(spaceKey));
5038
+ spaceId = await createIdFromSpaceKey(PublicKey4.from(spaceKey));
4029
5039
  this._spaceIdCache.set(spaceKey, spaceId);
4030
5040
  }
4031
- const object = DatabaseDirectory3.getInlineObject(doc, objectId);
5041
+ const object = DatabaseDirectory4.getInlineObject(doc, objectId);
4032
5042
  if (!object) {
4033
5043
  return null;
4034
5044
  }
@@ -4036,17 +5046,21 @@ var QueryExecutor = class extends Resource6 {
4036
5046
  objectId,
4037
5047
  documentId,
4038
5048
  spaceId,
4039
- doc: object
5049
+ queueId: null,
5050
+ queueNamespace: null,
5051
+ data: null,
5052
+ doc: object,
5053
+ rank: hit.rank
4040
5054
  };
4041
5055
  }
4042
5056
  async _loadFromDXN(dxn, { sourceSpaceId }) {
4043
5057
  const echoDxn = dxn.asEchoDXN();
4044
5058
  if (!echoDxn) {
4045
- log9.warn("unable to resolve DXN", {
5059
+ log10.warn("unable to resolve DXN", {
4046
5060
  dxn
4047
5061
  }, {
4048
- F: __dxlog_file11,
4049
- L: 771,
5062
+ F: __dxlog_file13,
5063
+ L: 1242,
4050
5064
  S: this,
4051
5065
  C: (f, a) => f(...a)
4052
5066
  });
@@ -4055,11 +5069,11 @@ var QueryExecutor = class extends Resource6 {
4055
5069
  const spaceId = echoDxn.spaceId ?? sourceSpaceId;
4056
5070
  const spaceRoot = this._spaceStateManager.getRootBySpaceId(spaceId);
4057
5071
  if (!spaceRoot) {
4058
- log9.warn("no space state found for", {
5072
+ log10.warn("no space state found for", {
4059
5073
  spaceId
4060
5074
  }, {
4061
- F: __dxlog_file11,
4062
- L: 779,
5075
+ F: __dxlog_file13,
5076
+ L: 1250,
4063
5077
  S: this,
4064
5078
  C: (f, a) => f(...a)
4065
5079
  });
@@ -4067,38 +5081,44 @@ var QueryExecutor = class extends Resource6 {
4067
5081
  }
4068
5082
  const dbDirectory = spaceRoot.doc();
4069
5083
  if (!dbDirectory) {
4070
- log9.warn("no space state found for", {
5084
+ log10.warn("no space state found for", {
4071
5085
  spaceId
4072
5086
  }, {
4073
- F: __dxlog_file11,
4074
- L: 784,
5087
+ F: __dxlog_file13,
5088
+ L: 1255,
4075
5089
  S: this,
4076
5090
  C: (f, a) => f(...a)
4077
5091
  });
4078
5092
  return null;
4079
5093
  }
4080
- const inlineObject = DatabaseDirectory3.getInlineObject(dbDirectory, echoDxn.echoId);
5094
+ const inlineObject = DatabaseDirectory4.getInlineObject(dbDirectory, echoDxn.echoId);
4081
5095
  if (inlineObject) {
4082
5096
  return {
4083
5097
  objectId: echoDxn.echoId,
4084
5098
  documentId: spaceRoot.documentId,
4085
5099
  spaceId,
4086
- doc: inlineObject
5100
+ queueId: null,
5101
+ queueNamespace: null,
5102
+ data: null,
5103
+ doc: inlineObject,
5104
+ rank: 1
4087
5105
  };
4088
5106
  }
4089
- const link = DatabaseDirectory3.getLink(dbDirectory, echoDxn.echoId);
5107
+ const link = DatabaseDirectory4.getLink(dbDirectory, echoDxn.echoId);
4090
5108
  if (!link) {
4091
5109
  return null;
4092
5110
  }
4093
- const handle = await this._automergeHost.loadDoc(Context3.default(void 0, {
4094
- F: __dxlog_file11,
4095
- L: 803
4096
- }), link);
5111
+ const handle = await this._automergeHost.loadDoc(Context5.default(void 0, {
5112
+ F: __dxlog_file13,
5113
+ L: 1278
5114
+ }), link, {
5115
+ fetchFromNetwork: true
5116
+ });
4097
5117
  const doc = handle.doc();
4098
5118
  if (!doc) {
4099
5119
  return null;
4100
5120
  }
4101
- const object = DatabaseDirectory3.getInlineObject(doc, echoDxn.echoId);
5121
+ const object = DatabaseDirectory4.getInlineObject(doc, echoDxn.echoId);
4102
5122
  if (!object) {
4103
5123
  return null;
4104
5124
  }
@@ -4106,7 +5126,11 @@ var QueryExecutor = class extends Resource6 {
4106
5126
  objectId: echoDxn.echoId,
4107
5127
  documentId: handle.documentId,
4108
5128
  spaceId,
4109
- doc: object
5129
+ queueId: null,
5130
+ queueNamespace: null,
5131
+ data: null,
5132
+ doc: object,
5133
+ rank: 1
4110
5134
  };
4111
5135
  }
4112
5136
  };
@@ -4118,7 +5142,7 @@ function _ts_decorate5(decorators, target, key, desc) {
4118
5142
  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;
4119
5143
  return c > 3 && r && Object.defineProperty(target, key, r), r;
4120
5144
  }
4121
- var __dxlog_file12 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/query-service.ts";
5145
+ var __dxlog_file14 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/query-service.ts";
4122
5146
  var QueryServiceImpl = class extends Resource7 {
4123
5147
  _params;
4124
5148
  // TODO(dmaretskyi): We need to implement query deduping. Idle composer has 80 queries with only 10 being unique.
@@ -4155,11 +5179,11 @@ var QueryServiceImpl = class extends Resource7 {
4155
5179
  execQuery(request) {
4156
5180
  return new Stream2(({ next, close, ctx }) => {
4157
5181
  if (this._params.indexer.config?.enabled !== true) {
4158
- log10.error("indexer is disabled", {
5182
+ log11.error("indexer is disabled", {
4159
5183
  config: this._params.indexer.config
4160
5184
  }, {
4161
- F: __dxlog_file12,
4162
- L: 102,
5185
+ F: __dxlog_file14,
5186
+ L: 107,
4163
5187
  S: this,
4164
5188
  C: (f, a) => f(...a)
4165
5189
  });
@@ -4179,9 +5203,9 @@ var QueryServiceImpl = class extends Resource7 {
4179
5203
  * Re-index all loaded documents.
4180
5204
  */
4181
5205
  async reindex() {
4182
- log10("Reindexing all documents...", void 0, {
4183
- F: __dxlog_file12,
4184
- L: 121,
5206
+ log11("Reindexing all documents...", void 0, {
5207
+ F: __dxlog_file14,
5208
+ L: 126,
4185
5209
  S: this,
4186
5210
  C: (f, a) => f(...a)
4187
5211
  });
@@ -4192,21 +5216,21 @@ var QueryServiceImpl = class extends Resource7 {
4192
5216
  ids.set(id, heads);
4193
5217
  }
4194
5218
  if (ids.size % 100 === 0) {
4195
- log10("Collected documents...", {
5219
+ log11("Collected documents...", {
4196
5220
  count: ids.size
4197
5221
  }, {
4198
- F: __dxlog_file12,
4199
- L: 129,
5222
+ F: __dxlog_file14,
5223
+ L: 134,
4200
5224
  S: this,
4201
5225
  C: (f, a) => f(...a)
4202
5226
  });
4203
5227
  }
4204
5228
  }
4205
- log10("Marking all documents as dirty...", {
5229
+ log11("Marking all documents as dirty...", {
4206
5230
  count: ids.size
4207
5231
  }, {
4208
- F: __dxlog_file12,
4209
- L: 133,
5232
+ F: __dxlog_file14,
5233
+ L: 138,
4210
5234
  S: this,
4211
5235
  C: (f, a) => f(...a)
4212
5236
  });
@@ -4226,6 +5250,8 @@ var QueryServiceImpl = class extends Resource7 {
4226
5250
  const queryEntry = {
4227
5251
  executor: new QueryExecutor({
4228
5252
  indexer: this._params.indexer,
5253
+ indexer2: this._params.indexer2,
5254
+ runtime: this._params.runtime,
4229
5255
  automergeHost: this._params.automergeHost,
4230
5256
  queryId: request.queryId ?? raise(new Error("query id required")),
4231
5257
  query: parsedQuery,
@@ -4270,20 +5296,20 @@ var QueryServiceImpl = class extends Resource7 {
4270
5296
  query.sendResults(query.executor.getResults());
4271
5297
  }
4272
5298
  } catch (err) {
4273
- log10.catch(err, void 0, {
4274
- F: __dxlog_file12,
4275
- L: 204,
5299
+ log11.catch(err, void 0, {
5300
+ F: __dxlog_file14,
5301
+ L: 211,
4276
5302
  S: this,
4277
5303
  C: (f, a) => f(...a)
4278
5304
  });
4279
5305
  }
4280
5306
  }));
4281
- log10.verbose("executed queries", {
5307
+ log11.verbose("executed queries", {
4282
5308
  count,
4283
5309
  duration: performance.now() - begin
4284
5310
  }, {
4285
- F: __dxlog_file12,
4286
- L: 208,
5311
+ F: __dxlog_file14,
5312
+ L: 215,
4287
5313
  S: this,
4288
5314
  C: (f, a) => f(...a)
4289
5315
  });
@@ -4312,7 +5338,7 @@ var createDocumentsIterator = (automergeHost) => (
4312
5338
  return;
4313
5339
  }
4314
5340
  const doc = handle.doc();
4315
- const spaceKey = DatabaseDirectory4.getSpaceKey(doc) ?? void 0;
5341
+ const spaceKey = DatabaseDirectory5.getSpaceKey(doc) ?? void 0;
4316
5342
  if (doc.objects) {
4317
5343
  yield Object.entries(doc.objects).map(([objectId, object]) => {
4318
5344
  return {
@@ -4332,10 +5358,12 @@ var createDocumentsIterator = (automergeHost) => (
4332
5358
  if (visited.has(urlString)) {
4333
5359
  continue;
4334
5360
  }
4335
- const linkHandle = await automergeHost.loadDoc(Context4.default(void 0, {
4336
- F: __dxlog_file12,
4337
- L: 248
4338
- }), urlString);
5361
+ const linkHandle = await automergeHost.loadDoc(Context6.default(void 0, {
5362
+ F: __dxlog_file14,
5363
+ L: 256
5364
+ }), urlString, {
5365
+ fetchFromNetwork: true
5366
+ });
4339
5367
  for await (const result of getObjectsFromHandle(linkHandle)) {
4340
5368
  yield result;
4341
5369
  }
@@ -4343,7 +5371,7 @@ var createDocumentsIterator = (automergeHost) => (
4343
5371
  }
4344
5372
  visited.add(handle.documentId);
4345
5373
  }
4346
- for (const handle of Object.values(automergeHost.repo.handles)) {
5374
+ for (const handle of Object.values(automergeHost.handles)) {
4347
5375
  if (visited.has(handle.documentId)) {
4348
5376
  continue;
4349
5377
  }
@@ -4355,22 +5383,127 @@ var createDocumentsIterator = (automergeHost) => (
4355
5383
  }
4356
5384
  );
4357
5385
 
5386
+ // src/db-host/queue-data-source.ts
5387
+ import * as Effect3 from "effect/Effect";
5388
+ import { RuntimeProvider as RuntimeProvider2 } from "@dxos/effect";
5389
+ import { FeedCursor } from "@dxos/feed";
5390
+ import { failedInvariant } from "@dxos/invariant";
5391
+ import { log as log12 } from "@dxos/log";
5392
+ var __dxlog_file15 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/queue-data-source.ts";
5393
+ var QueueDataSource = class {
5394
+ sourceName = "queue";
5395
+ _feedStore;
5396
+ _runtime;
5397
+ _getSpaceIds;
5398
+ constructor(options) {
5399
+ this._feedStore = options.feedStore;
5400
+ this._runtime = options.runtime;
5401
+ this._getSpaceIds = options.getSpaceIds;
5402
+ }
5403
+ getChangedObjects(cursors, opts) {
5404
+ return Effect3.gen(this, function* () {
5405
+ const objects = [];
5406
+ const updatedCursors = [];
5407
+ const existingSpaceIds = new Set(cursors.map((c) => c.spaceId).filter(Boolean));
5408
+ const allSpaceIds = this._getSpaceIds();
5409
+ const augmentedCursors = [
5410
+ ...cursors
5411
+ ];
5412
+ for (const spaceId of allSpaceIds) {
5413
+ if (!existingSpaceIds.has(spaceId)) {
5414
+ augmentedCursors.push({
5415
+ spaceId,
5416
+ resourceId: null,
5417
+ cursor: ""
5418
+ });
5419
+ }
5420
+ }
5421
+ let remainingLimit = opts?.limit ?? Infinity;
5422
+ for (const cursor of augmentedCursors) {
5423
+ if (remainingLimit <= 0) {
5424
+ updatedCursors.push(cursor);
5425
+ continue;
5426
+ }
5427
+ if (!cursor.spaceId) {
5428
+ updatedCursors.push(cursor);
5429
+ continue;
5430
+ }
5431
+ const currentCursor = typeof cursor.cursor === "string" && cursor.cursor !== "" ? FeedCursor.make(cursor.cursor) : void 0;
5432
+ try {
5433
+ const result = yield* this._feedStore.query({
5434
+ spaceId: cursor.spaceId,
5435
+ cursor: currentCursor,
5436
+ query: {
5437
+ // Query all feeds in data namespace
5438
+ feedNamespace: "data"
5439
+ },
5440
+ limit: remainingLimit
5441
+ });
5442
+ for (const block of result.blocks) {
5443
+ try {
5444
+ const dataString = new TextDecoder().decode(block.data);
5445
+ const data = JSON.parse(dataString);
5446
+ objects.push({
5447
+ spaceId: cursor.spaceId,
5448
+ queueId: block.feedId ?? failedInvariant(),
5449
+ documentId: null,
5450
+ recordId: null,
5451
+ data
5452
+ });
5453
+ } catch (err) {
5454
+ log12.warn("Failed to parse block data for indexing", {
5455
+ spaceId: cursor.spaceId,
5456
+ err
5457
+ }, {
5458
+ F: __dxlog_file15,
5459
+ L: 114,
5460
+ S: this,
5461
+ C: (f, a) => f(...a)
5462
+ });
5463
+ }
5464
+ }
5465
+ remainingLimit -= result.blocks.length;
5466
+ updatedCursors.push({
5467
+ spaceId: cursor.spaceId,
5468
+ resourceId: null,
5469
+ cursor: result.nextCursor
5470
+ });
5471
+ } catch (error) {
5472
+ log12.error("Error querying queue for indexing", {
5473
+ spaceId: cursor.spaceId,
5474
+ error
5475
+ }, {
5476
+ F: __dxlog_file15,
5477
+ L: 125,
5478
+ S: this,
5479
+ C: (f, a) => f(...a)
5480
+ });
5481
+ }
5482
+ }
5483
+ return {
5484
+ objects,
5485
+ cursors: updatedCursors
5486
+ };
5487
+ }).pipe(RuntimeProvider2.provide(this._runtime), Effect3.withSpan("QueueDataSource.getChangedObjects"), Effect3.orDie);
5488
+ }
5489
+ };
5490
+
4358
5491
  // src/db-host/space-state-manager.ts
4359
5492
  import { interpretAsDocumentId as interpretAsDocumentId3 } from "@automerge/automerge-repo";
4360
5493
  import isEqual from "lodash.isequal";
4361
- import { Event as Event3, UpdateScheduler as UpdateScheduler3 } from "@dxos/async";
4362
- import { Context as Context5, LifecycleState as LifecycleState4, Resource as Resource8 } from "@dxos/context";
4363
- import { invariant as invariant12 } from "@dxos/invariant";
5494
+ import { Event as Event4, UpdateScheduler as UpdateScheduler3 } from "@dxos/async";
5495
+ import { Context as Context7, LifecycleState as LifecycleState4, Resource as Resource8 } from "@dxos/context";
5496
+ import { invariant as invariant13 } from "@dxos/invariant";
4364
5497
 
4365
5498
  // src/db-host/database-root.ts
4366
5499
  import { interpretAsDocumentId as interpretAsDocumentId2 } from "@automerge/automerge-repo";
4367
- import { DatabaseDirectory as DatabaseDirectory5, SpaceDocVersion as SpaceDocVersion2 } from "@dxos/echo-protocol";
4368
- import { invariant as invariant11 } from "@dxos/invariant";
5500
+ import { DatabaseDirectory as DatabaseDirectory6, SpaceDocVersion as SpaceDocVersion3 } from "@dxos/echo-protocol";
5501
+ import { invariant as invariant12 } from "@dxos/invariant";
4369
5502
 
4370
5503
  // src/db-host/automerge-metrics.ts
4371
5504
  import * as A5 from "@automerge/automerge";
4372
- import { log as log11 } from "@dxos/log";
4373
- var __dxlog_file13 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/automerge-metrics.ts";
5505
+ import { log as log13 } from "@dxos/log";
5506
+ var __dxlog_file16 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/automerge-metrics.ts";
4374
5507
  var measureDocMetrics = (doc) => {
4375
5508
  const snapshot = A5.save(doc);
4376
5509
  const start = Date.now();
@@ -4381,10 +5514,10 @@ var measureDocMetrics = (doc) => {
4381
5514
  const mutationCount = A5.getAllChanges(doc).length;
4382
5515
  const getAllChangesEnd = Date.now();
4383
5516
  if (getAllChangesEnd - getAllChangesStart > 300) {
4384
- log11.warn("getAllChanges took too long", {
5517
+ log13.warn("getAllChanges took too long", {
4385
5518
  elapsed: getAllChangesEnd - getAllChangesStart
4386
5519
  }, {
4387
- F: __dxlog_file13,
5520
+ F: __dxlog_file16,
4388
5521
  L: 31,
4389
5522
  S: void 0,
4390
5523
  C: (f, a) => f(...a)
@@ -4398,7 +5531,7 @@ var measureDocMetrics = (doc) => {
4398
5531
  };
4399
5532
 
4400
5533
  // src/db-host/database-root.ts
4401
- var __dxlog_file14 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/database-root.ts";
5534
+ var __dxlog_file17 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/database-root.ts";
4402
5535
  var DatabaseRoot = class {
4403
5536
  _rootHandle;
4404
5537
  static mapLinks(doc, mapping) {
@@ -4437,14 +5570,14 @@ var DatabaseRoot = class {
4437
5570
  if (!doc) {
4438
5571
  return null;
4439
5572
  }
4440
- return doc.version ?? SpaceDocVersion2.LEGACY;
5573
+ return doc.version ?? SpaceDocVersion3.LEGACY;
4441
5574
  }
4442
5575
  getSpaceKey() {
4443
5576
  const doc = this.doc();
4444
5577
  if (!doc) {
4445
5578
  return null;
4446
5579
  }
4447
- return DatabaseDirectory5.getSpaceKey(doc);
5580
+ return DatabaseDirectory6.getSpaceKey(doc);
4448
5581
  }
4449
5582
  getInlineObjectCount() {
4450
5583
  const doc = this.doc();
@@ -4462,8 +5595,8 @@ var DatabaseRoot = class {
4462
5595
  }
4463
5596
  getAllLinkedDocuments() {
4464
5597
  const doc = this.doc();
4465
- invariant11(doc, void 0, {
4466
- F: __dxlog_file14,
5598
+ invariant12(doc, void 0, {
5599
+ F: __dxlog_file17,
4467
5600
  L: 88,
4468
5601
  S: this,
4469
5602
  A: [
@@ -4483,13 +5616,13 @@ var DatabaseRoot = class {
4483
5616
  };
4484
5617
 
4485
5618
  // src/db-host/space-state-manager.ts
4486
- var __dxlog_file15 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/space-state-manager.ts";
5619
+ var __dxlog_file18 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/space-state-manager.ts";
4487
5620
  var SpaceStateManager = class extends Resource8 {
4488
5621
  _roots = /* @__PURE__ */ new Map();
4489
5622
  _rootBySpace = /* @__PURE__ */ new Map();
4490
5623
  _perRootContext = /* @__PURE__ */ new Map();
4491
5624
  _lastSpaceDocumentList = /* @__PURE__ */ new Map();
4492
- spaceDocumentListUpdated = new Event3();
5625
+ spaceDocumentListUpdated = new Event4();
4493
5626
  async _close(ctx) {
4494
5627
  for (const [_, rootCtx] of this._perRootContext) {
4495
5628
  await rootCtx.dispose();
@@ -4499,6 +5632,9 @@ var SpaceStateManager = class extends Resource8 {
4499
5632
  get roots() {
4500
5633
  return this._roots;
4501
5634
  }
5635
+ get spaceIds() {
5636
+ return Array.from(this._rootBySpace.keys());
5637
+ }
4502
5638
  getRootByDocumentId(documentId) {
4503
5639
  return this._roots.get(documentId);
4504
5640
  }
@@ -4506,9 +5642,9 @@ var SpaceStateManager = class extends Resource8 {
4506
5642
  return this._rootBySpace.get(spaceId);
4507
5643
  }
4508
5644
  getRootBySpaceId(spaceId) {
4509
- invariant12(this._lifecycleState === LifecycleState4.OPEN, void 0, {
4510
- F: __dxlog_file15,
4511
- L: 44,
5645
+ invariant13(this._lifecycleState === LifecycleState4.OPEN, void 0, {
5646
+ F: __dxlog_file18,
5647
+ L: 48,
4512
5648
  S: this,
4513
5649
  A: [
4514
5650
  "this._lifecycleState === LifecycleState.OPEN",
@@ -4538,9 +5674,9 @@ var SpaceStateManager = class extends Resource8 {
4538
5674
  this._perRootContext.delete(prevRootId);
4539
5675
  }
4540
5676
  this._rootBySpace.set(spaceId, root.handle.documentId);
4541
- const ctx = new Context5(void 0, {
4542
- F: __dxlog_file15,
4543
- L: 72
5677
+ const ctx = new Context7(void 0, {
5678
+ F: __dxlog_file18,
5679
+ L: 76
4544
5680
  });
4545
5681
  this._perRootContext.set(root.handle.documentId, ctx);
4546
5682
  await root.handle.whenReady();
@@ -4576,11 +5712,24 @@ var SpaceDocumentListUpdatedEvent = class {
4576
5712
  }
4577
5713
  };
4578
5714
 
5715
+ // src/db-host/stub.ts
5716
+ var QueueServiceStub = class {
5717
+ queryQueue(request) {
5718
+ throw new Error("Not available.");
5719
+ }
5720
+ insertIntoQueue(request) {
5721
+ throw new Error("Not available.");
5722
+ }
5723
+ deleteFromQueue(request) {
5724
+ throw new Error("Not available.");
5725
+ }
5726
+ };
5727
+
4579
5728
  // src/db-host/echo-host.ts
4580
- var __dxlog_file16 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/echo-host.ts";
5729
+ var __dxlog_file19 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/db-host/echo-host.ts";
4581
5730
  var DEFAULT_INDEXING_CONFIG = {
4582
- // TODO(dmaretskyi): Disabled by default since embedding generation is expensive.
4583
- fullText: false,
5731
+ // TODO(mykola): Enable by default when SQLite indexer is stable.
5732
+ sqlIndex: false,
4584
5733
  vector: false
4585
5734
  };
4586
5735
  var EchoHost = class extends Resource9 {
@@ -4591,9 +5740,18 @@ var EchoHost = class extends Resource9 {
4591
5740
  _dataService;
4592
5741
  _spaceStateManager = new SpaceStateManager();
4593
5742
  _echoDataMonitor;
4594
- constructor({ kv, indexing = {}, peerIdProvider, getSpaceKeyByRootDocumentId }) {
5743
+ _automergeDataSource;
5744
+ _indexer2;
5745
+ _indexConfig;
5746
+ _runtime;
5747
+ _feedStore;
5748
+ _queueDataSource;
5749
+ _updateIndexes;
5750
+ _queuesService;
5751
+ _indexesUpToDate = false;
5752
+ constructor({ kv, localQueues, indexing = {}, peerIdProvider, getSpaceKeyByRootDocumentId, runtime, assignQueuePositions = false }) {
4595
5753
  super();
4596
- const indexingConfig = {
5754
+ this._indexConfig = {
4597
5755
  ...DEFAULT_INDEXING_CONFIG,
4598
5756
  ...indexing
4599
5757
  };
@@ -4608,6 +5766,22 @@ var EchoHost = class extends Resource9 {
4608
5766
  peerIdProvider,
4609
5767
  getSpaceKeyByRootDocumentId
4610
5768
  });
5769
+ this._runtime = runtime;
5770
+ this._automergeDataSource = new AutomergeDataSource(this._automergeHost);
5771
+ if (localQueues) {
5772
+ this._feedStore = new FeedStore({
5773
+ assignPositions: assignQueuePositions,
5774
+ localActorId: crypto.randomUUID()
5775
+ });
5776
+ this._queueDataSource = new QueueDataSource({
5777
+ feedStore: this._feedStore,
5778
+ runtime: this._runtime,
5779
+ getSpaceIds: () => this._spaceStateManager.spaceIds
5780
+ });
5781
+ this._queuesService = new LocalQueueServiceImpl(runtime, this._feedStore);
5782
+ } else {
5783
+ this._queuesService = new QueueServiceStub();
5784
+ }
4611
5785
  this._indexer = new Indexer({
4612
5786
  db: kv,
4613
5787
  indexStore: new IndexStore({
@@ -4627,21 +5801,19 @@ var EchoHost = class extends Resource9 {
4627
5801
  {
4628
5802
  kind: IndexKind.Kind.GRAPH
4629
5803
  },
4630
- ...indexingConfig.fullText ? [
4631
- {
4632
- kind: IndexKind.Kind.FULL_TEXT
4633
- }
4634
- ] : [],
4635
- ...indexingConfig.vector ? [
5804
+ ...this._indexConfig.vector ? [
4636
5805
  {
4637
5806
  kind: IndexKind.Kind.VECTOR
4638
5807
  }
4639
5808
  ] : []
4640
5809
  ]
4641
5810
  });
5811
+ this._indexer2 = new IndexEngine();
4642
5812
  this._queryService = new QueryServiceImpl({
4643
5813
  automergeHost: this._automergeHost,
4644
5814
  indexer: this._indexer,
5815
+ indexer2: this._indexConfig.sqlIndex ? this._indexer2 : void 0,
5816
+ runtime: this._indexConfig.sqlIndex ? this._runtime : void 0,
4645
5817
  spaceStateManager: this._spaceStateManager
4646
5818
  });
4647
5819
  this._dataService = new DataServiceImpl({
@@ -4649,6 +5821,11 @@ var EchoHost = class extends Resource9 {
4649
5821
  spaceStateManager: this._spaceStateManager,
4650
5822
  updateIndexes: async () => {
4651
5823
  await this._indexer.updateIndexes();
5824
+ if (this._indexConfig.sqlIndex) {
5825
+ do {
5826
+ await this._updateIndexes.runBlocking();
5827
+ } while (!this._indexesUpToDate);
5828
+ }
4652
5829
  }
4653
5830
  });
4654
5831
  trace5.diagnostic({
@@ -4695,20 +5872,36 @@ var EchoHost = class extends Resource9 {
4695
5872
  get dataService() {
4696
5873
  return this._dataService;
4697
5874
  }
4698
- /**
4699
- * @deprecated To be abstracted away.
4700
- */
4701
- get automergeRepo() {
4702
- return this._automergeHost.repo;
5875
+ get queuesService() {
5876
+ return this._queuesService;
4703
5877
  }
4704
5878
  get roots() {
4705
5879
  return this._spaceStateManager.roots;
4706
5880
  }
5881
+ /**
5882
+ * New index-core indexer for text and other queries.
5883
+ */
5884
+ get indexer2() {
5885
+ return this._indexer2;
5886
+ }
4707
5887
  async _open(ctx) {
4708
5888
  await this._automergeHost.open();
4709
5889
  await this._indexer.open(ctx);
4710
5890
  await this._queryService.open(ctx);
4711
5891
  await this._spaceStateManager.open(ctx);
5892
+ if (this._feedStore) {
5893
+ await RuntimeProvider3.runPromise(this._runtime)(this._feedStore.migrate());
5894
+ this._feedStore.onNewBlocks.on(this._ctx, () => {
5895
+ this._queryService.invalidateQueries();
5896
+ if (this._indexConfig.sqlIndex) {
5897
+ this._updateIndexes.schedule();
5898
+ }
5899
+ });
5900
+ }
5901
+ if (this._indexConfig.sqlIndex) {
5902
+ await RuntimeProvider3.runPromise(this._runtime)(this._indexer2.migrate());
5903
+ this._updateIndexes = new DeferredTask3(this._ctx, this._runUpdateIndexes);
5904
+ }
4712
5905
  this._spaceStateManager.spaceDocumentListUpdated.on(this._ctx, (e) => {
4713
5906
  if (e.previousRootId) {
4714
5907
  void this._automergeHost.clearLocalCollectionState(deriveCollectionIdFromSpaceId(e.spaceId, e.previousRootId));
@@ -4717,7 +5910,13 @@ var EchoHost = class extends Resource9 {
4717
5910
  });
4718
5911
  this._automergeHost.documentsSaved.on(this._ctx, () => {
4719
5912
  this._queryService.invalidateQueries();
5913
+ if (this._indexConfig.sqlIndex) {
5914
+ this._updateIndexes.schedule();
5915
+ }
4720
5916
  });
5917
+ if (this._indexConfig.sqlIndex) {
5918
+ this._updateIndexes.schedule();
5919
+ }
4721
5920
  }
4722
5921
  async _close(ctx) {
4723
5922
  await this._queryService.close(ctx);
@@ -4749,16 +5948,16 @@ var EchoHost = class extends Resource9 {
4749
5948
  /**
4750
5949
  * Create new persisted document.
4751
5950
  */
4752
- createDoc(initialValue, opts) {
5951
+ async createDoc(initialValue, opts) {
4753
5952
  return this._automergeHost.createDoc(initialValue, opts);
4754
5953
  }
4755
5954
  /**
4756
5955
  * Create new space root.
4757
5956
  */
4758
5957
  async createSpaceRoot(spaceKey) {
4759
- invariant13(this._lifecycleState === LifecycleState5.OPEN, void 0, {
4760
- F: __dxlog_file16,
4761
- L: 254,
5958
+ invariant14(this._lifecycleState === LifecycleState5.OPEN, void 0, {
5959
+ F: __dxlog_file19,
5960
+ L: 342,
4762
5961
  S: this,
4763
5962
  A: [
4764
5963
  "this._lifecycleState === LifecycleState.OPEN",
@@ -4766,8 +5965,8 @@ var EchoHost = class extends Resource9 {
4766
5965
  ]
4767
5966
  });
4768
5967
  const spaceId = await createIdFromSpaceKey2(spaceKey);
4769
- const automergeRoot = this._automergeHost.createDoc({
4770
- version: SpaceDocVersion3.CURRENT,
5968
+ const automergeRoot = await this._automergeHost.createDoc({
5969
+ version: SpaceDocVersion4.CURRENT,
4771
5970
  access: {
4772
5971
  spaceKey: spaceKey.toHex()
4773
5972
  },
@@ -4784,21 +5983,26 @@ var EchoHost = class extends Resource9 {
4784
5983
  }
4785
5984
  // TODO(dmaretskyi): Change to document id.
4786
5985
  async openSpaceRoot(spaceId, automergeUrl) {
4787
- invariant13(this._lifecycleState === LifecycleState5.OPEN, void 0, {
4788
- F: __dxlog_file16,
4789
- L: 273,
5986
+ invariant14(this._lifecycleState === LifecycleState5.OPEN, void 0, {
5987
+ F: __dxlog_file19,
5988
+ L: 361,
4790
5989
  S: this,
4791
5990
  A: [
4792
5991
  "this._lifecycleState === LifecycleState.OPEN",
4793
5992
  ""
4794
5993
  ]
4795
5994
  });
4796
- const handle = await this._automergeHost.repo.find(automergeUrl, FIND_PARAMS);
5995
+ const handle = await this._automergeHost.loadDoc(Context8.default(void 0, {
5996
+ F: __dxlog_file19,
5997
+ L: 362
5998
+ }), automergeUrl, {
5999
+ fetchFromNetwork: true
6000
+ });
4797
6001
  await handle.whenReady();
4798
6002
  return this._spaceStateManager.assignRootToSpace(spaceId, handle);
4799
6003
  }
4800
6004
  // TODO(dmaretskyi): Change to document id.
4801
- async closeSpaceRoot(automergeUrl) {
6005
+ async closeSpaceRoot(_automergeUrl) {
4802
6006
  todo();
4803
6007
  }
4804
6008
  /**
@@ -4813,16 +6017,102 @@ var EchoHost = class extends Resource9 {
4813
6017
  async removeReplicator(replicator) {
4814
6018
  await this._automergeHost.removeReplicator(replicator);
4815
6019
  }
6020
+ /**
6021
+ * Run collection sync for the given space.
6022
+ * Does not wait for the sync to complete.
6023
+ */
6024
+ async runCollectionSync(spaceId) {
6025
+ const root = this._spaceStateManager.getRootBySpaceId(spaceId);
6026
+ if (!root) {
6027
+ throw new Error(`Space not found: ${spaceId}`);
6028
+ }
6029
+ this._automergeHost.refreshCollection(deriveCollectionIdFromSpaceId(spaceId, root.documentId));
6030
+ }
6031
+ _runUpdateIndexes = async () => {
6032
+ if (!this._indexer2) {
6033
+ return;
6034
+ }
6035
+ let totalUpdated = 0;
6036
+ let totalDone = true;
6037
+ {
6038
+ performance.mark("indexer2.update.automerge:start");
6039
+ const { updated, done } = await this._indexer2.update(this._automergeDataSource, {
6040
+ spaceId: null,
6041
+ limit: 50
6042
+ }).pipe(RuntimeProvider3.runPromise(this._runtime));
6043
+ totalUpdated += updated;
6044
+ totalDone &&= done;
6045
+ performance.measure("Index Automerge", {
6046
+ start: "indexer2.update.automerge:start",
6047
+ detail: {
6048
+ devtools: {
6049
+ dataType: "track-entry",
6050
+ track: "Indexing",
6051
+ trackGroup: "ECHO",
6052
+ color: "tertiary-dark",
6053
+ properties: [
6054
+ [
6055
+ "count",
6056
+ updated
6057
+ ]
6058
+ ]
6059
+ }
6060
+ }
6061
+ });
6062
+ }
6063
+ if (this._queueDataSource) {
6064
+ performance.mark("indexer2.update.queue:start");
6065
+ const { updated, done } = await this._indexer2.update(this._queueDataSource, {
6066
+ spaceId: null,
6067
+ limit: 50
6068
+ }).pipe(RuntimeProvider3.runPromise(this._runtime));
6069
+ totalUpdated += updated;
6070
+ totalDone &&= done;
6071
+ performance.measure("Index Queues", {
6072
+ start: "indexer2.update.queue:start",
6073
+ detail: {
6074
+ devtools: {
6075
+ dataType: "track-entry",
6076
+ track: "Indexing",
6077
+ trackGroup: "ECHO",
6078
+ color: "tertiary-dark",
6079
+ properties: [
6080
+ [
6081
+ "count",
6082
+ updated
6083
+ ]
6084
+ ]
6085
+ }
6086
+ }
6087
+ });
6088
+ }
6089
+ log14.verbose("indexer2 update completed", {
6090
+ updated: totalUpdated,
6091
+ done: totalDone
6092
+ }, {
6093
+ F: __dxlog_file19,
6094
+ L: 452,
6095
+ S: this,
6096
+ C: (f, a) => f(...a)
6097
+ });
6098
+ await sleep(1);
6099
+ if (!totalDone) {
6100
+ this._indexesUpToDate = false;
6101
+ this._updateIndexes.schedule();
6102
+ } else {
6103
+ this._indexesUpToDate = true;
6104
+ }
6105
+ };
4816
6106
  };
4817
6107
 
4818
6108
  // src/edge/echo-edge-replicator.ts
4819
6109
  import * as Automerge from "@automerge/automerge";
4820
6110
  import { cbor as cbor2 } from "@automerge/automerge-repo";
4821
6111
  import { Mutex, scheduleMicroTask as scheduleMicroTask2, scheduleTask as scheduleTask2 } from "@dxos/async";
4822
- import { Context as Context6, Resource as Resource11 } from "@dxos/context";
6112
+ import { Context as Context9, Resource as Resource11 } from "@dxos/context";
4823
6113
  import { randomUUID } from "@dxos/crypto";
4824
- import { invariant as invariant14 } from "@dxos/invariant";
4825
- import { log as log13 } from "@dxos/log";
6114
+ import { invariant as invariant15 } from "@dxos/invariant";
6115
+ import { log as log16 } from "@dxos/log";
4826
6116
  import { DocumentCodec, EdgeService } from "@dxos/protocols";
4827
6117
  import { buf } from "@dxos/protocols/buf";
4828
6118
  import { MessageSchema as RouterMessageSchema } from "@dxos/protocols/buf/dxos/edge/messenger_pb";
@@ -4831,8 +6121,8 @@ import { bufferToArray as bufferToArray2, setDeep } from "@dxos/util";
4831
6121
  // src/edge/inflight-request-limiter.ts
4832
6122
  import { Trigger as Trigger2 } from "@dxos/async";
4833
6123
  import { Resource as Resource10 } from "@dxos/context";
4834
- import { log as log12 } from "@dxos/log";
4835
- var __dxlog_file17 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/edge/inflight-request-limiter.ts";
6124
+ import { log as log15 } from "@dxos/log";
6125
+ var __dxlog_file20 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/edge/inflight-request-limiter.ts";
4836
6126
  var InflightRequestLimiter = class extends Resource10 {
4837
6127
  _config;
4838
6128
  /**
@@ -4867,8 +6157,8 @@ var InflightRequestLimiter = class extends Resource10 {
4867
6157
  if (this._inflightRequestBalance === this._config.maxInflightRequests) {
4868
6158
  this._requestBarrier.reset();
4869
6159
  this._resetBalanceTimeout = setTimeout(() => {
4870
- log12.warn("Request balance has not changed during specified timeout, resetting request limiter.", void 0, {
4871
- F: __dxlog_file17,
6160
+ log15.warn("Request balance has not changed during specified timeout, resetting request limiter.", void 0, {
6161
+ F: __dxlog_file20,
4872
6162
  L: 52,
4873
6163
  S: this,
4874
6164
  C: (f, a) => f(...a)
@@ -4956,7 +6246,7 @@ function _ts_dispose_resources(env) {
4956
6246
  return next();
4957
6247
  })(env);
4958
6248
  }
4959
- var __dxlog_file18 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/edge/echo-edge-replicator.ts";
6249
+ var __dxlog_file21 = "/__w/dxos/dxos/packages/core/echo/echo-pipeline/src/edge/echo-edge-replicator.ts";
4960
6250
  var INITIAL_RESTART_DELAY = 500;
4961
6251
  var RESTART_DELAY_JITTER = 250;
4962
6252
  var MAX_RESTART_DELAY = 5e3;
@@ -4975,19 +6265,19 @@ var EchoEdgeReplicator = class {
4975
6265
  this._sharePolicyEnabled = !disableSharePolicy;
4976
6266
  }
4977
6267
  async connect(context) {
4978
- log13("connecting...", {
6268
+ log16("connecting...", {
4979
6269
  peerId: context.peerId,
4980
6270
  connectedSpaces: this._connectedSpaces.size
4981
6271
  }, {
4982
- F: __dxlog_file18,
4983
- L: 73,
6272
+ F: __dxlog_file21,
6273
+ L: 74,
4984
6274
  S: this,
4985
6275
  C: (f, a) => f(...a)
4986
6276
  });
4987
6277
  this._context = context;
4988
- this._ctx = Context6.default(void 0, {
4989
- F: __dxlog_file18,
4990
- L: 75
6278
+ this._ctx = Context9.default(void 0, {
6279
+ F: __dxlog_file21,
6280
+ L: 76
4991
6281
  });
4992
6282
  this._ctx.onDispose(this._edgeConnection.onReconnected(() => {
4993
6283
  this._ctx && scheduleMicroTask2(this._ctx, () => this._handleReconnect());
@@ -5047,6 +6337,14 @@ var EchoEdgeReplicator = class {
5047
6337
  hasError: false
5048
6338
  };
5049
6339
  try {
6340
+ log16("connectToSpace", {
6341
+ spaceId
6342
+ }, {
6343
+ F: __dxlog_file21,
6344
+ L: 111,
6345
+ S: this,
6346
+ C: (f, a) => f(...a)
6347
+ });
5050
6348
  const _guard = _ts_add_disposable_resource(env, await this._mutex.acquire(), false);
5051
6349
  if (this._connectedSpaces.has(spaceId)) {
5052
6350
  return;
@@ -5084,18 +6382,18 @@ var EchoEdgeReplicator = class {
5084
6382
  }
5085
6383
  }
5086
6384
  async _openConnection(spaceId, reconnects = 0) {
5087
- invariant14(this._context, void 0, {
5088
- F: __dxlog_file18,
5089
- L: 136,
6385
+ invariant15(this._context, void 0, {
6386
+ F: __dxlog_file21,
6387
+ L: 138,
5090
6388
  S: this,
5091
6389
  A: [
5092
6390
  "this._context",
5093
6391
  ""
5094
6392
  ]
5095
6393
  });
5096
- invariant14(!this._connections.has(spaceId), void 0, {
5097
- F: __dxlog_file18,
5098
- L: 137,
6394
+ invariant15(!this._connections.has(spaceId), void 0, {
6395
+ F: __dxlog_file21,
6396
+ L: 139,
5099
6397
  S: this,
5100
6398
  A: [
5101
6399
  "!this._connections.has(spaceId)",
@@ -5110,22 +6408,22 @@ var EchoEdgeReplicator = class {
5110
6408
  context: this._context,
5111
6409
  sharedPolicyEnabled: this._sharePolicyEnabled,
5112
6410
  onRemoteConnected: async () => {
5113
- log13.trace("dxos.echo.edge.replicator.onRemoteConnected", {
6411
+ log16.trace("dxos.echo.edge.replicator.onRemoteConnected", {
5114
6412
  spaceId
5115
6413
  }, {
5116
- F: __dxlog_file18,
5117
- L: 148,
6414
+ F: __dxlog_file21,
6415
+ L: 150,
5118
6416
  S: this,
5119
6417
  C: (f, a) => f(...a)
5120
6418
  });
5121
6419
  this._context?.onConnectionOpen(connection);
5122
6420
  },
5123
6421
  onRemoteDisconnected: async () => {
5124
- log13.trace("dxos.echo.edge.replicator.onRemoteDisconnected", {
6422
+ log16.trace("dxos.echo.edge.replicator.onRemoteDisconnected", {
5125
6423
  spaceId
5126
6424
  }, {
5127
- F: __dxlog_file18,
5128
- L: 152,
6425
+ F: __dxlog_file21,
6426
+ L: 154,
5129
6427
  S: this,
5130
6428
  C: (f, a) => f(...a)
5131
6429
  });
@@ -5136,13 +6434,13 @@ var EchoEdgeReplicator = class {
5136
6434
  return;
5137
6435
  }
5138
6436
  const restartDelay = Math.min(MAX_RESTART_DELAY, INITIAL_RESTART_DELAY * reconnects) + Math.random() * RESTART_DELAY_JITTER;
5139
- log13("connection restart scheduled", {
6437
+ log16("connection restart scheduled", {
5140
6438
  spaceId,
5141
6439
  reconnects,
5142
6440
  restartDelay
5143
6441
  }, {
5144
- F: __dxlog_file18,
5145
- L: 163,
6442
+ F: __dxlog_file21,
6443
+ L: 165,
5146
6444
  S: this,
5147
6445
  C: (f, a) => f(...a)
5148
6446
  });
@@ -5164,13 +6462,13 @@ var EchoEdgeReplicator = class {
5164
6462
  if (ctx?.disposed) {
5165
6463
  return;
5166
6464
  }
5167
- log13.trace("dxos.echo.edge.replicator.restart", {
6465
+ log16.trace("dxos.echo.edge.replicator.restart", {
5168
6466
  spaceId,
5169
6467
  reconnects,
5170
6468
  restartDelay
5171
6469
  }, {
5172
- F: __dxlog_file18,
5173
- L: 180,
6470
+ F: __dxlog_file21,
6471
+ L: 182,
5174
6472
  S: this,
5175
6473
  C: (f, a) => f(...a)
5176
6474
  });
@@ -5235,9 +6533,9 @@ var EdgeReplicatorConnection = class extends Resource11 {
5235
6533
  });
5236
6534
  }
5237
6535
  async _open(ctx) {
5238
- log13("opening...", void 0, {
5239
- F: __dxlog_file18,
5240
- L: 273,
6536
+ log16("opening...", void 0, {
6537
+ F: __dxlog_file21,
6538
+ L: 275,
5241
6539
  S: this,
5242
6540
  C: (f, a) => f(...a)
5243
6541
  });
@@ -5250,9 +6548,9 @@ var EdgeReplicatorConnection = class extends Resource11 {
5250
6548
  // NOTE: This will fire immediately if the connection is already open.
5251
6549
  this._edgeConnection.onReconnected(async () => {
5252
6550
  if (firstReconnect) {
5253
- log13.verbose("first reconnect skipped", void 0, {
5254
- F: __dxlog_file18,
5255
- L: 288,
6551
+ log16.verbose("first reconnect skipped", void 0, {
6552
+ F: __dxlog_file21,
6553
+ L: 290,
5256
6554
  S: this,
5257
6555
  C: (f, a) => f(...a)
5258
6556
  });
@@ -5265,9 +6563,9 @@ var EdgeReplicatorConnection = class extends Resource11 {
5265
6563
  await this._onRemoteConnected();
5266
6564
  }
5267
6565
  async _close() {
5268
- log13("closing...", void 0, {
5269
- F: __dxlog_file18,
5270
- L: 301,
6566
+ log16("closing...", void 0, {
6567
+ F: __dxlog_file21,
6568
+ L: 303,
5271
6569
  S: this,
5272
6570
  C: (f, a) => f(...a)
5273
6571
  });
@@ -5276,9 +6574,9 @@ var EdgeReplicatorConnection = class extends Resource11 {
5276
6574
  await this._onRemoteDisconnected();
5277
6575
  }
5278
6576
  get peerId() {
5279
- invariant14(this._remotePeerId, "Not connected", {
5280
- F: __dxlog_file18,
5281
- L: 310,
6577
+ invariant15(this._remotePeerId, "Not connected", {
6578
+ F: __dxlog_file21,
6579
+ L: 312,
5282
6580
  S: this,
5283
6581
  A: [
5284
6582
  "this._remotePeerId",
@@ -5297,13 +6595,13 @@ var EdgeReplicatorConnection = class extends Resource11 {
5297
6595
  documentId: params.documentId,
5298
6596
  peerId: this._remotePeerId
5299
6597
  });
5300
- log13.verbose("document not found locally for share policy check", {
6598
+ log16.verbose("document not found locally for share policy check", {
5301
6599
  documentId: params.documentId,
5302
6600
  acceptDocument: remoteDocumentExists,
5303
6601
  remoteId: this._remotePeerId
5304
6602
  }, {
5305
- F: __dxlog_file18,
5306
- L: 325,
6603
+ F: __dxlog_file21,
6604
+ L: 327,
5307
6605
  S: this,
5308
6606
  C: (f, a) => f(...a)
5309
6607
  });
@@ -5323,12 +6621,12 @@ var EdgeReplicatorConnection = class extends Resource11 {
5323
6621
  return;
5324
6622
  }
5325
6623
  const payload = cbor2.decode(message.payload.value);
5326
- log13.verbose("received", {
6624
+ log16.verbose("received", {
5327
6625
  ...getMessageInfo(payload),
5328
6626
  remoteId: this._remotePeerId
5329
6627
  }, {
5330
- F: __dxlog_file18,
5331
- L: 354,
6628
+ F: __dxlog_file21,
6629
+ L: 356,
5332
6630
  S: this,
5333
6631
  C: (f, a) => f(...a)
5334
6632
  });
@@ -5360,6 +6658,14 @@ var EdgeReplicatorConnection = class extends Resource11 {
5360
6658
  }
5361
6659
  _processMessage(message) {
5362
6660
  if (isErrorMessage(message)) {
6661
+ log16.verbose("stream error", {
6662
+ error: message.message
6663
+ }, {
6664
+ F: __dxlog_file21,
6665
+ L: 392,
6666
+ S: this,
6667
+ C: (f, a) => f(...a)
6668
+ });
5363
6669
  this._onRestartRequested();
5364
6670
  return;
5365
6671
  }
@@ -5376,12 +6682,12 @@ var EdgeReplicatorConnection = class extends Resource11 {
5376
6682
  "metadata",
5377
6683
  "dxos_connectionId"
5378
6684
  ], this._connectionId);
5379
- log13.verbose("sending...", {
6685
+ log16.verbose("sending...", {
5380
6686
  ...getMessageInfo(message),
5381
6687
  remoteId: this._remotePeerId
5382
6688
  }, {
5383
- F: __dxlog_file18,
5384
- L: 407,
6689
+ F: __dxlog_file21,
6690
+ L: 410,
5385
6691
  S: this,
5386
6692
  C: (f, a) => f(...a)
5387
6693
  });
@@ -5398,11 +6704,11 @@ var EdgeReplicatorConnection = class extends Resource11 {
5398
6704
  }
5399
6705
  }));
5400
6706
  } catch (err) {
5401
- log13.error("failed to send message", {
6707
+ log16.error("failed to send message", {
5402
6708
  err
5403
6709
  }, {
5404
- F: __dxlog_file18,
5405
- L: 426,
6710
+ F: __dxlog_file21,
6711
+ L: 429,
5406
6712
  S: this,
5407
6713
  C: (f, a) => f(...a)
5408
6714
  });
@@ -5418,6 +6724,7 @@ var getMessageInfo = (msg) => {
5418
6724
  return {
5419
6725
  type: msg.type,
5420
6726
  documentId: "documentId" in msg ? msg.documentId : void 0,
6727
+ collectionId: "collectionId" in msg ? msg.collectionId : void 0,
5421
6728
  have,
5422
6729
  heads,
5423
6730
  need,
@@ -5427,16 +6734,20 @@ var getMessageInfo = (msg) => {
5427
6734
  };
5428
6735
 
5429
6736
  // src/util.ts
5430
- import { ObjectStructure as ObjectStructure2, decodeReference } from "@dxos/echo-protocol";
6737
+ import { EncodedReference, ObjectStructure as ObjectStructure2 } from "@dxos/echo-protocol";
5431
6738
  var findInlineObjectOfType = (spaceDoc, typename) => {
5432
6739
  for (const id in spaceDoc.objects ?? {}) {
5433
6740
  const obj = spaceDoc.objects[id];
5434
6741
  const objType = ObjectStructure2.getTypeReference(obj);
5435
- if (objType && decodeReference(objType).objectId === typename) {
5436
- return [
5437
- id,
5438
- obj
5439
- ];
6742
+ if (objType) {
6743
+ const typeDXN = EncodedReference.toDXN(objType);
6744
+ const typeDXNInfo = typeDXN.asTypeDXN();
6745
+ if (typeDXNInfo?.type === typename) {
6746
+ return [
6747
+ id,
6748
+ obj
6749
+ ];
6750
+ }
5440
6751
  }
5441
6752
  }
5442
6753
  return void 0;
@@ -5444,6 +6755,7 @@ var findInlineObjectOfType = (spaceDoc, typename) => {
5444
6755
  export {
5445
6756
  AuthExtension,
5446
6757
  AuthStatus,
6758
+ AutomergeDataSource,
5447
6759
  AutomergeHost,
5448
6760
  CredentialRetrieverExtension,
5449
6761
  CredentialServerExtension,
@@ -5484,6 +6796,7 @@ export {
5484
6796
  findInlineObjectOfType,
5485
6797
  getSpaceIdFromCollectionId,
5486
6798
  hasInvitationExpired,
6799
+ headsCodec,
5487
6800
  mapFeedIndexesToTimeframe,
5488
6801
  mapTimeframeToFeedIndexes,
5489
6802
  startAfter,