@powerhousedao/reactor 6.2.3-dev.22 → 6.2.3-dev.24
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/{build-worker-executor-DUjyF4NM.js → build-worker-executor-DxmDJ4QQ.js} +24 -8
- package/dist/build-worker-executor-DxmDJ4QQ.js.map +1 -0
- package/dist/{document-indexer-C1oY6CaR.js → document-indexer-Dn9RB0sg.js} +6 -5
- package/dist/document-indexer-Dn9RB0sg.js.map +1 -0
- package/dist/{drive-container-types-CS5IxDiA.js → drive-container-types-Be5-EY9W.js} +843 -144
- package/dist/drive-container-types-Be5-EY9W.js.map +1 -0
- package/dist/entry.js +10 -5
- package/dist/entry.js.map +1 -1
- package/dist/index.d.ts +1985 -1826
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +716 -302
- package/dist/index.js.map +1 -1
- package/dist/projection-entry.js +4 -4
- package/dist/{projection-shard-manager-CUo4bF4O.js → projection-shard-manager-mQhfVipO.js} +2 -2
- package/dist/{projection-shard-manager-CUo4bF4O.js.map → projection-shard-manager-mQhfVipO.js.map} +1 -1
- package/dist/{types-DMKLa0Ok.js → types-DxDCmtId.js} +3 -2
- package/dist/types-DxDCmtId.js.map +1 -0
- package/dist/{worker-g03lNM42.js → worker-BDVzCtuf.js} +2 -2
- package/dist/{worker-g03lNM42.js.map → worker-BDVzCtuf.js.map} +1 -1
- package/dist/{worker-handle-CrERzl8s.js → worker-handle-B3p-nuqG.js} +14 -9
- package/dist/worker-handle-B3p-nuqG.js.map +1 -0
- package/package.json +9 -7
- package/dist/build-worker-executor-DUjyF4NM.js.map +0 -1
- package/dist/document-indexer-C1oY6CaR.js.map +0 -1
- package/dist/drive-container-types-CS5IxDiA.js.map +0 -1
- package/dist/types-DMKLa0Ok.js.map +0 -1
- package/dist/worker-handle-CrERzl8s.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { n as ReactorEventTypes, t as EventBusAggregateError } from "./types-
|
|
1
|
+
import { $ as RelationshipNotFoundError, A as submittedActionIds, B as DocumentAlreadyExistsError, C as DuplicateManifestError, D as GATED_DOCUMENT_ACTIONS, E as ModuleNotFoundError, F as documentDecisionModel, G as AuthEnforcementDisabledError, H as DuplicateOperationError, I as authDecisionModel, J as DocumentDeletedError, K as AuthTimestampNotMonotonicError, L as buildDecisionModel, M as targetDocumentId, N as decideAtHead, O as createConsistencyToken, P as selectDecisionModel, Q as InvalidSignatureError, R as APPEND_CONDITION_FAILED_PREFIX, S as JobExecutorEventTypes, T as InvalidModuleError, U as OptimisticLockError, V as DocumentExistence, W as RevisionMismatchError, X as ExcessiveReshuffleError, Y as DocumentNotFoundError, Z as InvalidOperationTimestampError, _ as KyselyWriteCache, a as createForwardingPoolInstrumentation, b as CollectionMembershipCache, c as KyselyKeyframeStore, d as verifyActionSignature, et as UpgradePreconditionFailedError, f as PassthroughSigner, g as EventBus, h as resolveFeatureFlags, i as runMigrations, j as summarizeSubmittedActions, k as createEmptyConsistencyToken, l as DocumentModelRegistry, m as KyselyExecutionScope, n as REACTOR_SCHEMA, nt as parsePagingOptions, o as instrumentPgPool, p as DriveCollectionId, q as AuthorizationDeniedError, r as getMigrationStatus, rt as throwIfAborted, s as KyselyOperationStore, t as DEFAULT_DRIVE_CONTAINER_TYPES, tt as matchesScope, u as SimpleJobExecutor, v as KyselyOperationIndex, w as DuplicateModuleError, x as DEFAULT_DEFERRED_JOB_TTL_MS, y as DocumentMetaCache, z as AppendConditionFailedError } from "./drive-container-types-Be5-EY9W.js";
|
|
2
|
+
import { n as ReactorEventTypes, t as EventBusAggregateError } from "./types-DxDCmtId.js";
|
|
3
3
|
import { i as WorkerInitFailedError, r as WorkerExitedError, t as WorkerAbortTimeoutError } from "./errors-D3S6Eysd.js";
|
|
4
|
-
import { a as KyselyDocumentView, c as ReadModelCoordinator, d as DEFAULT_READ_MODEL_YIELD_DEADLINE_MS, f as defaultReadModelIndexingConfig, i as DeletedDocumentRead, l as BaseReadModel, n as ConsistencyTracker, o as DOCUMENT_INDEXER_READ_MODEL, p as unchunkedReadModelIndexingConfig, r as makeConsistencyKey, s as DOCUMENT_VIEW_READ_MODEL, t as KyselyDocumentIndexer, u as DEFAULT_COMMIT_CHUNK_SIZE } from "./document-indexer-
|
|
4
|
+
import { a as KyselyDocumentView, c as ReadModelCoordinator, d as DEFAULT_READ_MODEL_YIELD_DEADLINE_MS, f as defaultReadModelIndexingConfig, i as DeletedDocumentRead, l as BaseReadModel, n as ConsistencyTracker, o as DOCUMENT_INDEXER_READ_MODEL, p as unchunkedReadModelIndexingConfig, r as makeConsistencyKey, s as DOCUMENT_VIEW_READ_MODEL, t as KyselyDocumentIndexer, u as DEFAULT_COMMIT_CHUNK_SIZE } from "./document-indexer-Dn9RB0sg.js";
|
|
5
5
|
import { n as errorToInfo, r as sanitizeArg, t as createForwardingLogger } from "./forwarding-logger-BBkMSxuJ.js";
|
|
6
|
-
import { t as workerEntryPath } from "./worker-
|
|
7
|
-
import { DowngradeNotSupportedError, MAX_AUTH_GRANTS, UnsupportedDocumentModelVersionError, actions, actions as documentActions,
|
|
6
|
+
import { t as workerEntryPath } from "./worker-BDVzCtuf.js";
|
|
7
|
+
import { DEFAULT_SIGNATURE_POLICY, DowngradeNotSupportedError, MAX_AUTH_GRANTS, UnsupportedDocumentModelVersionError, actionSignerIdentity, actionSigningTarget, actions, actions as documentActions, createCopyHeader, decide, deserializeSignature, garbageCollect, generateId, groupDocumentType, groupMembershipActionTypes, hashDocumentStateForScope, normalizeDocumentModelVersion, requestedSignaturePolicy, sortOperations, toTransportAction, withSignaturePolicy } from "@powerhousedao/shared/document-model";
|
|
8
8
|
import { addFile, addFolder, copyNode, deleteNode, driveCreateDocument, generateNodesCopy, getDescendants, handleTargetNameCollisions, isFileNode, isFolderNode, moveNode, updateNode } from "@powerhousedao/shared/document-drive";
|
|
9
9
|
import { v4 } from "uuid";
|
|
10
10
|
import { ConsoleLogger, childLogger } from "document-model";
|
|
@@ -237,37 +237,31 @@ function getSharedActionScope(actions) {
|
|
|
237
237
|
return baseScope;
|
|
238
238
|
}
|
|
239
239
|
/**
|
|
240
|
-
* Signs an action
|
|
241
|
-
*
|
|
240
|
+
* Signs an action for `target`, the log it is written to. An action already
|
|
241
|
+
* signed under a key is returned unchanged; one whose signer or last tuple has
|
|
242
|
+
* no key is unsigned, and is signed like any other.
|
|
242
243
|
*/
|
|
243
|
-
const signAction = async (action, signer, signal) => {
|
|
244
|
-
const
|
|
245
|
-
if (
|
|
246
|
-
const signature = await signer.signAction(action, signal);
|
|
244
|
+
const signAction = async (action, signer, target, signal) => {
|
|
245
|
+
const existing = action.context?.signer;
|
|
246
|
+
if (existing?.app?.key && existing.signatures.at(-1)?.[1]) return action;
|
|
247
|
+
const signature = await signer.signAction(action, target, signal);
|
|
247
248
|
return {
|
|
248
249
|
...action,
|
|
249
250
|
context: {
|
|
250
251
|
...action.context,
|
|
251
252
|
signer: {
|
|
252
|
-
|
|
253
|
-
address: signer.user?.address || "",
|
|
254
|
-
networkId: signer.user?.networkId || "",
|
|
255
|
-
chainId: signer.user?.chainId || 0
|
|
256
|
-
},
|
|
257
|
-
app: {
|
|
258
|
-
name: signer.app?.name || "",
|
|
259
|
-
key: signer.app?.key || ""
|
|
260
|
-
},
|
|
253
|
+
...actionSignerIdentity(signer),
|
|
261
254
|
signatures: [signature]
|
|
262
255
|
}
|
|
263
256
|
}
|
|
264
257
|
};
|
|
265
258
|
};
|
|
266
259
|
/**
|
|
267
|
-
* Signs
|
|
260
|
+
* Signs the actions of a job on `job.documentId`, each for the log it is
|
|
261
|
+
* written to: a relationship action lands in its source document.
|
|
268
262
|
*/
|
|
269
|
-
const signActions = async (actions, signer, signal) => {
|
|
270
|
-
return Promise.all(actions.map((action) => signAction(action, signer, signal)));
|
|
263
|
+
const signActions = async (actions, signer, job, signal) => {
|
|
264
|
+
return Promise.all(actions.map((action) => signAction(action, signer, actionSigningTarget(action, job.documentId, job.branch), signal)));
|
|
271
265
|
};
|
|
272
266
|
function buildSingleJobMeta(jobId, callerMeta) {
|
|
273
267
|
return {
|
|
@@ -329,11 +323,11 @@ var DriveClient = class {
|
|
|
329
323
|
}
|
|
330
324
|
async create(input, signal) {
|
|
331
325
|
this.logger.verbose("drives.create(@input)", input);
|
|
332
|
-
const driveDoc = driveCreateDocument({ global: {
|
|
326
|
+
const driveDoc = withSignaturePolicy(driveCreateDocument({ global: {
|
|
333
327
|
name: input.global.name || "",
|
|
334
328
|
icon: input.global.icon ?? null,
|
|
335
329
|
nodes: []
|
|
336
|
-
} });
|
|
330
|
+
} }), requestedSignaturePolicy(input, await this.client.getCreateSignaturePolicy()), { protocolVersions: input.protocolVersions });
|
|
337
331
|
if (input.preferredEditor) driveDoc.header.meta = {
|
|
338
332
|
...driveDoc.header.meta,
|
|
339
333
|
preferredEditor: input.preferredEditor
|
|
@@ -369,13 +363,19 @@ var DriveClient = class {
|
|
|
369
363
|
initialState: document.state
|
|
370
364
|
}),
|
|
371
365
|
addRelationshipAction(driveIdentifier, documentId, "child")
|
|
372
|
-
], this.signer,
|
|
366
|
+
], this.signer, {
|
|
367
|
+
documentId,
|
|
368
|
+
branch: "main"
|
|
369
|
+
}, signal);
|
|
373
370
|
const driveActions = await signActions([addFile({
|
|
374
371
|
id: documentId,
|
|
375
372
|
name: document.header.name || documentId,
|
|
376
373
|
documentType: document.header.documentType,
|
|
377
374
|
parentFolder
|
|
378
|
-
})], this.signer,
|
|
375
|
+
})], this.signer, {
|
|
376
|
+
documentId: driveIdentifier,
|
|
377
|
+
branch: "main"
|
|
378
|
+
}, signal);
|
|
379
379
|
await this.runJobs([{
|
|
380
380
|
key: "document",
|
|
381
381
|
documentId,
|
|
@@ -465,18 +465,20 @@ var DriveClient = class {
|
|
|
465
465
|
});
|
|
466
466
|
resolvedNamesByTargetId.set(entry.targetId, resolved);
|
|
467
467
|
}
|
|
468
|
+
const policy = await this.client.getCreateSignaturePolicy();
|
|
468
469
|
for (const entry of copyPlan) {
|
|
469
470
|
const node = drive.state.global.nodes.find((n) => n.id === entry.srcId);
|
|
470
471
|
if (!node || !isFileNode(node)) continue;
|
|
471
472
|
const srcDoc = await this.client.get(entry.srcId, void 0, signal);
|
|
472
473
|
const duplicated = {
|
|
473
474
|
...srcDoc,
|
|
474
|
-
header:
|
|
475
|
+
header: createCopyHeader(srcDoc.header, entry.targetId, policy),
|
|
475
476
|
initialState: srcDoc.state,
|
|
476
477
|
operations: {}
|
|
477
478
|
};
|
|
478
479
|
const resolvedName = resolvedNamesByTargetId.get(entry.targetId);
|
|
479
480
|
if (resolvedName) duplicated.header.name = resolvedName;
|
|
481
|
+
entry.targetId = duplicated.header.id;
|
|
480
482
|
await this.addFile(driveIdentifier, duplicated, entry.targetParentFolder ?? void 0, signal);
|
|
481
483
|
}
|
|
482
484
|
return this.client.execute(driveIdentifier, "main", copyPlan.map((entry) => copyNode(entry)), signal);
|
|
@@ -529,8 +531,14 @@ var DriveClient = class {
|
|
|
529
531
|
}
|
|
530
532
|
}
|
|
531
533
|
async removeFileNode(driveId, fileId, signal) {
|
|
532
|
-
const relationshipActions = await signActions([removeRelationshipAction(driveId, fileId, "child")], this.signer,
|
|
533
|
-
|
|
534
|
+
const relationshipActions = await signActions([removeRelationshipAction(driveId, fileId, "child")], this.signer, {
|
|
535
|
+
documentId: driveId,
|
|
536
|
+
branch: "main"
|
|
537
|
+
}, signal);
|
|
538
|
+
const driveActions = await signActions([deleteNode({ id: fileId })], this.signer, {
|
|
539
|
+
documentId: driveId,
|
|
540
|
+
branch: "main"
|
|
541
|
+
}, signal);
|
|
534
542
|
const batchResult = await this.reactor.executeBatch({ jobs: [{
|
|
535
543
|
key: "relationship",
|
|
536
544
|
documentId: driveId,
|
|
@@ -1049,8 +1057,9 @@ var ReactorClient = class {
|
|
|
1049
1057
|
documentView;
|
|
1050
1058
|
readGate;
|
|
1051
1059
|
actionEvaluation;
|
|
1060
|
+
createSignaturePolicy;
|
|
1052
1061
|
drives;
|
|
1053
|
-
constructor(logger, reactor, signer, subscriptionManager, jobAwaiter, documentIndexer, documentView, readGate = new BareReadGate(), actionEvaluation) {
|
|
1062
|
+
constructor(logger, reactor, signer, subscriptionManager, jobAwaiter, documentIndexer, documentView, readGate = new BareReadGate(), actionEvaluation, createSignaturePolicy = DEFAULT_SIGNATURE_POLICY) {
|
|
1054
1063
|
this.logger = logger;
|
|
1055
1064
|
this.reactor = reactor;
|
|
1056
1065
|
this.signer = signer;
|
|
@@ -1060,6 +1069,7 @@ var ReactorClient = class {
|
|
|
1060
1069
|
this.documentView = documentView;
|
|
1061
1070
|
this.readGate = readGate;
|
|
1062
1071
|
this.actionEvaluation = actionEvaluation;
|
|
1072
|
+
this.createSignaturePolicy = createSignaturePolicy;
|
|
1063
1073
|
this.drives = new DriveClient(this, logger, reactor, signer);
|
|
1064
1074
|
this.logger.verbose("ReactorClient initialized");
|
|
1065
1075
|
}
|
|
@@ -1403,12 +1413,16 @@ var ReactorClient = class {
|
|
|
1403
1413
|
scopeStates: document.state ?? {}
|
|
1404
1414
|
};
|
|
1405
1415
|
}
|
|
1416
|
+
getCreateSignaturePolicy() {
|
|
1417
|
+
return Promise.resolve(this.createSignaturePolicy);
|
|
1418
|
+
}
|
|
1406
1419
|
/**
|
|
1407
1420
|
* Creates a document and waits for completion
|
|
1408
1421
|
*/
|
|
1409
1422
|
async create(document, parentIdentifier, signal) {
|
|
1410
1423
|
this.logger.verbose("create(@id, @parentIdentifier)", document.header.id, parentIdentifier);
|
|
1411
1424
|
const documentId = document.header.id;
|
|
1425
|
+
const branch = document.header.branch || "main";
|
|
1412
1426
|
const createActions = await signActions([createDocumentAction({
|
|
1413
1427
|
model: document.header.documentType,
|
|
1414
1428
|
version: 0,
|
|
@@ -1431,17 +1445,23 @@ var ReactorClient = class {
|
|
|
1431
1445
|
fromVersion: 0,
|
|
1432
1446
|
toVersion: normalizeDocumentModelVersion(document.state.document?.version),
|
|
1433
1447
|
initialState: document.state
|
|
1434
|
-
})], this.signer,
|
|
1448
|
+
})], this.signer, {
|
|
1449
|
+
documentId,
|
|
1450
|
+
branch
|
|
1451
|
+
}, signal);
|
|
1435
1452
|
const jobs = [{
|
|
1436
1453
|
key: "create",
|
|
1437
1454
|
documentId,
|
|
1438
1455
|
scope: getSharedActionScope(createActions),
|
|
1439
|
-
branch
|
|
1456
|
+
branch,
|
|
1440
1457
|
actions: createActions,
|
|
1441
1458
|
dependsOn: []
|
|
1442
1459
|
}];
|
|
1443
1460
|
if (parentIdentifier) {
|
|
1444
|
-
const parentActions = await signActions([addRelationshipAction(parentIdentifier, documentId, "child")], this.signer,
|
|
1461
|
+
const parentActions = await signActions([addRelationshipAction(parentIdentifier, documentId, "child")], this.signer, {
|
|
1462
|
+
documentId: parentIdentifier,
|
|
1463
|
+
branch: "main"
|
|
1464
|
+
}, signal);
|
|
1445
1465
|
jobs.push({
|
|
1446
1466
|
key: "parent",
|
|
1447
1467
|
documentId: parentIdentifier,
|
|
@@ -1475,7 +1495,7 @@ var ReactorClient = class {
|
|
|
1475
1495
|
}, void 0);
|
|
1476
1496
|
if (!module) throw new Error(`Document model not found for type: ${documentModelType}`);
|
|
1477
1497
|
}
|
|
1478
|
-
const document = module.utils.createDocument();
|
|
1498
|
+
const document = withSignaturePolicy(module.utils.createDocument(), requestedSignaturePolicy(options, this.createSignaturePolicy), { protocolVersions: options?.protocolVersions });
|
|
1479
1499
|
document.state.document.version = normalizeDocumentModelVersion(module.version);
|
|
1480
1500
|
return this.create(document, options?.parentIdentifier, signal);
|
|
1481
1501
|
}
|
|
@@ -1510,7 +1530,10 @@ var ReactorClient = class {
|
|
|
1510
1530
|
fromVersion,
|
|
1511
1531
|
toVersion: targetVersion,
|
|
1512
1532
|
revision: { ...document.header.revision }
|
|
1513
|
-
})], this.signer,
|
|
1533
|
+
})], this.signer, {
|
|
1534
|
+
documentId,
|
|
1535
|
+
branch
|
|
1536
|
+
}, signal);
|
|
1514
1537
|
const jobInfo = await this.reactor.execute(documentId, branch, signedActions, signal);
|
|
1515
1538
|
const completedJob = await this.waitForJob(jobInfo, signal);
|
|
1516
1539
|
if (completedJob.status !== JobStatus.FAILED) {
|
|
@@ -1540,8 +1563,12 @@ var ReactorClient = class {
|
|
|
1540
1563
|
*/
|
|
1541
1564
|
async execute(documentIdentifier, branch, actions, signal, subject) {
|
|
1542
1565
|
this.logger.verbose("execute(@documentIdentifier, @branch, @count actions)", documentIdentifier, branch, actions.length);
|
|
1543
|
-
const
|
|
1544
|
-
const
|
|
1566
|
+
const documentId = await this.resolveWriteTarget(documentIdentifier, branch, actions, signal);
|
|
1567
|
+
const signedActions = await signActions(actions, this.signer, {
|
|
1568
|
+
documentId,
|
|
1569
|
+
branch
|
|
1570
|
+
}, signal);
|
|
1571
|
+
const jobInfo = await this.reactor.execute(documentId, branch, signedActions, signal);
|
|
1545
1572
|
const completedJob = await this.waitForJob(jobInfo, signal);
|
|
1546
1573
|
if (completedJob.status === JobStatus.FAILED) throw new Error(completedJob.error?.message);
|
|
1547
1574
|
const view = {
|
|
@@ -1556,15 +1583,38 @@ var ReactorClient = class {
|
|
|
1556
1583
|
*/
|
|
1557
1584
|
async executeAsync(documentIdentifier, branch, actions, signal) {
|
|
1558
1585
|
this.logger.verbose("executeAsync(@documentIdentifier, @branch, @count actions)", documentIdentifier, branch, actions.length);
|
|
1559
|
-
const
|
|
1560
|
-
|
|
1586
|
+
const documentId = await this.resolveWriteTarget(documentIdentifier, branch, actions, signal);
|
|
1587
|
+
const signedActions = await signActions(actions, this.signer, {
|
|
1588
|
+
documentId,
|
|
1589
|
+
branch
|
|
1590
|
+
}, signal);
|
|
1591
|
+
return this.reactor.execute(documentId, branch, signedActions, signal);
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* The id a write on `identifier` is stored under, which its signatures bind.
|
|
1595
|
+
* A create names its own id, and an id no slug maps to is taken as given, so
|
|
1596
|
+
* a document still in flight resolves to itself.
|
|
1597
|
+
*/
|
|
1598
|
+
async resolveWriteTarget(identifier, branch, actions, signal) {
|
|
1599
|
+
if (actions.some((action) => action.type === "CREATE_DOCUMENT")) return identifier;
|
|
1600
|
+
const view = { branch };
|
|
1601
|
+
const bySlug = await this.documentView.resolveSlug(identifier, view, void 0, signal);
|
|
1602
|
+
if (bySlug === void 0 || bySlug === identifier) return identifier;
|
|
1603
|
+
return this.documentView.resolveIdOrSlug(identifier, view, void 0, signal);
|
|
1561
1604
|
}
|
|
1562
1605
|
async executeBatch(request, signal) {
|
|
1563
1606
|
this.logger.verbose("executeBatch(@count jobs)", request.jobs.length);
|
|
1564
|
-
const signedJobs = await Promise.all(request.jobs.map(async (job) =>
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1607
|
+
const signedJobs = await Promise.all(request.jobs.map(async (job) => {
|
|
1608
|
+
const documentId = await this.resolveWriteTarget(job.documentId, job.branch, job.actions, signal);
|
|
1609
|
+
return {
|
|
1610
|
+
...job,
|
|
1611
|
+
documentId,
|
|
1612
|
+
actions: await signActions(job.actions, this.signer, {
|
|
1613
|
+
documentId,
|
|
1614
|
+
branch: job.branch
|
|
1615
|
+
}, signal)
|
|
1616
|
+
};
|
|
1617
|
+
}));
|
|
1568
1618
|
const batchResult = await this.reactor.executeBatch({ jobs: signedJobs }, signal);
|
|
1569
1619
|
const completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.waitForJob(job, signal)));
|
|
1570
1620
|
for (const job of completedJobs) if (job.status === JobStatus.FAILED) throw new Error(job.error?.message);
|
|
@@ -1870,7 +1920,7 @@ var JobResultHandler = class {
|
|
|
1870
1920
|
callbacks.deferJob(result.error.documentId, handle.job);
|
|
1871
1921
|
return;
|
|
1872
1922
|
}
|
|
1873
|
-
if (result.error && (DocumentDeletedError.isError(result.error) || DocumentAlreadyExistsError.isError(result.error) || DocumentNotFoundError.isError(result.error) || AuthorizationDeniedError.isError(result.error) || AuthTimestampNotMonotonicError.isError(result.error) || InvalidOperationTimestampError.isError(result.error) || ExcessiveReshuffleError.isError(result.error) || UpgradePreconditionFailedError.isError(result.error))) {
|
|
1923
|
+
if (result.error && (DocumentDeletedError.isError(result.error) || DocumentAlreadyExistsError.isError(result.error) || DocumentNotFoundError.isError(result.error) || AuthorizationDeniedError.isError(result.error) || AuthTimestampNotMonotonicError.isError(result.error) || InvalidOperationTimestampError.isError(result.error) || ExcessiveReshuffleError.isError(result.error) || InvalidSignatureError.isError(result.error) || UpgradePreconditionFailedError.isError(result.error))) {
|
|
1874
1924
|
const errorInfo = toErrorInfo(result.error);
|
|
1875
1925
|
this.jobTracker.markFailed(handle.job.id, errorInfo, handle.job);
|
|
1876
1926
|
this.eventBus.emit(ReactorEventTypes.JOB_FAILED, {
|
|
@@ -2258,6 +2308,7 @@ var WorkerPoolJobExecutorManager = class {
|
|
|
2258
2308
|
await this.tryDispatchFor(worker);
|
|
2259
2309
|
return;
|
|
2260
2310
|
}
|
|
2311
|
+
for (const refusal of outcome.signatureRefusals ?? []) this.eventBus.emit(ReactorEventTypes.SIGNATURE_REFUSED, refusal).catch(() => {});
|
|
2261
2312
|
if (outcome.result.success) {
|
|
2262
2313
|
this.totalJobsProcessed++;
|
|
2263
2314
|
const completedEvent = {
|
|
@@ -2727,24 +2778,267 @@ function resolveProcessorSlots(records, legacy) {
|
|
|
2727
2778
|
});
|
|
2728
2779
|
}
|
|
2729
2780
|
//#endregion
|
|
2781
|
+
//#region src/processors/processor-queue.ts
|
|
2782
|
+
function isDelivery(task) {
|
|
2783
|
+
return task?.kind === "live" || task?.kind === "advance";
|
|
2784
|
+
}
|
|
2785
|
+
function errorMessage(error) {
|
|
2786
|
+
return error instanceof Error ? error.message : String(error);
|
|
2787
|
+
}
|
|
2788
|
+
function lowestOf(ops) {
|
|
2789
|
+
let lowest = ops[0].context.ordinal;
|
|
2790
|
+
for (const op of ops) lowest = Math.min(lowest, op.context.ordinal);
|
|
2791
|
+
return lowest;
|
|
2792
|
+
}
|
|
2793
|
+
function highestOf(ops) {
|
|
2794
|
+
let highest = 0;
|
|
2795
|
+
for (const op of ops) highest = Math.max(highest, op.context.ordinal);
|
|
2796
|
+
return highest;
|
|
2797
|
+
}
|
|
2798
|
+
var ProcessorQueue = class {
|
|
2799
|
+
tasks = [];
|
|
2800
|
+
running = false;
|
|
2801
|
+
closed = false;
|
|
2802
|
+
replaysAhead = 0;
|
|
2803
|
+
unrouted = /* @__PURE__ */ new Set();
|
|
2804
|
+
constructor(options) {
|
|
2805
|
+
this.options = options;
|
|
2806
|
+
}
|
|
2807
|
+
get isClosed() {
|
|
2808
|
+
return this.closed;
|
|
2809
|
+
}
|
|
2810
|
+
/** Resolves at once behind a replay, so a pass never waits out a backfill. */
|
|
2811
|
+
live(ops) {
|
|
2812
|
+
const delivered = this.push((done) => ({
|
|
2813
|
+
kind: "live",
|
|
2814
|
+
ops,
|
|
2815
|
+
done
|
|
2816
|
+
}));
|
|
2817
|
+
return this.replaysAhead > 0 ? Promise.resolve() : delivered;
|
|
2818
|
+
}
|
|
2819
|
+
/** Raises the cursor past a batch with nothing for this processor. */
|
|
2820
|
+
advance(through) {
|
|
2821
|
+
const last = this.tasks.at(-1);
|
|
2822
|
+
if (last?.kind === "advance") {
|
|
2823
|
+
last.through = Math.max(last.through, through);
|
|
2824
|
+
return Promise.resolve();
|
|
2825
|
+
}
|
|
2826
|
+
return this.push((done) => ({
|
|
2827
|
+
kind: "advance",
|
|
2828
|
+
through,
|
|
2829
|
+
done
|
|
2830
|
+
}));
|
|
2831
|
+
}
|
|
2832
|
+
/** Replays from the cursor as it stands when the task runs. */
|
|
2833
|
+
backfill() {
|
|
2834
|
+
return this.replay("backfill", () => this.runBackfill());
|
|
2835
|
+
}
|
|
2836
|
+
/** Clears an error and replays from the cursor. No-op when active. */
|
|
2837
|
+
retry() {
|
|
2838
|
+
return this.replay("retry", async () => {
|
|
2839
|
+
const { cursor } = this.options;
|
|
2840
|
+
if (cursor.status !== "errored") return;
|
|
2841
|
+
cursor.status = "active";
|
|
2842
|
+
cursor.lastError = void 0;
|
|
2843
|
+
cursor.lastErrorTimestamp = void 0;
|
|
2844
|
+
await this.persist();
|
|
2845
|
+
await this.runBackfill();
|
|
2846
|
+
});
|
|
2847
|
+
}
|
|
2848
|
+
/** Stops cursor writes now; queued tasks still run before the disconnect. */
|
|
2849
|
+
close() {
|
|
2850
|
+
if (this.closed) return Promise.resolve();
|
|
2851
|
+
const disconnect = this.enqueue("disconnect", async () => {
|
|
2852
|
+
try {
|
|
2853
|
+
await this.options.processor.onDisconnect();
|
|
2854
|
+
} catch (error) {
|
|
2855
|
+
this.options.logger.error("Error disconnecting processor '@ProcessorId': @Error", this.options.processorId, error);
|
|
2856
|
+
}
|
|
2857
|
+
});
|
|
2858
|
+
this.closed = true;
|
|
2859
|
+
return disconnect;
|
|
2860
|
+
}
|
|
2861
|
+
replay(kind, run) {
|
|
2862
|
+
if (this.closed) return Promise.resolve();
|
|
2863
|
+
this.replaysAhead++;
|
|
2864
|
+
return this.enqueue(kind, async () => {
|
|
2865
|
+
try {
|
|
2866
|
+
await run();
|
|
2867
|
+
} finally {
|
|
2868
|
+
this.replaysAhead--;
|
|
2869
|
+
}
|
|
2870
|
+
});
|
|
2871
|
+
}
|
|
2872
|
+
enqueue(kind, run) {
|
|
2873
|
+
return this.push((done) => ({
|
|
2874
|
+
kind,
|
|
2875
|
+
run,
|
|
2876
|
+
done
|
|
2877
|
+
}));
|
|
2878
|
+
}
|
|
2879
|
+
push(task) {
|
|
2880
|
+
if (this.closed) return Promise.resolve();
|
|
2881
|
+
return new Promise((resolve) => {
|
|
2882
|
+
this.tasks.push(task(resolve));
|
|
2883
|
+
if (this.running) return;
|
|
2884
|
+
this.running = true;
|
|
2885
|
+
queueMicrotask(() => void this.drain());
|
|
2886
|
+
});
|
|
2887
|
+
}
|
|
2888
|
+
async drain() {
|
|
2889
|
+
while (this.tasks.length > 0) {
|
|
2890
|
+
const task = this.tasks.shift();
|
|
2891
|
+
const batch = [];
|
|
2892
|
+
if (isDelivery(task)) {
|
|
2893
|
+
batch.push(task);
|
|
2894
|
+
let size = task.kind === "live" ? task.ops.length : 0;
|
|
2895
|
+
let next = this.tasks[0];
|
|
2896
|
+
while (isDelivery(next) && size < 500) {
|
|
2897
|
+
if (next.kind === "live") size += next.ops.length;
|
|
2898
|
+
batch.push(next);
|
|
2899
|
+
this.tasks.shift();
|
|
2900
|
+
next = this.tasks[0];
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
try {
|
|
2904
|
+
await (isDelivery(task) ? this.deliverLive(batch) : task.run());
|
|
2905
|
+
} catch (error) {
|
|
2906
|
+
this.options.logger.error("Processor '@ProcessorId' task '@Kind' failed: @Error", this.options.processorId, task.kind, error);
|
|
2907
|
+
} finally {
|
|
2908
|
+
task.done();
|
|
2909
|
+
for (const merged of batch.slice(1)) merged.done();
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
this.running = false;
|
|
2913
|
+
}
|
|
2914
|
+
async deliverLive(batch) {
|
|
2915
|
+
const { cursor, floor } = this.options;
|
|
2916
|
+
const ops = [];
|
|
2917
|
+
let through = 0;
|
|
2918
|
+
for (const task of batch) if (task.kind === "live") ops.push(...task.ops);
|
|
2919
|
+
else through = Math.max(through, task.through);
|
|
2920
|
+
const fresh = ops.filter((op) => {
|
|
2921
|
+
const ordinal = op.context.ordinal;
|
|
2922
|
+
if (ordinal <= floor) return false;
|
|
2923
|
+
return !this.unrouted.delete(ordinal);
|
|
2924
|
+
});
|
|
2925
|
+
if (fresh.length === 0) {
|
|
2926
|
+
await this.raiseCursor(through);
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
if (cursor.status !== "active") {
|
|
2930
|
+
await this.parkBelow(fresh);
|
|
2931
|
+
return;
|
|
2932
|
+
}
|
|
2933
|
+
if (!await this.deliver(fresh)) {
|
|
2934
|
+
await this.parkBelow(fresh);
|
|
2935
|
+
return;
|
|
2936
|
+
}
|
|
2937
|
+
await this.raiseCursor(Math.max(highestOf(fresh), through));
|
|
2938
|
+
}
|
|
2939
|
+
async runBackfill() {
|
|
2940
|
+
const { cursor, filter, floor } = this.options;
|
|
2941
|
+
if (cursor.status !== "active") return;
|
|
2942
|
+
let page;
|
|
2943
|
+
try {
|
|
2944
|
+
page = await this.options.readSince(cursor.lastOrdinal);
|
|
2945
|
+
} catch (error) {
|
|
2946
|
+
await this.fail(error, "reading backfill");
|
|
2947
|
+
return;
|
|
2948
|
+
}
|
|
2949
|
+
while (page.results.length > 0) {
|
|
2950
|
+
if (this.closed) return;
|
|
2951
|
+
const matching = page.results.filter((op) => op.context.ordinal > floor && matchesFilter(op, filter));
|
|
2952
|
+
if (matching.length > 0) {
|
|
2953
|
+
if (!await this.deliver(matching)) {
|
|
2954
|
+
await this.persist();
|
|
2955
|
+
return;
|
|
2956
|
+
}
|
|
2957
|
+
this.dedupeQueued(matching);
|
|
2958
|
+
}
|
|
2959
|
+
await this.raiseCursor(highestOf(page.results));
|
|
2960
|
+
if (!page.next) break;
|
|
2961
|
+
try {
|
|
2962
|
+
page = await page.next();
|
|
2963
|
+
} catch (error) {
|
|
2964
|
+
await this.fail(error, "reading backfill");
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
dedupeQueued(delivered) {
|
|
2970
|
+
const routed = this.options.routedThrough();
|
|
2971
|
+
const queued = /* @__PURE__ */ new Set();
|
|
2972
|
+
for (const op of delivered) {
|
|
2973
|
+
const ordinal = op.context.ordinal;
|
|
2974
|
+
if (ordinal > routed) this.unrouted.add(ordinal);
|
|
2975
|
+
else queued.add(ordinal);
|
|
2976
|
+
}
|
|
2977
|
+
if (queued.size === 0) return;
|
|
2978
|
+
for (const task of this.tasks) {
|
|
2979
|
+
if (task.kind !== "live") continue;
|
|
2980
|
+
task.ops = task.ops.filter((op) => !queued.has(op.context.ordinal));
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
async deliver(ops) {
|
|
2984
|
+
try {
|
|
2985
|
+
await this.options.processor.onOperations(ops);
|
|
2986
|
+
return true;
|
|
2987
|
+
} catch (error) {
|
|
2988
|
+
this.markErrored(error);
|
|
2989
|
+
this.options.logger.error("Processor '@ProcessorId' failed at ordinal @Ordinal: @Error", this.options.processorId, lowestOf(ops), error);
|
|
2990
|
+
return false;
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
async fail(error, during) {
|
|
2994
|
+
this.markErrored(error);
|
|
2995
|
+
await this.persist();
|
|
2996
|
+
this.options.logger.error("Processor '@ProcessorId' failed @During: @Error", this.options.processorId, during, error);
|
|
2997
|
+
}
|
|
2998
|
+
markErrored(error) {
|
|
2999
|
+
const { cursor } = this.options;
|
|
3000
|
+
cursor.status = "errored";
|
|
3001
|
+
cursor.lastError = errorMessage(error);
|
|
3002
|
+
cursor.lastErrorTimestamp = /* @__PURE__ */ new Date();
|
|
3003
|
+
}
|
|
3004
|
+
async raiseCursor(through) {
|
|
3005
|
+
const { cursor } = this.options;
|
|
3006
|
+
if (cursor.status !== "active") return;
|
|
3007
|
+
if (through <= cursor.lastOrdinal) return;
|
|
3008
|
+
cursor.lastOrdinal = through;
|
|
3009
|
+
await this.persist();
|
|
3010
|
+
}
|
|
3011
|
+
async parkBelow(missed) {
|
|
3012
|
+
const { cursor } = this.options;
|
|
3013
|
+
cursor.lastOrdinal = Math.min(cursor.lastOrdinal, lowestOf(missed) - 1);
|
|
3014
|
+
await this.persist();
|
|
3015
|
+
}
|
|
3016
|
+
async persist() {
|
|
3017
|
+
if (this.closed) return;
|
|
3018
|
+
const { cursor } = this.options;
|
|
3019
|
+
try {
|
|
3020
|
+
await this.options.persist({
|
|
3021
|
+
lastOrdinal: cursor.lastOrdinal,
|
|
3022
|
+
status: cursor.status,
|
|
3023
|
+
lastError: cursor.lastError,
|
|
3024
|
+
lastErrorTimestamp: cursor.lastErrorTimestamp
|
|
3025
|
+
});
|
|
3026
|
+
} catch (error) {
|
|
3027
|
+
this.options.logger.error("Failed to persist cursor for '@ProcessorId': @Error", this.options.processorId, error);
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
};
|
|
3031
|
+
//#endregion
|
|
2730
3032
|
//#region src/processors/processor-manager.ts
|
|
2731
|
-
/**
|
|
2732
|
-
* Manages processor lifecycle based on operations.
|
|
2733
|
-
* Extends BaseReadModel to receive operations from ReadModelCoordinator.
|
|
2734
|
-
*
|
|
2735
|
-
* Responsibilities:
|
|
2736
|
-
* 1. Detect drive creation from CREATE_DOCUMENT operations
|
|
2737
|
-
* 2. Create processors for each drive using registered factories
|
|
2738
|
-
* 3. Route operations to matching processors based on filters
|
|
2739
|
-
* 4. Clean up processors when drives are deleted or factories are unregistered
|
|
2740
|
-
* 5. Track per-processor cursors for failure recovery and backfill
|
|
2741
|
-
*/
|
|
2742
3033
|
var ProcessorManager = class extends BaseReadModel {
|
|
2743
3034
|
factoryRegistry = /* @__PURE__ */ new Map();
|
|
2744
3035
|
processorsByDrive = /* @__PURE__ */ new Map();
|
|
2745
|
-
|
|
3036
|
+
pendingSlots = /* @__PURE__ */ new Set();
|
|
2746
3037
|
knownDrives = /* @__PURE__ */ new Map();
|
|
3038
|
+
highestRoutedOrdinal = 0;
|
|
2747
3039
|
cursorCache = /* @__PURE__ */ new Map();
|
|
3040
|
+
cursorWrites = /* @__PURE__ */ new Map();
|
|
3041
|
+
draining = /* @__PURE__ */ new Map();
|
|
2748
3042
|
logger;
|
|
2749
3043
|
driveContainerTypes;
|
|
2750
3044
|
legacyProcessorIds;
|
|
@@ -2759,39 +3053,31 @@ var ProcessorManager = class extends BaseReadModel {
|
|
|
2759
3053
|
this.legacyProcessorIds = options.legacyProcessorIds ?? true;
|
|
2760
3054
|
}
|
|
2761
3055
|
async init() {
|
|
2762
|
-
await super.init();
|
|
2763
3056
|
await this.loadAllCursors();
|
|
3057
|
+
await super.init();
|
|
2764
3058
|
await this.discoverExistingDrives();
|
|
2765
3059
|
}
|
|
2766
3060
|
async commitOperations(items) {
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
3061
|
+
const { runs, reserved } = this.detectNewDrives(items);
|
|
3062
|
+
const disconnects = this.detectDeletedDrives(items);
|
|
3063
|
+
const deliveries = this.enqueueRouted(items, reserved);
|
|
3064
|
+
await Promise.all([
|
|
3065
|
+
...runs.map((run) => run()),
|
|
3066
|
+
...disconnects,
|
|
3067
|
+
...deliveries
|
|
3068
|
+
]);
|
|
2770
3069
|
}
|
|
2771
3070
|
async registerFactory(identifier, factory) {
|
|
2772
|
-
|
|
3071
|
+
const removals = this.removeFactory(identifier);
|
|
2773
3072
|
this.factoryRegistry.set(identifier, factory);
|
|
2774
|
-
this.
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
3073
|
+
const previous = this.draining.get(identifier);
|
|
3074
|
+
const creationOrdinal = this.highWater() + 1;
|
|
3075
|
+
const runs = [];
|
|
3076
|
+
for (const [driveId, documentType] of this.knownDrives) runs.push(this.reserveSlot(identifier, factory, driveId, createMinimalDriveHeader(driveId, documentType), creationOrdinal, void 0, false, previous).run);
|
|
3077
|
+
await Promise.all([...removals, ...runs.map((run) => run())]);
|
|
2779
3078
|
}
|
|
2780
3079
|
async unregisterFactory(identifier) {
|
|
2781
|
-
|
|
2782
|
-
if (!factoryProcessors) return;
|
|
2783
|
-
for (const [driveId, tracked] of factoryProcessors) {
|
|
2784
|
-
for (const t of tracked) await this.safeDisconnect(t.record.processor);
|
|
2785
|
-
const driveProcessors = this.processorsByDrive.get(driveId);
|
|
2786
|
-
if (driveProcessors) {
|
|
2787
|
-
const remaining = driveProcessors.filter((p) => !tracked.includes(p));
|
|
2788
|
-
if (remaining.length > 0) this.processorsByDrive.set(driveId, remaining);
|
|
2789
|
-
else this.processorsByDrive.delete(driveId);
|
|
2790
|
-
}
|
|
2791
|
-
}
|
|
2792
|
-
await this.deleteProcessorCursors({ factoryId: identifier });
|
|
2793
|
-
this.factoryToProcessors.delete(identifier);
|
|
2794
|
-
this.factoryRegistry.delete(identifier);
|
|
3080
|
+
await Promise.all(this.removeFactory(identifier));
|
|
2795
3081
|
}
|
|
2796
3082
|
get(processorId) {
|
|
2797
3083
|
for (const tracked of this.allTrackedProcessors()) if (tracked.processorId === processorId) return tracked;
|
|
@@ -2799,208 +3085,283 @@ var ProcessorManager = class extends BaseReadModel {
|
|
|
2799
3085
|
getAll() {
|
|
2800
3086
|
return Array.from(this.allTrackedProcessors());
|
|
2801
3087
|
}
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
for (const op of
|
|
3088
|
+
/** Synchronous: reserves a slot per registered factory for each new drive. */
|
|
3089
|
+
detectNewDrives(items) {
|
|
3090
|
+
const runs = [];
|
|
3091
|
+
const reserved = /* @__PURE__ */ new Set();
|
|
3092
|
+
for (const op of items) {
|
|
2807
3093
|
if (!this.isDriveCreation(op)) continue;
|
|
2808
3094
|
const driveId = op.context.documentId;
|
|
2809
3095
|
if (this.knownDrives.has(driveId)) continue;
|
|
2810
3096
|
this.knownDrives.set(driveId, op.context.documentType);
|
|
2811
3097
|
const driveHeader = extractDriveHeader(op);
|
|
2812
3098
|
if (!driveHeader) continue;
|
|
2813
|
-
for (const [identifier, factory] of this.factoryRegistry)
|
|
3099
|
+
for (const [identifier, factory] of this.factoryRegistry) {
|
|
3100
|
+
const { slot, run } = this.reserveSlot(identifier, factory, driveId, driveHeader, op.context.ordinal, items, true);
|
|
3101
|
+
reserved.add(slot);
|
|
3102
|
+
runs.push(run);
|
|
3103
|
+
}
|
|
2814
3104
|
}
|
|
3105
|
+
return {
|
|
3106
|
+
runs,
|
|
3107
|
+
reserved
|
|
3108
|
+
};
|
|
2815
3109
|
}
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
for (const op of operations) {
|
|
3110
|
+
/** Synchronous: drops a deleted drive's processors from the tables. */
|
|
3111
|
+
detectDeletedDrives(items) {
|
|
3112
|
+
const pending = [];
|
|
3113
|
+
for (const op of items) {
|
|
2821
3114
|
if (!isDriveDeletion(op)) continue;
|
|
2822
3115
|
const driveId = extractDeletedDocumentId(op);
|
|
2823
3116
|
if (!driveId || !this.knownDrives.has(driveId)) continue;
|
|
2824
|
-
if (!this.isDeletedDocumentADrive(driveId)) continue;
|
|
2825
|
-
await this.cleanupDriveProcessors(driveId);
|
|
2826
3117
|
this.knownDrives.delete(driveId);
|
|
3118
|
+
for (const slot of this.pendingSlots) if (slot.driveId === driveId) this.pendingSlots.delete(slot);
|
|
3119
|
+
for (const { queue } of this.processorsByDrive.get(driveId) ?? []) queue.close();
|
|
3120
|
+
this.processorsByDrive.delete(driveId);
|
|
3121
|
+
pending.push(...this.deleteCursors((row) => row.driveId === driveId));
|
|
3122
|
+
}
|
|
3123
|
+
return pending;
|
|
3124
|
+
}
|
|
3125
|
+
/** Synchronous: puts each processor's share of the batch on its queue. */
|
|
3126
|
+
enqueueRouted(items, reserved) {
|
|
3127
|
+
if (items.length === 0) return [];
|
|
3128
|
+
let lowest = items[0].context.ordinal;
|
|
3129
|
+
let highest = 0;
|
|
3130
|
+
for (const item of items) {
|
|
3131
|
+
lowest = Math.min(lowest, item.context.ordinal);
|
|
3132
|
+
highest = Math.max(highest, item.context.ordinal);
|
|
3133
|
+
}
|
|
3134
|
+
this.highestRoutedOrdinal = Math.max(this.highestRoutedOrdinal, highest);
|
|
3135
|
+
for (const slot of this.pendingSlots) {
|
|
3136
|
+
if (reserved.has(slot)) continue;
|
|
3137
|
+
slot.lowestRoutedOrdinal = Math.min(slot.lowestRoutedOrdinal ?? lowest, lowest);
|
|
3138
|
+
}
|
|
3139
|
+
const deliveries = [];
|
|
3140
|
+
for (const { tracked, queue } of this.allBound()) {
|
|
3141
|
+
const matching = items.filter((op) => matchesFilter(op, tracked.record.filter));
|
|
3142
|
+
if (matching.length > 0) deliveries.push(queue.live(matching));
|
|
3143
|
+
else queue.advance(highest);
|
|
3144
|
+
}
|
|
3145
|
+
return deliveries;
|
|
3146
|
+
}
|
|
3147
|
+
/** Synchronous: binds records, or discards them if the slot was cancelled. */
|
|
3148
|
+
bind(slot, records, creationOrdinal, creationItems) {
|
|
3149
|
+
const released = this.pendingSlots.delete(slot);
|
|
3150
|
+
if (!records || records.length === 0) {
|
|
3151
|
+
const settled = Promise.resolve();
|
|
3152
|
+
return {
|
|
3153
|
+
persisted: settled,
|
|
3154
|
+
delivered: settled
|
|
3155
|
+
};
|
|
2827
3156
|
}
|
|
3157
|
+
if (!released) {
|
|
3158
|
+
const discarded = records.map((record) => this.discard(slot, record.processor.onDisconnect.bind(record.processor)));
|
|
3159
|
+
const settled = Promise.all(discarded).then(() => void 0);
|
|
3160
|
+
return {
|
|
3161
|
+
persisted: settled,
|
|
3162
|
+
delivered: settled
|
|
3163
|
+
};
|
|
3164
|
+
}
|
|
3165
|
+
const { factoryId, driveId, lowestRoutedOrdinal } = slot;
|
|
3166
|
+
const ids = resolveProcessorSlots(records, this.legacyProcessorIds);
|
|
3167
|
+
const bound = records.map((record, i) => this.track(slot, record, i, `${factoryId}:${driveId}:${ids[i]}`, creationOrdinal, lowestRoutedOrdinal));
|
|
3168
|
+
const drive = this.processorsByDrive.get(driveId) ?? [];
|
|
3169
|
+
this.processorsByDrive.set(driveId, [...drive, ...bound]);
|
|
3170
|
+
const liveIds = new Set(bound.map((b) => b.tracked.processorId));
|
|
3171
|
+
const writes = this.deleteCursors((row) => row.factoryId === factoryId && row.driveId === driveId && !liveIds.has(row.processorId));
|
|
3172
|
+
for (const { tracked } of bound) writes.push(this.writeCursor(tracked, tracked));
|
|
3173
|
+
const deliveries = [];
|
|
3174
|
+
for (const { tracked, queue } of bound) {
|
|
3175
|
+
const missed = tracked.lastOrdinal < slot.reservedAt || lowestRoutedOrdinal !== void 0;
|
|
3176
|
+
if (tracked.status === "active" && missed) deliveries.push(queue.backfill());
|
|
3177
|
+
const matching = creationItems?.filter((op) => matchesFilter(op, tracked.record.filter));
|
|
3178
|
+
if (matching && matching.length > 0) deliveries.push(queue.live(matching));
|
|
3179
|
+
}
|
|
3180
|
+
return {
|
|
3181
|
+
persisted: Promise.all(writes).then(() => void 0),
|
|
3182
|
+
delivered: Promise.all(deliveries).then(() => void 0)
|
|
3183
|
+
};
|
|
2828
3184
|
}
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
3185
|
+
/** Synchronous: removes a factory's slots, processors and cursor rows. */
|
|
3186
|
+
removeFactory(identifier) {
|
|
3187
|
+
if (!this.factoryRegistry.delete(identifier)) return [];
|
|
3188
|
+
const closing = [];
|
|
3189
|
+
for (const slot of this.pendingSlots) {
|
|
3190
|
+
if (slot.factoryId !== identifier) continue;
|
|
3191
|
+
this.pendingSlots.delete(slot);
|
|
3192
|
+
if (slot.settled) closing.push(slot.settled);
|
|
3193
|
+
}
|
|
3194
|
+
for (const [driveId, drive] of this.processorsByDrive) {
|
|
3195
|
+
const remaining = [];
|
|
3196
|
+
for (const b of drive) if (b.tracked.factoryId === identifier) closing.push(b.queue.close());
|
|
3197
|
+
else remaining.push(b);
|
|
3198
|
+
if (remaining.length > 0) this.processorsByDrive.set(driveId, remaining);
|
|
3199
|
+
else this.processorsByDrive.delete(driveId);
|
|
3200
|
+
}
|
|
3201
|
+
if (closing.length > 0) {
|
|
3202
|
+
const drained = Promise.all([this.draining.get(identifier), ...closing]).then(() => void 0);
|
|
3203
|
+
this.draining.set(identifier, drained);
|
|
3204
|
+
drained.then(() => {
|
|
3205
|
+
if (this.draining.get(identifier) === drained) this.draining.delete(identifier);
|
|
3206
|
+
});
|
|
3207
|
+
}
|
|
3208
|
+
return this.deleteCursors((row) => row.factoryId === identifier);
|
|
2832
3209
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
3210
|
+
reserveSlot(factoryId, factory, driveId, driveHeader, creationOrdinal, creationItems, awaitDelivery, previous) {
|
|
3211
|
+
const slot = {
|
|
3212
|
+
factoryId,
|
|
3213
|
+
driveId,
|
|
3214
|
+
reservedAt: this.highWater(),
|
|
3215
|
+
lowestRoutedOrdinal: void 0,
|
|
3216
|
+
settled: void 0
|
|
3217
|
+
};
|
|
3218
|
+
this.pendingSlots.add(slot);
|
|
3219
|
+
const run = async () => {
|
|
3220
|
+
const bound = (async () => {
|
|
3221
|
+
await previous;
|
|
3222
|
+
const records = await this.runFactory(slot, factory, driveHeader);
|
|
3223
|
+
return this.bind(slot, records, creationOrdinal, creationItems);
|
|
3224
|
+
})();
|
|
3225
|
+
slot.settled = bound.then(({ persisted }) => persisted);
|
|
3226
|
+
const { persisted, delivered } = await bound;
|
|
3227
|
+
await (awaitDelivery ? Promise.all([persisted, delivered]) : persisted);
|
|
3228
|
+
};
|
|
3229
|
+
return {
|
|
3230
|
+
slot,
|
|
3231
|
+
run
|
|
3232
|
+
};
|
|
2835
3233
|
}
|
|
2836
|
-
async
|
|
2837
|
-
let records;
|
|
3234
|
+
async runFactory(slot, factory, driveHeader) {
|
|
2838
3235
|
try {
|
|
2839
|
-
|
|
3236
|
+
return await factory(driveHeader);
|
|
2840
3237
|
} catch (error) {
|
|
2841
|
-
this.logger.error("Factory '@FactoryId' failed for drive '@DriveId': @Error",
|
|
3238
|
+
this.logger.error("Factory '@FactoryId' failed for drive '@DriveId': @Error", slot.factoryId, slot.driveId, error);
|
|
2842
3239
|
return;
|
|
2843
3240
|
}
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
const
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
status = "active";
|
|
2863
|
-
lastError = void 0;
|
|
2864
|
-
lastErrorTimestamp = void 0;
|
|
2865
|
-
}
|
|
2866
|
-
const tracked = {
|
|
2867
|
-
processorId,
|
|
2868
|
-
factoryId: identifier,
|
|
2869
|
-
driveId,
|
|
2870
|
-
processorIndex: i,
|
|
2871
|
-
record,
|
|
2872
|
-
lastOrdinal,
|
|
2873
|
-
status,
|
|
2874
|
-
lastError,
|
|
2875
|
-
lastErrorTimestamp,
|
|
2876
|
-
retry: () => this.retryProcessor(tracked)
|
|
3241
|
+
}
|
|
3242
|
+
track(slot, record, processorIndex, processorId, creationOrdinal, lowestRoutedOrdinal) {
|
|
3243
|
+
const cached = this.cursorCache.get(processorId);
|
|
3244
|
+
let floor = 0;
|
|
3245
|
+
let cursor;
|
|
3246
|
+
if (cached) cursor = {
|
|
3247
|
+
lastOrdinal: cached.lastOrdinal,
|
|
3248
|
+
status: cached.status,
|
|
3249
|
+
lastError: cached.lastError ?? void 0,
|
|
3250
|
+
lastErrorTimestamp: cached.lastErrorTimestamp ?? void 0
|
|
3251
|
+
};
|
|
3252
|
+
else {
|
|
3253
|
+
if (record.startFrom === "current") floor = creationOrdinal - 1;
|
|
3254
|
+
cursor = {
|
|
3255
|
+
lastOrdinal: floor,
|
|
3256
|
+
status: "active",
|
|
3257
|
+
lastError: void 0,
|
|
3258
|
+
lastErrorTimestamp: void 0
|
|
2877
3259
|
};
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
if (!page.next) break;
|
|
2907
|
-
page = await page.next();
|
|
2908
|
-
}
|
|
2909
|
-
}
|
|
2910
|
-
async retryProcessor(tracked) {
|
|
2911
|
-
if (tracked.status !== "errored") return;
|
|
2912
|
-
tracked.status = "active";
|
|
2913
|
-
tracked.lastError = void 0;
|
|
2914
|
-
tracked.lastErrorTimestamp = void 0;
|
|
2915
|
-
await this.saveProcessorCursor(tracked);
|
|
2916
|
-
await this.backfillProcessor(tracked);
|
|
2917
|
-
}
|
|
2918
|
-
async cleanupDriveProcessors(driveId) {
|
|
2919
|
-
const processors = this.processorsByDrive.get(driveId);
|
|
2920
|
-
if (!processors) return;
|
|
2921
|
-
for (const tracked of processors) await this.safeDisconnect(tracked.record.processor);
|
|
2922
|
-
this.processorsByDrive.delete(driveId);
|
|
2923
|
-
for (const factoryProcessors of this.factoryToProcessors.values()) factoryProcessors.delete(driveId);
|
|
2924
|
-
await this.deleteProcessorCursors({ driveId });
|
|
2925
|
-
}
|
|
2926
|
-
async safeDisconnect(processor) {
|
|
3260
|
+
}
|
|
3261
|
+
if (lowestRoutedOrdinal !== void 0) cursor.lastOrdinal = Math.max(floor, Math.min(cursor.lastOrdinal, lowestRoutedOrdinal - 1));
|
|
3262
|
+
const tracked = {
|
|
3263
|
+
processorId,
|
|
3264
|
+
factoryId: slot.factoryId,
|
|
3265
|
+
driveId: slot.driveId,
|
|
3266
|
+
processorIndex,
|
|
3267
|
+
record,
|
|
3268
|
+
...cursor,
|
|
3269
|
+
retry: () => queue.retry()
|
|
3270
|
+
};
|
|
3271
|
+
const queue = new ProcessorQueue({
|
|
3272
|
+
processorId,
|
|
3273
|
+
processor: record.processor,
|
|
3274
|
+
filter: record.filter,
|
|
3275
|
+
cursor: tracked,
|
|
3276
|
+
floor,
|
|
3277
|
+
readSince: (ordinal) => this.operationIndex.getSinceOrdinal(ordinal),
|
|
3278
|
+
routedThrough: () => this.highWater(),
|
|
3279
|
+
persist: (state) => this.writeCursor(tracked, state),
|
|
3280
|
+
logger: this.logger
|
|
3281
|
+
});
|
|
3282
|
+
return {
|
|
3283
|
+
tracked,
|
|
3284
|
+
queue
|
|
3285
|
+
};
|
|
3286
|
+
}
|
|
3287
|
+
async discard(slot, disconnect) {
|
|
2927
3288
|
try {
|
|
2928
|
-
await
|
|
3289
|
+
await disconnect();
|
|
2929
3290
|
} catch (error) {
|
|
2930
|
-
this.logger.error("Error disconnecting processor: @Error", error);
|
|
3291
|
+
this.logger.error("Error disconnecting discarded processor for '@FactoryId' on '@DriveId': @Error", slot.factoryId, slot.driveId, error);
|
|
2931
3292
|
}
|
|
2932
3293
|
}
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
return;
|
|
2949
|
-
}
|
|
2950
|
-
tracked.lastOrdinal = maxOrdinal;
|
|
2951
|
-
await this.safeSaveProcessorCursor(tracked);
|
|
2952
|
-
}));
|
|
3294
|
+
highWater() {
|
|
3295
|
+
return Math.max(this.lastOrdinal, this.highestRoutedOrdinal);
|
|
3296
|
+
}
|
|
3297
|
+
*allBound() {
|
|
3298
|
+
for (const drive of this.processorsByDrive.values()) yield* drive;
|
|
3299
|
+
}
|
|
3300
|
+
*allTrackedProcessors() {
|
|
3301
|
+
for (const { tracked } of this.allBound()) yield tracked;
|
|
3302
|
+
}
|
|
3303
|
+
isDriveCreation(op) {
|
|
3304
|
+
return op.operation.action.type === "CREATE_DOCUMENT" && this.driveContainerTypes.has(op.context.documentType);
|
|
3305
|
+
}
|
|
3306
|
+
async discoverExistingDrives() {
|
|
3307
|
+
const drives = await this.db.selectFrom("DocumentSnapshot").select(["documentId", "documentType"]).where("documentType", "in", [...this.driveContainerTypes]).where("isDeleted", "=", false).execute();
|
|
3308
|
+
for (const drive of drives) this.knownDrives.set(drive.documentId, drive.documentType);
|
|
2953
3309
|
}
|
|
2954
3310
|
async loadAllCursors() {
|
|
2955
3311
|
const rows = await this.db.selectFrom("ProcessorCursor").selectAll().execute();
|
|
2956
3312
|
for (const row of rows) this.cursorCache.set(row.processorId, row);
|
|
2957
3313
|
}
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
}
|
|
2962
|
-
|
|
2963
|
-
|
|
3314
|
+
lane(processorId, write) {
|
|
3315
|
+
const next = (this.cursorWrites.get(processorId) ?? Promise.resolve()).then(write).then(() => void 0, (error) => {
|
|
3316
|
+
this.logger.error("Failed to write cursor for '@ProcessorId': @Error", processorId, error);
|
|
3317
|
+
});
|
|
3318
|
+
this.cursorWrites.set(processorId, next);
|
|
3319
|
+
next.then(() => {
|
|
3320
|
+
if (this.cursorWrites.get(processorId) === next) this.cursorWrites.delete(processorId);
|
|
3321
|
+
});
|
|
3322
|
+
return next;
|
|
2964
3323
|
}
|
|
2965
|
-
|
|
2966
|
-
|
|
3324
|
+
writeCursor(tracked, state) {
|
|
3325
|
+
const now = /* @__PURE__ */ new Date();
|
|
3326
|
+
const row = {
|
|
2967
3327
|
processorId: tracked.processorId,
|
|
2968
3328
|
factoryId: tracked.factoryId,
|
|
2969
3329
|
driveId: tracked.driveId,
|
|
2970
3330
|
processorIndex: tracked.processorIndex,
|
|
2971
|
-
lastOrdinal:
|
|
2972
|
-
status:
|
|
2973
|
-
lastError:
|
|
2974
|
-
lastErrorTimestamp:
|
|
2975
|
-
|
|
3331
|
+
lastOrdinal: state.lastOrdinal,
|
|
3332
|
+
status: state.status,
|
|
3333
|
+
lastError: state.lastError ?? null,
|
|
3334
|
+
lastErrorTimestamp: state.lastErrorTimestamp ?? null,
|
|
3335
|
+
createdAt: now,
|
|
3336
|
+
updatedAt: now
|
|
3337
|
+
};
|
|
3338
|
+
this.cursorCache.set(row.processorId, row);
|
|
3339
|
+
return this.lane(row.processorId, () => this.db.insertInto("ProcessorCursor").values({
|
|
3340
|
+
processorId: row.processorId,
|
|
3341
|
+
factoryId: row.factoryId,
|
|
3342
|
+
driveId: row.driveId,
|
|
3343
|
+
processorIndex: row.processorIndex,
|
|
3344
|
+
lastOrdinal: row.lastOrdinal,
|
|
3345
|
+
status: row.status,
|
|
3346
|
+
lastError: row.lastError,
|
|
3347
|
+
lastErrorTimestamp: row.lastErrorTimestamp,
|
|
3348
|
+
updatedAt: now
|
|
2976
3349
|
}).onConflict((oc) => oc.column("processorId").doUpdateSet({
|
|
2977
|
-
lastOrdinal:
|
|
2978
|
-
status:
|
|
2979
|
-
lastError:
|
|
2980
|
-
lastErrorTimestamp:
|
|
2981
|
-
updatedAt:
|
|
2982
|
-
})).execute();
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
2993
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
2994
|
-
});
|
|
2995
|
-
}
|
|
2996
|
-
async deleteProcessorCursors(filter) {
|
|
2997
|
-
if ("factoryId" in filter) {
|
|
2998
|
-
await this.db.deleteFrom("ProcessorCursor").where("factoryId", "=", filter.factoryId).execute();
|
|
2999
|
-
for (const [id, row] of this.cursorCache) if (row.factoryId === filter.factoryId) this.cursorCache.delete(id);
|
|
3000
|
-
} else {
|
|
3001
|
-
await this.db.deleteFrom("ProcessorCursor").where("driveId", "=", filter.driveId).execute();
|
|
3002
|
-
for (const [id, row] of this.cursorCache) if (row.driveId === filter.driveId) this.cursorCache.delete(id);
|
|
3003
|
-
}
|
|
3350
|
+
lastOrdinal: row.lastOrdinal,
|
|
3351
|
+
status: row.status,
|
|
3352
|
+
lastError: row.lastError,
|
|
3353
|
+
lastErrorTimestamp: row.lastErrorTimestamp,
|
|
3354
|
+
updatedAt: now
|
|
3355
|
+
})).execute());
|
|
3356
|
+
}
|
|
3357
|
+
deleteCursors(matches) {
|
|
3358
|
+
const deletes = [];
|
|
3359
|
+
for (const [processorId, row] of this.cursorCache) {
|
|
3360
|
+
if (!matches(row)) continue;
|
|
3361
|
+
this.cursorCache.delete(processorId);
|
|
3362
|
+
deletes.push(this.lane(processorId, () => this.db.deleteFrom("ProcessorCursor").where("processorId", "=", processorId).execute()));
|
|
3363
|
+
}
|
|
3364
|
+
return deletes;
|
|
3004
3365
|
}
|
|
3005
3366
|
};
|
|
3006
3367
|
//#endregion
|
|
@@ -7497,7 +7858,7 @@ var Reactor = class {
|
|
|
7497
7858
|
this.logger.verbose("create(@id, @type, @slug)", document.header.id, document.header.documentType, document.header.slug);
|
|
7498
7859
|
const createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
7499
7860
|
throwIfAborted(signal, () => new AbortError());
|
|
7500
|
-
|
|
7861
|
+
const createAction = createDocumentAction({
|
|
7501
7862
|
model: document.header.documentType,
|
|
7502
7863
|
version: 0,
|
|
7503
7864
|
documentId: document.header.id,
|
|
@@ -7513,14 +7874,20 @@ var Reactor = class {
|
|
|
7513
7874
|
branch: document.header.branch,
|
|
7514
7875
|
meta: document.header.meta,
|
|
7515
7876
|
protocolVersions: document.header.protocolVersions ?? { "base-reducer": 2 }
|
|
7516
|
-
})
|
|
7877
|
+
});
|
|
7878
|
+
const upgradeAction = upgradeDocumentAction({
|
|
7517
7879
|
documentId: document.header.id,
|
|
7518
7880
|
model: document.header.documentType,
|
|
7519
7881
|
fromVersion: 0,
|
|
7520
7882
|
toVersion: normalizeDocumentModelVersion(document.state.document?.version),
|
|
7521
7883
|
initialState: document.state
|
|
7522
|
-
})
|
|
7523
|
-
|
|
7884
|
+
});
|
|
7885
|
+
const branch = document.header.branch || "main";
|
|
7886
|
+
let actions = [createAction, upgradeAction];
|
|
7887
|
+
if (signer) actions = await signActions(actions, signer, {
|
|
7888
|
+
documentId: document.header.id,
|
|
7889
|
+
branch
|
|
7890
|
+
}, signal);
|
|
7524
7891
|
const jobId = v4();
|
|
7525
7892
|
const jobMeta = buildSingleJobMeta(jobId, meta);
|
|
7526
7893
|
const job = {
|
|
@@ -7528,7 +7895,7 @@ var Reactor = class {
|
|
|
7528
7895
|
kind: "mutation",
|
|
7529
7896
|
documentId: document.header.id,
|
|
7530
7897
|
scope: "document",
|
|
7531
|
-
branch
|
|
7898
|
+
branch,
|
|
7532
7899
|
actions,
|
|
7533
7900
|
operations: [],
|
|
7534
7901
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -7559,7 +7926,10 @@ var Reactor = class {
|
|
|
7559
7926
|
const createdAtUtcIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
7560
7927
|
throwIfAborted(signal, () => new AbortError());
|
|
7561
7928
|
let action = deleteDocumentAction(id);
|
|
7562
|
-
if (signer) action = await signAction(action, signer,
|
|
7929
|
+
if (signer) action = await signAction(action, signer, {
|
|
7930
|
+
documentId: id,
|
|
7931
|
+
branch: "main"
|
|
7932
|
+
}, signal);
|
|
7563
7933
|
const jobId = v4();
|
|
7564
7934
|
const jobMeta = buildSingleJobMeta(jobId, meta);
|
|
7565
7935
|
const job = {
|
|
@@ -7816,21 +8186,30 @@ var Reactor = class {
|
|
|
7816
8186
|
this.logger.verbose("addRelationship(@sourceId, @targetId, @relationshipType, @metadata, @branch)", sourceId, targetId, relationshipType, metadata, branch);
|
|
7817
8187
|
throwIfAborted(signal, () => new AbortError());
|
|
7818
8188
|
let actions = [addRelationshipAction(sourceId, targetId, relationshipType, metadata)];
|
|
7819
|
-
if (signer) actions = await signActions(actions, signer,
|
|
8189
|
+
if (signer) actions = await signActions(actions, signer, {
|
|
8190
|
+
documentId: sourceId,
|
|
8191
|
+
branch
|
|
8192
|
+
}, signal);
|
|
7820
8193
|
return await this.execute(sourceId, branch, actions, signal);
|
|
7821
8194
|
}
|
|
7822
8195
|
async updateRelationship(sourceId, targetId, relationshipType, metadata, branch = "main", signer, signal) {
|
|
7823
8196
|
this.logger.verbose("updateRelationship(@sourceId, @targetId, @relationshipType, @metadata, @branch)", sourceId, targetId, relationshipType, metadata, branch);
|
|
7824
8197
|
throwIfAborted(signal, () => new AbortError());
|
|
7825
8198
|
let actions = [updateRelationshipAction(sourceId, targetId, relationshipType, metadata)];
|
|
7826
|
-
if (signer) actions = await signActions(actions, signer,
|
|
8199
|
+
if (signer) actions = await signActions(actions, signer, {
|
|
8200
|
+
documentId: sourceId,
|
|
8201
|
+
branch
|
|
8202
|
+
}, signal);
|
|
7827
8203
|
return await this.execute(sourceId, branch, actions, signal);
|
|
7828
8204
|
}
|
|
7829
8205
|
async removeRelationship(sourceId, targetId, relationshipType, branch = "main", signer, signal) {
|
|
7830
8206
|
this.logger.verbose("removeRelationship(@sourceId, @targetId, @relationshipType, @branch)", sourceId, targetId, relationshipType, branch);
|
|
7831
8207
|
throwIfAborted(signal, () => new AbortError());
|
|
7832
8208
|
let actions = [removeRelationshipAction(sourceId, targetId, relationshipType)];
|
|
7833
|
-
if (signer) actions = await signActions(actions, signer,
|
|
8209
|
+
if (signer) actions = await signActions(actions, signer, {
|
|
8210
|
+
documentId: sourceId,
|
|
8211
|
+
branch
|
|
8212
|
+
}, signal);
|
|
7834
8213
|
return await this.execute(sourceId, branch, actions, signal);
|
|
7835
8214
|
}
|
|
7836
8215
|
getJobStatus(jobId, signal) {
|
|
@@ -7934,8 +8313,11 @@ var ReactorBuilder = class {
|
|
|
7934
8313
|
eventBus;
|
|
7935
8314
|
readModelCoordinator;
|
|
7936
8315
|
readModelCoordinatorFactory;
|
|
7937
|
-
signatureVerifier;
|
|
7938
8316
|
kyselyInstance;
|
|
8317
|
+
signer;
|
|
8318
|
+
workerSigner;
|
|
8319
|
+
trustPolicy;
|
|
8320
|
+
workerTrustPolicy;
|
|
7939
8321
|
signalHandlersEnabled = false;
|
|
7940
8322
|
queueInstance;
|
|
7941
8323
|
channelScheme;
|
|
@@ -8034,10 +8416,34 @@ var ReactorBuilder = class {
|
|
|
8034
8416
|
this.eventBus = eventBus;
|
|
8035
8417
|
return this;
|
|
8036
8418
|
}
|
|
8037
|
-
|
|
8038
|
-
|
|
8419
|
+
/**
|
|
8420
|
+
* Signs the operations the executor synthesizes: the NOOP an UNDO becomes and
|
|
8421
|
+
* the action a REDO rebuilds. Without one they are stored unsigned. Pooled
|
|
8422
|
+
* workers import `workerSigner` to build the same signer.
|
|
8423
|
+
*/
|
|
8424
|
+
withSigner(signer, workerSigner) {
|
|
8425
|
+
this.signer = signer;
|
|
8426
|
+
this.workerSigner = workerSigner;
|
|
8427
|
+
return this;
|
|
8428
|
+
}
|
|
8429
|
+
/** Whether {@link withSigner} was called. */
|
|
8430
|
+
hasSigner() {
|
|
8431
|
+
return this.signer !== void 0;
|
|
8432
|
+
}
|
|
8433
|
+
/**
|
|
8434
|
+
* Decides at admission whether a key may sign as the user it claims; see
|
|
8435
|
+
* {@link SignatureTrustPolicy} for the contract and the default. Pooled
|
|
8436
|
+
* workers import `workerTrustPolicy` to build the same policy.
|
|
8437
|
+
*/
|
|
8438
|
+
withTrustPolicy(trustPolicy, workerTrustPolicy) {
|
|
8439
|
+
this.trustPolicy = trustPolicy;
|
|
8440
|
+
this.workerTrustPolicy = workerTrustPolicy;
|
|
8039
8441
|
return this;
|
|
8040
8442
|
}
|
|
8443
|
+
/** Whether {@link withTrustPolicy} was called. */
|
|
8444
|
+
hasTrustPolicy() {
|
|
8445
|
+
return this.trustPolicy !== void 0;
|
|
8446
|
+
}
|
|
8041
8447
|
withKysely(kysely) {
|
|
8042
8448
|
this.kyselyInstance = kysely;
|
|
8043
8449
|
return this;
|
|
@@ -8091,8 +8497,7 @@ var ReactorBuilder = class {
|
|
|
8091
8497
|
* this enables the pool — there is no `enabled` flag. Provide `db`
|
|
8092
8498
|
* (each worker opens its own Postgres pool; the parent database is built
|
|
8093
8499
|
* from it too unless {@link withKysely} is set) or a custom `factory`
|
|
8094
|
-
* transport.
|
|
8095
|
-
* omitted = no executor-side signature verification.
|
|
8500
|
+
* transport.
|
|
8096
8501
|
*/
|
|
8097
8502
|
withWorkerPool(options) {
|
|
8098
8503
|
this.workerPool = options;
|
|
@@ -8185,13 +8590,15 @@ var ReactorBuilder = class {
|
|
|
8185
8590
|
let factory = pool.factory;
|
|
8186
8591
|
if (!factory) {
|
|
8187
8592
|
if (pool.db === void 0) throw new Error("unreachable: worker pool configured without db or factory");
|
|
8188
|
-
|
|
8593
|
+
if (this.signer && !this.workerSigner) this.logger.warn("Worker pool has no signer spec; pooled workers store synthesized operations unsigned");
|
|
8594
|
+
if (this.trustPolicy && !this.workerTrustPolicy) this.logger.warn("Worker pool has no trust policy spec; pooled workers apply the default trust policy");
|
|
8595
|
+
factory = await this.createDefaultWorkerFactory(pool.numWorkers, pool.db);
|
|
8189
8596
|
}
|
|
8190
8597
|
const poolManager = new WorkerPoolJobExecutorManager(factory, eventBus, queue, jobTracker, this.logger, resolver, operationIndex, this.executorConfig.jobTimeoutMs, this.executorConfig.deferredJobTtlMs);
|
|
8191
8598
|
executorManager = poolManager;
|
|
8192
8599
|
executorStartCount = pool.numWorkers;
|
|
8193
8600
|
if (resolver instanceof DocumentModelResolver) resolver.setBroadcastHook((entry) => poolManager.loadModel(entry));
|
|
8194
|
-
} else executorManager = new SimpleJobExecutorManager(() => new SimpleJobExecutor(this.logger, documentModelRegistry, operationStore, eventBus, writeCache, operationIndex, documentMetaCache, collectionMembershipCache, this.driveContainerTypes, this.executorConfig, this.
|
|
8601
|
+
} else executorManager = new SimpleJobExecutorManager(() => new SimpleJobExecutor(this.logger, documentModelRegistry, operationStore, eventBus, writeCache, operationIndex, documentMetaCache, collectionMembershipCache, this.driveContainerTypes, this.executorConfig, executionScope, this.signer, this.trustPolicy), eventBus, queue, jobTracker, this.logger, resolver, this.executorConfig.jobTimeoutMs, this.executorConfig.deferredJobTtlMs);
|
|
8195
8602
|
await executorManager.start(executorStartCount);
|
|
8196
8603
|
const callerReadModels = Array.from(new Set([...this.readModels]));
|
|
8197
8604
|
const degradedComponents = [];
|
|
@@ -8364,7 +8771,7 @@ var ReactorBuilder = class {
|
|
|
8364
8771
|
poolInstrumentations.push(forwarder);
|
|
8365
8772
|
this.instrumentedPools.push(forwarder);
|
|
8366
8773
|
}
|
|
8367
|
-
const { ProjectionShardManager } = await import("./projection-shard-manager-
|
|
8774
|
+
const { ProjectionShardManager } = await import("./projection-shard-manager-mQhfVipO.js");
|
|
8368
8775
|
const manager = new ProjectionShardManager({
|
|
8369
8776
|
shardCount: config.shardCount,
|
|
8370
8777
|
db,
|
|
@@ -8406,11 +8813,11 @@ var ReactorBuilder = class {
|
|
|
8406
8813
|
* custom `factory`. Each worker spawns a real `node:worker_threads`
|
|
8407
8814
|
* Worker pointing at the compiled `worker/entry.js`.
|
|
8408
8815
|
*/
|
|
8409
|
-
async createDefaultWorkerFactory(numWorkers, db
|
|
8816
|
+
async createDefaultWorkerFactory(numWorkers, db) {
|
|
8410
8817
|
const [{ WorkerHandle }, { createThreadTransport }, { workerEntryPath }] = await Promise.all([
|
|
8411
|
-
import("./worker-handle-
|
|
8818
|
+
import("./worker-handle-B3p-nuqG.js"),
|
|
8412
8819
|
import("./transport-ByGviWdZ.js"),
|
|
8413
|
-
import("./worker-
|
|
8820
|
+
import("./worker-BDVzCtuf.js").then((n) => n.n)
|
|
8414
8821
|
]);
|
|
8415
8822
|
const poolConfig = {
|
|
8416
8823
|
enabled: true,
|
|
@@ -8430,9 +8837,10 @@ var ReactorBuilder = class {
|
|
|
8430
8837
|
initPayload: {
|
|
8431
8838
|
poolConfig,
|
|
8432
8839
|
db,
|
|
8433
|
-
signatureVerifier,
|
|
8434
8840
|
models,
|
|
8435
|
-
executorConfig: this.executorConfig
|
|
8841
|
+
executorConfig: this.executorConfig,
|
|
8842
|
+
signer: this.workerSigner,
|
|
8843
|
+
trustPolicy: this.workerTrustPolicy
|
|
8436
8844
|
},
|
|
8437
8845
|
logger,
|
|
8438
8846
|
poolInstrumentation
|
|
@@ -8506,7 +8914,7 @@ var ReactorBuilder = class {
|
|
|
8506
8914
|
}
|
|
8507
8915
|
this.logger.info("Shutdown complete");
|
|
8508
8916
|
nodeProcess.exit = realExit;
|
|
8509
|
-
realExit(pendingExitCode ?? 0);
|
|
8917
|
+
realExit(pendingExitCode || Number(nodeProcess.exitCode ?? 0));
|
|
8510
8918
|
};
|
|
8511
8919
|
nodeProcess.prependListener("SIGINT", () => void handler("SIGINT"));
|
|
8512
8920
|
nodeProcess.prependListener("SIGTERM", () => void handler("SIGTERM"));
|
|
@@ -8675,30 +9083,6 @@ function createHybridProjectionCoordinatorFactory(options = {}) {
|
|
|
8675
9083
|
};
|
|
8676
9084
|
}
|
|
8677
9085
|
//#endregion
|
|
8678
|
-
//#region src/signer/passthrough-signer.ts
|
|
8679
|
-
/**
|
|
8680
|
-
* A no-op signer that returns empty values for all methods.
|
|
8681
|
-
* Used when signing is not required.
|
|
8682
|
-
*/
|
|
8683
|
-
var PassthroughSigner = class {
|
|
8684
|
-
publicKey = {};
|
|
8685
|
-
sign() {
|
|
8686
|
-
return Promise.resolve(new Uint8Array(0));
|
|
8687
|
-
}
|
|
8688
|
-
verify() {
|
|
8689
|
-
return Promise.resolve();
|
|
8690
|
-
}
|
|
8691
|
-
signAction() {
|
|
8692
|
-
return Promise.resolve([
|
|
8693
|
-
"",
|
|
8694
|
-
"",
|
|
8695
|
-
"",
|
|
8696
|
-
"",
|
|
8697
|
-
""
|
|
8698
|
-
]);
|
|
8699
|
-
}
|
|
8700
|
-
};
|
|
8701
|
-
//#endregion
|
|
8702
9086
|
//#region src/core/reactor-client-builder.ts
|
|
8703
9087
|
/**
|
|
8704
9088
|
* Builder class for constructing ReactorClient instances with proper configuration
|
|
@@ -8711,7 +9095,10 @@ var ReactorClientBuilder = class {
|
|
|
8711
9095
|
documentIndexer;
|
|
8712
9096
|
documentView;
|
|
8713
9097
|
signer;
|
|
8714
|
-
|
|
9098
|
+
workerSigner;
|
|
9099
|
+
trustPolicy;
|
|
9100
|
+
workerTrustPolicy;
|
|
9101
|
+
createSignaturePolicy = DEFAULT_SIGNATURE_POLICY;
|
|
8715
9102
|
subscriptionManager;
|
|
8716
9103
|
jobAwaiter;
|
|
8717
9104
|
documentModelLoader;
|
|
@@ -8745,17 +9132,28 @@ var ReactorClientBuilder = class {
|
|
|
8745
9132
|
return this;
|
|
8746
9133
|
}
|
|
8747
9134
|
/**
|
|
8748
|
-
*
|
|
8749
|
-
*
|
|
8750
|
-
*
|
|
9135
|
+
* Signs submitted actions, and the operations a reactor built from
|
|
9136
|
+
* `withReactorBuilder` synthesizes unless that builder has its own signer.
|
|
9137
|
+
* A `trustPolicy` reaches that builder unless it has its own.
|
|
8751
9138
|
*/
|
|
8752
9139
|
withSigner(config) {
|
|
8753
9140
|
if ("signer" in config) {
|
|
8754
9141
|
this.signer = config.signer;
|
|
8755
|
-
this.
|
|
9142
|
+
this.workerSigner = config.workerSigner;
|
|
9143
|
+
this.trustPolicy = config.trustPolicy;
|
|
9144
|
+
this.workerTrustPolicy = config.workerTrustPolicy;
|
|
8756
9145
|
} else this.signer = config;
|
|
8757
9146
|
return this;
|
|
8758
9147
|
}
|
|
9148
|
+
/**
|
|
9149
|
+
* What the client creates new documents as when a call does not say:
|
|
9150
|
+
* `v2-required` (the default) or `legacy`, for a fleet with peers that
|
|
9151
|
+
* predate v2-required documents. Existing documents keep their policy.
|
|
9152
|
+
*/
|
|
9153
|
+
withCreateSignaturePolicy(policy) {
|
|
9154
|
+
this.createSignaturePolicy = policy;
|
|
9155
|
+
return this;
|
|
9156
|
+
}
|
|
8759
9157
|
withSubscriptionManager(subscriptionManager) {
|
|
8760
9158
|
this.subscriptionManager = subscriptionManager;
|
|
8761
9159
|
return this;
|
|
@@ -8820,8 +9218,9 @@ var ReactorClientBuilder = class {
|
|
|
8820
9218
|
let documentView;
|
|
8821
9219
|
let reactorModule;
|
|
8822
9220
|
if (this.reactorBuilder) {
|
|
8823
|
-
if (this.signatureVerifier) this.reactorBuilder.withSignatureVerifier(this.signatureVerifier);
|
|
8824
9221
|
if (this.documentModelLoader) this.reactorBuilder.withDocumentModelLoader(this.documentModelLoader);
|
|
9222
|
+
if (this.signer && !this.reactorBuilder.hasSigner()) this.reactorBuilder.withSigner(this.signer, this.workerSigner);
|
|
9223
|
+
if (this.trustPolicy && !this.reactorBuilder.hasTrustPolicy()) this.reactorBuilder.withTrustPolicy(this.trustPolicy, this.workerTrustPolicy);
|
|
8825
9224
|
reactorModule = await this.reactorBuilder.buildModule();
|
|
8826
9225
|
reactor = reactorModule.reactor;
|
|
8827
9226
|
eventBus = reactorModule.eventBus;
|
|
@@ -8839,7 +9238,7 @@ var ReactorClientBuilder = class {
|
|
|
8839
9238
|
const jobAwaiter = this.jobAwaiter ?? new JobAwaiter(eventBus, (jobId, signal) => reactor.getJobStatus(jobId, signal));
|
|
8840
9239
|
const decisionModel = reactorModule ? readDecisionModel(reactorModule.featureFlags, reactorModule.documentModelRegistry) : void 0;
|
|
8841
9240
|
return {
|
|
8842
|
-
client: new ReactorClient(this.logger, reactor, signer, subscriptionManager, jobAwaiter, documentIndexer, documentView, this.readGate ?? this.resolveReadGate(reactorModule, documentView, decisionModel), this.resolveActionEvaluation(reactorModule, decisionModel)),
|
|
9241
|
+
client: new ReactorClient(this.logger, reactor, signer, subscriptionManager, jobAwaiter, documentIndexer, documentView, this.readGate ?? this.resolveReadGate(reactorModule, documentView, decisionModel), this.resolveActionEvaluation(reactorModule, decisionModel), this.createSignaturePolicy),
|
|
8843
9242
|
reactor,
|
|
8844
9243
|
eventBus,
|
|
8845
9244
|
documentIndexer,
|
|
@@ -8877,6 +9276,21 @@ function driveIdFromUrl(url) {
|
|
|
8877
9276
|
return url.split("/").pop() ?? "";
|
|
8878
9277
|
}
|
|
8879
9278
|
//#endregion
|
|
9279
|
+
//#region src/signer/types.ts
|
|
9280
|
+
const SIGNATURE_REFUSAL_CODES = [
|
|
9281
|
+
"UNSIGNED_REQUIRED",
|
|
9282
|
+
"UNSIGNED_IDENTITY",
|
|
9283
|
+
"KEY_MISMATCH",
|
|
9284
|
+
"MALFORMED_TUPLE",
|
|
9285
|
+
"TIMESTAMP_MISMATCH",
|
|
9286
|
+
"HASH_MISMATCH",
|
|
9287
|
+
"BAD_SIGNATURE",
|
|
9288
|
+
"SCHEME_BELOW_POLICY",
|
|
9289
|
+
"ID_MISMATCH",
|
|
9290
|
+
"DUPLICATE_ACTION",
|
|
9291
|
+
"SIGNER_UNAUTHORIZED"
|
|
9292
|
+
];
|
|
9293
|
+
//#endregion
|
|
8880
9294
|
//#region src/decision/sync-scope-gate.ts
|
|
8881
9295
|
/** What a subject may read of a document that is not there to be read. */
|
|
8882
9296
|
const META_ONLY = (scope) => ALWAYS_READABLE_SCOPES.has(scope);
|
|
@@ -9104,6 +9518,6 @@ var DocumentIntegrityService = class {
|
|
|
9104
9518
|
}
|
|
9105
9519
|
};
|
|
9106
9520
|
//#endregion
|
|
9107
|
-
export { ALWAYS_READABLE_SCOPES, APPEND_CONDITION_FAILED_PREFIX, AppendConditionFailedError, AuthEnforcementDisabledError, BareReadGate, BaseReadModel, ChannelError, ChannelErrorSource, ChannelScheme, ConsistencyTracker, DEFAULT_COMMIT_CHUNK_SIZE, DEFAULT_DRIVE_CONTAINER_TYPES, DEFAULT_READ_MODEL_YIELD_DEADLINE_MS, DOCUMENT_INDEXER_READ_MODEL, DOCUMENT_VIEW_READ_MODEL, DRIVE_AUTH_ERROR_MESSAGES, DefaultSubscriptionErrorHandler, DeletedDocumentRead, DocumentAlreadyExistsError, DocumentChangeType, DocumentExistence, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, DriveClient, DriveCollectionId, DriveRequestError, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, EventBus, EventBusAggregateError, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, HybridProjectionCoordinator, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, IntervalPollTimer, InvalidModuleError, JobAwaiter, JobExecutorEventTypes, JobStatus, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, Mailbox, ModelReadGate, ModuleNotFoundError, NullDocumentModelResolver, OptimisticLockError, PollBehavior, PollingChannelError, ProcessorManager, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, RECOVERABLE_GRAPHQL_ERROR_CODES, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, ReactorEventTypes, ReactorSubscriptionManager, ReadModelCoordinator, RelationalDbProcessor, RelationshipChangeType, RelationshipNotFoundError, RetryAccounting, RevisionMismatchError, SeededStateReader, SimpleJobExecutorManager, SyncBuilder, SyncEventTypes, SyncOperation, SyncOperationAggregateError, SyncOperationStatus, SyncScopeGate, SyncStatus, SyncStatusTracker, addRelationshipAction, authDecisionModel, batchOperationsByDocument, buildDecisionModel, classifyJobFailure, consolidateSyncOperations, createDocumentAction, createForwardingLogger, createHybridProjectionCoordinatorFactory, createMutableShutdownStatus, createReactorHostModuleBase, createRelationalDb, decideAtHead, defaultReadModelIndexingConfig, deleteDocumentAction, documentActions, documentDecisionModel, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, firstOutOfOrderPair, getMigrationStatus, instrumentPgPool, isDriveAuthError, isRecoverableGraphQLError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, quarantinesDocument, readDecisionModel, removeRelationshipAction, runMigrations, sanitizeArg, selectDecisionModel, supportsLiveReadModelRegistration, syncOperationErrorType, trimMailboxFromAckOrdinal, unchunkedReadModelIndexingConfig, updateRelationshipAction, upgradeDocumentAction, workerEntryPath };
|
|
9521
|
+
export { ALWAYS_READABLE_SCOPES, APPEND_CONDITION_FAILED_PREFIX, AppendConditionFailedError, AuthEnforcementDisabledError, BareReadGate, BaseReadModel, ChannelError, ChannelErrorSource, ChannelScheme, ConsistencyTracker, DEFAULT_COMMIT_CHUNK_SIZE, DEFAULT_DRIVE_CONTAINER_TYPES, DEFAULT_READ_MODEL_YIELD_DEADLINE_MS, DOCUMENT_INDEXER_READ_MODEL, DOCUMENT_VIEW_READ_MODEL, DRIVE_AUTH_ERROR_MESSAGES, DefaultSubscriptionErrorHandler, DeletedDocumentRead, DocumentAlreadyExistsError, DocumentChangeType, DocumentExistence, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, DriveClient, DriveCollectionId, DriveRequestError, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, EventBus, EventBusAggregateError, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, HybridProjectionCoordinator, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, IntervalPollTimer, InvalidModuleError, InvalidSignatureError, JobAwaiter, JobExecutorEventTypes, JobStatus, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, Mailbox, ModelReadGate, ModuleNotFoundError, NullDocumentModelResolver, OptimisticLockError, PollBehavior, PollingChannelError, ProcessorManager, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, RECOVERABLE_GRAPHQL_ERROR_CODES, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, ReactorEventTypes, ReactorSubscriptionManager, ReadModelCoordinator, RelationalDbProcessor, RelationshipChangeType, RelationshipNotFoundError, RetryAccounting, RevisionMismatchError, SIGNATURE_REFUSAL_CODES, SeededStateReader, SimpleJobExecutorManager, SyncBuilder, SyncEventTypes, SyncOperation, SyncOperationAggregateError, SyncOperationStatus, SyncScopeGate, SyncStatus, SyncStatusTracker, addRelationshipAction, authDecisionModel, batchOperationsByDocument, buildDecisionModel, classifyJobFailure, consolidateSyncOperations, createDocumentAction, createForwardingLogger, createHybridProjectionCoordinatorFactory, createMutableShutdownStatus, createReactorHostModuleBase, createRelationalDb, decideAtHead, defaultReadModelIndexingConfig, deleteDocumentAction, documentActions, documentDecisionModel, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, firstOutOfOrderPair, getMigrationStatus, instrumentPgPool, isDriveAuthError, isRecoverableGraphQLError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, quarantinesDocument, readDecisionModel, removeRelationshipAction, runMigrations, sanitizeArg, selectDecisionModel, supportsLiveReadModelRegistration, syncOperationErrorType, trimMailboxFromAckOrdinal, unchunkedReadModelIndexingConfig, updateRelationshipAction, upgradeDocumentAction, verifyActionSignature, workerEntryPath };
|
|
9108
9522
|
|
|
9109
9523
|
//# sourceMappingURL=index.js.map
|