@dxos/echo-pipeline 0.8.2-staging.7ac8446 → 0.8.2

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 (182) hide show
  1. package/dist/lib/browser/{chunk-32WDI3LB.mjs → chunk-3XSXS5EX.mjs} +15 -21
  2. package/dist/lib/browser/chunk-3XSXS5EX.mjs.map +7 -0
  3. package/dist/lib/browser/chunk-CGS2ULMK.mjs +11 -0
  4. package/dist/lib/browser/chunk-CGS2ULMK.mjs.map +7 -0
  5. package/dist/lib/browser/chunk-TQJTKNMS.mjs +126 -0
  6. package/dist/lib/browser/chunk-TQJTKNMS.mjs.map +7 -0
  7. package/dist/lib/browser/filter/index.mjs +11 -0
  8. package/dist/lib/browser/filter/index.mjs.map +7 -0
  9. package/dist/lib/browser/index.mjs +1380 -516
  10. package/dist/lib/browser/index.mjs.map +4 -4
  11. package/dist/lib/browser/meta.json +1 -1
  12. package/dist/lib/browser/testing/index.mjs +202 -22
  13. package/dist/lib/browser/testing/index.mjs.map +4 -4
  14. package/dist/lib/node/chunk-HOPOFWAL.cjs +147 -0
  15. package/dist/lib/node/chunk-HOPOFWAL.cjs.map +7 -0
  16. package/dist/lib/node/chunk-Q7SFCCGT.cjs +33 -0
  17. package/dist/lib/node/chunk-Q7SFCCGT.cjs.map +7 -0
  18. package/dist/lib/node/{chunk-TC2PRBEU.cjs → chunk-SG2PL5RH.cjs} +18 -24
  19. package/dist/lib/node/chunk-SG2PL5RH.cjs.map +7 -0
  20. package/dist/lib/node/filter/index.cjs +32 -0
  21. package/dist/lib/node/filter/index.cjs.map +7 -0
  22. package/dist/lib/node/index.cjs +1381 -525
  23. package/dist/lib/node/index.cjs.map +4 -4
  24. package/dist/lib/node/meta.json +1 -1
  25. package/dist/lib/node/testing/index.cjs +207 -31
  26. package/dist/lib/node/testing/index.cjs.map +4 -4
  27. package/dist/lib/node-esm/{chunk-UKOLB3LW.mjs → chunk-3BZP75TJ.mjs} +15 -21
  28. package/dist/lib/node-esm/chunk-3BZP75TJ.mjs.map +7 -0
  29. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  30. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  31. package/dist/lib/node-esm/chunk-RVK35BS7.mjs +126 -0
  32. package/dist/lib/node-esm/chunk-RVK35BS7.mjs.map +7 -0
  33. package/dist/lib/node-esm/filter/index.mjs +11 -0
  34. package/dist/lib/node-esm/filter/index.mjs.map +7 -0
  35. package/dist/lib/node-esm/index.mjs +1380 -516
  36. package/dist/lib/node-esm/index.mjs.map +4 -4
  37. package/dist/lib/node-esm/meta.json +1 -1
  38. package/dist/lib/node-esm/testing/index.mjs +202 -22
  39. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  40. package/dist/types/src/automerge/automerge-host.d.ts +6 -4
  41. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  42. package/dist/types/src/automerge/collection-synchronizer.d.ts +1 -1
  43. package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
  44. package/dist/types/src/automerge/echo-data-monitor.d.ts +6 -6
  45. package/dist/types/src/automerge/echo-data-monitor.d.ts.map +1 -1
  46. package/dist/types/src/automerge/echo-network-adapter.d.ts +4 -1
  47. package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
  48. package/dist/types/src/automerge/heads-store.d.ts +2 -2
  49. package/dist/types/src/automerge/heads-store.d.ts.map +1 -1
  50. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +1 -1
  51. package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -1
  52. package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
  53. package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
  54. package/dist/types/src/automerge/network-protocol.d.ts +1 -1
  55. package/dist/types/src/automerge/network-protocol.d.ts.map +1 -1
  56. package/dist/types/src/automerge/space-collection.d.ts +1 -1
  57. package/dist/types/src/automerge/space-collection.d.ts.map +1 -1
  58. package/dist/types/src/common/feeds.d.ts.map +1 -1
  59. package/dist/types/src/common/space-id.d.ts.map +1 -1
  60. package/dist/types/src/db-host/automerge-metrics.d.ts +1 -1
  61. package/dist/types/src/db-host/automerge-metrics.d.ts.map +1 -1
  62. package/dist/types/src/db-host/data-service.d.ts.map +1 -1
  63. package/dist/types/src/db-host/database-root.d.ts +7 -7
  64. package/dist/types/src/db-host/database-root.d.ts.map +1 -1
  65. package/dist/types/src/db-host/documents-iterator.d.ts +1 -1
  66. package/dist/types/src/db-host/documents-iterator.d.ts.map +1 -1
  67. package/dist/types/src/db-host/documents-synchronizer.d.ts +4 -4
  68. package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
  69. package/dist/types/src/db-host/echo-host.d.ts +13 -2
  70. package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
  71. package/dist/types/src/db-host/index.d.ts +0 -1
  72. package/dist/types/src/db-host/index.d.ts.map +1 -1
  73. package/dist/types/src/db-host/query-service.d.ts +2 -0
  74. package/dist/types/src/db-host/query-service.d.ts.map +1 -1
  75. package/dist/types/src/db-host/space-state-manager.d.ts +4 -3
  76. package/dist/types/src/db-host/space-state-manager.d.ts.map +1 -1
  77. package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
  78. package/dist/types/src/edge/inflight-request-limiter.d.ts.map +1 -1
  79. package/dist/types/src/filter/filter-match.d.ts +13 -0
  80. package/dist/types/src/filter/filter-match.d.ts.map +1 -0
  81. package/dist/types/src/filter/filter-match.test.d.ts +2 -0
  82. package/dist/types/src/filter/filter-match.test.d.ts.map +1 -0
  83. package/dist/types/src/filter/index.d.ts +2 -0
  84. package/dist/types/src/filter/index.d.ts.map +1 -0
  85. package/dist/types/src/index.d.ts +1 -0
  86. package/dist/types/src/index.d.ts.map +1 -1
  87. package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
  88. package/dist/types/src/pipeline/message-selector.d.ts.map +1 -1
  89. package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
  90. package/dist/types/src/pipeline/timeframe-clock.d.ts.map +1 -1
  91. package/dist/types/src/query/errors.d.ts +23 -0
  92. package/dist/types/src/query/errors.d.ts.map +1 -0
  93. package/dist/types/src/query/index.d.ts +5 -0
  94. package/dist/types/src/query/index.d.ts.map +1 -0
  95. package/dist/types/src/query/plan.d.ts +132 -0
  96. package/dist/types/src/query/plan.d.ts.map +1 -0
  97. package/dist/types/src/query/query-executor.d.ts +83 -0
  98. package/dist/types/src/query/query-executor.d.ts.map +1 -0
  99. package/dist/types/src/query/query-planner.d.ts +33 -0
  100. package/dist/types/src/query/query-planner.d.ts.map +1 -0
  101. package/dist/types/src/query/query-planner.test.d.ts +2 -0
  102. package/dist/types/src/query/query-planner.test.d.ts.map +1 -0
  103. package/dist/types/src/space/admission-discovery-extension.d.ts.map +1 -1
  104. package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
  105. package/dist/types/src/space/space-manager.d.ts.map +1 -1
  106. package/dist/types/src/space/space-protocol.d.ts.map +1 -1
  107. package/dist/types/src/space/space.d.ts.map +1 -1
  108. package/dist/types/src/testing/change-metadata.d.ts.map +1 -1
  109. package/dist/types/src/testing/index.d.ts +2 -0
  110. package/dist/types/src/testing/index.d.ts.map +1 -1
  111. package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
  112. package/dist/types/src/testing/test-data.d.ts +18 -0
  113. package/dist/types/src/testing/test-data.d.ts.map +1 -0
  114. package/dist/types/src/testing/test-network-adapter.d.ts +3 -2
  115. package/dist/types/src/testing/test-network-adapter.d.ts.map +1 -1
  116. package/dist/types/src/testing/test-schema.d.ts +39 -0
  117. package/dist/types/src/testing/test-schema.d.ts.map +1 -0
  118. package/dist/types/src/util.d.ts +2 -2
  119. package/dist/types/src/util.d.ts.map +1 -1
  120. package/dist/types/tsconfig.tsbuildinfo +1 -1
  121. package/package.json +43 -34
  122. package/src/automerge/automerge-host.test.ts +7 -7
  123. package/src/automerge/automerge-host.ts +58 -60
  124. package/src/automerge/automerge-repo.test.ts +65 -65
  125. package/src/automerge/collection-synchronizer.test.ts +1 -1
  126. package/src/automerge/collection-synchronizer.ts +11 -10
  127. package/src/automerge/echo-data-monitor.ts +21 -20
  128. package/src/automerge/echo-network-adapter.test.ts +1 -1
  129. package/src/automerge/echo-network-adapter.ts +25 -18
  130. package/src/automerge/heads-store.ts +4 -3
  131. package/src/automerge/leveldb-storage-adapter.ts +1 -1
  132. package/src/automerge/mesh-echo-replicator-connection.ts +6 -5
  133. package/src/automerge/mesh-echo-replicator.ts +2 -2
  134. package/src/automerge/network-protocol.ts +2 -1
  135. package/src/automerge/space-collection.ts +2 -1
  136. package/src/db-host/automerge-metrics.ts +2 -1
  137. package/src/db-host/data-service.ts +4 -3
  138. package/src/db-host/database-root.ts +17 -22
  139. package/src/db-host/documents-iterator.ts +9 -8
  140. package/src/db-host/documents-synchronizer.test.ts +2 -2
  141. package/src/db-host/documents-synchronizer.ts +20 -18
  142. package/src/db-host/echo-host.ts +44 -15
  143. package/src/db-host/index.ts +0 -1
  144. package/src/db-host/query-service.ts +43 -37
  145. package/src/db-host/space-state-manager.ts +14 -4
  146. package/src/edge/echo-edge-replicator.test.ts +3 -3
  147. package/src/edge/echo-edge-replicator.ts +9 -8
  148. package/src/edge/inflight-request-limiter.ts +4 -4
  149. package/src/filter/filter-match.test.ts +101 -0
  150. package/src/filter/filter-match.ts +174 -0
  151. package/src/filter/index.ts +5 -0
  152. package/src/index.ts +1 -0
  153. package/src/metadata/metadata-store.ts +13 -13
  154. package/src/pipeline/pipeline-stress.test.ts +9 -9
  155. package/src/pipeline/pipeline.ts +13 -13
  156. package/src/pipeline/timeframe-clock.ts +5 -5
  157. package/src/query/errors.ts +7 -0
  158. package/src/query/index.ts +8 -0
  159. package/src/query/plan.ts +179 -0
  160. package/src/query/query-executor.ts +648 -0
  161. package/src/query/query-planner.test.ts +613 -0
  162. package/src/query/query-planner.ts +470 -0
  163. package/src/space/admission-discovery-extension.ts +2 -2
  164. package/src/space/control-pipeline.ts +8 -8
  165. package/src/space/space-manager.ts +5 -4
  166. package/src/space/space-protocol.browser.test.ts +1 -0
  167. package/src/space/space-protocol.test.ts +1 -0
  168. package/src/space/space-protocol.ts +4 -4
  169. package/src/space/space.ts +5 -5
  170. package/src/testing/index.ts +2 -0
  171. package/src/testing/test-agent-builder.ts +6 -6
  172. package/src/testing/test-data.ts +127 -0
  173. package/src/testing/test-network-adapter.ts +15 -12
  174. package/src/testing/test-replicator.ts +2 -2
  175. package/src/testing/test-schema.ts +53 -0
  176. package/src/util.ts +7 -3
  177. package/dist/lib/browser/chunk-32WDI3LB.mjs.map +0 -7
  178. package/dist/lib/node/chunk-TC2PRBEU.cjs.map +0 -7
  179. package/dist/lib/node-esm/chunk-UKOLB3LW.mjs.map +0 -7
  180. package/dist/types/src/db-host/query-state.d.ts +0 -41
  181. package/dist/types/src/db-host/query-state.d.ts.map +0 -1
  182. package/src/db-host/query-state.ts +0 -217
@@ -0,0 +1,174 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { decodeReference, isEncodedReference, type QueryAST, type ObjectStructure } from '@dxos/echo-protocol';
6
+ import { EXPANDO_TYPENAME } from '@dxos/echo-schema';
7
+ import { DXN, type ObjectId, type SpaceId } from '@dxos/keys';
8
+
9
+ export type MatchedObject = {
10
+ id: ObjectId;
11
+ spaceId: SpaceId;
12
+ doc: ObjectStructure;
13
+ };
14
+
15
+ /**
16
+ * Matches an object against a filter AST.
17
+ */
18
+ export const filterMatchObject = (filter: QueryAST.Filter, obj: MatchedObject): boolean => {
19
+ switch (filter.type) {
20
+ case 'object': {
21
+ // Check typename if specified
22
+ if (filter.typename !== null) {
23
+ // TODO(dmaretskyi): `system` is missing in some cases.
24
+ if (!obj.doc.system?.type?.['/']) {
25
+ // Objects with no type are considered to be expando objects
26
+ const expectedDXN = DXN.parse(filter.typename).asTypeDXN();
27
+ if (expectedDXN?.type !== EXPANDO_TYPENAME) {
28
+ return false;
29
+ }
30
+ } else {
31
+ const actualDXN = DXN.parse(obj.doc.system.type['/']);
32
+ const expectedDXN = DXN.parse(filter.typename);
33
+
34
+ if (!compareTypename(expectedDXN, actualDXN)) {
35
+ return false;
36
+ }
37
+ }
38
+ }
39
+
40
+ // Check IDs if specified
41
+ if (filter.id && filter.id.length > 0 && !filter.id.includes(obj.id)) {
42
+ return false;
43
+ }
44
+
45
+ // Check properties
46
+ if (filter.props) {
47
+ for (const [key, valueFilter] of Object.entries(filter.props)) {
48
+ const value = obj.doc.data[key];
49
+ if (!filterMatchValue(valueFilter, value)) {
50
+ return false;
51
+ }
52
+ }
53
+ }
54
+
55
+ // Check foreign keys if specified
56
+ if (filter.foreignKeys && filter.foreignKeys.length > 0) {
57
+ const hasMatchingKey = filter.foreignKeys.some((filterKey) =>
58
+ obj.doc.meta.keys.some((objKey) => objKey.source === filterKey.source && objKey.id === filterKey.id),
59
+ );
60
+ if (!hasMatchingKey) {
61
+ return false;
62
+ }
63
+ }
64
+
65
+ return true;
66
+ }
67
+
68
+ case 'text-search': {
69
+ // TODO: Implement text search
70
+ return false;
71
+ }
72
+
73
+ case 'not': {
74
+ return !filterMatchObject(filter.filter, obj);
75
+ }
76
+
77
+ case 'and': {
78
+ return filter.filters.every((f) => filterMatchObject(f, obj));
79
+ }
80
+
81
+ case 'or': {
82
+ return filter.filters.some((f) => filterMatchObject(f, obj));
83
+ }
84
+
85
+ default:
86
+ return false;
87
+ }
88
+ };
89
+
90
+ export const filterMatchValue = (filter: QueryAST.Filter, value: unknown): boolean => {
91
+ switch (filter.type) {
92
+ case 'compare': {
93
+ const compareValue = filter.value as any;
94
+ switch (filter.operator) {
95
+ case 'eq':
96
+ if (isEncodedReference(compareValue)) {
97
+ if (!isEncodedReference(value)) {
98
+ return false;
99
+ }
100
+ return DXN.equals(decodeReference(value).toDXN(), decodeReference(compareValue).toDXN());
101
+ }
102
+ return value === compareValue;
103
+ case 'neq':
104
+ return value !== compareValue;
105
+ case 'gt':
106
+ return (value as any) > compareValue;
107
+ case 'gte':
108
+ return (value as any) >= compareValue;
109
+ case 'lt':
110
+ return (value as any) < compareValue;
111
+ case 'lte':
112
+ return (value as any) <= compareValue;
113
+ }
114
+ break;
115
+ }
116
+ case 'in': {
117
+ return filter.values.includes(value);
118
+ }
119
+ case 'range': {
120
+ return (value as any) >= filter.from && (value as any) <= filter.to;
121
+ }
122
+ case 'not': {
123
+ return !filterMatchValue(filter.filter, value);
124
+ }
125
+ case 'and': {
126
+ return filter.filters.every((f) => filterMatchValue(f, value));
127
+ }
128
+ case 'or': {
129
+ return filter.filters.some((f) => filterMatchValue(f, value));
130
+ }
131
+ default:
132
+ return false;
133
+ }
134
+ };
135
+
136
+ /**
137
+ * Compares typename DXNs.
138
+ * @returns true if they match
139
+ *
140
+ * Compares typename string.
141
+ * Missing version (on either actual or expected) matches any version.
142
+ * non `type` DXNs are compared exactly.
143
+ *
144
+ * Examples: (expected) (actual)
145
+ *
146
+ * dxn:type:example.org/type/Task !== dxn:type:example.org/type/Contact
147
+ * dxn:type:example.org/type/Task === dxn:type:example.org/type/Task
148
+ * dxn:type:example.org/type/Task:0.1.0 !== dxn:type:example.org/type/Task:0.2.0
149
+ * dxn:type:example.org/type/Task === dxn:type:example.org/type/Task:0.1.0
150
+ * dxn:type:example.org/type/Task:0.1.0 === dxn:type:example.org/type/Task
151
+ *
152
+ */
153
+ const compareTypename = (expectedDXN: DXN, actualDXN: DXN): boolean => {
154
+ const expectedTypeDXN = expectedDXN.asTypeDXN();
155
+ if (expectedTypeDXN) {
156
+ const actualTypeDXN = actualDXN.asTypeDXN();
157
+ if (!actualTypeDXN) {
158
+ return false;
159
+ }
160
+ if (
161
+ actualTypeDXN.type !== expectedTypeDXN.type ||
162
+ (expectedTypeDXN.version !== undefined &&
163
+ actualTypeDXN.version !== undefined &&
164
+ actualTypeDXN.version !== expectedTypeDXN.version)
165
+ ) {
166
+ return false;
167
+ }
168
+ } else {
169
+ if (!DXN.equals(actualDXN, expectedDXN)) {
170
+ return false;
171
+ }
172
+ }
173
+ return true;
174
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './filter-match';
package/src/index.ts CHANGED
@@ -10,3 +10,4 @@ export * from './space';
10
10
  export * from './automerge';
11
11
  export * from './edge';
12
12
  export * from './util';
13
+ export * from './query';
@@ -126,7 +126,7 @@ export class MetadataStore {
126
126
  log('saved', { size: encoded.length, checksum });
127
127
  }
128
128
 
129
- async close() {
129
+ async close(): Promise<void> {
130
130
  await this._invitationCleanupCtx.dispose();
131
131
  await this.flush();
132
132
  await this._metadataFile?.close();
@@ -220,7 +220,7 @@ export class MetadataStore {
220
220
  await this._writeFile(file, LargeSpaceMetadata, data);
221
221
  }
222
222
 
223
- async flush() {
223
+ async flush(): Promise<void> {
224
224
  await this._directory.flush();
225
225
  }
226
226
 
@@ -268,7 +268,7 @@ export class MetadataStore {
268
268
  return this._metadata.identity;
269
269
  }
270
270
 
271
- async setIdentityRecord(record: IdentityRecord) {
271
+ async setIdentityRecord(record: IdentityRecord): Promise<void> {
272
272
  invariant(!this._metadata.identity, 'Cannot overwrite existing identity in metadata');
273
273
 
274
274
  this._metadata.identity = record;
@@ -280,7 +280,7 @@ export class MetadataStore {
280
280
  return this._metadata.invitations ?? [];
281
281
  }
282
282
 
283
- async addInvitation(invitation: Invitation) {
283
+ async addInvitation(invitation: Invitation): Promise<void> {
284
284
  if (this._metadata.invitations?.find((i) => i.invitationId === invitation.invitationId)) {
285
285
  return;
286
286
  }
@@ -290,13 +290,13 @@ export class MetadataStore {
290
290
  await this.flush();
291
291
  }
292
292
 
293
- async removeInvitation(invitationId: string) {
293
+ async removeInvitation(invitationId: string): Promise<void> {
294
294
  this._metadata.invitations = (this._metadata.invitations ?? []).filter((i) => i.invitationId !== invitationId);
295
295
  await this._save();
296
296
  await this.flush();
297
297
  }
298
298
 
299
- async addSpace(record: SpaceMetadata) {
299
+ async addSpace(record: SpaceMetadata): Promise<void> {
300
300
  invariant(
301
301
  !(this._metadata.spaces ?? []).find((space) => space.key.equals(record.key)),
302
302
  'Cannot overwrite existing space in metadata',
@@ -307,23 +307,23 @@ export class MetadataStore {
307
307
  await this.flush();
308
308
  }
309
309
 
310
- async setSpaceDataLatestTimeframe(spaceKey: PublicKey, timeframe: Timeframe) {
310
+ async setSpaceDataLatestTimeframe(spaceKey: PublicKey, timeframe: Timeframe): Promise<void> {
311
311
  this._getSpace(spaceKey).dataTimeframe = timeframe;
312
312
  await this._save();
313
313
  }
314
314
 
315
- async setSpaceControlLatestTimeframe(spaceKey: PublicKey, timeframe: Timeframe) {
315
+ async setSpaceControlLatestTimeframe(spaceKey: PublicKey, timeframe: Timeframe): Promise<void> {
316
316
  this._getSpace(spaceKey).controlTimeframe = timeframe;
317
317
  await this._save();
318
318
  await this.flush();
319
319
  }
320
320
 
321
- async setCache(spaceKey: PublicKey, cache: SpaceCache) {
321
+ async setCache(spaceKey: PublicKey, cache: SpaceCache): Promise<void> {
322
322
  this._getSpace(spaceKey).cache = cache;
323
323
  await this._save();
324
324
  }
325
325
 
326
- async setWritableFeedKeys(spaceKey: PublicKey, controlFeedKey: PublicKey, dataFeedKey: PublicKey) {
326
+ async setWritableFeedKeys(spaceKey: PublicKey, controlFeedKey: PublicKey, dataFeedKey: PublicKey): Promise<void> {
327
327
  const space = this._getSpace(spaceKey);
328
328
  space.controlFeedKey = controlFeedKey;
329
329
  space.dataFeedKey = dataFeedKey;
@@ -331,7 +331,7 @@ export class MetadataStore {
331
331
  await this.flush();
332
332
  }
333
333
 
334
- async setSpaceState(spaceKey: PublicKey, state: SpaceState) {
334
+ async setSpaceState(spaceKey: PublicKey, state: SpaceState): Promise<void> {
335
335
  this._getSpace(spaceKey).state = state;
336
336
  await this._save();
337
337
  await this.flush();
@@ -341,7 +341,7 @@ export class MetadataStore {
341
341
  return this._getLargeSpaceMetadata(spaceKey).controlPipelineSnapshot;
342
342
  }
343
343
 
344
- async setSpaceControlPipelineSnapshot(spaceKey: PublicKey, snapshot: ControlPipelineSnapshot) {
344
+ async setSpaceControlPipelineSnapshot(spaceKey: PublicKey, snapshot: ControlPipelineSnapshot): Promise<void> {
345
345
  this._getLargeSpaceMetadata(spaceKey).controlPipelineSnapshot = snapshot;
346
346
  await this._saveSpaceLargeMetadata(spaceKey);
347
347
  await this.flush();
@@ -351,7 +351,7 @@ export class MetadataStore {
351
351
  return this.hasSpace(spaceKey) ? this._getSpace(spaceKey).edgeReplication : undefined;
352
352
  }
353
353
 
354
- async setSpaceEdgeReplicationSetting(spaceKey: PublicKey, setting: EdgeReplicationSetting) {
354
+ async setSpaceEdgeReplicationSetting(spaceKey: PublicKey, setting: EdgeReplicationSetting): Promise<void> {
355
355
  this._getSpace(spaceKey).edgeReplication = setting;
356
356
  await this._save();
357
357
  await this.flush();
@@ -83,12 +83,12 @@ class Agent {
83
83
  public id: string,
84
84
  ) {}
85
85
 
86
- async open() {
86
+ async open(): Promise<void> {
87
87
  const key = await this.builder.keyring.createKey();
88
88
  this.feed = await this.feedStore.openFeed(key, { writable: true });
89
89
  }
90
90
 
91
- async start() {
91
+ async start(): Promise<void> {
92
92
  this.pipeline = new Pipeline();
93
93
  await this.pipeline.setCursor(this.startingTimeframe);
94
94
  await this.pipeline.start();
@@ -101,22 +101,22 @@ class Agent {
101
101
  void this.consume();
102
102
  }
103
103
 
104
- async stop() {
104
+ async stop(): Promise<void> {
105
105
  await this.pipeline.stop();
106
106
  this.startingTimeframe = this.pipeline.state.timeframe;
107
107
  }
108
108
 
109
- async close() {
109
+ async close(): Promise<void> {
110
110
  await this.feed.close();
111
111
  }
112
112
 
113
- write(message: FeedMessage.Payload) {
113
+ write(message: FeedMessage.Payload): void {
114
114
  const prev = this.writePromise;
115
115
  const promise = this.pipeline.writer!.write(message);
116
116
  this.writePromise = Promise.all([prev, promise]);
117
117
  }
118
118
 
119
- async consume() {
119
+ async consume(): Promise<void> {
120
120
  for await (const msg of this.pipeline.consume()) {
121
121
  this.messages.push(msg);
122
122
  }
@@ -139,7 +139,7 @@ class WriteCommand implements fc.AsyncCommand<Model, Real> {
139
139
 
140
140
  check = () => true;
141
141
 
142
- async run(model: Model, real: Real) {
142
+ async run(model: Model, real: Real): Promise<void> {
143
143
  // console.log(`WriteCommand(${this.agent}, ${this.count})`);
144
144
  const agent = real.agents.get(this.agent)!;
145
145
  const toWrite = Math.min(this.count, NUM_MESSAGES - agent.feed.length);
@@ -156,7 +156,7 @@ class WriteCommand implements fc.AsyncCommand<Model, Real> {
156
156
  class SyncCommand implements fc.AsyncCommand<Model, Real> {
157
157
  check = () => true;
158
158
 
159
- async run(model: Model, real: Real) {
159
+ async run(model: Model, real: Real): Promise<void> {
160
160
  // console.log('SyncCommand()');
161
161
  const targets: any = {};
162
162
 
@@ -217,7 +217,7 @@ class RestartCommand implements fc.AsyncCommand<Model, Real> {
217
217
 
218
218
  check = () => true;
219
219
 
220
- async run(model: Model, real: Real) {
220
+ async run(model: Model, real: Real): Promise<void> {
221
221
  log(`RestartCommand(${this.agent})`);
222
222
 
223
223
  const agent = real.agents.get(this.agent)!;
@@ -110,11 +110,11 @@ export class PipelineState {
110
110
  return Array.from(this._feeds.values());
111
111
  }
112
112
 
113
- async waitUntilTimeframe(target: Timeframe) {
113
+ async waitUntilTimeframe(target: Timeframe): Promise<void> {
114
114
  await this._timeframeClock.waitUntilReached(target);
115
115
  }
116
116
 
117
- setTargetTimeframe(target: Timeframe) {
117
+ setTargetTimeframe(target: Timeframe): void {
118
118
  this._targetTimeframe = target;
119
119
  }
120
120
 
@@ -129,7 +129,7 @@ export class PipelineState {
129
129
  ctx = new Context(),
130
130
  timeout,
131
131
  breakOnStall = true,
132
- }: WaitUntilReachedTargetParams = {}) {
132
+ }: WaitUntilReachedTargetParams = {}): Promise<void> {
133
133
  log('waitUntilReachedTargetTimeframe', {
134
134
  timeout,
135
135
  current: this.timeframe,
@@ -244,7 +244,7 @@ export class Pipeline implements PipelineAccessor {
244
244
  return this._writer;
245
245
  }
246
246
 
247
- hasFeed(feedKey: PublicKey) {
247
+ hasFeed(feedKey: PublicKey): boolean {
248
248
  return this._feeds.has(feedKey);
249
249
  }
250
250
 
@@ -254,7 +254,7 @@ export class Pipeline implements PipelineAccessor {
254
254
 
255
255
  // NOTE: This cannot be synchronized with `stop` because stop waits for the mutation processing to complete,
256
256
  // which might be opening feeds during the mutation processing, which w
257
- async addFeed(feed: FeedWrapper<FeedMessage>) {
257
+ async addFeed(feed: FeedWrapper<FeedMessage>): Promise<void> {
258
258
  this._feeds.set(feed.key, feed);
259
259
 
260
260
  if (this._feedSetIterator) {
@@ -266,7 +266,7 @@ export class Pipeline implements PipelineAccessor {
266
266
  }
267
267
  }
268
268
 
269
- setWriteFeed(feed: FeedWrapper<FeedMessage>) {
269
+ setWriteFeed(feed: FeedWrapper<FeedMessage>): void {
270
270
  invariant(!this._writer, 'Writer already set.');
271
271
  invariant(feed.properties.writable, 'Feed must be writable.');
272
272
 
@@ -280,7 +280,7 @@ export class Pipeline implements PipelineAccessor {
280
280
  }
281
281
 
282
282
  @synchronized
283
- async start() {
283
+ async start(): Promise<void> {
284
284
  invariant(!this._isStarted, 'Pipeline is already started.');
285
285
  log('starting...');
286
286
  await this._initIterator();
@@ -296,7 +296,7 @@ export class Pipeline implements PipelineAccessor {
296
296
  }
297
297
 
298
298
  @synchronized
299
- async stop() {
299
+ async stop(): Promise<void> {
300
300
  log('stopping...');
301
301
  this._isStopping = true;
302
302
  for (const [feed, handle] of this._downloads.entries()) {
@@ -318,7 +318,7 @@ export class Pipeline implements PipelineAccessor {
318
318
  * The pipeline will start processing messages AFTER this timeframe.
319
319
  */
320
320
  @synchronized
321
- async setCursor(timeframe: Timeframe) {
321
+ async setCursor(timeframe: Timeframe): Promise<void> {
322
322
  invariant(!this._isStarted || this._isPaused, 'Invalid state.');
323
323
 
324
324
  this._state._startTimeframe = timeframe;
@@ -336,7 +336,7 @@ export class Pipeline implements PipelineAccessor {
336
336
  * Calling pause while processing will cause a deadlock.
337
337
  */
338
338
  @synchronized
339
- async pause() {
339
+ async pause(): Promise<void> {
340
340
  if (this._isPaused) {
341
341
  return;
342
342
  }
@@ -347,7 +347,7 @@ export class Pipeline implements PipelineAccessor {
347
347
  }
348
348
 
349
349
  @synchronized
350
- async unpause() {
350
+ async unpause(): Promise<void> {
351
351
  invariant(this._isPaused, 'Pipeline is not paused.');
352
352
 
353
353
  this._pauseTrigger.wake();
@@ -396,7 +396,7 @@ export class Pipeline implements PipelineAccessor {
396
396
  this._isBeingConsumed = false;
397
397
  }
398
398
 
399
- private _setFeedDownloadState(feed: FeedWrapper<FeedMessage>) {
399
+ private _setFeedDownloadState(feed: FeedWrapper<FeedMessage>): void {
400
400
  let handle = this._downloads.get(feed); // TODO(burdon): Always undefined?
401
401
  if (handle) {
402
402
  feed.undownload(handle);
@@ -416,7 +416,7 @@ export class Pipeline implements PipelineAccessor {
416
416
  this._downloads.set(feed, handle);
417
417
  }
418
418
 
419
- private async _initIterator() {
419
+ private async _initIterator(): Promise<void> {
420
420
  this._feedSetIterator = new FeedSetIterator<FeedMessage>(createMessageSelector(this._timeframeClock), {
421
421
  start: startAfter(this._timeframeClock.timeframe),
422
422
  stallTimeout: 1000,
@@ -45,28 +45,28 @@ export class TimeframeClock {
45
45
  return this._pendingTimeframe;
46
46
  }
47
47
 
48
- setTimeframe(timeframe: Timeframe) {
48
+ setTimeframe(timeframe: Timeframe): void {
49
49
  this._timeframe = timeframe;
50
50
  this._pendingTimeframe = timeframe;
51
51
  this.update.emit(this._timeframe);
52
52
  }
53
53
 
54
- updatePendingTimeframe(key: PublicKey, seq: number) {
54
+ updatePendingTimeframe(key: PublicKey, seq: number): void {
55
55
  this._pendingTimeframe = Timeframe.merge(this._pendingTimeframe, new Timeframe([[key, seq]]));
56
56
  }
57
57
 
58
- updateTimeframe() {
58
+ updateTimeframe(): void {
59
59
  this._timeframe = this._pendingTimeframe;
60
60
  this.update.emit(this._timeframe);
61
61
  }
62
62
 
63
- hasGaps(timeframe: Timeframe) {
63
+ hasGaps(timeframe: Timeframe): boolean {
64
64
  const gaps = Timeframe.dependencies(timeframe, this._timeframe);
65
65
  return !gaps.isEmpty();
66
66
  }
67
67
 
68
68
  @timed(5_000)
69
- async waitUntilReached(target: Timeframe) {
69
+ async waitUntilReached(target: Timeframe): Promise<void> {
70
70
  log('waitUntilReached', { target, current: this._timeframe });
71
71
  await this.update.waitForCondition(() => {
72
72
  log('check if reached', {
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { BaseError } from '@dxos/errors';
6
+
7
+ export class QueryError extends BaseError.extend('QUERY_ERROR') {}
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './query-executor';
6
+ export * from './query-planner';
7
+ export * from './plan';
8
+ export * from '../filter/filter-match';