@powerhousedao/reactor 6.0.0-dev.26 → 6.0.0-dev.28
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/src/cache/document-meta-cache.js +3 -3
- package/dist/src/cache/document-meta-cache.js.map +1 -1
- package/dist/src/cache/kysely-operation-index.d.ts +2 -1
- package/dist/src/cache/kysely-operation-index.d.ts.map +1 -1
- package/dist/src/cache/kysely-operation-index.js +16 -4
- package/dist/src/cache/kysely-operation-index.js.map +1 -1
- package/dist/src/cache/kysely-write-cache.js +8 -8
- package/dist/src/cache/kysely-write-cache.js.map +1 -1
- package/dist/src/cache/operation-index-types.d.ts +2 -1
- package/dist/src/cache/operation-index-types.d.ts.map +1 -1
- package/dist/src/cache/operation-index-types.js.map +1 -1
- package/dist/src/client/reactor-client.d.ts +4 -6
- package/dist/src/client/reactor-client.d.ts.map +1 -1
- package/dist/src/client/reactor-client.js +20 -25
- package/dist/src/client/reactor-client.js.map +1 -1
- package/dist/src/client/types.d.ts +1 -4
- package/dist/src/client/types.d.ts.map +1 -1
- package/dist/src/core/reactor-builder.d.ts +3 -0
- package/dist/src/core/reactor-builder.d.ts.map +1 -1
- package/dist/src/core/reactor-builder.js +50 -6
- package/dist/src/core/reactor-builder.js.map +1 -1
- package/dist/src/core/reactor-client-builder.d.ts +3 -2
- package/dist/src/core/reactor-client-builder.d.ts.map +1 -1
- package/dist/src/core/reactor-client-builder.js +13 -4
- package/dist/src/core/reactor-client-builder.js.map +1 -1
- package/dist/src/core/reactor.d.ts +11 -75
- package/dist/src/core/reactor.d.ts.map +1 -1
- package/dist/src/core/reactor.js +87 -556
- package/dist/src/core/reactor.js.map +1 -1
- package/dist/src/core/types.d.ts +28 -19
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/core/utils.d.ts +6 -1
- package/dist/src/core/utils.d.ts.map +1 -1
- package/dist/src/core/utils.js +22 -6
- package/dist/src/core/utils.js.map +1 -1
- package/dist/src/executor/simple-job-executor.js +5 -5
- package/dist/src/executor/simple-job-executor.js.map +1 -1
- package/dist/src/index.d.ts +3 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/read-models/base-read-model.js +4 -4
- package/dist/src/read-models/base-read-model.js.map +1 -1
- package/dist/src/read-models/document-view.d.ts +5 -2
- package/dist/src/read-models/document-view.d.ts.map +1 -1
- package/dist/src/read-models/document-view.js +129 -28
- package/dist/src/read-models/document-view.js.map +1 -1
- package/dist/src/shared/collect-all-pages.d.ts +7 -0
- package/dist/src/shared/collect-all-pages.d.ts.map +1 -0
- package/dist/src/shared/collect-all-pages.js +17 -0
- package/dist/src/shared/collect-all-pages.js.map +1 -0
- package/dist/src/shared/drive-url.d.ts +1 -1
- package/dist/src/shared/drive-url.js +2 -2
- package/dist/src/shared/drive-url.js.map +1 -1
- package/dist/src/shared/factories.d.ts +6 -2
- package/dist/src/shared/factories.d.ts.map +1 -1
- package/dist/src/shared/factories.js +10 -2
- package/dist/src/shared/factories.js.map +1 -1
- package/dist/src/shared/types.d.ts +8 -0
- package/dist/src/shared/types.d.ts.map +1 -1
- package/dist/src/shared/types.js.map +1 -1
- package/dist/src/signer/passthrough-signer.d.ts +1 -1
- package/dist/src/signer/passthrough-signer.d.ts.map +1 -1
- package/dist/src/signer/passthrough-signer.js +1 -3
- package/dist/src/signer/passthrough-signer.js.map +1 -1
- package/dist/src/storage/interfaces.d.ts +38 -94
- package/dist/src/storage/interfaces.d.ts.map +1 -1
- package/dist/src/storage/interfaces.js.map +1 -1
- package/dist/src/storage/kysely/document-indexer.d.ts +6 -6
- package/dist/src/storage/kysely/document-indexer.d.ts.map +1 -1
- package/dist/src/storage/kysely/document-indexer.js +123 -52
- package/dist/src/storage/kysely/document-indexer.js.map +1 -1
- package/dist/src/storage/kysely/store.d.ts +2 -1
- package/dist/src/storage/kysely/store.d.ts.map +1 -1
- package/dist/src/storage/kysely/store.js +33 -15
- package/dist/src/storage/kysely/store.js.map +1 -1
- package/dist/src/sync/channels/composite-channel-factory.d.ts.map +1 -1
- package/dist/src/sync/channels/composite-channel-factory.js +5 -2
- package/dist/src/sync/channels/composite-channel-factory.js.map +1 -1
- package/dist/src/sync/channels/gql-channel-factory.d.ts.map +1 -1
- package/dist/src/sync/channels/gql-channel-factory.js +5 -2
- package/dist/src/sync/channels/gql-channel-factory.js.map +1 -1
- package/dist/src/sync/channels/gql-channel.d.ts +4 -9
- package/dist/src/sync/channels/gql-channel.d.ts.map +1 -1
- package/dist/src/sync/channels/gql-channel.js +11 -31
- package/dist/src/sync/channels/gql-channel.js.map +1 -1
- package/dist/src/sync/channels/index.d.ts +2 -0
- package/dist/src/sync/channels/index.d.ts.map +1 -1
- package/dist/src/sync/channels/index.js +2 -0
- package/dist/src/sync/channels/index.js.map +1 -1
- package/dist/src/sync/channels/interval-poll-timer.d.ts +18 -0
- package/dist/src/sync/channels/interval-poll-timer.d.ts.map +1 -0
- package/dist/src/sync/channels/interval-poll-timer.js +43 -0
- package/dist/src/sync/channels/interval-poll-timer.js.map +1 -0
- package/dist/src/sync/channels/poll-timer.d.ts +14 -0
- package/dist/src/sync/channels/poll-timer.d.ts.map +1 -0
- package/dist/src/sync/channels/poll-timer.js +2 -0
- package/dist/src/sync/channels/poll-timer.js.map +1 -0
- package/dist/src/sync/index.d.ts +1 -1
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/index.js +1 -1
- package/dist/src/sync/index.js.map +1 -1
- package/dist/src/sync/sync-manager.d.ts.map +1 -1
- package/dist/src/sync/sync-manager.js +3 -2
- package/dist/src/sync/sync-manager.js.map +1 -1
- package/package.json +3 -3
- package/dist/src/storage/consistency-aware-legacy-storage.d.ts +0 -33
- package/dist/src/storage/consistency-aware-legacy-storage.d.ts.map +0 -1
- package/dist/src/storage/consistency-aware-legacy-storage.js +0 -65
- package/dist/src/storage/consistency-aware-legacy-storage.js.map +0 -1
package/dist/src/core/reactor.js
CHANGED
|
@@ -5,7 +5,7 @@ import { ReactorEventTypes } from "../events/types.js";
|
|
|
5
5
|
import { createMutableShutdownStatus } from "../shared/factories.js";
|
|
6
6
|
import { JobStatus } from "../shared/types.js";
|
|
7
7
|
import { matchesScope } from "../shared/utils.js";
|
|
8
|
-
import { filterByType,
|
|
8
|
+
import { filterByType, getSharedActionScope, getSharedOperationScope, signAction, signActions, toErrorInfo, topologicalSort, validateActionScopes, validateBatchRequest, } from "./utils.js";
|
|
9
9
|
/**
|
|
10
10
|
* This class implements the IReactor interface and serves as the main entry point
|
|
11
11
|
* for the new Reactor architecture.
|
|
@@ -13,67 +13,62 @@ import { filterByType, getSharedScope, signAction, signActions, toErrorInfo, top
|
|
|
13
13
|
export class Reactor {
|
|
14
14
|
logger;
|
|
15
15
|
documentModelRegistry;
|
|
16
|
-
documentStorage;
|
|
17
16
|
shutdownStatus;
|
|
18
17
|
setShutdown;
|
|
18
|
+
setCompleted;
|
|
19
19
|
queue;
|
|
20
20
|
jobTracker;
|
|
21
21
|
readModelCoordinator;
|
|
22
22
|
features;
|
|
23
23
|
documentView;
|
|
24
|
-
|
|
24
|
+
documentIndexer;
|
|
25
25
|
operationStore;
|
|
26
26
|
eventBus;
|
|
27
|
-
|
|
27
|
+
executorManager;
|
|
28
|
+
constructor(logger, documentModelRegistry, queue, jobTracker, readModelCoordinator, features, documentView, documentIndexer, operationStore, eventBus, executorManager) {
|
|
28
29
|
this.logger = logger;
|
|
29
30
|
this.documentModelRegistry = documentModelRegistry;
|
|
30
|
-
this.documentStorage = documentStorage;
|
|
31
31
|
this.queue = queue;
|
|
32
32
|
this.jobTracker = jobTracker;
|
|
33
33
|
this.readModelCoordinator = readModelCoordinator;
|
|
34
34
|
this.features = features;
|
|
35
35
|
this.documentView = documentView;
|
|
36
|
-
this.
|
|
36
|
+
this.documentIndexer = documentIndexer;
|
|
37
37
|
this.operationStore = operationStore;
|
|
38
38
|
this.eventBus = eventBus;
|
|
39
|
-
|
|
39
|
+
this.executorManager = executorManager;
|
|
40
|
+
const [status, setShutdown, setCompleted] = createMutableShutdownStatus(false);
|
|
40
41
|
this.shutdownStatus = status;
|
|
41
|
-
this.setShutdown =
|
|
42
|
-
this.
|
|
42
|
+
this.setShutdown = setShutdown;
|
|
43
|
+
this.setCompleted = setCompleted;
|
|
43
44
|
this.readModelCoordinator.start();
|
|
44
45
|
}
|
|
45
|
-
/**
|
|
46
|
-
* Signals that the reactor should shutdown.
|
|
47
|
-
*/
|
|
48
46
|
kill() {
|
|
49
47
|
this.logger.verbose("kill()");
|
|
50
|
-
|
|
48
|
+
if (this.shutdownStatus.isShutdown) {
|
|
49
|
+
return this.shutdownStatus;
|
|
50
|
+
}
|
|
51
51
|
this.setShutdown(true);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
const shutdownAsync = async () => {
|
|
53
|
+
await this.executorManager.stop(true);
|
|
54
|
+
this.readModelCoordinator.stop();
|
|
55
|
+
this.jobTracker.shutdown();
|
|
56
|
+
};
|
|
57
|
+
this.setCompleted(shutdownAsync());
|
|
56
58
|
return this.shutdownStatus;
|
|
57
59
|
}
|
|
58
|
-
/**
|
|
59
|
-
* Retrieves a list of document model specifications
|
|
60
|
-
*/
|
|
61
60
|
getDocumentModels(namespace, paging, signal) {
|
|
62
61
|
this.logger.verbose("getDocumentModels(@namespace, @paging)", namespace, paging);
|
|
63
|
-
|
|
62
|
+
if (signal?.aborted) {
|
|
63
|
+
throw new AbortError();
|
|
64
|
+
}
|
|
64
65
|
const modules = this.documentModelRegistry.getAllModules();
|
|
65
66
|
const filteredModels = modules.filter((module) => !namespace || module.documentModel.global.id.startsWith(namespace));
|
|
66
|
-
// Apply paging
|
|
67
67
|
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
68
68
|
const limit = paging?.limit || filteredModels.length;
|
|
69
69
|
const pagedModels = filteredModels.slice(startIndex, startIndex + limit);
|
|
70
|
-
// Create paged results
|
|
71
70
|
const hasMore = startIndex + limit < filteredModels.length;
|
|
72
71
|
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
73
|
-
// even thought this is currently synchronous, they could have passed in an already-aborted signal
|
|
74
|
-
if (signal?.aborted) {
|
|
75
|
-
throw new AbortError();
|
|
76
|
-
}
|
|
77
72
|
return Promise.resolve({
|
|
78
73
|
results: pagedModels,
|
|
79
74
|
options: paging || { cursor: "0", limit: filteredModels.length },
|
|
@@ -83,197 +78,70 @@ export class Reactor {
|
|
|
83
78
|
: undefined,
|
|
84
79
|
});
|
|
85
80
|
}
|
|
86
|
-
/**
|
|
87
|
-
* Retrieves a specific PHDocument by id
|
|
88
|
-
*/
|
|
89
81
|
async get(id, view, consistencyToken, signal) {
|
|
90
82
|
this.logger.verbose("get(@id, @view)", id, view);
|
|
91
|
-
|
|
92
|
-
const document = await this.documentStorage.get(id, consistencyToken, signal);
|
|
93
|
-
if (signal?.aborted) {
|
|
94
|
-
throw new AbortError();
|
|
95
|
-
}
|
|
96
|
-
const childIds = await this.documentStorage.getChildren(id, consistencyToken, signal);
|
|
97
|
-
if (signal?.aborted) {
|
|
98
|
-
throw new AbortError();
|
|
99
|
-
}
|
|
100
|
-
for (const scope in document.state) {
|
|
101
|
-
if (!matchesScope(view, scope)) {
|
|
102
|
-
delete document.state[scope];
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return {
|
|
106
|
-
document,
|
|
107
|
-
childIds,
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
const document = await this.documentView.get(id, view, consistencyToken, signal);
|
|
112
|
-
if (signal?.aborted) {
|
|
113
|
-
throw new AbortError();
|
|
114
|
-
}
|
|
115
|
-
const relationships = await this._documentIndexer.getOutgoing(id, ["child"], consistencyToken, signal);
|
|
116
|
-
if (signal?.aborted) {
|
|
117
|
-
throw new AbortError();
|
|
118
|
-
}
|
|
119
|
-
const childIds = relationships.map((rel) => rel.targetId);
|
|
120
|
-
return {
|
|
121
|
-
document,
|
|
122
|
-
childIds,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
83
|
+
return await this.documentView.get(id, view, consistencyToken, signal);
|
|
125
84
|
}
|
|
126
|
-
/**
|
|
127
|
-
* Retrieves a specific PHDocument by slug
|
|
128
|
-
*/
|
|
129
85
|
async getBySlug(slug, view, consistencyToken, signal) {
|
|
130
86
|
this.logger.verbose("getBySlug(@slug, @view)", slug, view);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
ids = await this.documentStorage.resolveIds([slug], consistencyToken, signal);
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
if (error instanceof Error && error.message.includes("not found")) {
|
|
138
|
-
throw new Error(`Document not found with slug: ${slug}`);
|
|
139
|
-
}
|
|
140
|
-
throw error;
|
|
141
|
-
}
|
|
142
|
-
if (ids.length === 0 || !ids[0]) {
|
|
143
|
-
throw new Error(`Document not found with slug: ${slug}`);
|
|
144
|
-
}
|
|
145
|
-
return await this.get(ids[0], view, consistencyToken, signal);
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
const documentId = await this.documentView.resolveSlug(slug, view, consistencyToken, signal);
|
|
149
|
-
if (!documentId) {
|
|
150
|
-
throw new Error(`Document not found with slug: ${slug}`);
|
|
151
|
-
}
|
|
152
|
-
return await this.get(documentId, view, consistencyToken, signal);
|
|
87
|
+
const documentId = await this.documentView.resolveSlug(slug, view, consistencyToken, signal);
|
|
88
|
+
if (!documentId) {
|
|
89
|
+
throw new Error(`Document not found with slug: ${slug}`);
|
|
153
90
|
}
|
|
91
|
+
return await this.get(documentId, view, consistencyToken, signal);
|
|
154
92
|
}
|
|
155
|
-
/**
|
|
156
|
-
* Retrieves a specific PHDocument by identifier (either id or slug)
|
|
157
|
-
*/
|
|
158
93
|
async getByIdOrSlug(identifier, view, consistencyToken, signal) {
|
|
159
94
|
this.logger.verbose("getByIdOrSlug(@identifier, @view)", identifier, view);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const ids = await this.documentStorage.resolveIds([identifier], consistencyToken, signal);
|
|
167
|
-
if (ids.length === 0 || !ids[0]) {
|
|
168
|
-
throw new Error(`Document not found: ${identifier}`);
|
|
169
|
-
}
|
|
170
|
-
return await this.get(ids[0], view, consistencyToken, signal);
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
throw new Error(`Document not found: ${identifier}`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
95
|
+
return await this.documentView.getByIdOrSlug(identifier, view, consistencyToken, signal);
|
|
96
|
+
}
|
|
97
|
+
async getChildren(documentId, consistencyToken, signal) {
|
|
98
|
+
const relationships = await this.documentIndexer.getOutgoing(documentId, ["child"], undefined, consistencyToken, signal);
|
|
99
|
+
if (signal?.aborted) {
|
|
100
|
+
throw new AbortError();
|
|
176
101
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (signal?.aborted) {
|
|
184
|
-
throw new AbortError();
|
|
185
|
-
}
|
|
186
|
-
const childIds = relationships.map((rel) => rel.targetId);
|
|
187
|
-
return {
|
|
188
|
-
document,
|
|
189
|
-
childIds,
|
|
190
|
-
};
|
|
102
|
+
return relationships.results.map((rel) => rel.targetId);
|
|
103
|
+
}
|
|
104
|
+
async getParents(childId, consistencyToken, signal) {
|
|
105
|
+
const relationships = await this.documentIndexer.getIncoming(childId, ["parent"], undefined, consistencyToken, signal);
|
|
106
|
+
if (signal?.aborted) {
|
|
107
|
+
throw new AbortError();
|
|
191
108
|
}
|
|
109
|
+
return relationships.results.map((rel) => rel.sourceId);
|
|
192
110
|
}
|
|
193
|
-
/**
|
|
194
|
-
* Retrieves the operations for a document
|
|
195
|
-
*/
|
|
196
111
|
async getOperations(documentId, view, filter, paging, consistencyToken, signal) {
|
|
197
112
|
this.logger.verbose("getOperations(@documentId, @view, @filter, @paging)", documentId, view, filter, paging);
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
const operations = document.operations;
|
|
204
|
-
const result = {};
|
|
205
|
-
for (const scope in operations) {
|
|
206
|
-
if (matchesScope(view, scope)) {
|
|
207
|
-
let scopeOperations = operations[scope];
|
|
208
|
-
if (filter) {
|
|
209
|
-
if (filter.actionTypes && filter.actionTypes.length > 0) {
|
|
210
|
-
scopeOperations = scopeOperations.filter((op) => filter.actionTypes.includes(op.action.type));
|
|
211
|
-
}
|
|
212
|
-
if (filter.sinceRevision !== undefined) {
|
|
213
|
-
scopeOperations = scopeOperations.filter((op) => op.index >= filter.sinceRevision);
|
|
214
|
-
}
|
|
215
|
-
if (filter.timestampFrom) {
|
|
216
|
-
const fromMs = new Date(filter.timestampFrom).getTime();
|
|
217
|
-
scopeOperations = scopeOperations.filter((op) => new Date(op.timestampUtcMs).getTime() >= fromMs);
|
|
218
|
-
}
|
|
219
|
-
if (filter.timestampTo) {
|
|
220
|
-
const toMs = new Date(filter.timestampTo).getTime();
|
|
221
|
-
scopeOperations = scopeOperations.filter((op) => new Date(op.timestampUtcMs).getTime() <= toMs);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
225
|
-
const limit = paging?.limit || scopeOperations.length;
|
|
226
|
-
const pagedOperations = scopeOperations.slice(startIndex, startIndex + limit);
|
|
227
|
-
result[scope] = {
|
|
228
|
-
results: pagedOperations,
|
|
229
|
-
options: { cursor: String(startIndex + limit), limit },
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return Promise.resolve(result);
|
|
113
|
+
const branch = view?.branch || "main";
|
|
114
|
+
const revisions = await this.operationStore.getRevisions(documentId, branch, signal);
|
|
115
|
+
if (signal?.aborted) {
|
|
116
|
+
throw new AbortError();
|
|
234
117
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
118
|
+
const allScopes = Object.keys(revisions.revision);
|
|
119
|
+
const result = {};
|
|
120
|
+
for (const scope of allScopes) {
|
|
121
|
+
if (!matchesScope(view, scope)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
238
124
|
if (signal?.aborted) {
|
|
239
125
|
throw new AbortError();
|
|
240
126
|
}
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
cursor: scopeResult.nextCursor || String(currentCursor),
|
|
257
|
-
limit: currentLimit,
|
|
258
|
-
},
|
|
259
|
-
nextCursor: scopeResult.nextCursor,
|
|
260
|
-
next: scopeResult.hasMore
|
|
261
|
-
? async () => {
|
|
262
|
-
const nextPage = await this.getOperations(documentId, view, filter, {
|
|
263
|
-
cursor: scopeResult.nextCursor,
|
|
264
|
-
limit: currentLimit,
|
|
265
|
-
}, consistencyToken, signal);
|
|
266
|
-
return nextPage[scope];
|
|
267
|
-
}
|
|
268
|
-
: undefined,
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
return result;
|
|
127
|
+
const scopeResult = await this.operationStore.getSince(documentId, scope, branch, -1, filter, paging, signal);
|
|
128
|
+
result[scope] = {
|
|
129
|
+
results: scopeResult.results,
|
|
130
|
+
options: scopeResult.options,
|
|
131
|
+
nextCursor: scopeResult.nextCursor,
|
|
132
|
+
next: scopeResult.next
|
|
133
|
+
? async () => {
|
|
134
|
+
const nextPage = await this.getOperations(documentId, view, filter, {
|
|
135
|
+
cursor: scopeResult.nextCursor,
|
|
136
|
+
limit: scopeResult.options.limit,
|
|
137
|
+
}, consistencyToken, signal);
|
|
138
|
+
return nextPage[scope];
|
|
139
|
+
}
|
|
140
|
+
: undefined,
|
|
141
|
+
};
|
|
272
142
|
}
|
|
143
|
+
return result;
|
|
273
144
|
}
|
|
274
|
-
/**
|
|
275
|
-
* Filters documents by criteria and returns a list of them
|
|
276
|
-
*/
|
|
277
145
|
async find(search, view, paging, consistencyToken, signal) {
|
|
278
146
|
this.logger.verbose("find(@search, @view, @paging)", search, view, paging);
|
|
279
147
|
let results;
|
|
@@ -293,7 +161,7 @@ export class Reactor {
|
|
|
293
161
|
}
|
|
294
162
|
}
|
|
295
163
|
else if (search.parentId) {
|
|
296
|
-
results = await this.findByParentId(search.parentId, view, paging, signal);
|
|
164
|
+
results = await this.findByParentId(search.parentId, view, paging, consistencyToken, signal);
|
|
297
165
|
if (search.type) {
|
|
298
166
|
results = filterByType(results, search.type);
|
|
299
167
|
}
|
|
@@ -309,9 +177,6 @@ export class Reactor {
|
|
|
309
177
|
}
|
|
310
178
|
return results;
|
|
311
179
|
}
|
|
312
|
-
/**
|
|
313
|
-
* Creates a document
|
|
314
|
-
*/
|
|
315
180
|
async create(document, signer, signal, meta) {
|
|
316
181
|
this.logger.verbose("create(@id, @type, @slug)", document.header.id, document.header.documentType, document.header.slug);
|
|
317
182
|
const createdAtUtcIso = new Date().toISOString();
|
|
@@ -345,12 +210,10 @@ export class Reactor {
|
|
|
345
210
|
toVersion: document.state.document.version,
|
|
346
211
|
initialState: document.state,
|
|
347
212
|
});
|
|
348
|
-
// Sign actions if signer is provided
|
|
349
213
|
let actions = [createAction, upgradeAction];
|
|
350
214
|
if (signer) {
|
|
351
215
|
actions = await signActions(actions, signer, signal);
|
|
352
216
|
}
|
|
353
|
-
// Create a single job with both CREATE_DOCUMENT and UPGRADE_DOCUMENT actions
|
|
354
217
|
const job = {
|
|
355
218
|
id: uuidv4(),
|
|
356
219
|
kind: "mutation",
|
|
@@ -365,7 +228,6 @@ export class Reactor {
|
|
|
365
228
|
errorHistory: [],
|
|
366
229
|
meta,
|
|
367
230
|
};
|
|
368
|
-
// Create job info and register with tracker
|
|
369
231
|
const jobInfo = {
|
|
370
232
|
id: job.id,
|
|
371
233
|
status: JobStatus.PENDING,
|
|
@@ -379,13 +241,9 @@ export class Reactor {
|
|
|
379
241
|
};
|
|
380
242
|
this.jobTracker.registerJob(jobInfo);
|
|
381
243
|
this.emitJobPending(jobInfo.id, meta);
|
|
382
|
-
// Enqueue the job
|
|
383
244
|
await this.queue.enqueue(job);
|
|
384
245
|
return jobInfo;
|
|
385
246
|
}
|
|
386
|
-
/**
|
|
387
|
-
* Deletes a document
|
|
388
|
-
*/
|
|
389
247
|
async deleteDocument(id, signer, signal, meta) {
|
|
390
248
|
this.logger.verbose("deleteDocument(@id)", id);
|
|
391
249
|
const createdAtUtcIso = new Date().toISOString();
|
|
@@ -393,7 +251,6 @@ export class Reactor {
|
|
|
393
251
|
throw new AbortError();
|
|
394
252
|
}
|
|
395
253
|
let action = deleteDocumentAction(id);
|
|
396
|
-
// Sign action if signer is provided
|
|
397
254
|
if (signer) {
|
|
398
255
|
action = await signAction(action, signer, signal);
|
|
399
256
|
}
|
|
@@ -427,18 +284,13 @@ export class Reactor {
|
|
|
427
284
|
await this.queue.enqueue(job);
|
|
428
285
|
return jobInfo;
|
|
429
286
|
}
|
|
430
|
-
/**
|
|
431
|
-
* Applies a list of actions to a document
|
|
432
|
-
*/
|
|
433
287
|
async execute(docId, branch, actions, signal, meta) {
|
|
434
288
|
this.logger.verbose("execute(@docId, @branch, @actions)", docId, branch, actions);
|
|
435
289
|
if (signal?.aborted) {
|
|
436
290
|
throw new AbortError();
|
|
437
291
|
}
|
|
438
292
|
const createdAtUtcIso = new Date().toISOString();
|
|
439
|
-
|
|
440
|
-
const scope = actions.length > 0 ? actions[0].scope || "global" : "global";
|
|
441
|
-
// Create a single job with all actions
|
|
293
|
+
const scope = getSharedActionScope(actions);
|
|
442
294
|
const job = {
|
|
443
295
|
id: uuidv4(),
|
|
444
296
|
kind: "mutation",
|
|
@@ -453,7 +305,6 @@ export class Reactor {
|
|
|
453
305
|
errorHistory: [],
|
|
454
306
|
meta,
|
|
455
307
|
};
|
|
456
|
-
// Create job info and register with tracker
|
|
457
308
|
const jobInfo = {
|
|
458
309
|
id: job.id,
|
|
459
310
|
status: JobStatus.PENDING,
|
|
@@ -467,18 +318,12 @@ export class Reactor {
|
|
|
467
318
|
};
|
|
468
319
|
this.jobTracker.registerJob(jobInfo);
|
|
469
320
|
this.emitJobPending(jobInfo.id, meta);
|
|
470
|
-
// Enqueue the job
|
|
471
321
|
await this.queue.enqueue(job);
|
|
472
322
|
if (signal?.aborted) {
|
|
473
323
|
throw new AbortError();
|
|
474
324
|
}
|
|
475
325
|
return jobInfo;
|
|
476
326
|
}
|
|
477
|
-
/**
|
|
478
|
-
* Imports pre-existing operations that were produced by another reactor.
|
|
479
|
-
* This function may cause a reshuffle, which will generate additional
|
|
480
|
-
* operations.
|
|
481
|
-
*/
|
|
482
327
|
async load(docId, branch, operations, signal, meta) {
|
|
483
328
|
this.logger.verbose("load(@docId, @branch, @count, @operations)", docId, branch, operations.length, operations);
|
|
484
329
|
if (signal?.aborted) {
|
|
@@ -487,13 +332,7 @@ export class Reactor {
|
|
|
487
332
|
if (operations.length === 0) {
|
|
488
333
|
throw new Error("load requires at least one operation");
|
|
489
334
|
}
|
|
490
|
-
|
|
491
|
-
const scope = getSharedScope(operations);
|
|
492
|
-
operations.forEach((operation, index) => {
|
|
493
|
-
if (!operation.timestampUtcMs) {
|
|
494
|
-
throw new Error(`Operation at position ${index} is missing timestampUtcMs`);
|
|
495
|
-
}
|
|
496
|
-
});
|
|
335
|
+
const scope = getSharedOperationScope(operations);
|
|
497
336
|
const createdAtUtcIso = new Date().toISOString();
|
|
498
337
|
const job = {
|
|
499
338
|
id: uuidv4(),
|
|
@@ -528,9 +367,6 @@ export class Reactor {
|
|
|
528
367
|
}
|
|
529
368
|
return jobInfo;
|
|
530
369
|
}
|
|
531
|
-
/**
|
|
532
|
-
* Applies multiple mutations across documents with dependency management
|
|
533
|
-
*/
|
|
534
370
|
async executeBatch(request, signal, meta) {
|
|
535
371
|
this.logger.verbose("executeBatch(@count jobs)", request.jobs.length);
|
|
536
372
|
if (signal?.aborted) {
|
|
@@ -611,39 +447,28 @@ export class Reactor {
|
|
|
611
447
|
};
|
|
612
448
|
return result;
|
|
613
449
|
}
|
|
614
|
-
/**
|
|
615
|
-
* Adds multiple documents as children to another
|
|
616
|
-
*/
|
|
617
450
|
async addChildren(parentId, documentIds, branch = "main", signer, signal) {
|
|
618
451
|
this.logger.verbose("addChildren(@parentId, @count children, @branch)", parentId, documentIds.length, branch);
|
|
619
452
|
if (signal?.aborted) {
|
|
620
453
|
throw new AbortError();
|
|
621
454
|
}
|
|
622
455
|
let actions = documentIds.map((childId) => addRelationshipAction(parentId, childId, "child"));
|
|
623
|
-
// Sign actions if signer is provided
|
|
624
456
|
if (signer) {
|
|
625
457
|
actions = await signActions(actions, signer, signal);
|
|
626
458
|
}
|
|
627
459
|
return await this.execute(parentId, branch, actions, signal);
|
|
628
460
|
}
|
|
629
|
-
/**
|
|
630
|
-
* Removes multiple documents as children from another
|
|
631
|
-
*/
|
|
632
461
|
async removeChildren(parentId, documentIds, branch = "main", signer, signal) {
|
|
633
462
|
this.logger.verbose("removeChildren(@parentId, @count children, @branch)", parentId, documentIds.length, branch);
|
|
634
463
|
if (signal?.aborted) {
|
|
635
464
|
throw new AbortError();
|
|
636
465
|
}
|
|
637
466
|
let actions = documentIds.map((childId) => removeRelationshipAction(parentId, childId, "child"));
|
|
638
|
-
// Sign actions if signer is provided
|
|
639
467
|
if (signer) {
|
|
640
468
|
actions = await signActions(actions, signer, signal);
|
|
641
469
|
}
|
|
642
470
|
return await this.execute(parentId, branch, actions, signal);
|
|
643
471
|
}
|
|
644
|
-
/**
|
|
645
|
-
* Retrieves the status of a job
|
|
646
|
-
*/
|
|
647
472
|
getJobStatus(jobId, signal) {
|
|
648
473
|
this.logger.verbose("getJobStatus(@jobId)", jobId);
|
|
649
474
|
if (signal?.aborted) {
|
|
@@ -651,7 +476,6 @@ export class Reactor {
|
|
|
651
476
|
}
|
|
652
477
|
const jobInfo = this.jobTracker.getJobStatus(jobId);
|
|
653
478
|
if (!jobInfo) {
|
|
654
|
-
// Job not found - return FAILED status with appropriate error
|
|
655
479
|
const now = new Date().toISOString();
|
|
656
480
|
return Promise.resolve({
|
|
657
481
|
id: jobId,
|
|
@@ -668,327 +492,34 @@ export class Reactor {
|
|
|
668
492
|
}
|
|
669
493
|
return Promise.resolve(jobInfo);
|
|
670
494
|
}
|
|
671
|
-
/**
|
|
672
|
-
* Finds documents by their IDs
|
|
673
|
-
*/
|
|
674
495
|
async findByIds(ids, view, paging, consistencyToken, signal) {
|
|
675
496
|
this.logger.verbose("findByIds(@count ids)", ids.length);
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
try {
|
|
688
|
-
document = await this.documentStorage.get(id, consistencyToken, signal);
|
|
689
|
-
}
|
|
690
|
-
catch {
|
|
691
|
-
// Skip documents that don't exist or can't be accessed
|
|
692
|
-
// This matches the behavior expected from a search operation
|
|
693
|
-
continue;
|
|
694
|
-
}
|
|
695
|
-
// Apply view filter - This will be removed when we pass the viewfilter along
|
|
696
|
-
// to the underlying store, but is here now for the interface.
|
|
697
|
-
for (const scope in document.state) {
|
|
698
|
-
if (!matchesScope(view, scope)) {
|
|
699
|
-
delete document.state[scope];
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
documents.push(document);
|
|
703
|
-
}
|
|
704
|
-
if (signal?.aborted) {
|
|
705
|
-
throw new AbortError();
|
|
706
|
-
}
|
|
707
|
-
// Apply paging
|
|
708
|
-
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
709
|
-
const limit = paging?.limit || documents.length;
|
|
710
|
-
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
711
|
-
// Create paged results
|
|
712
|
-
const hasMore = startIndex + limit < documents.length;
|
|
713
|
-
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
714
|
-
return {
|
|
715
|
-
results: pagedDocuments,
|
|
716
|
-
options: paging || { cursor: "0", limit: documents.length },
|
|
717
|
-
nextCursor,
|
|
718
|
-
next: hasMore
|
|
719
|
-
? () => this.findByIds(ids, view, { cursor: nextCursor, limit }, consistencyToken, signal)
|
|
720
|
-
: undefined,
|
|
721
|
-
};
|
|
722
|
-
}
|
|
723
|
-
else {
|
|
724
|
-
const documents = [];
|
|
725
|
-
// Fetch each document by ID using documentView
|
|
726
|
-
for (const id of ids) {
|
|
727
|
-
if (signal?.aborted) {
|
|
728
|
-
throw new AbortError();
|
|
729
|
-
}
|
|
730
|
-
try {
|
|
731
|
-
const document = await this.documentView.get(id, view, undefined, signal);
|
|
732
|
-
documents.push(document);
|
|
733
|
-
}
|
|
734
|
-
catch {
|
|
735
|
-
// Skip documents that don't exist or can't be accessed
|
|
736
|
-
continue;
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
if (signal?.aborted) {
|
|
740
|
-
throw new AbortError();
|
|
741
|
-
}
|
|
742
|
-
// Apply paging
|
|
743
|
-
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
744
|
-
const limit = paging?.limit || documents.length;
|
|
745
|
-
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
746
|
-
// Create paged results
|
|
747
|
-
const hasMore = startIndex + limit < documents.length;
|
|
748
|
-
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
749
|
-
return {
|
|
750
|
-
results: pagedDocuments,
|
|
751
|
-
options: paging || { cursor: "0", limit: documents.length },
|
|
752
|
-
nextCursor,
|
|
753
|
-
next: hasMore
|
|
754
|
-
? () => this.findByIds(ids, view, { cursor: nextCursor, limit }, consistencyToken, signal)
|
|
755
|
-
: undefined,
|
|
756
|
-
};
|
|
757
|
-
}
|
|
497
|
+
const startIndex = paging?.cursor ? parseInt(paging.cursor) || 0 : 0;
|
|
498
|
+
const limit = paging?.limit || ids.length;
|
|
499
|
+
const pagedIds = ids.slice(startIndex, startIndex + limit);
|
|
500
|
+
const results = await this.documentView.getMany(pagedIds, view, consistencyToken, signal);
|
|
501
|
+
const hasMore = startIndex + limit < ids.length;
|
|
502
|
+
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
503
|
+
return {
|
|
504
|
+
results,
|
|
505
|
+
options: paging || { cursor: "0", limit: ids.length },
|
|
506
|
+
nextCursor,
|
|
507
|
+
};
|
|
758
508
|
}
|
|
759
|
-
/**
|
|
760
|
-
* Finds documents by their slugs
|
|
761
|
-
*/
|
|
762
509
|
async findBySlugs(slugs, view, paging, consistencyToken, signal) {
|
|
763
510
|
this.logger.verbose("findBySlugs(@count slugs)", slugs.length);
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
}
|
|
767
|
-
if (this.features.legacyStorageEnabled) {
|
|
768
|
-
const documents = [];
|
|
769
|
-
// Use storage to resolve slugs to IDs
|
|
770
|
-
let ids;
|
|
771
|
-
try {
|
|
772
|
-
ids = await this.documentStorage.resolveIds(slugs, consistencyToken, signal);
|
|
773
|
-
}
|
|
774
|
-
catch {
|
|
775
|
-
// If slug resolution fails, return empty results
|
|
776
|
-
// This matches the behavior expected from a search operation
|
|
777
|
-
ids = [];
|
|
778
|
-
}
|
|
779
|
-
// Fetch each document by resolved ID
|
|
780
|
-
for (const id of ids) {
|
|
781
|
-
if (signal?.aborted) {
|
|
782
|
-
throw new AbortError();
|
|
783
|
-
}
|
|
784
|
-
let document;
|
|
785
|
-
try {
|
|
786
|
-
document = await this.documentStorage.get(id, consistencyToken, signal);
|
|
787
|
-
}
|
|
788
|
-
catch {
|
|
789
|
-
// Skip documents that don't exist or can't be accessed
|
|
790
|
-
continue;
|
|
791
|
-
}
|
|
792
|
-
// Apply view filter - This will be removed when we pass the viewfilter along
|
|
793
|
-
// to the underlying store, but is here now for the interface.
|
|
794
|
-
for (const scope in document.state) {
|
|
795
|
-
if (!matchesScope(view, scope)) {
|
|
796
|
-
delete document.state[scope];
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
documents.push(document);
|
|
800
|
-
}
|
|
801
|
-
if (signal?.aborted) {
|
|
802
|
-
throw new AbortError();
|
|
803
|
-
}
|
|
804
|
-
// Apply paging - this will be removed when we pass the paging along
|
|
805
|
-
// to the underlying store, but is here now for the interface.
|
|
806
|
-
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
807
|
-
const limit = paging?.limit || documents.length;
|
|
808
|
-
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
809
|
-
// Create paged results
|
|
810
|
-
const hasMore = startIndex + limit < documents.length;
|
|
811
|
-
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
812
|
-
return {
|
|
813
|
-
results: pagedDocuments,
|
|
814
|
-
options: paging || { cursor: "0", limit: documents.length },
|
|
815
|
-
nextCursor,
|
|
816
|
-
next: hasMore
|
|
817
|
-
? () => this.findBySlugs(slugs, view, { cursor: nextCursor, limit }, consistencyToken, signal)
|
|
818
|
-
: undefined,
|
|
819
|
-
};
|
|
820
|
-
}
|
|
821
|
-
else {
|
|
822
|
-
const documents = [];
|
|
823
|
-
// Resolve each slug to a document ID
|
|
824
|
-
const documentIds = [];
|
|
825
|
-
for (const slug of slugs) {
|
|
826
|
-
if (signal?.aborted) {
|
|
827
|
-
throw new AbortError();
|
|
828
|
-
}
|
|
829
|
-
const documentId = await this.documentView.resolveSlug(slug, view, undefined, signal);
|
|
830
|
-
if (documentId) {
|
|
831
|
-
documentIds.push(documentId);
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
// Fetch each document
|
|
835
|
-
for (const documentId of documentIds) {
|
|
836
|
-
if (signal?.aborted) {
|
|
837
|
-
throw new AbortError();
|
|
838
|
-
}
|
|
839
|
-
try {
|
|
840
|
-
const document = await this.documentView.get(documentId, view, undefined, signal);
|
|
841
|
-
documents.push(document);
|
|
842
|
-
}
|
|
843
|
-
catch {
|
|
844
|
-
// Skip documents that don't exist or can't be accessed
|
|
845
|
-
continue;
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
if (signal?.aborted) {
|
|
849
|
-
throw new AbortError();
|
|
850
|
-
}
|
|
851
|
-
// Apply paging
|
|
852
|
-
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
853
|
-
const limit = paging?.limit || documents.length;
|
|
854
|
-
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
855
|
-
// Create paged results
|
|
856
|
-
const hasMore = startIndex + limit < documents.length;
|
|
857
|
-
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
858
|
-
return {
|
|
859
|
-
results: pagedDocuments,
|
|
860
|
-
options: paging || { cursor: "0", limit: documents.length },
|
|
861
|
-
nextCursor,
|
|
862
|
-
next: hasMore
|
|
863
|
-
? () => this.findBySlugs(slugs, view, { cursor: nextCursor, limit }, consistencyToken, signal)
|
|
864
|
-
: undefined,
|
|
865
|
-
};
|
|
866
|
-
}
|
|
511
|
+
const ids = await this.documentView.resolveSlugs(slugs, view, consistencyToken, signal);
|
|
512
|
+
return await this.findByIds(ids, view, paging, consistencyToken, signal);
|
|
867
513
|
}
|
|
868
|
-
|
|
869
|
-
* Finds documents by parent ID
|
|
870
|
-
*/
|
|
871
|
-
async findByParentId(parentId, view, paging, signal) {
|
|
514
|
+
async findByParentId(parentId, view, paging, consistencyToken, signal) {
|
|
872
515
|
this.logger.verbose("findByParentId(@parentId)", parentId);
|
|
873
|
-
|
|
874
|
-
const
|
|
875
|
-
|
|
876
|
-
throw new AbortError();
|
|
877
|
-
}
|
|
878
|
-
const documents = [];
|
|
879
|
-
// Fetch each child document using the appropriate storage method
|
|
880
|
-
for (const relationship of relationships) {
|
|
881
|
-
if (signal?.aborted) {
|
|
882
|
-
throw new AbortError();
|
|
883
|
-
}
|
|
884
|
-
try {
|
|
885
|
-
let document;
|
|
886
|
-
if (this.features.legacyStorageEnabled) {
|
|
887
|
-
document = await this.documentStorage.get(relationship.targetId);
|
|
888
|
-
// Apply view filter for legacy storage
|
|
889
|
-
for (const scope in document.state) {
|
|
890
|
-
if (!matchesScope(view, scope)) {
|
|
891
|
-
delete document.state[scope];
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
else {
|
|
896
|
-
document = await this.documentView.get(relationship.targetId, view, undefined, signal);
|
|
897
|
-
}
|
|
898
|
-
documents.push(document);
|
|
899
|
-
}
|
|
900
|
-
catch {
|
|
901
|
-
// Skip documents that don't exist or can't be accessed
|
|
902
|
-
continue;
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
if (signal?.aborted) {
|
|
906
|
-
throw new AbortError();
|
|
907
|
-
}
|
|
908
|
-
// Apply paging
|
|
909
|
-
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
910
|
-
const limit = paging?.limit || documents.length;
|
|
911
|
-
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
912
|
-
// Create paged results
|
|
913
|
-
const hasMore = startIndex + limit < documents.length;
|
|
914
|
-
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
915
|
-
return {
|
|
916
|
-
results: pagedDocuments,
|
|
917
|
-
options: paging || { cursor: "0", limit: documents.length },
|
|
918
|
-
nextCursor,
|
|
919
|
-
next: hasMore
|
|
920
|
-
? () => this.findByParentId(parentId, view, { cursor: nextCursor, limit }, signal)
|
|
921
|
-
: undefined,
|
|
922
|
-
};
|
|
516
|
+
const relationships = await this.documentIndexer.getOutgoing(parentId, ["child"], paging, consistencyToken, signal);
|
|
517
|
+
const ids = relationships.results.map((rel) => rel.targetId);
|
|
518
|
+
return await this.findByIds(ids, view, paging, undefined, signal);
|
|
923
519
|
}
|
|
924
|
-
/**
|
|
925
|
-
* Finds documents by type
|
|
926
|
-
*/
|
|
927
520
|
async findByType(type, view, paging, consistencyToken, signal) {
|
|
928
521
|
this.logger.verbose("findByType(@type)", type);
|
|
929
|
-
|
|
930
|
-
await this.documentView.waitForConsistency(consistencyToken, undefined, signal);
|
|
931
|
-
}
|
|
932
|
-
if (this.features.legacyStorageEnabled) {
|
|
933
|
-
const documents = [];
|
|
934
|
-
// Use storage's findByType method directly
|
|
935
|
-
const cursor = paging?.cursor;
|
|
936
|
-
const limit = paging?.limit || 100;
|
|
937
|
-
// Get document IDs of the specified type
|
|
938
|
-
const { documents: documentIds, nextCursor } = await this.documentStorage.findByType(type, limit, cursor, consistencyToken, signal);
|
|
939
|
-
if (signal?.aborted) {
|
|
940
|
-
throw new AbortError();
|
|
941
|
-
}
|
|
942
|
-
// Fetch each document by its ID
|
|
943
|
-
for (const documentId of documentIds) {
|
|
944
|
-
if (signal?.aborted) {
|
|
945
|
-
throw new AbortError();
|
|
946
|
-
}
|
|
947
|
-
let document;
|
|
948
|
-
try {
|
|
949
|
-
document = await this.documentStorage.get(documentId, consistencyToken, signal);
|
|
950
|
-
}
|
|
951
|
-
catch {
|
|
952
|
-
// Skip documents that can't be retrieved
|
|
953
|
-
continue;
|
|
954
|
-
}
|
|
955
|
-
// Apply view filter
|
|
956
|
-
for (const scope in document.state) {
|
|
957
|
-
if (!matchesScope(view, scope)) {
|
|
958
|
-
delete document.state[scope];
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
documents.push(document);
|
|
962
|
-
}
|
|
963
|
-
if (signal?.aborted) {
|
|
964
|
-
throw new AbortError();
|
|
965
|
-
}
|
|
966
|
-
// Results are already paged from the storage layer
|
|
967
|
-
return {
|
|
968
|
-
results: documents,
|
|
969
|
-
options: paging || { cursor: cursor || "0", limit },
|
|
970
|
-
nextCursor,
|
|
971
|
-
next: nextCursor
|
|
972
|
-
? async () => this.findByType(type, view, { cursor: nextCursor, limit }, consistencyToken, signal)
|
|
973
|
-
: undefined,
|
|
974
|
-
};
|
|
975
|
-
}
|
|
976
|
-
else {
|
|
977
|
-
const result = await this.documentView.findByType(type, view, paging, consistencyToken, signal);
|
|
978
|
-
if (signal?.aborted) {
|
|
979
|
-
throw new AbortError();
|
|
980
|
-
}
|
|
981
|
-
const cursor = paging?.cursor;
|
|
982
|
-
const limit = paging?.limit || 100;
|
|
983
|
-
return {
|
|
984
|
-
results: result.items,
|
|
985
|
-
options: paging || { cursor: cursor || "0", limit },
|
|
986
|
-
nextCursor: result.nextCursor,
|
|
987
|
-
next: result.nextCursor
|
|
988
|
-
? async () => this.findByType(type, view, { cursor: result.nextCursor, limit }, consistencyToken, signal)
|
|
989
|
-
: undefined,
|
|
990
|
-
};
|
|
991
|
-
}
|
|
522
|
+
return await this.documentView.findByType(type, view, paging, consistencyToken, signal);
|
|
992
523
|
}
|
|
993
524
|
emitJobPending(jobId, meta) {
|
|
994
525
|
const event = {
|