@powerhousedao/reactor 4.1.0-dev.100 → 4.1.0-dev.102
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/kysely-write-cache.d.ts +4 -3
- package/dist/src/cache/kysely-write-cache.d.ts.map +1 -1
- package/dist/src/cache/kysely-write-cache.js +12 -12
- package/dist/src/cache/kysely-write-cache.js.map +1 -1
- package/dist/src/client/reactor-client.d.ts.map +1 -1
- package/dist/src/client/reactor-client.js +3 -3
- package/dist/src/client/reactor-client.js.map +1 -1
- package/dist/src/core/reactor-builder.d.ts +5 -0
- package/dist/src/core/reactor-builder.d.ts.map +1 -1
- package/dist/src/core/reactor-builder.js +16 -4
- package/dist/src/core/reactor-builder.js.map +1 -1
- package/dist/src/core/reactor.d.ts +14 -9
- package/dist/src/core/reactor.d.ts.map +1 -1
- package/dist/src/core/reactor.js +471 -217
- package/dist/src/core/reactor.js.map +1 -1
- package/dist/src/core/types.d.ts +9 -5
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/executor/simple-job-executor-manager.d.ts.map +1 -1
- package/dist/src/executor/simple-job-executor-manager.js +3 -1
- package/dist/src/executor/simple-job-executor-manager.js.map +1 -1
- package/dist/src/executor/simple-job-executor.d.ts.map +1 -1
- package/dist/src/executor/simple-job-executor.js +1 -0
- package/dist/src/executor/simple-job-executor.js.map +1 -1
- package/dist/src/executor/util.d.ts +18 -0
- package/dist/src/executor/util.d.ts.map +1 -1
- package/dist/src/executor/util.js +41 -0
- package/dist/src/executor/util.js.map +1 -1
- package/dist/src/index.d.ts +6 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/job-tracker/in-memory-job-tracker.d.ts +2 -2
- package/dist/src/job-tracker/in-memory-job-tracker.d.ts.map +1 -1
- package/dist/src/job-tracker/in-memory-job-tracker.js +7 -1
- package/dist/src/job-tracker/in-memory-job-tracker.js.map +1 -1
- package/dist/src/job-tracker/interfaces.d.ts +3 -2
- package/dist/src/job-tracker/interfaces.d.ts.map +1 -1
- package/dist/src/read-models/document-view.d.ts +10 -4
- package/dist/src/read-models/document-view.d.ts.map +1 -1
- package/dist/src/read-models/document-view.js +115 -3
- package/dist/src/read-models/document-view.js.map +1 -1
- package/dist/src/shared/consistency-tracker.d.ts +48 -0
- package/dist/src/shared/consistency-tracker.d.ts.map +1 -0
- package/dist/src/shared/consistency-tracker.js +123 -0
- package/dist/src/shared/consistency-tracker.js.map +1 -0
- package/dist/src/shared/types.d.ts +23 -0
- package/dist/src/shared/types.d.ts.map +1 -1
- package/dist/src/shared/types.js.map +1 -1
- package/dist/src/storage/interfaces.d.ts +67 -9
- 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 +13 -8
- package/dist/src/storage/kysely/document-indexer.d.ts.map +1 -1
- package/dist/src/storage/kysely/document-indexer.js +79 -10
- package/dist/src/storage/kysely/document-indexer.js.map +1 -1
- package/package.json +3 -3
package/dist/src/core/reactor.js
CHANGED
|
@@ -16,13 +16,21 @@ export class Reactor {
|
|
|
16
16
|
queue;
|
|
17
17
|
jobTracker;
|
|
18
18
|
readModelCoordinator;
|
|
19
|
-
|
|
19
|
+
features;
|
|
20
|
+
documentView;
|
|
21
|
+
documentIndexer;
|
|
22
|
+
operationStore;
|
|
23
|
+
constructor(driveServer, documentStorage, queue, jobTracker, readModelCoordinator, features, documentView, documentIndexer, operationStore) {
|
|
20
24
|
// Store required dependencies
|
|
21
25
|
this.driveServer = driveServer;
|
|
22
26
|
this.documentStorage = documentStorage;
|
|
23
27
|
this.queue = queue;
|
|
24
28
|
this.jobTracker = jobTracker;
|
|
25
29
|
this.readModelCoordinator = readModelCoordinator;
|
|
30
|
+
this.features = features;
|
|
31
|
+
this.documentView = documentView;
|
|
32
|
+
this.documentIndexer = documentIndexer;
|
|
33
|
+
this.operationStore = operationStore;
|
|
26
34
|
// Start the read model coordinator
|
|
27
35
|
this.readModelCoordinator.start();
|
|
28
36
|
// Create mutable shutdown status using factory method
|
|
@@ -72,87 +80,153 @@ export class Reactor {
|
|
|
72
80
|
/**
|
|
73
81
|
* Retrieves a specific PHDocument by id
|
|
74
82
|
*/
|
|
75
|
-
async get(id, view, signal) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
async get(id, view, consistencyToken, signal) {
|
|
84
|
+
if (this.features.legacyStorageEnabled) {
|
|
85
|
+
const document = await this.documentStorage.get(id);
|
|
86
|
+
if (signal?.aborted) {
|
|
87
|
+
throw new AbortError();
|
|
88
|
+
}
|
|
89
|
+
const childIds = await this.documentStorage.getChildren(id);
|
|
90
|
+
if (signal?.aborted) {
|
|
91
|
+
throw new AbortError();
|
|
92
|
+
}
|
|
93
|
+
for (const scope in document.state) {
|
|
94
|
+
if (!matchesScope(view, scope)) {
|
|
95
|
+
delete document.state[scope];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
document,
|
|
100
|
+
childIds,
|
|
101
|
+
};
|
|
83
102
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
103
|
+
else {
|
|
104
|
+
const document = await this.documentView.get(id, view, consistencyToken, signal);
|
|
105
|
+
if (signal?.aborted) {
|
|
106
|
+
throw new AbortError();
|
|
107
|
+
}
|
|
108
|
+
const relationships = await this.documentIndexer.getOutgoing(id, ["child"], consistencyToken, signal);
|
|
109
|
+
if (signal?.aborted) {
|
|
110
|
+
throw new AbortError();
|
|
89
111
|
}
|
|
112
|
+
const childIds = relationships.map((rel) => rel.targetId);
|
|
113
|
+
return {
|
|
114
|
+
document,
|
|
115
|
+
childIds,
|
|
116
|
+
};
|
|
90
117
|
}
|
|
91
|
-
return {
|
|
92
|
-
document,
|
|
93
|
-
childIds,
|
|
94
|
-
};
|
|
95
118
|
}
|
|
96
119
|
/**
|
|
97
120
|
* Retrieves a specific PHDocument by slug
|
|
98
121
|
*/
|
|
99
|
-
async getBySlug(slug, view, signal) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
122
|
+
async getBySlug(slug, view, consistencyToken, signal) {
|
|
123
|
+
if (this.features.legacyStorageEnabled) {
|
|
124
|
+
let ids;
|
|
125
|
+
try {
|
|
126
|
+
ids = await this.documentStorage.resolveIds([slug], signal);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error instanceof Error && error.message.includes("not found")) {
|
|
130
|
+
throw new Error(`Document not found with slug: ${slug}`);
|
|
131
|
+
}
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
if (ids.length === 0 || !ids[0]) {
|
|
108
135
|
throw new Error(`Document not found with slug: ${slug}`);
|
|
109
136
|
}
|
|
110
|
-
|
|
137
|
+
return await this.get(ids[0], view, consistencyToken, signal);
|
|
111
138
|
}
|
|
112
|
-
|
|
113
|
-
|
|
139
|
+
else {
|
|
140
|
+
const documentId = await this.documentView.resolveSlug(slug, view, consistencyToken, signal);
|
|
141
|
+
if (!documentId) {
|
|
142
|
+
throw new Error(`Document not found with slug: ${slug}`);
|
|
143
|
+
}
|
|
144
|
+
return await this.get(documentId, view, consistencyToken, signal);
|
|
114
145
|
}
|
|
115
|
-
// Now get the document by its resolved ID
|
|
116
|
-
return await this.get(ids[0], view, signal);
|
|
117
146
|
}
|
|
118
147
|
/**
|
|
119
148
|
* Retrieves the operations for a document
|
|
120
149
|
*/
|
|
121
|
-
async getOperations(documentId, view, paging, signal) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
150
|
+
async getOperations(documentId, view, paging, consistencyToken, signal) {
|
|
151
|
+
if (this.features.legacyStorageEnabled) {
|
|
152
|
+
// Use storage directly to get the document
|
|
153
|
+
const document = await this.documentStorage.get(documentId);
|
|
154
|
+
if (signal?.aborted) {
|
|
155
|
+
throw new AbortError();
|
|
156
|
+
}
|
|
157
|
+
const operations = document.operations;
|
|
158
|
+
const result = {};
|
|
159
|
+
// apply view filter, per scope -- this will be removed when we pass the viewfilter along
|
|
160
|
+
// to the underlying store, but is here now for the interface.
|
|
161
|
+
for (const scope in operations) {
|
|
162
|
+
if (matchesScope(view, scope)) {
|
|
163
|
+
const scopeOperations = operations[scope];
|
|
164
|
+
// apply paging too
|
|
165
|
+
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
166
|
+
const limit = paging?.limit || scopeOperations.length;
|
|
167
|
+
const pagedOperations = scopeOperations.slice(startIndex, startIndex + limit);
|
|
168
|
+
result[scope] = {
|
|
169
|
+
results: pagedOperations,
|
|
170
|
+
options: { cursor: String(startIndex + limit), limit },
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return Promise.resolve(result);
|
|
126
175
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
176
|
+
else {
|
|
177
|
+
// Use operation store to get operations
|
|
178
|
+
const branch = view?.branch || "main";
|
|
179
|
+
// Get all scopes for this document
|
|
180
|
+
const revisions = await this.operationStore.getRevisions(documentId, branch, signal);
|
|
181
|
+
if (signal?.aborted) {
|
|
182
|
+
throw new AbortError();
|
|
183
|
+
}
|
|
184
|
+
const allScopes = Object.keys(revisions.revision);
|
|
185
|
+
const result = {};
|
|
186
|
+
// Filter scopes based on view filter and query operations for each
|
|
187
|
+
for (const scope of allScopes) {
|
|
188
|
+
if (!matchesScope(view, scope)) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (signal?.aborted) {
|
|
192
|
+
throw new AbortError();
|
|
193
|
+
}
|
|
194
|
+
// Get operations for this scope
|
|
195
|
+
const scopeResult = await this.operationStore.getSince(documentId, scope, branch, -1, paging, signal);
|
|
196
|
+
// Transform to Reactor's PagedResults format
|
|
197
|
+
const currentCursor = paging?.cursor ? parseInt(paging.cursor) : 0;
|
|
198
|
+
const currentLimit = paging?.limit || 100;
|
|
138
199
|
result[scope] = {
|
|
139
|
-
results:
|
|
140
|
-
options: {
|
|
200
|
+
results: scopeResult.items,
|
|
201
|
+
options: {
|
|
202
|
+
cursor: scopeResult.nextCursor || String(currentCursor),
|
|
203
|
+
limit: currentLimit,
|
|
204
|
+
},
|
|
205
|
+
nextCursor: scopeResult.nextCursor,
|
|
206
|
+
next: scopeResult.hasMore
|
|
207
|
+
? async () => {
|
|
208
|
+
const nextPage = await this.getOperations(documentId, view, {
|
|
209
|
+
cursor: scopeResult.nextCursor,
|
|
210
|
+
limit: currentLimit,
|
|
211
|
+
}, consistencyToken, signal);
|
|
212
|
+
return nextPage[scope];
|
|
213
|
+
}
|
|
214
|
+
: undefined,
|
|
141
215
|
};
|
|
142
216
|
}
|
|
217
|
+
return result;
|
|
143
218
|
}
|
|
144
|
-
return Promise.resolve(result);
|
|
145
219
|
}
|
|
146
220
|
/**
|
|
147
221
|
* Filters documents by criteria and returns a list of them
|
|
148
222
|
*/
|
|
149
|
-
async find(search, view, paging, signal) {
|
|
223
|
+
async find(search, view, paging, consistencyToken, signal) {
|
|
150
224
|
let results;
|
|
151
225
|
if (search.ids) {
|
|
152
226
|
if (search.slugs && search.slugs.length > 0) {
|
|
153
227
|
throw new Error("Cannot use both ids and slugs in the same search");
|
|
154
228
|
}
|
|
155
|
-
results = await this.findByIds(search.ids, view, paging, signal);
|
|
229
|
+
results = await this.findByIds(search.ids, view, paging, consistencyToken, signal);
|
|
156
230
|
if (search.parentId) {
|
|
157
231
|
results = filterByParentId(results, search.parentId);
|
|
158
232
|
}
|
|
@@ -161,7 +235,7 @@ export class Reactor {
|
|
|
161
235
|
}
|
|
162
236
|
}
|
|
163
237
|
else if (search.slugs) {
|
|
164
|
-
results = await this.findBySlugs(search.slugs, view, paging, signal);
|
|
238
|
+
results = await this.findBySlugs(search.slugs, view, paging, consistencyToken, signal);
|
|
165
239
|
if (search.parentId) {
|
|
166
240
|
results = filterByParentId(results, search.parentId);
|
|
167
241
|
}
|
|
@@ -176,7 +250,7 @@ export class Reactor {
|
|
|
176
250
|
}
|
|
177
251
|
}
|
|
178
252
|
else if (search.type) {
|
|
179
|
-
results = await this.findByType(search.type, view, paging, signal);
|
|
253
|
+
results = await this.findByType(search.type, view, paging, consistencyToken, signal);
|
|
180
254
|
}
|
|
181
255
|
else {
|
|
182
256
|
throw new Error("No search criteria provided");
|
|
@@ -252,6 +326,11 @@ export class Reactor {
|
|
|
252
326
|
id: job.id,
|
|
253
327
|
status: JobStatus.PENDING,
|
|
254
328
|
createdAtUtcIso,
|
|
329
|
+
consistencyToken: {
|
|
330
|
+
version: 1,
|
|
331
|
+
createdAtUtcIso,
|
|
332
|
+
coordinates: [],
|
|
333
|
+
},
|
|
255
334
|
};
|
|
256
335
|
this.jobTracker.registerJob(jobInfo);
|
|
257
336
|
// Enqueue the job
|
|
@@ -292,6 +371,11 @@ export class Reactor {
|
|
|
292
371
|
id: job.id,
|
|
293
372
|
status: JobStatus.PENDING,
|
|
294
373
|
createdAtUtcIso,
|
|
374
|
+
consistencyToken: {
|
|
375
|
+
version: 1,
|
|
376
|
+
createdAtUtcIso,
|
|
377
|
+
coordinates: [],
|
|
378
|
+
},
|
|
295
379
|
};
|
|
296
380
|
this.jobTracker.registerJob(jobInfo);
|
|
297
381
|
await this.queue.enqueue(job);
|
|
@@ -321,6 +405,11 @@ export class Reactor {
|
|
|
321
405
|
id: job.id,
|
|
322
406
|
status: JobStatus.PENDING,
|
|
323
407
|
createdAtUtcIso,
|
|
408
|
+
consistencyToken: {
|
|
409
|
+
version: 1,
|
|
410
|
+
createdAtUtcIso,
|
|
411
|
+
coordinates: [],
|
|
412
|
+
},
|
|
324
413
|
};
|
|
325
414
|
this.jobTracker.registerJob(jobInfo);
|
|
326
415
|
// Enqueue the job
|
|
@@ -350,6 +439,11 @@ export class Reactor {
|
|
|
350
439
|
id: jobId,
|
|
351
440
|
status: JobStatus.PENDING,
|
|
352
441
|
createdAtUtcIso,
|
|
442
|
+
consistencyToken: {
|
|
443
|
+
version: 1,
|
|
444
|
+
createdAtUtcIso,
|
|
445
|
+
coordinates: [],
|
|
446
|
+
},
|
|
353
447
|
};
|
|
354
448
|
this.jobTracker.registerJob(jobInfo);
|
|
355
449
|
jobInfos.set(jobPlan.key, jobInfo);
|
|
@@ -385,7 +479,7 @@ export class Reactor {
|
|
|
385
479
|
try {
|
|
386
480
|
await this.queue.remove(jobId);
|
|
387
481
|
}
|
|
388
|
-
catch
|
|
482
|
+
catch {
|
|
389
483
|
// Ignore removal errors during cleanup
|
|
390
484
|
}
|
|
391
485
|
}
|
|
@@ -402,7 +496,7 @@ export class Reactor {
|
|
|
402
496
|
/**
|
|
403
497
|
* Adds multiple documents as children to another
|
|
404
498
|
*/
|
|
405
|
-
async addChildren(parentId, documentIds,
|
|
499
|
+
async addChildren(parentId, documentIds, _view, signal) {
|
|
406
500
|
if (signal?.aborted) {
|
|
407
501
|
throw new AbortError();
|
|
408
502
|
}
|
|
@@ -422,7 +516,7 @@ export class Reactor {
|
|
|
422
516
|
/**
|
|
423
517
|
* Removes multiple documents as children from another
|
|
424
518
|
*/
|
|
425
|
-
async removeChildren(parentId, documentIds,
|
|
519
|
+
async removeChildren(parentId, documentIds, _view, signal) {
|
|
426
520
|
if (signal?.aborted) {
|
|
427
521
|
throw new AbortError();
|
|
428
522
|
}
|
|
@@ -449,12 +543,18 @@ export class Reactor {
|
|
|
449
543
|
const jobInfo = this.jobTracker.getJobStatus(jobId);
|
|
450
544
|
if (!jobInfo) {
|
|
451
545
|
// Job not found - return FAILED status with appropriate error
|
|
546
|
+
const now = new Date().toISOString();
|
|
452
547
|
return Promise.resolve({
|
|
453
548
|
id: jobId,
|
|
454
549
|
status: JobStatus.FAILED,
|
|
455
|
-
createdAtUtcIso:
|
|
456
|
-
completedAtUtcIso:
|
|
550
|
+
createdAtUtcIso: now,
|
|
551
|
+
completedAtUtcIso: now,
|
|
457
552
|
error: toErrorInfo("Job not found"),
|
|
553
|
+
consistencyToken: {
|
|
554
|
+
version: 1,
|
|
555
|
+
createdAtUtcIso: now,
|
|
556
|
+
coordinates: [],
|
|
557
|
+
},
|
|
458
558
|
});
|
|
459
559
|
}
|
|
460
560
|
return Promise.resolve(jobInfo);
|
|
@@ -462,205 +562,359 @@ export class Reactor {
|
|
|
462
562
|
/**
|
|
463
563
|
* Finds documents by their IDs
|
|
464
564
|
*/
|
|
465
|
-
async findByIds(ids, view, paging, signal) {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
565
|
+
async findByIds(ids, view, paging, consistencyToken, signal) {
|
|
566
|
+
if (consistencyToken) {
|
|
567
|
+
await this.documentView.waitForConsistency(consistencyToken, undefined, signal);
|
|
568
|
+
}
|
|
569
|
+
if (this.features.legacyStorageEnabled) {
|
|
570
|
+
const documents = [];
|
|
571
|
+
// Fetch each document by ID using storage directly
|
|
572
|
+
for (const id of ids) {
|
|
573
|
+
if (signal?.aborted) {
|
|
574
|
+
throw new AbortError();
|
|
575
|
+
}
|
|
576
|
+
let document;
|
|
577
|
+
try {
|
|
578
|
+
document = await this.documentStorage.get(id);
|
|
579
|
+
}
|
|
580
|
+
catch {
|
|
581
|
+
// Skip documents that don't exist or can't be accessed
|
|
582
|
+
// This matches the behavior expected from a search operation
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
// Apply view filter - This will be removed when we pass the viewfilter along
|
|
586
|
+
// to the underlying store, but is here now for the interface.
|
|
587
|
+
for (const scope in document.state) {
|
|
588
|
+
if (!matchesScope(view, scope)) {
|
|
589
|
+
delete document.state[scope];
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
documents.push(document);
|
|
593
|
+
}
|
|
469
594
|
if (signal?.aborted) {
|
|
470
595
|
throw new AbortError();
|
|
471
596
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
597
|
+
// Apply paging
|
|
598
|
+
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
599
|
+
const limit = paging?.limit || documents.length;
|
|
600
|
+
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
601
|
+
// Create paged results
|
|
602
|
+
const hasMore = startIndex + limit < documents.length;
|
|
603
|
+
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
604
|
+
return {
|
|
605
|
+
results: pagedDocuments,
|
|
606
|
+
options: paging || { cursor: "0", limit: documents.length },
|
|
607
|
+
nextCursor,
|
|
608
|
+
next: hasMore
|
|
609
|
+
? () => this.findByIds(ids, view, { cursor: nextCursor, limit }, undefined, signal)
|
|
610
|
+
: undefined,
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
const documents = [];
|
|
615
|
+
// Fetch each document by ID using documentView
|
|
616
|
+
for (const id of ids) {
|
|
617
|
+
if (signal?.aborted) {
|
|
618
|
+
throw new AbortError();
|
|
619
|
+
}
|
|
620
|
+
try {
|
|
621
|
+
const document = await this.documentView.get(id, view, undefined, signal);
|
|
622
|
+
documents.push(document);
|
|
623
|
+
}
|
|
624
|
+
catch {
|
|
625
|
+
// Skip documents that don't exist or can't be accessed
|
|
626
|
+
continue;
|
|
486
627
|
}
|
|
487
628
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
629
|
+
if (signal?.aborted) {
|
|
630
|
+
throw new AbortError();
|
|
631
|
+
}
|
|
632
|
+
// Apply paging
|
|
633
|
+
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
634
|
+
const limit = paging?.limit || documents.length;
|
|
635
|
+
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
636
|
+
// Create paged results
|
|
637
|
+
const hasMore = startIndex + limit < documents.length;
|
|
638
|
+
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
639
|
+
return {
|
|
640
|
+
results: pagedDocuments,
|
|
641
|
+
options: paging || { cursor: "0", limit: documents.length },
|
|
642
|
+
nextCursor,
|
|
643
|
+
next: hasMore
|
|
644
|
+
? () => this.findByIds(ids, view, { cursor: nextCursor, limit }, undefined, signal)
|
|
645
|
+
: undefined,
|
|
646
|
+
};
|
|
492
647
|
}
|
|
493
|
-
// Apply paging
|
|
494
|
-
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
495
|
-
const limit = paging?.limit || documents.length;
|
|
496
|
-
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
497
|
-
// Create paged results
|
|
498
|
-
const hasMore = startIndex + limit < documents.length;
|
|
499
|
-
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
500
|
-
return {
|
|
501
|
-
results: pagedDocuments,
|
|
502
|
-
options: paging || { cursor: "0", limit: documents.length },
|
|
503
|
-
nextCursor,
|
|
504
|
-
next: hasMore
|
|
505
|
-
? () => this.findByIds(ids, view, { cursor: nextCursor, limit }, signal)
|
|
506
|
-
: undefined,
|
|
507
|
-
};
|
|
508
648
|
}
|
|
509
649
|
/**
|
|
510
650
|
* Finds documents by their slugs
|
|
511
651
|
*/
|
|
512
|
-
async findBySlugs(slugs, view, paging, signal) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
// If slug resolution fails, return empty results
|
|
521
|
-
// This matches the behavior expected from a search operation
|
|
522
|
-
ids = [];
|
|
523
|
-
}
|
|
524
|
-
// Fetch each document by resolved ID
|
|
525
|
-
for (const id of ids) {
|
|
526
|
-
if (signal?.aborted) {
|
|
527
|
-
throw new AbortError();
|
|
528
|
-
}
|
|
529
|
-
let document;
|
|
652
|
+
async findBySlugs(slugs, view, paging, consistencyToken, signal) {
|
|
653
|
+
if (consistencyToken) {
|
|
654
|
+
await this.documentView.waitForConsistency(consistencyToken, undefined, signal);
|
|
655
|
+
}
|
|
656
|
+
if (this.features.legacyStorageEnabled) {
|
|
657
|
+
const documents = [];
|
|
658
|
+
// Use storage to resolve slugs to IDs
|
|
659
|
+
let ids;
|
|
530
660
|
try {
|
|
531
|
-
|
|
661
|
+
ids = await this.documentStorage.resolveIds(slugs, signal);
|
|
532
662
|
}
|
|
533
663
|
catch {
|
|
534
|
-
//
|
|
535
|
-
|
|
664
|
+
// If slug resolution fails, return empty results
|
|
665
|
+
// This matches the behavior expected from a search operation
|
|
666
|
+
ids = [];
|
|
536
667
|
}
|
|
537
|
-
//
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
668
|
+
// Fetch each document by resolved ID
|
|
669
|
+
for (const id of ids) {
|
|
670
|
+
if (signal?.aborted) {
|
|
671
|
+
throw new AbortError();
|
|
672
|
+
}
|
|
673
|
+
let document;
|
|
674
|
+
try {
|
|
675
|
+
document = await this.documentStorage.get(id);
|
|
676
|
+
}
|
|
677
|
+
catch {
|
|
678
|
+
// Skip documents that don't exist or can't be accessed
|
|
679
|
+
continue;
|
|
542
680
|
}
|
|
681
|
+
// Apply view filter - This will be removed when we pass the viewfilter along
|
|
682
|
+
// to the underlying store, but is here now for the interface.
|
|
683
|
+
for (const scope in document.state) {
|
|
684
|
+
if (!matchesScope(view, scope)) {
|
|
685
|
+
delete document.state[scope];
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
documents.push(document);
|
|
689
|
+
}
|
|
690
|
+
if (signal?.aborted) {
|
|
691
|
+
throw new AbortError();
|
|
543
692
|
}
|
|
544
|
-
|
|
693
|
+
// Apply paging - this will be removed when we pass the paging along
|
|
694
|
+
// to the underlying store, but is here now for the interface.
|
|
695
|
+
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
696
|
+
const limit = paging?.limit || documents.length;
|
|
697
|
+
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
698
|
+
// Create paged results
|
|
699
|
+
const hasMore = startIndex + limit < documents.length;
|
|
700
|
+
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
701
|
+
return {
|
|
702
|
+
results: pagedDocuments,
|
|
703
|
+
options: paging || { cursor: "0", limit: documents.length },
|
|
704
|
+
nextCursor,
|
|
705
|
+
next: hasMore
|
|
706
|
+
? () => this.findBySlugs(slugs, view, { cursor: nextCursor, limit }, undefined, signal)
|
|
707
|
+
: undefined,
|
|
708
|
+
};
|
|
545
709
|
}
|
|
546
|
-
|
|
547
|
-
|
|
710
|
+
else {
|
|
711
|
+
const documents = [];
|
|
712
|
+
// Resolve each slug to a document ID
|
|
713
|
+
const documentIds = [];
|
|
714
|
+
for (const slug of slugs) {
|
|
715
|
+
if (signal?.aborted) {
|
|
716
|
+
throw new AbortError();
|
|
717
|
+
}
|
|
718
|
+
const documentId = await this.documentView.resolveSlug(slug, view, undefined, signal);
|
|
719
|
+
if (documentId) {
|
|
720
|
+
documentIds.push(documentId);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
// Fetch each document
|
|
724
|
+
for (const documentId of documentIds) {
|
|
725
|
+
if (signal?.aborted) {
|
|
726
|
+
throw new AbortError();
|
|
727
|
+
}
|
|
728
|
+
try {
|
|
729
|
+
const document = await this.documentView.get(documentId, view, undefined, signal);
|
|
730
|
+
documents.push(document);
|
|
731
|
+
}
|
|
732
|
+
catch {
|
|
733
|
+
// Skip documents that don't exist or can't be accessed
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
if (signal?.aborted) {
|
|
738
|
+
throw new AbortError();
|
|
739
|
+
}
|
|
740
|
+
// Apply paging
|
|
741
|
+
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
742
|
+
const limit = paging?.limit || documents.length;
|
|
743
|
+
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
744
|
+
// Create paged results
|
|
745
|
+
const hasMore = startIndex + limit < documents.length;
|
|
746
|
+
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
747
|
+
return {
|
|
748
|
+
results: pagedDocuments,
|
|
749
|
+
options: paging || { cursor: "0", limit: documents.length },
|
|
750
|
+
nextCursor,
|
|
751
|
+
next: hasMore
|
|
752
|
+
? () => this.findBySlugs(slugs, view, { cursor: nextCursor, limit }, undefined, signal)
|
|
753
|
+
: undefined,
|
|
754
|
+
};
|
|
548
755
|
}
|
|
549
|
-
// Apply paging - this will be removed when we pass the paging along
|
|
550
|
-
// to the underlying store, but is here now for the interface.
|
|
551
|
-
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
552
|
-
const limit = paging?.limit || documents.length;
|
|
553
|
-
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
554
|
-
// Create paged results
|
|
555
|
-
const hasMore = startIndex + limit < documents.length;
|
|
556
|
-
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
557
|
-
return {
|
|
558
|
-
results: pagedDocuments,
|
|
559
|
-
options: paging || { cursor: "0", limit: documents.length },
|
|
560
|
-
nextCursor,
|
|
561
|
-
next: hasMore
|
|
562
|
-
? () => this.findBySlugs(slugs, view, { cursor: nextCursor, limit }, signal)
|
|
563
|
-
: undefined,
|
|
564
|
-
};
|
|
565
756
|
}
|
|
566
757
|
/**
|
|
567
758
|
* Finds documents by parent ID
|
|
568
759
|
*/
|
|
569
760
|
async findByParentId(parentId, view, paging, signal) {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
throw new AbortError();
|
|
574
|
-
}
|
|
575
|
-
const documents = [];
|
|
576
|
-
// Fetch each child document
|
|
577
|
-
for (const childId of childIds) {
|
|
761
|
+
if (this.features.legacyStorageEnabled) {
|
|
762
|
+
// Get child document IDs from storage
|
|
763
|
+
const childIds = await this.documentStorage.getChildren(parentId);
|
|
578
764
|
if (signal?.aborted) {
|
|
579
765
|
throw new AbortError();
|
|
580
766
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
767
|
+
const documents = [];
|
|
768
|
+
// Fetch each child document
|
|
769
|
+
for (const childId of childIds) {
|
|
770
|
+
if (signal?.aborted) {
|
|
771
|
+
throw new AbortError();
|
|
772
|
+
}
|
|
773
|
+
let document;
|
|
774
|
+
try {
|
|
775
|
+
document = await this.documentStorage.get(childId);
|
|
776
|
+
}
|
|
777
|
+
catch {
|
|
778
|
+
// Skip documents that don't exist or can't be accessed
|
|
779
|
+
// This matches the behavior expected from a search operation
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
// Apply view filter - This will be removed when we pass the viewfilter along
|
|
783
|
+
// to the underlying store, but is here now for the interface.
|
|
784
|
+
for (const scope in document.state) {
|
|
785
|
+
if (!matchesScope(view, scope)) {
|
|
786
|
+
delete document.state[scope];
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
documents.push(document);
|
|
584
790
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
// This matches the behavior expected from a search operation
|
|
588
|
-
continue;
|
|
791
|
+
if (signal?.aborted) {
|
|
792
|
+
throw new AbortError();
|
|
589
793
|
}
|
|
590
|
-
// Apply
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
794
|
+
// Apply paging
|
|
795
|
+
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
796
|
+
const limit = paging?.limit || documents.length;
|
|
797
|
+
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
798
|
+
// Create paged results
|
|
799
|
+
const hasMore = startIndex + limit < documents.length;
|
|
800
|
+
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
801
|
+
return {
|
|
802
|
+
results: pagedDocuments,
|
|
803
|
+
options: paging || { cursor: "0", limit: documents.length },
|
|
804
|
+
nextCursor,
|
|
805
|
+
next: hasMore
|
|
806
|
+
? () => this.findByParentId(parentId, view, { cursor: nextCursor, limit }, signal)
|
|
807
|
+
: undefined,
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
// Get child relationships from indexer
|
|
812
|
+
const relationships = await this.documentIndexer.getOutgoing(parentId, ["child"], undefined, signal);
|
|
813
|
+
if (signal?.aborted) {
|
|
814
|
+
throw new AbortError();
|
|
815
|
+
}
|
|
816
|
+
const documents = [];
|
|
817
|
+
// Fetch each child document
|
|
818
|
+
for (const relationship of relationships) {
|
|
819
|
+
if (signal?.aborted) {
|
|
820
|
+
throw new AbortError();
|
|
821
|
+
}
|
|
822
|
+
try {
|
|
823
|
+
const document = await this.documentView.get(relationship.targetId, view, undefined, signal);
|
|
824
|
+
documents.push(document);
|
|
825
|
+
}
|
|
826
|
+
catch {
|
|
827
|
+
// Skip documents that don't exist or can't be accessed
|
|
828
|
+
continue;
|
|
595
829
|
}
|
|
596
830
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
831
|
+
if (signal?.aborted) {
|
|
832
|
+
throw new AbortError();
|
|
833
|
+
}
|
|
834
|
+
// Apply paging
|
|
835
|
+
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
836
|
+
const limit = paging?.limit || documents.length;
|
|
837
|
+
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
838
|
+
// Create paged results
|
|
839
|
+
const hasMore = startIndex + limit < documents.length;
|
|
840
|
+
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
841
|
+
return {
|
|
842
|
+
results: pagedDocuments,
|
|
843
|
+
options: paging || { cursor: "0", limit: documents.length },
|
|
844
|
+
nextCursor,
|
|
845
|
+
next: hasMore
|
|
846
|
+
? () => this.findByParentId(parentId, view, { cursor: nextCursor, limit }, signal)
|
|
847
|
+
: undefined,
|
|
848
|
+
};
|
|
601
849
|
}
|
|
602
|
-
// Apply paging
|
|
603
|
-
const startIndex = paging ? parseInt(paging.cursor) || 0 : 0;
|
|
604
|
-
const limit = paging?.limit || documents.length;
|
|
605
|
-
const pagedDocuments = documents.slice(startIndex, startIndex + limit);
|
|
606
|
-
// Create paged results
|
|
607
|
-
const hasMore = startIndex + limit < documents.length;
|
|
608
|
-
const nextCursor = hasMore ? String(startIndex + limit) : undefined;
|
|
609
|
-
return {
|
|
610
|
-
results: pagedDocuments,
|
|
611
|
-
options: paging || { cursor: "0", limit: documents.length },
|
|
612
|
-
nextCursor,
|
|
613
|
-
next: hasMore
|
|
614
|
-
? () => this.findByParentId(parentId, view, { cursor: nextCursor, limit }, signal)
|
|
615
|
-
: undefined,
|
|
616
|
-
};
|
|
617
850
|
}
|
|
618
851
|
/**
|
|
619
852
|
* Finds documents by type
|
|
620
853
|
*/
|
|
621
|
-
async findByType(type, view, paging, signal) {
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
for (const documentId of documentIds) {
|
|
854
|
+
async findByType(type, view, paging, consistencyToken, signal) {
|
|
855
|
+
if (consistencyToken) {
|
|
856
|
+
await this.documentView.waitForConsistency(consistencyToken, undefined, signal);
|
|
857
|
+
}
|
|
858
|
+
if (this.features.legacyStorageEnabled) {
|
|
859
|
+
const documents = [];
|
|
860
|
+
// Use storage's findByType method directly
|
|
861
|
+
const cursor = paging?.cursor;
|
|
862
|
+
const limit = paging?.limit || 100;
|
|
863
|
+
// Get document IDs of the specified type
|
|
864
|
+
const { documents: documentIds, nextCursor } = await this.documentStorage.findByType(type, limit, cursor);
|
|
633
865
|
if (signal?.aborted) {
|
|
634
866
|
throw new AbortError();
|
|
635
867
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
// Apply view filter
|
|
645
|
-
for (const scope in document.state) {
|
|
646
|
-
if (!matchesScope(view, scope)) {
|
|
647
|
-
delete document.state[scope];
|
|
868
|
+
// Fetch each document by its ID
|
|
869
|
+
for (const documentId of documentIds) {
|
|
870
|
+
if (signal?.aborted) {
|
|
871
|
+
throw new AbortError();
|
|
872
|
+
}
|
|
873
|
+
let document;
|
|
874
|
+
try {
|
|
875
|
+
document = await this.documentStorage.get(documentId);
|
|
648
876
|
}
|
|
877
|
+
catch {
|
|
878
|
+
// Skip documents that can't be retrieved
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
// Apply view filter
|
|
882
|
+
for (const scope in document.state) {
|
|
883
|
+
if (!matchesScope(view, scope)) {
|
|
884
|
+
delete document.state[scope];
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
documents.push(document);
|
|
649
888
|
}
|
|
650
|
-
|
|
889
|
+
if (signal?.aborted) {
|
|
890
|
+
throw new AbortError();
|
|
891
|
+
}
|
|
892
|
+
// Results are already paged from the storage layer
|
|
893
|
+
return {
|
|
894
|
+
results: documents,
|
|
895
|
+
options: paging || { cursor: cursor || "0", limit },
|
|
896
|
+
nextCursor,
|
|
897
|
+
next: nextCursor
|
|
898
|
+
? async () => this.findByType(type, view, { cursor: nextCursor, limit }, undefined, signal)
|
|
899
|
+
: undefined,
|
|
900
|
+
};
|
|
651
901
|
}
|
|
652
|
-
|
|
653
|
-
|
|
902
|
+
else {
|
|
903
|
+
const result = await this.documentView.findByType(type, view, paging, undefined, signal);
|
|
904
|
+
if (signal?.aborted) {
|
|
905
|
+
throw new AbortError();
|
|
906
|
+
}
|
|
907
|
+
const cursor = paging?.cursor;
|
|
908
|
+
const limit = paging?.limit || 100;
|
|
909
|
+
return {
|
|
910
|
+
results: result.items,
|
|
911
|
+
options: paging || { cursor: cursor || "0", limit },
|
|
912
|
+
nextCursor: result.nextCursor,
|
|
913
|
+
next: result.nextCursor
|
|
914
|
+
? async () => this.findByType(type, view, { cursor: result.nextCursor, limit }, undefined, signal)
|
|
915
|
+
: undefined,
|
|
916
|
+
};
|
|
654
917
|
}
|
|
655
|
-
// Results are already paged from the storage layer
|
|
656
|
-
return {
|
|
657
|
-
results: documents,
|
|
658
|
-
options: paging || { cursor: cursor || "0", limit },
|
|
659
|
-
nextCursor,
|
|
660
|
-
next: nextCursor
|
|
661
|
-
? async () => this.findByType(type, view, { cursor: nextCursor, limit }, signal)
|
|
662
|
-
: undefined,
|
|
663
|
-
};
|
|
664
918
|
}
|
|
665
919
|
}
|
|
666
920
|
//# sourceMappingURL=reactor.js.map
|