@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.
- package/dist/lib/browser/{chunk-32WDI3LB.mjs → chunk-3XSXS5EX.mjs} +15 -21
- package/dist/lib/browser/chunk-3XSXS5EX.mjs.map +7 -0
- package/dist/lib/browser/chunk-CGS2ULMK.mjs +11 -0
- package/dist/lib/browser/chunk-CGS2ULMK.mjs.map +7 -0
- package/dist/lib/browser/chunk-TQJTKNMS.mjs +126 -0
- package/dist/lib/browser/chunk-TQJTKNMS.mjs.map +7 -0
- package/dist/lib/browser/filter/index.mjs +11 -0
- package/dist/lib/browser/filter/index.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +1380 -516
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +202 -22
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node/chunk-HOPOFWAL.cjs +147 -0
- package/dist/lib/node/chunk-HOPOFWAL.cjs.map +7 -0
- package/dist/lib/node/chunk-Q7SFCCGT.cjs +33 -0
- package/dist/lib/node/chunk-Q7SFCCGT.cjs.map +7 -0
- package/dist/lib/node/{chunk-TC2PRBEU.cjs → chunk-SG2PL5RH.cjs} +18 -24
- package/dist/lib/node/chunk-SG2PL5RH.cjs.map +7 -0
- package/dist/lib/node/filter/index.cjs +32 -0
- package/dist/lib/node/filter/index.cjs.map +7 -0
- package/dist/lib/node/index.cjs +1381 -525
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +207 -31
- package/dist/lib/node/testing/index.cjs.map +4 -4
- package/dist/lib/node-esm/{chunk-UKOLB3LW.mjs → chunk-3BZP75TJ.mjs} +15 -21
- package/dist/lib/node-esm/chunk-3BZP75TJ.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-RVK35BS7.mjs +126 -0
- package/dist/lib/node-esm/chunk-RVK35BS7.mjs.map +7 -0
- package/dist/lib/node-esm/filter/index.mjs +11 -0
- package/dist/lib/node-esm/filter/index.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +1380 -516
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +202 -22
- package/dist/lib/node-esm/testing/index.mjs.map +4 -4
- package/dist/types/src/automerge/automerge-host.d.ts +6 -4
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/automerge/collection-synchronizer.d.ts +1 -1
- package/dist/types/src/automerge/collection-synchronizer.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-data-monitor.d.ts +6 -6
- package/dist/types/src/automerge/echo-data-monitor.d.ts.map +1 -1
- package/dist/types/src/automerge/echo-network-adapter.d.ts +4 -1
- package/dist/types/src/automerge/echo-network-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/heads-store.d.ts +2 -2
- package/dist/types/src/automerge/heads-store.d.ts.map +1 -1
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts +1 -1
- package/dist/types/src/automerge/leveldb-storage-adapter.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator-connection.d.ts.map +1 -1
- package/dist/types/src/automerge/mesh-echo-replicator.d.ts.map +1 -1
- package/dist/types/src/automerge/network-protocol.d.ts +1 -1
- package/dist/types/src/automerge/network-protocol.d.ts.map +1 -1
- package/dist/types/src/automerge/space-collection.d.ts +1 -1
- package/dist/types/src/automerge/space-collection.d.ts.map +1 -1
- package/dist/types/src/common/feeds.d.ts.map +1 -1
- package/dist/types/src/common/space-id.d.ts.map +1 -1
- package/dist/types/src/db-host/automerge-metrics.d.ts +1 -1
- package/dist/types/src/db-host/automerge-metrics.d.ts.map +1 -1
- package/dist/types/src/db-host/data-service.d.ts.map +1 -1
- package/dist/types/src/db-host/database-root.d.ts +7 -7
- package/dist/types/src/db-host/database-root.d.ts.map +1 -1
- package/dist/types/src/db-host/documents-iterator.d.ts +1 -1
- package/dist/types/src/db-host/documents-iterator.d.ts.map +1 -1
- package/dist/types/src/db-host/documents-synchronizer.d.ts +4 -4
- package/dist/types/src/db-host/documents-synchronizer.d.ts.map +1 -1
- package/dist/types/src/db-host/echo-host.d.ts +13 -2
- package/dist/types/src/db-host/echo-host.d.ts.map +1 -1
- package/dist/types/src/db-host/index.d.ts +0 -1
- package/dist/types/src/db-host/index.d.ts.map +1 -1
- package/dist/types/src/db-host/query-service.d.ts +2 -0
- package/dist/types/src/db-host/query-service.d.ts.map +1 -1
- package/dist/types/src/db-host/space-state-manager.d.ts +4 -3
- package/dist/types/src/db-host/space-state-manager.d.ts.map +1 -1
- package/dist/types/src/edge/echo-edge-replicator.d.ts.map +1 -1
- package/dist/types/src/edge/inflight-request-limiter.d.ts.map +1 -1
- package/dist/types/src/filter/filter-match.d.ts +13 -0
- package/dist/types/src/filter/filter-match.d.ts.map +1 -0
- package/dist/types/src/filter/filter-match.test.d.ts +2 -0
- package/dist/types/src/filter/filter-match.test.d.ts.map +1 -0
- package/dist/types/src/filter/index.d.ts +2 -0
- package/dist/types/src/filter/index.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/metadata/metadata-store.d.ts.map +1 -1
- package/dist/types/src/pipeline/message-selector.d.ts.map +1 -1
- package/dist/types/src/pipeline/pipeline.d.ts.map +1 -1
- package/dist/types/src/pipeline/timeframe-clock.d.ts.map +1 -1
- package/dist/types/src/query/errors.d.ts +23 -0
- package/dist/types/src/query/errors.d.ts.map +1 -0
- package/dist/types/src/query/index.d.ts +5 -0
- package/dist/types/src/query/index.d.ts.map +1 -0
- package/dist/types/src/query/plan.d.ts +132 -0
- package/dist/types/src/query/plan.d.ts.map +1 -0
- package/dist/types/src/query/query-executor.d.ts +83 -0
- package/dist/types/src/query/query-executor.d.ts.map +1 -0
- package/dist/types/src/query/query-planner.d.ts +33 -0
- package/dist/types/src/query/query-planner.d.ts.map +1 -0
- package/dist/types/src/query/query-planner.test.d.ts +2 -0
- package/dist/types/src/query/query-planner.test.d.ts.map +1 -0
- package/dist/types/src/space/admission-discovery-extension.d.ts.map +1 -1
- package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
- package/dist/types/src/space/space-manager.d.ts.map +1 -1
- package/dist/types/src/space/space-protocol.d.ts.map +1 -1
- package/dist/types/src/space/space.d.ts.map +1 -1
- package/dist/types/src/testing/change-metadata.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-data.d.ts +18 -0
- package/dist/types/src/testing/test-data.d.ts.map +1 -0
- package/dist/types/src/testing/test-network-adapter.d.ts +3 -2
- package/dist/types/src/testing/test-network-adapter.d.ts.map +1 -1
- package/dist/types/src/testing/test-schema.d.ts +39 -0
- package/dist/types/src/testing/test-schema.d.ts.map +1 -0
- package/dist/types/src/util.d.ts +2 -2
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +43 -34
- package/src/automerge/automerge-host.test.ts +7 -7
- package/src/automerge/automerge-host.ts +58 -60
- package/src/automerge/automerge-repo.test.ts +65 -65
- package/src/automerge/collection-synchronizer.test.ts +1 -1
- package/src/automerge/collection-synchronizer.ts +11 -10
- package/src/automerge/echo-data-monitor.ts +21 -20
- package/src/automerge/echo-network-adapter.test.ts +1 -1
- package/src/automerge/echo-network-adapter.ts +25 -18
- package/src/automerge/heads-store.ts +4 -3
- package/src/automerge/leveldb-storage-adapter.ts +1 -1
- package/src/automerge/mesh-echo-replicator-connection.ts +6 -5
- package/src/automerge/mesh-echo-replicator.ts +2 -2
- package/src/automerge/network-protocol.ts +2 -1
- package/src/automerge/space-collection.ts +2 -1
- package/src/db-host/automerge-metrics.ts +2 -1
- package/src/db-host/data-service.ts +4 -3
- package/src/db-host/database-root.ts +17 -22
- package/src/db-host/documents-iterator.ts +9 -8
- package/src/db-host/documents-synchronizer.test.ts +2 -2
- package/src/db-host/documents-synchronizer.ts +20 -18
- package/src/db-host/echo-host.ts +44 -15
- package/src/db-host/index.ts +0 -1
- package/src/db-host/query-service.ts +43 -37
- package/src/db-host/space-state-manager.ts +14 -4
- package/src/edge/echo-edge-replicator.test.ts +3 -3
- package/src/edge/echo-edge-replicator.ts +9 -8
- package/src/edge/inflight-request-limiter.ts +4 -4
- package/src/filter/filter-match.test.ts +101 -0
- package/src/filter/filter-match.ts +174 -0
- package/src/filter/index.ts +5 -0
- package/src/index.ts +1 -0
- package/src/metadata/metadata-store.ts +13 -13
- package/src/pipeline/pipeline-stress.test.ts +9 -9
- package/src/pipeline/pipeline.ts +13 -13
- package/src/pipeline/timeframe-clock.ts +5 -5
- package/src/query/errors.ts +7 -0
- package/src/query/index.ts +8 -0
- package/src/query/plan.ts +179 -0
- package/src/query/query-executor.ts +648 -0
- package/src/query/query-planner.test.ts +613 -0
- package/src/query/query-planner.ts +470 -0
- package/src/space/admission-discovery-extension.ts +2 -2
- package/src/space/control-pipeline.ts +8 -8
- package/src/space/space-manager.ts +5 -4
- package/src/space/space-protocol.browser.test.ts +1 -0
- package/src/space/space-protocol.test.ts +1 -0
- package/src/space/space-protocol.ts +4 -4
- package/src/space/space.ts +5 -5
- package/src/testing/index.ts +2 -0
- package/src/testing/test-agent-builder.ts +6 -6
- package/src/testing/test-data.ts +127 -0
- package/src/testing/test-network-adapter.ts +15 -12
- package/src/testing/test-replicator.ts +2 -2
- package/src/testing/test-schema.ts +53 -0
- package/src/util.ts +7 -3
- package/dist/lib/browser/chunk-32WDI3LB.mjs.map +0 -7
- package/dist/lib/node/chunk-TC2PRBEU.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-UKOLB3LW.mjs.map +0 -7
- package/dist/types/src/db-host/query-state.d.ts +0 -41
- package/dist/types/src/db-host/query-state.d.ts.map +0 -1
- 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
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -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)!;
|
package/src/pipeline/pipeline.ts
CHANGED
|
@@ -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', {
|