@powerhousedao/reactor 6.2.3-dev.24 → 6.2.3-dev.25
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-DxmDJ4QQ.js → build-worker-executor-DPGjh9Uc.js} +4 -4
- package/dist/{build-worker-executor-DxmDJ4QQ.js.map → build-worker-executor-DPGjh9Uc.js.map} +1 -1
- package/dist/{document-indexer-Dn9RB0sg.js → document-indexer-zbdzqZ3K.js} +18 -9
- package/dist/{document-indexer-Dn9RB0sg.js.map → document-indexer-zbdzqZ3K.js.map} +1 -1
- package/dist/entry.d.ts +2 -1
- package/dist/entry.js +2 -3
- package/dist/entry.js.map +1 -1
- package/dist/{errors-D3S6Eysd.js → errors-BM_ULVWd.js} +9 -1
- package/dist/{errors-D3S6Eysd.js.map → errors-BM_ULVWd.js.map} +1 -1
- package/dist/{drive-container-types-Be5-EY9W.js → forwarding-logger-CSsCJ38f.js} +247 -39
- package/dist/forwarding-logger-CSsCJ38f.js.map +1 -0
- package/dist/index.d.ts +359 -235
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +247 -171
- package/dist/index.js.map +1 -1
- package/dist/projection-entry.d.ts +2 -1
- package/dist/projection-entry.js +7 -13
- package/dist/projection-entry.js.map +1 -1
- package/dist/{projection-shard-manager-mQhfVipO.js → projection-shard-manager-B-j8VYzA.js} +2 -3
- package/dist/{projection-shard-manager-mQhfVipO.js.map → projection-shard-manager-B-j8VYzA.js.map} +1 -1
- package/dist/{projection-worker-wI4PwcV2.js → projection-worker-D8uNFdwX.js} +1 -1
- package/dist/{projection-worker-wI4PwcV2.js.map → projection-worker-D8uNFdwX.js.map} +1 -1
- package/dist/{transport-CuogVKN_.js → transport-B3G50KVd.js} +1 -1
- package/dist/{transport-CuogVKN_.js.map → transport-B3G50KVd.js.map} +1 -1
- package/dist/{transport-ByGviWdZ.js → transport-CZDHzfvy.js} +1 -1
- package/dist/{transport-ByGviWdZ.js.map → transport-CZDHzfvy.js.map} +1 -1
- package/dist/{worker-handle-B3p-nuqG.js → worker-handle-CwWNTpUg.js} +9 -8
- package/dist/{worker-handle-B3p-nuqG.js.map → worker-handle-CwWNTpUg.js.map} +1 -1
- package/package.json +5 -5
- package/dist/drive-container-types-Be5-EY9W.js.map +0 -1
- package/dist/error-info-Cpu4OY3o.js +0 -62
- package/dist/error-info-Cpu4OY3o.js.map +0 -1
- package/dist/forwarding-logger-BBkMSxuJ.js +0 -85
- package/dist/forwarding-logger-BBkMSxuJ.js.map +0 -1
- package/dist/types-DxDCmtId.js +0 -34
- package/dist/types-DxDCmtId.js.map +0 -1
- package/dist/worker-BDVzCtuf.js +0 -22
- package/dist/worker-BDVzCtuf.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import {
|
|
3
|
-
import { i as
|
|
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
|
-
import { n as errorToInfo, r as sanitizeArg, t as createForwardingLogger } from "./forwarding-logger-BBkMSxuJ.js";
|
|
6
|
-
import { t as workerEntryPath } from "./worker-BDVzCtuf.js";
|
|
1
|
+
import { $ as DocumentNotFoundError, A as ModuleNotFoundError, B as authDecisionModel, C as DocumentMetaCache, D as DuplicateManifestError, E as JobExecutorEventTypes, F as summarizeSubmittedActions, G as DocumentExistence, H as APPEND_CONDITION_FAILED_PREFIX, I as targetDocumentId, J as RevisionMismatchError, K as DuplicateOperationError, L as decideAtHead, M as createConsistencyToken, N as createEmptyConsistencyToken, O as DuplicateModuleError, P as submittedActionIds, Q as DocumentDeletedError, R as selectDecisionModel, S as KyselyOperationIndex, T as DEFAULT_DEFERRED_JOB_TTL_MS, U as AppendConditionFailedError, V as buildDecisionModel, W as DocumentAlreadyExistsError, X as AuthTimestampNotMonotonicError, Y as AuthEnforcementDisabledError, Z as AuthorizationDeniedError, _ as DriveCollectionId, a as DEFAULT_DRIVE_CONTAINER_TYPES, at as EventBusAggregateError, b as EventBus, c as runMigrations, ct as parsePagingOptions, d as KyselyOperationStore, dt as __exportAll, et as ExcessiveReshuffleError, f as KyselyKeyframeStore, g as PassthroughSigner, h as verifyActionSignature, it as UpgradePreconditionFailedError, j as GATED_DOCUMENT_ACTIONS, k as InvalidModuleError, l as createForwardingPoolInstrumentation, lt as throwIfAborted, m as SimpleJobExecutor, n as errorToInfo, nt as InvalidSignatureError, o as REACTOR_SCHEMA, ot as ReactorEventTypes, p as DocumentModelRegistry, q as OptimisticLockError, r as sanitizeArg, rt as RelationshipNotFoundError, s as getMigrationStatus, st as matchesScope, t as createForwardingLogger, tt as InvalidOperationTimestampError, u as instrumentPgPool, v as KyselyExecutionScope, w as CollectionMembershipCache, x as KyselyWriteCache, y as resolveFeatureFlags, z as documentDecisionModel } from "./forwarding-logger-CSsCJ38f.js";
|
|
2
|
+
import { i as WorkerInitFailedError, r as WorkerExitedError, t as WorkerAbortTimeoutError } from "./errors-BM_ULVWd.js";
|
|
3
|
+
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-zbdzqZ3K.js";
|
|
7
4
|
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
5
|
import { addFile, addFolder, copyNode, deleteNode, driveCreateDocument, generateNodesCopy, getDescendants, handleTargetNameCollisions, isFileNode, isFolderNode, moveNode, updateNode } from "@powerhousedao/shared/document-drive";
|
|
9
6
|
import { v4 } from "uuid";
|
|
@@ -315,6 +312,10 @@ let JobStatus = /* @__PURE__ */ function(JobStatus) {
|
|
|
315
312
|
* during construction, so the partial-`this` hazard does not apply.
|
|
316
313
|
*/
|
|
317
314
|
var DriveClient = class {
|
|
315
|
+
client;
|
|
316
|
+
logger;
|
|
317
|
+
reactor;
|
|
318
|
+
signer;
|
|
318
319
|
constructor(client, logger, reactor, signer) {
|
|
319
320
|
this.client = client;
|
|
320
321
|
this.logger = logger;
|
|
@@ -337,24 +338,25 @@ var DriveClient = class {
|
|
|
337
338
|
async addFile(driveIdentifier, document, parentFolder, signal) {
|
|
338
339
|
this.logger.verbose("drives.addFile(@driveIdentifier, @document, @parentFolder)", driveIdentifier, document.header.id, parentFolder);
|
|
339
340
|
const documentId = document.header.id;
|
|
341
|
+
const createInput = {
|
|
342
|
+
model: document.header.documentType,
|
|
343
|
+
version: 0,
|
|
344
|
+
documentId: document.header.id,
|
|
345
|
+
signing: {
|
|
346
|
+
signature: document.header.id,
|
|
347
|
+
publicKey: document.header.sig.publicKey,
|
|
348
|
+
nonce: document.header.sig.nonce,
|
|
349
|
+
createdAtUtcIso: document.header.createdAtUtcIso,
|
|
350
|
+
documentType: document.header.documentType
|
|
351
|
+
},
|
|
352
|
+
slug: document.header.slug,
|
|
353
|
+
name: document.header.name,
|
|
354
|
+
branch: document.header.branch,
|
|
355
|
+
meta: document.header.meta,
|
|
356
|
+
protocolVersions: document.header.protocolVersions ?? { "base-reducer": 2 }
|
|
357
|
+
};
|
|
340
358
|
const documentActions = await signActions([
|
|
341
|
-
createDocumentAction(
|
|
342
|
-
model: document.header.documentType,
|
|
343
|
-
version: 0,
|
|
344
|
-
documentId: document.header.id,
|
|
345
|
-
signing: {
|
|
346
|
-
signature: document.header.id,
|
|
347
|
-
publicKey: document.header.sig.publicKey,
|
|
348
|
-
nonce: document.header.sig.nonce,
|
|
349
|
-
createdAtUtcIso: document.header.createdAtUtcIso,
|
|
350
|
-
documentType: document.header.documentType
|
|
351
|
-
},
|
|
352
|
-
slug: document.header.slug,
|
|
353
|
-
name: document.header.name,
|
|
354
|
-
branch: document.header.branch,
|
|
355
|
-
meta: document.header.meta,
|
|
356
|
-
protocolVersions: document.header.protocolVersions ?? { "base-reducer": 2 }
|
|
357
|
-
}),
|
|
359
|
+
createDocumentAction(createInput),
|
|
358
360
|
upgradeDocumentAction({
|
|
359
361
|
documentId: document.header.id,
|
|
360
362
|
model: document.header.documentType,
|
|
@@ -514,7 +516,7 @@ var DriveClient = class {
|
|
|
514
516
|
async runJobs(jobs, signal) {
|
|
515
517
|
const batchResult = await this.reactor.executeBatch({ jobs }, signal);
|
|
516
518
|
const completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.client.waitForJob(job, signal)));
|
|
517
|
-
for (const job of completedJobs) if (job.status ===
|
|
519
|
+
for (const job of completedJobs) if (job.status === "FAILED") throw this.toError(job);
|
|
518
520
|
return completedJobs;
|
|
519
521
|
}
|
|
520
522
|
toError(job) {
|
|
@@ -555,10 +557,10 @@ var DriveClient = class {
|
|
|
555
557
|
dependsOn: ["relationship"]
|
|
556
558
|
}] }, signal);
|
|
557
559
|
const completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.client.waitForJob(job, signal)));
|
|
558
|
-
for (const job of completedJobs) if (job.status ===
|
|
560
|
+
for (const job of completedJobs) if (job.status === "FAILED") throw new Error(job.error?.message);
|
|
559
561
|
const deleteJob = await this.reactor.deleteDocument(fileId, this.signer, signal);
|
|
560
562
|
const deleteCompleted = await this.client.waitForJob(deleteJob, signal);
|
|
561
|
-
if (deleteCompleted.status ===
|
|
563
|
+
if (deleteCompleted.status === "FAILED") throw new Error(deleteCompleted.error?.message);
|
|
562
564
|
}
|
|
563
565
|
};
|
|
564
566
|
//#endregion
|
|
@@ -569,13 +571,15 @@ var DriveClient = class {
|
|
|
569
571
|
* Only READ_READY and FAILED are truly terminal.
|
|
570
572
|
*/
|
|
571
573
|
function isTerminalStatus(status) {
|
|
572
|
-
return status ===
|
|
574
|
+
return status === "READ_READY" || status === "FAILED";
|
|
573
575
|
}
|
|
574
576
|
/**
|
|
575
577
|
* Event-driven implementation of IJobAwaiter.
|
|
576
578
|
* Subscribes to operation events to detect job completion without polling.
|
|
577
579
|
*/
|
|
578
580
|
var JobAwaiter = class {
|
|
581
|
+
eventBus;
|
|
582
|
+
getJobStatus;
|
|
579
583
|
pendingJobs = /* @__PURE__ */ new Map();
|
|
580
584
|
unsubscribers = [];
|
|
581
585
|
constructor(eventBus, getJobStatus) {
|
|
@@ -717,7 +721,7 @@ let DocumentChangeType = /* @__PURE__ */ function(DocumentChangeType) {
|
|
|
717
721
|
* would diverge permanently. The document scope carries the metadata the same
|
|
718
722
|
* argument covers. Grants gate domain-scope reads only.
|
|
719
723
|
*/
|
|
720
|
-
const ALWAYS_READABLE_SCOPES = new Set(["auth", "document"]);
|
|
724
|
+
const ALWAYS_READABLE_SCOPES = /* @__PURE__ */ new Set(["auth", "document"]);
|
|
721
725
|
/** What a gate does with an uninitialized policy when told nothing. */
|
|
722
726
|
const OPEN_BY_DEFAULT = { withholdUninitialized: false };
|
|
723
727
|
/**
|
|
@@ -791,6 +795,9 @@ var BareReadGate = class {
|
|
|
791
795
|
* list names is fetched.
|
|
792
796
|
*/
|
|
793
797
|
var SeededStateReader = class {
|
|
798
|
+
documentView;
|
|
799
|
+
seed;
|
|
800
|
+
branch;
|
|
794
801
|
constructor(documentView, seed, branch) {
|
|
795
802
|
this.documentView = documentView;
|
|
796
803
|
this.seed = seed;
|
|
@@ -820,7 +827,7 @@ var SeededStateReader = class {
|
|
|
820
827
|
if (DocumentNotFoundError.isError(error)) return;
|
|
821
828
|
let exists;
|
|
822
829
|
try {
|
|
823
|
-
exists = await this.documentView.exists([documentId],
|
|
830
|
+
exists = await this.documentView.exists([documentId], "LiveOnly", void 0, signal);
|
|
824
831
|
} catch {
|
|
825
832
|
throw error;
|
|
826
833
|
}
|
|
@@ -841,6 +848,12 @@ var SeededStateReader = class {
|
|
|
841
848
|
* from state no commit ever invalidates.
|
|
842
849
|
*/
|
|
843
850
|
var ModelReadGate = class {
|
|
851
|
+
model;
|
|
852
|
+
documentView;
|
|
853
|
+
servesGroups;
|
|
854
|
+
operationIndex;
|
|
855
|
+
logger;
|
|
856
|
+
options;
|
|
844
857
|
constructor(model, documentView, servesGroups, operationIndex, logger, options = OPEN_BY_DEFAULT) {
|
|
845
858
|
this.model = model;
|
|
846
859
|
this.documentView = documentView;
|
|
@@ -980,7 +993,7 @@ function authSubjectFromSigner(signer) {
|
|
|
980
993
|
function withAuthScope(view) {
|
|
981
994
|
if (view?.scopes && view.scopes.length > 0) return {
|
|
982
995
|
...view,
|
|
983
|
-
scopes: [
|
|
996
|
+
scopes: [.../* @__PURE__ */ new Set([...view.scopes, "auth"])]
|
|
984
997
|
};
|
|
985
998
|
return view;
|
|
986
999
|
}
|
|
@@ -1160,7 +1173,7 @@ var ReactorClient = class {
|
|
|
1160
1173
|
/** True when the id is taken; a soft-deleted document's id is still taken. */
|
|
1161
1174
|
async isDocumentIdTaken(documentId, signal) {
|
|
1162
1175
|
this.logger.verbose("isDocumentIdTaken(@documentId)", documentId);
|
|
1163
|
-
return (await this.documentView.exists([documentId],
|
|
1176
|
+
return (await this.documentView.exists([documentId], "IncludingDeleted", void 0, signal))[0];
|
|
1164
1177
|
}
|
|
1165
1178
|
/**
|
|
1166
1179
|
* Retrieves operations for a document
|
|
@@ -1423,7 +1436,7 @@ var ReactorClient = class {
|
|
|
1423
1436
|
this.logger.verbose("create(@id, @parentIdentifier)", document.header.id, parentIdentifier);
|
|
1424
1437
|
const documentId = document.header.id;
|
|
1425
1438
|
const branch = document.header.branch || "main";
|
|
1426
|
-
const
|
|
1439
|
+
const createInput = {
|
|
1427
1440
|
model: document.header.documentType,
|
|
1428
1441
|
version: 0,
|
|
1429
1442
|
documentId,
|
|
@@ -1439,7 +1452,8 @@ var ReactorClient = class {
|
|
|
1439
1452
|
branch: document.header.branch,
|
|
1440
1453
|
meta: document.header.meta,
|
|
1441
1454
|
protocolVersions: document.header.protocolVersions ?? { "base-reducer": 2 }
|
|
1442
|
-
}
|
|
1455
|
+
};
|
|
1456
|
+
const createActions = await signActions([createDocumentAction(createInput), upgradeDocumentAction({
|
|
1443
1457
|
documentId,
|
|
1444
1458
|
model: document.header.documentType,
|
|
1445
1459
|
fromVersion: 0,
|
|
@@ -1473,7 +1487,7 @@ var ReactorClient = class {
|
|
|
1473
1487
|
}
|
|
1474
1488
|
const batchResult = await this.reactor.executeBatch({ jobs }, signal);
|
|
1475
1489
|
const completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.waitForJob(job, signal)));
|
|
1476
|
-
for (const job of completedJobs) if (job.status ===
|
|
1490
|
+
for (const job of completedJobs) if (job.status === "FAILED") throw new Error(job.error?.message);
|
|
1477
1491
|
const created = await this.reactor.get(documentId);
|
|
1478
1492
|
return this.gateDocument(created, void 0, signal);
|
|
1479
1493
|
}
|
|
@@ -1521,22 +1535,26 @@ var ReactorClient = class {
|
|
|
1521
1535
|
const branch = document.header.branch || "main";
|
|
1522
1536
|
const fromVersion = normalizeDocumentModelVersion(document.state.document?.version);
|
|
1523
1537
|
let targetVersion = toVersion;
|
|
1524
|
-
if (targetVersion === void 0)
|
|
1538
|
+
if (targetVersion === void 0) {
|
|
1539
|
+
const module = await this.getDocumentModelModule(documentType);
|
|
1540
|
+
targetVersion = normalizeDocumentModelVersion(module.version);
|
|
1541
|
+
}
|
|
1525
1542
|
if (targetVersion === fromVersion) return this.gateDocument(document, { branch }, signal);
|
|
1526
1543
|
if (targetVersion < fromVersion) throw new DowngradeNotSupportedError(documentType, fromVersion, targetVersion);
|
|
1527
|
-
const
|
|
1544
|
+
const action = upgradeDocumentAction({
|
|
1528
1545
|
documentId,
|
|
1529
1546
|
model: documentType,
|
|
1530
1547
|
fromVersion,
|
|
1531
1548
|
toVersion: targetVersion,
|
|
1532
1549
|
revision: { ...document.header.revision }
|
|
1533
|
-
})
|
|
1550
|
+
});
|
|
1551
|
+
const signedActions = await signActions([action], this.signer, {
|
|
1534
1552
|
documentId,
|
|
1535
1553
|
branch
|
|
1536
1554
|
}, signal);
|
|
1537
1555
|
const jobInfo = await this.reactor.execute(documentId, branch, signedActions, signal);
|
|
1538
1556
|
const completedJob = await this.waitForJob(jobInfo, signal);
|
|
1539
|
-
if (completedJob.status !==
|
|
1557
|
+
if (completedJob.status !== "FAILED") {
|
|
1540
1558
|
const upgraded = await this.reactor.getByIdOrSlug(documentId, { branch }, completedJob.consistencyToken, signal);
|
|
1541
1559
|
return this.gateDocument(upgraded, { branch }, signal);
|
|
1542
1560
|
}
|
|
@@ -1570,7 +1588,7 @@ var ReactorClient = class {
|
|
|
1570
1588
|
}, signal);
|
|
1571
1589
|
const jobInfo = await this.reactor.execute(documentId, branch, signedActions, signal);
|
|
1572
1590
|
const completedJob = await this.waitForJob(jobInfo, signal);
|
|
1573
|
-
if (completedJob.status ===
|
|
1591
|
+
if (completedJob.status === "FAILED") throw new Error(completedJob.error?.message);
|
|
1574
1592
|
const view = {
|
|
1575
1593
|
branch,
|
|
1576
1594
|
subject
|
|
@@ -1617,7 +1635,7 @@ var ReactorClient = class {
|
|
|
1617
1635
|
}));
|
|
1618
1636
|
const batchResult = await this.reactor.executeBatch({ jobs: signedJobs }, signal);
|
|
1619
1637
|
const completedJobs = await Promise.all(Object.values(batchResult.jobs).map((job) => this.waitForJob(job, signal)));
|
|
1620
|
-
for (const job of completedJobs) if (job.status ===
|
|
1638
|
+
for (const job of completedJobs) if (job.status === "FAILED") throw new Error(job.error?.message);
|
|
1621
1639
|
return batchResult;
|
|
1622
1640
|
}
|
|
1623
1641
|
/**
|
|
@@ -1642,7 +1660,7 @@ var ReactorClient = class {
|
|
|
1642
1660
|
this.logger.verbose("addRelationship(@sourceIdentifier, @targetIdentifier, @relationshipType, @metadata, @branch)", sourceIdentifier, targetIdentifier, relationshipType, metadata, branch);
|
|
1643
1661
|
const jobInfo = await this.reactor.addRelationship(sourceIdentifier, targetIdentifier, relationshipType, metadata, branch, this.signer, signal);
|
|
1644
1662
|
const completedJob = await this.waitForJob(jobInfo, signal);
|
|
1645
|
-
if (completedJob.status ===
|
|
1663
|
+
if (completedJob.status === "FAILED") throw new Error(completedJob.error?.message);
|
|
1646
1664
|
const result = await this.reactor.getByIdOrSlug(sourceIdentifier, { branch }, completedJob.consistencyToken, signal);
|
|
1647
1665
|
return this.gateDocument(result, { branch }, signal);
|
|
1648
1666
|
}
|
|
@@ -1654,7 +1672,7 @@ var ReactorClient = class {
|
|
|
1654
1672
|
if (!await this.readRelationshipEdge(sourceIdentifier, targetIdentifier, relationshipType, { branch }, signal)) throw new RelationshipNotFoundError(sourceIdentifier, targetIdentifier, relationshipType);
|
|
1655
1673
|
const jobInfo = await this.reactor.updateRelationship(sourceIdentifier, targetIdentifier, relationshipType, metadata, branch, this.signer, signal);
|
|
1656
1674
|
const completedJob = await this.waitForJob(jobInfo, signal);
|
|
1657
|
-
if (completedJob.status ===
|
|
1675
|
+
if (completedJob.status === "FAILED") throw new Error(completedJob.error?.message);
|
|
1658
1676
|
const result = await this.reactor.getByIdOrSlug(sourceIdentifier, { branch }, completedJob.consistencyToken, signal);
|
|
1659
1677
|
return this.gateDocument(result, { branch }, signal);
|
|
1660
1678
|
}
|
|
@@ -1665,7 +1683,7 @@ var ReactorClient = class {
|
|
|
1665
1683
|
this.logger.verbose("removeRelationship(@sourceIdentifier, @targetIdentifier, @relationshipType, @branch)", sourceIdentifier, targetIdentifier, relationshipType, branch);
|
|
1666
1684
|
const jobInfo = await this.reactor.removeRelationship(sourceIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);
|
|
1667
1685
|
const completedJob = await this.waitForJob(jobInfo, signal);
|
|
1668
|
-
if (completedJob.status ===
|
|
1686
|
+
if (completedJob.status === "FAILED") throw new Error(completedJob.error?.message);
|
|
1669
1687
|
const result = await this.reactor.getByIdOrSlug(sourceIdentifier, { branch }, completedJob.consistencyToken, signal);
|
|
1670
1688
|
return this.gateDocument(result, { branch }, signal);
|
|
1671
1689
|
}
|
|
@@ -1677,10 +1695,10 @@ var ReactorClient = class {
|
|
|
1677
1695
|
const metadata = (await this.readRelationshipEdge(sourceParentIdentifier, targetIdentifier, relationshipType, { branch }, signal))?.metadata;
|
|
1678
1696
|
const removeJobInfo = await this.reactor.removeRelationship(sourceParentIdentifier, targetIdentifier, relationshipType, branch, this.signer, signal);
|
|
1679
1697
|
const removeCompletedJob = await this.waitForJob(removeJobInfo, signal);
|
|
1680
|
-
if (removeCompletedJob.status ===
|
|
1698
|
+
if (removeCompletedJob.status === "FAILED") throw new Error(removeCompletedJob.error?.message);
|
|
1681
1699
|
const addJobInfo = await this.reactor.addRelationship(targetParentIdentifier, targetIdentifier, relationshipType, metadata, branch, this.signer, signal);
|
|
1682
1700
|
const addCompletedJob = await this.waitForJob(addJobInfo, signal);
|
|
1683
|
-
if (addCompletedJob.status ===
|
|
1701
|
+
if (addCompletedJob.status === "FAILED") throw new Error(addCompletedJob.error?.message);
|
|
1684
1702
|
const sourceResult = await this.reactor.getByIdOrSlug(sourceParentIdentifier, { branch }, removeCompletedJob.consistencyToken, signal);
|
|
1685
1703
|
const targetResult = await this.reactor.getByIdOrSlug(targetParentIdentifier, { branch }, addCompletedJob.consistencyToken, signal);
|
|
1686
1704
|
return {
|
|
@@ -1694,7 +1712,7 @@ var ReactorClient = class {
|
|
|
1694
1712
|
const completedJobs = await Promise.all(Object.entries(result.jobs).map(async ([key, jobInfo]) => {
|
|
1695
1713
|
return [key, await this.waitForJob(jobInfo, signal)];
|
|
1696
1714
|
}));
|
|
1697
|
-
for (const [, completedJob] of completedJobs) if (completedJob.status ===
|
|
1715
|
+
for (const [, completedJob] of completedJobs) if (completedJob.status === "FAILED") throw new Error(completedJob.error?.message);
|
|
1698
1716
|
return { jobs: Object.fromEntries(completedJobs) };
|
|
1699
1717
|
}
|
|
1700
1718
|
/**
|
|
@@ -1703,8 +1721,8 @@ var ReactorClient = class {
|
|
|
1703
1721
|
async deleteDocument(identifier, propagate, signal) {
|
|
1704
1722
|
this.logger.verbose("deleteDocument(@identifier, @propagate)", identifier, propagate);
|
|
1705
1723
|
const jobs = [];
|
|
1706
|
-
if (propagate ===
|
|
1707
|
-
const toDelete = new Set([identifier]);
|
|
1724
|
+
if (propagate === "cascade") {
|
|
1725
|
+
const toDelete = /* @__PURE__ */ new Set([identifier]);
|
|
1708
1726
|
let changed = true;
|
|
1709
1727
|
while (changed) {
|
|
1710
1728
|
if (signal?.aborted) throw new Error("Operation aborted");
|
|
@@ -1728,7 +1746,7 @@ var ReactorClient = class {
|
|
|
1728
1746
|
const jobInfo = await this.reactor.deleteDocument(identifier, this.signer, signal);
|
|
1729
1747
|
jobs.push(jobInfo);
|
|
1730
1748
|
const completedJobs = await Promise.all(jobs.map((job) => this.waitForJob(job, signal)));
|
|
1731
|
-
for (const completedJob of completedJobs) if (completedJob.status ===
|
|
1749
|
+
for (const completedJob of completedJobs) if (completedJob.status === "FAILED") throw new Error(completedJob.error?.message);
|
|
1732
1750
|
}
|
|
1733
1751
|
/**
|
|
1734
1752
|
* Deletes documents and waits for completion
|
|
@@ -1788,27 +1806,27 @@ var ReactorClient = class {
|
|
|
1788
1806
|
deliver((async () => {
|
|
1789
1807
|
const documents = await Promise.all(result.results.map((id) => this.reactor.get(id, withAuthScope(view), void 0, void 0)));
|
|
1790
1808
|
return {
|
|
1791
|
-
type:
|
|
1809
|
+
type: "created",
|
|
1792
1810
|
documents: await Promise.all(documents.map(readable))
|
|
1793
1811
|
};
|
|
1794
1812
|
})());
|
|
1795
1813
|
}, search);
|
|
1796
1814
|
const unsubscribeDeleted = this.subscriptionManager.onDocumentDeleted((documentIds) => {
|
|
1797
1815
|
deliver({
|
|
1798
|
-
type:
|
|
1816
|
+
type: "deleted",
|
|
1799
1817
|
documents: [],
|
|
1800
1818
|
context: { childId: documentIds[0] }
|
|
1801
1819
|
});
|
|
1802
1820
|
}, search);
|
|
1803
1821
|
const unsubscribeUpdated = this.subscriptionManager.onDocumentStateUpdated((result) => {
|
|
1804
1822
|
deliver((async () => ({
|
|
1805
|
-
type:
|
|
1823
|
+
type: "updated",
|
|
1806
1824
|
documents: await Promise.all(result.results.map(readable))
|
|
1807
1825
|
}))());
|
|
1808
1826
|
}, search, view);
|
|
1809
1827
|
const unsubscribeRelationship = this.subscriptionManager.onRelationshipChanged((parentId, childId, changeType) => {
|
|
1810
1828
|
deliver({
|
|
1811
|
-
type: changeType ===
|
|
1829
|
+
type: changeType === "added" ? "child_added" : "child_removed",
|
|
1812
1830
|
documents: [],
|
|
1813
1831
|
context: {
|
|
1814
1832
|
parentId,
|
|
@@ -1837,18 +1855,6 @@ var ReactorClient = class {
|
|
|
1837
1855
|
//#endregion
|
|
1838
1856
|
//#region src/queue/types.ts
|
|
1839
1857
|
/**
|
|
1840
|
-
* State of a job in the queue
|
|
1841
|
-
*/
|
|
1842
|
-
let JobQueueState = /* @__PURE__ */ function(JobQueueState) {
|
|
1843
|
-
JobQueueState[JobQueueState["UNKNOWN"] = -1] = "UNKNOWN";
|
|
1844
|
-
JobQueueState[JobQueueState["PREPROCESSING"] = 0] = "PREPROCESSING";
|
|
1845
|
-
JobQueueState[JobQueueState["PENDING"] = 1] = "PENDING";
|
|
1846
|
-
JobQueueState[JobQueueState["READY"] = 2] = "READY";
|
|
1847
|
-
JobQueueState[JobQueueState["RUNNING"] = 3] = "RUNNING";
|
|
1848
|
-
JobQueueState[JobQueueState["RESOLVED"] = 4] = "RESOLVED";
|
|
1849
|
-
return JobQueueState;
|
|
1850
|
-
}({});
|
|
1851
|
-
/**
|
|
1852
1858
|
* How a retry is accounted against the job's retry limit.
|
|
1853
1859
|
* - `CountAgainstLimit` (default): a fault; the job eventually exhausts its
|
|
1854
1860
|
* retries and fails terminally.
|
|
@@ -1881,6 +1887,11 @@ function toErrorInfo(error) {
|
|
|
1881
1887
|
};
|
|
1882
1888
|
}
|
|
1883
1889
|
var JobResultHandler = class {
|
|
1890
|
+
queue;
|
|
1891
|
+
jobTracker;
|
|
1892
|
+
eventBus;
|
|
1893
|
+
resolver;
|
|
1894
|
+
logger;
|
|
1884
1895
|
constructor(queue, jobTracker, eventBus, resolver, logger) {
|
|
1885
1896
|
this.queue = queue;
|
|
1886
1897
|
this.jobTracker = jobTracker;
|
|
@@ -1911,7 +1922,7 @@ var JobResultHandler = class {
|
|
|
1911
1922
|
if (result.error && AppendConditionFailedError.isError(result.error) && this.countConflicts(handle.job) < MAX_EXEMPT_CONFLICT_RETRIES) {
|
|
1912
1923
|
const errorInfo = toErrorInfo(result.error);
|
|
1913
1924
|
try {
|
|
1914
|
-
await this.queue.retryJob(handle.job.id, errorInfo,
|
|
1925
|
+
await this.queue.retryJob(handle.job.id, errorInfo, "exempt-from-limit");
|
|
1915
1926
|
return;
|
|
1916
1927
|
} catch {}
|
|
1917
1928
|
}
|
|
@@ -2009,6 +2020,12 @@ var JobResultHandler = class {
|
|
|
2009
2020
|
* is stranded at PENDING for as long as the deferral lasts.
|
|
2010
2021
|
*/
|
|
2011
2022
|
var DeferredJobs = class {
|
|
2023
|
+
queue;
|
|
2024
|
+
jobTracker;
|
|
2025
|
+
eventBus;
|
|
2026
|
+
logger;
|
|
2027
|
+
ttlMs;
|
|
2028
|
+
onReleased;
|
|
2012
2029
|
#byDocumentId = /* @__PURE__ */ new Map();
|
|
2013
2030
|
#timers = /* @__PURE__ */ new Map();
|
|
2014
2031
|
constructor(queue, jobTracker, eventBus, logger, ttlMs = DEFAULT_DEFERRED_JOB_TTL_MS, onReleased = () => Promise.resolve()) {
|
|
@@ -2170,6 +2187,13 @@ function bucketFor(documentId, numWorkers) {
|
|
|
2170
2187
|
* (Powerhouse board wiki id: d400d711-f07e-4389-a226-4e9fdd4fa8ba)
|
|
2171
2188
|
*/
|
|
2172
2189
|
var WorkerPoolJobExecutorManager = class {
|
|
2190
|
+
workerFactory;
|
|
2191
|
+
eventBus;
|
|
2192
|
+
queue;
|
|
2193
|
+
jobTracker;
|
|
2194
|
+
logger;
|
|
2195
|
+
resolver;
|
|
2196
|
+
operationIndex;
|
|
2173
2197
|
workers = [];
|
|
2174
2198
|
isRunning = false;
|
|
2175
2199
|
activeJobs = 0;
|
|
@@ -2434,6 +2458,12 @@ function fillMissingMemberships(documentIds, found) {
|
|
|
2434
2458
|
* Listens for job available events and dispatches jobs to executors.
|
|
2435
2459
|
*/
|
|
2436
2460
|
var SimpleJobExecutorManager = class {
|
|
2461
|
+
executorFactory;
|
|
2462
|
+
eventBus;
|
|
2463
|
+
queue;
|
|
2464
|
+
jobTracker;
|
|
2465
|
+
logger;
|
|
2466
|
+
resolver;
|
|
2437
2467
|
executors = [];
|
|
2438
2468
|
isRunning = false;
|
|
2439
2469
|
activeJobs = 0;
|
|
@@ -2608,6 +2638,7 @@ var SimpleJobExecutorManager = class {
|
|
|
2608
2638
|
* Subscribes to operation events to update job states.
|
|
2609
2639
|
*/
|
|
2610
2640
|
var InMemoryJobTracker = class {
|
|
2641
|
+
eventBus;
|
|
2611
2642
|
jobs = /* @__PURE__ */ new Map();
|
|
2612
2643
|
unsubscribers = [];
|
|
2613
2644
|
constructor(eventBus) {
|
|
@@ -2628,11 +2659,11 @@ var InMemoryJobTracker = class {
|
|
|
2628
2659
|
handleWriteReady(event) {
|
|
2629
2660
|
const jobId = event.jobId;
|
|
2630
2661
|
const job = this.jobs.get(jobId);
|
|
2631
|
-
if (job && job.status ===
|
|
2662
|
+
if (job && job.status === "RUNNING") {
|
|
2632
2663
|
const consistencyToken = createConsistencyToken(event.operations);
|
|
2633
2664
|
this.jobs.set(jobId, {
|
|
2634
2665
|
...job,
|
|
2635
|
-
status:
|
|
2666
|
+
status: "WRITE_READY",
|
|
2636
2667
|
consistencyToken,
|
|
2637
2668
|
result: summarizeSubmittedActions(event.operations, event.submittedActionIds)
|
|
2638
2669
|
});
|
|
@@ -2641,9 +2672,9 @@ var InMemoryJobTracker = class {
|
|
|
2641
2672
|
handleReadReady(event) {
|
|
2642
2673
|
const jobId = event.jobId;
|
|
2643
2674
|
const job = this.jobs.get(jobId);
|
|
2644
|
-
if (job && job.status ===
|
|
2675
|
+
if (job && job.status === "WRITE_READY") this.jobs.set(jobId, {
|
|
2645
2676
|
...job,
|
|
2646
|
-
status:
|
|
2677
|
+
status: "READ_READY"
|
|
2647
2678
|
});
|
|
2648
2679
|
}
|
|
2649
2680
|
handleJobFailed(event) {
|
|
@@ -2666,7 +2697,7 @@ var InMemoryJobTracker = class {
|
|
|
2666
2697
|
this.jobs.set(jobId, {
|
|
2667
2698
|
id: jobId,
|
|
2668
2699
|
documentId: "",
|
|
2669
|
-
status:
|
|
2700
|
+
status: "RUNNING",
|
|
2670
2701
|
createdAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2671
2702
|
consistencyToken: createEmptyConsistencyToken(),
|
|
2672
2703
|
meta: {
|
|
@@ -2678,7 +2709,7 @@ var InMemoryJobTracker = class {
|
|
|
2678
2709
|
}
|
|
2679
2710
|
this.jobs.set(jobId, {
|
|
2680
2711
|
...job,
|
|
2681
|
-
status:
|
|
2712
|
+
status: "RUNNING"
|
|
2682
2713
|
});
|
|
2683
2714
|
}
|
|
2684
2715
|
markFailed(jobId, error, job) {
|
|
@@ -2687,7 +2718,7 @@ var InMemoryJobTracker = class {
|
|
|
2687
2718
|
this.jobs.set(jobId, {
|
|
2688
2719
|
id: jobId,
|
|
2689
2720
|
documentId: job?.documentId ?? "",
|
|
2690
|
-
status:
|
|
2721
|
+
status: "FAILED",
|
|
2691
2722
|
createdAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2692
2723
|
completedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2693
2724
|
error,
|
|
@@ -2702,7 +2733,7 @@ var InMemoryJobTracker = class {
|
|
|
2702
2733
|
}
|
|
2703
2734
|
this.jobs.set(jobId, {
|
|
2704
2735
|
...existing,
|
|
2705
|
-
status:
|
|
2736
|
+
status: "FAILED",
|
|
2706
2737
|
completedAtUtcIso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2707
2738
|
error,
|
|
2708
2739
|
job,
|
|
@@ -2796,6 +2827,7 @@ function highestOf(ops) {
|
|
|
2796
2827
|
return highest;
|
|
2797
2828
|
}
|
|
2798
2829
|
var ProcessorQueue = class {
|
|
2830
|
+
options;
|
|
2799
2831
|
tasks = [];
|
|
2800
2832
|
running = false;
|
|
2801
2833
|
closed = false;
|
|
@@ -3378,11 +3410,11 @@ var JobExecutionHandle = class {
|
|
|
3378
3410
|
onDefer;
|
|
3379
3411
|
getStateName(state) {
|
|
3380
3412
|
switch (state) {
|
|
3381
|
-
case
|
|
3382
|
-
case
|
|
3383
|
-
case
|
|
3384
|
-
case
|
|
3385
|
-
case
|
|
3413
|
+
case 0: return "PREPROCESSING";
|
|
3414
|
+
case 1: return "PENDING";
|
|
3415
|
+
case 2: return "READY";
|
|
3416
|
+
case 3: return "RUNNING";
|
|
3417
|
+
case 4: return "RESOLVED";
|
|
3386
3418
|
default: return `UNKNOWN`;
|
|
3387
3419
|
}
|
|
3388
3420
|
}
|
|
@@ -3401,23 +3433,23 @@ var JobExecutionHandle = class {
|
|
|
3401
3433
|
return this._state;
|
|
3402
3434
|
}
|
|
3403
3435
|
start() {
|
|
3404
|
-
if (this._state !==
|
|
3405
|
-
this._state =
|
|
3436
|
+
if (this._state !== 2) throw new Error(`Cannot start job in state ${this.getStateName(this._state)}`);
|
|
3437
|
+
this._state = 3;
|
|
3406
3438
|
this.onStart?.();
|
|
3407
3439
|
}
|
|
3408
3440
|
complete() {
|
|
3409
|
-
if (this._state !==
|
|
3410
|
-
this._state =
|
|
3441
|
+
if (this._state !== 3) throw new Error(`Cannot complete job in state ${this.getStateName(this._state)}`);
|
|
3442
|
+
this._state = 4;
|
|
3411
3443
|
this.onComplete?.();
|
|
3412
3444
|
}
|
|
3413
3445
|
fail(error) {
|
|
3414
|
-
if (this._state !==
|
|
3415
|
-
this._state =
|
|
3446
|
+
if (this._state !== 3) throw new Error(`Cannot fail job in state ${this.getStateName(this._state)}`);
|
|
3447
|
+
this._state = 4;
|
|
3416
3448
|
this.onFail?.(error);
|
|
3417
3449
|
}
|
|
3418
3450
|
defer() {
|
|
3419
|
-
if (this._state !==
|
|
3420
|
-
this._state =
|
|
3451
|
+
if (this._state !== 3) throw new Error(`Cannot defer job in state ${this.getStateName(this._state)}`);
|
|
3452
|
+
this._state = 4;
|
|
3421
3453
|
this.onDefer?.();
|
|
3422
3454
|
}
|
|
3423
3455
|
};
|
|
@@ -3430,6 +3462,8 @@ var JobExecutionHandle = class {
|
|
|
3430
3462
|
* Implements dependency management through queue hints.
|
|
3431
3463
|
*/
|
|
3432
3464
|
var InMemoryQueue = class {
|
|
3465
|
+
eventBus;
|
|
3466
|
+
resolver;
|
|
3433
3467
|
queues = /* @__PURE__ */ new Map();
|
|
3434
3468
|
jobIdToQueueKey = /* @__PURE__ */ new Map();
|
|
3435
3469
|
docIdToJobId = /* @__PURE__ */ new Map();
|
|
@@ -3564,7 +3598,7 @@ var InMemoryQueue = class {
|
|
|
3564
3598
|
this.jobIdToQueueKey.delete(job.id);
|
|
3565
3599
|
this.markJobExecuting(job);
|
|
3566
3600
|
if (queue.length === 0) this.queues.delete(queueKey);
|
|
3567
|
-
const handle = new JobExecutionHandle(job,
|
|
3601
|
+
const handle = new JobExecutionHandle(job, 2, {
|
|
3568
3602
|
onStart: () => {},
|
|
3569
3603
|
onComplete: () => {
|
|
3570
3604
|
this.completeJob(job.id);
|
|
@@ -3590,7 +3624,7 @@ var InMemoryQueue = class {
|
|
|
3590
3624
|
this.jobIdToQueueKey.delete(job.id);
|
|
3591
3625
|
this.markJobExecuting(job);
|
|
3592
3626
|
if (queue.length === 0) this.queues.delete(queueKey);
|
|
3593
|
-
const handle = new JobExecutionHandle(job,
|
|
3627
|
+
const handle = new JobExecutionHandle(job, 2, {
|
|
3594
3628
|
onStart: () => {},
|
|
3595
3629
|
onComplete: () => {
|
|
3596
3630
|
this.completeJob(job.id);
|
|
@@ -3624,7 +3658,7 @@ var InMemoryQueue = class {
|
|
|
3624
3658
|
this.jobIdToQueueKey.delete(job.id);
|
|
3625
3659
|
this.markJobExecuting(job);
|
|
3626
3660
|
if (queue.length === 0) this.queues.delete(queueKey);
|
|
3627
|
-
const handle = new JobExecutionHandle(job,
|
|
3661
|
+
const handle = new JobExecutionHandle(job, 2, {
|
|
3628
3662
|
onStart: () => {},
|
|
3629
3663
|
onComplete: () => {
|
|
3630
3664
|
this.completeJob(job.id);
|
|
@@ -3726,7 +3760,7 @@ var InMemoryQueue = class {
|
|
|
3726
3760
|
if (documentId) this.markJobComplete(jobId, documentId);
|
|
3727
3761
|
this.jobIndex.delete(jobId);
|
|
3728
3762
|
}
|
|
3729
|
-
async retryJob(jobId, error, accounting =
|
|
3763
|
+
async retryJob(jobId, error, accounting = "count-against-limit") {
|
|
3730
3764
|
const job = this.jobIndex.get(jobId);
|
|
3731
3765
|
if (!job) return;
|
|
3732
3766
|
job.lastError = error;
|
|
@@ -3738,7 +3772,7 @@ var InMemoryQueue = class {
|
|
|
3738
3772
|
const retryCount = job.retryCount || 0;
|
|
3739
3773
|
const updatedJob = {
|
|
3740
3774
|
...job,
|
|
3741
|
-
retryCount: accounting ===
|
|
3775
|
+
retryCount: accounting === "count-against-limit" ? retryCount + 1 : retryCount,
|
|
3742
3776
|
lastError: error
|
|
3743
3777
|
};
|
|
3744
3778
|
await this.enqueue(updatedJob);
|
|
@@ -3939,6 +3973,8 @@ function describeSource(source) {
|
|
|
3939
3973
|
* and failure-caching state.
|
|
3940
3974
|
*/
|
|
3941
3975
|
var DocumentModelResolver = class {
|
|
3976
|
+
registry;
|
|
3977
|
+
loader;
|
|
3942
3978
|
loadingModels = /* @__PURE__ */ new Map();
|
|
3943
3979
|
failedModelTypes = /* @__PURE__ */ new Set();
|
|
3944
3980
|
broadcastHook = null;
|
|
@@ -4009,6 +4045,7 @@ var DocumentModelResolver = class {
|
|
|
4009
4045
|
* Since there is no loader, missing models cannot be recovered.
|
|
4010
4046
|
*/
|
|
4011
4047
|
var NullDocumentModelResolver = class {
|
|
4048
|
+
registry;
|
|
4012
4049
|
constructor(registry) {
|
|
4013
4050
|
this.registry = registry;
|
|
4014
4051
|
}
|
|
@@ -4232,6 +4269,8 @@ var ReactorSubscriptionManager = class {
|
|
|
4232
4269
|
* is emitted, so that reactor.get() returns fresh data when callbacks fire.
|
|
4233
4270
|
*/
|
|
4234
4271
|
var SubscriptionNotificationReadModel = class {
|
|
4272
|
+
subscriptionManager;
|
|
4273
|
+
documentView;
|
|
4235
4274
|
name = "subscription-notification";
|
|
4236
4275
|
constructor(subscriptionManager, documentView) {
|
|
4237
4276
|
this.subscriptionManager = subscriptionManager;
|
|
@@ -4254,10 +4293,10 @@ var SubscriptionNotificationReadModel = class {
|
|
|
4254
4293
|
deleted.push(deletedId);
|
|
4255
4294
|
} else if (actionType === "ADD_RELATIONSHIP") {
|
|
4256
4295
|
const input = operation.action.input;
|
|
4257
|
-
this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId,
|
|
4296
|
+
this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "added", input.childType);
|
|
4258
4297
|
} else if (actionType === "REMOVE_RELATIONSHIP") {
|
|
4259
4298
|
const input = operation.action.input;
|
|
4260
|
-
this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId,
|
|
4299
|
+
this.subscriptionManager.notifyRelationshipChanged(input.sourceId, input.targetId, "removed", input.childType);
|
|
4261
4300
|
} else if (!created.includes(context.documentId)) updatedIds.add(context.documentId);
|
|
4262
4301
|
}
|
|
4263
4302
|
if (created.length > 0) this.subscriptionManager.notifyDocumentsCreated(created, documentTypes, parentIds);
|
|
@@ -4282,6 +4321,10 @@ var SubscriptionNotificationReadModel = class {
|
|
|
4282
4321
|
* keeps the common case (a membership write later than all history) free.
|
|
4283
4322
|
*/
|
|
4284
4323
|
var GroupReevaluationTrigger = class {
|
|
4324
|
+
logger;
|
|
4325
|
+
eventBus;
|
|
4326
|
+
queue;
|
|
4327
|
+
operationIndex;
|
|
4285
4328
|
unsubscribe;
|
|
4286
4329
|
constructor(logger, eventBus, queue, operationIndex) {
|
|
4287
4330
|
this.logger = logger;
|
|
@@ -4433,7 +4476,7 @@ var Mailbox = class {
|
|
|
4433
4476
|
this.itemsMap.set(item.id, item);
|
|
4434
4477
|
for (const op of item.operations) this._latestOrdinal = Math.max(this._latestOrdinal, op.context.ordinal);
|
|
4435
4478
|
item.on((syncOp, _, next) => {
|
|
4436
|
-
if (next ===
|
|
4479
|
+
if (next === 2) for (const op of syncOp.operations) this._ack = Math.max(this._ack, op.context.ordinal);
|
|
4437
4480
|
});
|
|
4438
4481
|
}
|
|
4439
4482
|
if (this.paused) {
|
|
@@ -4547,7 +4590,7 @@ var BufferedMailbox = class {
|
|
|
4547
4590
|
this.itemsMap.set(item.id, item);
|
|
4548
4591
|
for (const op of item.operations) this._latestOrdinal = Math.max(this._latestOrdinal, op.context.ordinal);
|
|
4549
4592
|
item.on((syncOp, _, next) => {
|
|
4550
|
-
if (next ===
|
|
4593
|
+
if (next === 2) for (const op of syncOp.operations) this._ack = Math.max(this._ack, op.context.ordinal);
|
|
4551
4594
|
});
|
|
4552
4595
|
}
|
|
4553
4596
|
this.addedBuffer.push(...items);
|
|
@@ -4661,7 +4704,14 @@ var GraphQLRequestError = class extends Error {
|
|
|
4661
4704
|
* difference between a channel that recovers and one that is dead for the
|
|
4662
4705
|
* process lifetime.
|
|
4663
4706
|
*/
|
|
4664
|
-
const RECOVERABLE_GRAPHQL_ERROR_CODES = {
|
|
4707
|
+
const RECOVERABLE_GRAPHQL_ERROR_CODES = {
|
|
4708
|
+
/**
|
|
4709
|
+
* A stored operation cannot be represented in the schema - an action with no
|
|
4710
|
+
* id, say. The document holding it needs repairing, but the channel serves
|
|
4711
|
+
* every other document, and a peer that stopped polling would stop receiving
|
|
4712
|
+
* those too.
|
|
4713
|
+
*/
|
|
4714
|
+
malformedStoredOperation: "MALFORMED_STORED_OPERATION" };
|
|
4665
4715
|
const RECOVERABLE_CODES = new Set(Object.values(RECOVERABLE_GRAPHQL_ERROR_CODES));
|
|
4666
4716
|
/**
|
|
4667
4717
|
* True when every error the response carried named a recoverable code.
|
|
@@ -4770,23 +4820,23 @@ var SyncOperation = class {
|
|
|
4770
4820
|
this.scopes = scopes;
|
|
4771
4821
|
this.branch = branch;
|
|
4772
4822
|
this.operations = operations;
|
|
4773
|
-
this.status =
|
|
4823
|
+
this.status = -1;
|
|
4774
4824
|
}
|
|
4775
4825
|
on(callback) {
|
|
4776
4826
|
this.callbacks.push(callback);
|
|
4777
4827
|
}
|
|
4778
4828
|
started() {
|
|
4779
|
-
this.transition(
|
|
4829
|
+
this.transition(0);
|
|
4780
4830
|
}
|
|
4781
4831
|
transported() {
|
|
4782
|
-
this.transition(
|
|
4832
|
+
this.transition(1);
|
|
4783
4833
|
}
|
|
4784
4834
|
executed() {
|
|
4785
|
-
this.transition(
|
|
4835
|
+
this.transition(2);
|
|
4786
4836
|
}
|
|
4787
4837
|
failed(error) {
|
|
4788
4838
|
this.error = error;
|
|
4789
|
-
this.transition(
|
|
4839
|
+
this.transition(3);
|
|
4790
4840
|
}
|
|
4791
4841
|
transition(next) {
|
|
4792
4842
|
const prev = this.status;
|
|
@@ -4996,9 +5046,11 @@ function consolidateSyncOperations(syncOps) {
|
|
|
4996
5046
|
}
|
|
4997
5047
|
const first = group.ops[0];
|
|
4998
5048
|
const merged = new SyncOperation(first.id, first.jobId, remappedDeps, first.remoteName, first.documentId, first.scopes, first.branch, allOperations);
|
|
4999
|
-
if (first.status >
|
|
5000
|
-
|
|
5001
|
-
|
|
5049
|
+
if (first.status > 0) {
|
|
5050
|
+
if (first.status >= 3) merged.executed();
|
|
5051
|
+
else if (first.status >= 2) merged.transported();
|
|
5052
|
+
else merged.started();
|
|
5053
|
+
}
|
|
5002
5054
|
result.push(merged);
|
|
5003
5055
|
}
|
|
5004
5056
|
return result;
|
|
@@ -5129,7 +5181,7 @@ function syncOperationErrorType(error) {
|
|
|
5129
5181
|
return error?.errorType ?? classifyJobFailure(error?.error?.name ?? "Error");
|
|
5130
5182
|
}
|
|
5131
5183
|
/** Dead-letter types that must not stop the document syncing. */
|
|
5132
|
-
const NON_QUARANTINING_ERROR_TYPES = new Set(["AUTH_TIMESTAMP_NOT_MONOTONIC"]);
|
|
5184
|
+
const NON_QUARANTINING_ERROR_TYPES = /* @__PURE__ */ new Set(["AUTH_TIMESTAMP_NOT_MONOTONIC"]);
|
|
5133
5185
|
/**
|
|
5134
5186
|
* A held auth operation must not quarantine: reconciling the two policies needs
|
|
5135
5187
|
* the traffic a quarantine would stop.
|
|
@@ -5355,7 +5407,7 @@ function envelopesToSyncOperations(envelope, remoteName) {
|
|
|
5355
5407
|
}
|
|
5356
5408
|
const getLatestAppliedOrdinal = (syncOps) => {
|
|
5357
5409
|
let maxOrdinal = 0;
|
|
5358
|
-
for (const syncOp of syncOps) if (syncOp.status ===
|
|
5410
|
+
for (const syncOp of syncOps) if (syncOp.status === 2) for (const op of syncOp.operations) maxOrdinal = Math.max(maxOrdinal, op.context.ordinal);
|
|
5359
5411
|
return maxOrdinal;
|
|
5360
5412
|
};
|
|
5361
5413
|
//#endregion
|
|
@@ -5370,6 +5422,7 @@ const DECISION_FIELDS = ["deniedReason", "errorType"];
|
|
|
5370
5422
|
* GraphQL-based synchronization channel for network communication between reactors.
|
|
5371
5423
|
*/
|
|
5372
5424
|
var GqlRequestChannel = class {
|
|
5425
|
+
logger;
|
|
5373
5426
|
inbox;
|
|
5374
5427
|
outbox;
|
|
5375
5428
|
deadLetter;
|
|
@@ -5577,7 +5630,7 @@ var GqlRequestChannel = class {
|
|
|
5577
5630
|
const syncOps = [];
|
|
5578
5631
|
for (const dl of deadLetters) {
|
|
5579
5632
|
const syncOp = new SyncOperation(crypto.randomUUID(), dl.jobId, [], this.remoteName, dl.documentId, dl.scopes, dl.branch, []);
|
|
5580
|
-
syncOp.failed(new ChannelError(
|
|
5633
|
+
syncOp.failed(new ChannelError("outbox", new Error(dl.error), dl.errorType ?? void 0));
|
|
5581
5634
|
syncOps.push(syncOp);
|
|
5582
5635
|
}
|
|
5583
5636
|
this.deadLetter.add(...syncOps);
|
|
@@ -5597,7 +5650,7 @@ var GqlRequestChannel = class {
|
|
|
5597
5650
|
const classification = this.classifyError(err);
|
|
5598
5651
|
this.failureCount++;
|
|
5599
5652
|
this.lastFailureUtcMs = Date.now();
|
|
5600
|
-
const channelError = new ChannelError(
|
|
5653
|
+
const channelError = new ChannelError("inbox", err);
|
|
5601
5654
|
this.logger.error("GqlChannel poll error (@FailureCount, @Classification): @Error", this.failureCount, classification, channelError);
|
|
5602
5655
|
if (classification === "unrecoverable") {
|
|
5603
5656
|
this.pollTimer.stop();
|
|
@@ -5841,7 +5894,7 @@ var GqlRequestChannel = class {
|
|
|
5841
5894
|
this.transitionConnectionState("reconnecting");
|
|
5842
5895
|
this.schedulePushRetry();
|
|
5843
5896
|
} else {
|
|
5844
|
-
const channelError = new ChannelError(
|
|
5897
|
+
const channelError = new ChannelError("outbox", err);
|
|
5845
5898
|
for (const syncOp of syncOps) syncOp.failed(channelError);
|
|
5846
5899
|
this.deadLetter.add(...syncOps);
|
|
5847
5900
|
this.outbox.remove(...syncOps);
|
|
@@ -6063,7 +6116,7 @@ var GqlRequestChannelFactory = class {
|
|
|
6063
6116
|
...retryMaxDelayMs !== void 0 && { retryMaxDelayMs },
|
|
6064
6117
|
...maxQueueDepth !== void 0 && { maxQueueDepth },
|
|
6065
6118
|
...backpressureCheckIntervalMs !== void 0 && { backpressureCheckIntervalMs },
|
|
6066
|
-
startPaused: options?.pollBehavior ===
|
|
6119
|
+
startPaused: options?.pollBehavior === "manual"
|
|
6067
6120
|
});
|
|
6068
6121
|
return new GqlRequestChannel(this.logger, remoteId, remoteName, cursorStorage, gqlConfig, operationIndex, pollTimer);
|
|
6069
6122
|
}
|
|
@@ -6080,6 +6133,7 @@ function firstOrdinalOf$1(syncOp) {
|
|
|
6080
6133
|
* In general, the resolvers are responsible for updating mailboxes.
|
|
6081
6134
|
*/
|
|
6082
6135
|
var GqlResponseChannel = class {
|
|
6136
|
+
logger;
|
|
6083
6137
|
inbox;
|
|
6084
6138
|
outbox;
|
|
6085
6139
|
deadLetter;
|
|
@@ -6190,7 +6244,7 @@ var GqlResponseChannel = class {
|
|
|
6190
6244
|
*/
|
|
6191
6245
|
rememberUnserved(syncOps) {
|
|
6192
6246
|
for (const syncOp of syncOps) {
|
|
6193
|
-
if (syncOp.status ===
|
|
6247
|
+
if (syncOp.status === 2) continue;
|
|
6194
6248
|
const first = firstOrdinalOf$1(syncOp);
|
|
6195
6249
|
if (first > 0 && first < this.evictedOutboxFloor) this.evictedOutboxFloor = first;
|
|
6196
6250
|
}
|
|
@@ -6235,7 +6289,7 @@ var GqlResponseChannel = class {
|
|
|
6235
6289
|
unservedFloor() {
|
|
6236
6290
|
let floor = this.evictedOutboxFloor;
|
|
6237
6291
|
for (const syncOp of this.outbox.items) {
|
|
6238
|
-
if (syncOp.status ===
|
|
6292
|
+
if (syncOp.status === 2) continue;
|
|
6239
6293
|
const first = firstOrdinalOf$1(syncOp);
|
|
6240
6294
|
if (first > 0 && first < floor) floor = first;
|
|
6241
6295
|
}
|
|
@@ -6275,6 +6329,7 @@ function remoteCursorToRow(cursor) {
|
|
|
6275
6329
|
};
|
|
6276
6330
|
}
|
|
6277
6331
|
var KyselySyncCursorStorage = class {
|
|
6332
|
+
db;
|
|
6278
6333
|
constructor(db) {
|
|
6279
6334
|
this.db = db;
|
|
6280
6335
|
}
|
|
@@ -6350,6 +6405,7 @@ function deadLetterRecordToRow(record) {
|
|
|
6350
6405
|
* PGlite/Kysely-backed implementation of {@link ISyncDeadLetterStorage}.
|
|
6351
6406
|
*/
|
|
6352
6407
|
var KyselySyncDeadLetterStorage = class {
|
|
6408
|
+
db;
|
|
6353
6409
|
constructor(db) {
|
|
6354
6410
|
this.db = db;
|
|
6355
6411
|
}
|
|
@@ -6471,6 +6527,7 @@ function remoteRecordToRow(remote) {
|
|
|
6471
6527
|
};
|
|
6472
6528
|
}
|
|
6473
6529
|
var KyselySyncRemoteStorage = class {
|
|
6530
|
+
db;
|
|
6474
6531
|
constructor(db) {
|
|
6475
6532
|
this.db = db;
|
|
6476
6533
|
}
|
|
@@ -6621,6 +6678,7 @@ var BatchAggregator = class {
|
|
|
6621
6678
|
* to provide a fast path for jobs that have already synced.
|
|
6622
6679
|
*/
|
|
6623
6680
|
var SyncAwaiter = class {
|
|
6681
|
+
eventBus;
|
|
6624
6682
|
completedResults = /* @__PURE__ */ new Map();
|
|
6625
6683
|
pendingWaiters = /* @__PURE__ */ new Map();
|
|
6626
6684
|
unsubscribers = [];
|
|
@@ -6820,24 +6878,19 @@ var SyncStatusTracker = class {
|
|
|
6820
6878
|
}
|
|
6821
6879
|
};
|
|
6822
6880
|
function deriveStatus(inboxCount, outboxCount, errorCount) {
|
|
6823
|
-
if (errorCount > 0) return
|
|
6824
|
-
if (inboxCount > 0 && outboxCount > 0) return
|
|
6825
|
-
if (inboxCount > 0) return
|
|
6826
|
-
if (outboxCount > 0) return
|
|
6827
|
-
return
|
|
6881
|
+
if (errorCount > 0) return "ERROR";
|
|
6882
|
+
if (inboxCount > 0 && outboxCount > 0) return "OUTGOING_AND_INCOMING";
|
|
6883
|
+
if (inboxCount > 0) return "INCOMING";
|
|
6884
|
+
if (outboxCount > 0) return "OUTGOING";
|
|
6885
|
+
return "SYNCED";
|
|
6828
6886
|
}
|
|
6829
6887
|
//#endregion
|
|
6830
6888
|
//#region src/sync/sync-manager.ts
|
|
6831
|
-
var OutboxMode = /* @__PURE__ */ function(OutboxMode) {
|
|
6832
|
-
OutboxMode["Backfill"] = "backfill";
|
|
6833
|
-
OutboxMode["BatchTriggered"] = "batch-triggered";
|
|
6834
|
-
return OutboxMode;
|
|
6835
|
-
}(OutboxMode || {});
|
|
6836
6889
|
const defaultSyncManagerConfig = {
|
|
6837
6890
|
maxDeadLettersPerRemote: 100,
|
|
6838
6891
|
maxInboxBatchSize: 32,
|
|
6839
6892
|
maxHeldOperationsPerRemote: 1e4,
|
|
6840
|
-
staleRemotePollWindowMs:
|
|
6893
|
+
staleRemotePollWindowMs: 3e5
|
|
6841
6894
|
};
|
|
6842
6895
|
const PLAN_KEY_TO_JOB_UUID_CAP = 1e4;
|
|
6843
6896
|
/**
|
|
@@ -6940,7 +6993,7 @@ var SyncManager = class {
|
|
|
6940
6993
|
if (outboxAckOrdinal > 0) {
|
|
6941
6994
|
const backfillController = new AbortController();
|
|
6942
6995
|
this.backfillAbortControllers.set(record.name, backfillController);
|
|
6943
|
-
this.updateOutbox(remote, outboxAckOrdinal,
|
|
6996
|
+
this.updateOutbox(remote, outboxAckOrdinal, "backfill", backfillController.signal).catch((error) => {
|
|
6944
6997
|
if (backfillController.signal.aborted) return;
|
|
6945
6998
|
this.logger.error("Backfill failed for remote @RemoteName: @Error", remote.meta.name, error instanceof Error ? error : new Error(String(error)));
|
|
6946
6999
|
}).finally(() => {
|
|
@@ -7059,7 +7112,7 @@ var SyncManager = class {
|
|
|
7059
7112
|
}
|
|
7060
7113
|
const backfillController = new AbortController();
|
|
7061
7114
|
this.backfillAbortControllers.set(name, backfillController);
|
|
7062
|
-
this.updateOutbox(remote, 0,
|
|
7115
|
+
this.updateOutbox(remote, 0, "backfill", backfillController.signal).catch((error) => {
|
|
7063
7116
|
if (backfillController.signal.aborted) return;
|
|
7064
7117
|
this.logger.error("Backfill failed for remote @RemoteName: @Error", remote.meta.name, error instanceof Error ? error : new Error(String(error)));
|
|
7065
7118
|
}).finally(() => {
|
|
@@ -7179,7 +7232,7 @@ var SyncManager = class {
|
|
|
7179
7232
|
scopes: syncOp.scopes,
|
|
7180
7233
|
branch: syncOp.branch,
|
|
7181
7234
|
operations: syncOp.operations,
|
|
7182
|
-
errorSource: syncOp.error?.source ??
|
|
7235
|
+
errorSource: syncOp.error?.source ?? "none",
|
|
7183
7236
|
errorMessage: syncOp.error?.error.message ?? "unknown",
|
|
7184
7237
|
errorType
|
|
7185
7238
|
};
|
|
@@ -7239,7 +7292,7 @@ var SyncManager = class {
|
|
|
7239
7292
|
for (const remote of affectedRemotes) trimMailboxFromBatch(remote.channel.inbox, batch);
|
|
7240
7293
|
for (const remote of affectedRemotes) {
|
|
7241
7294
|
if (!this.remotes.has(remote.meta.name) || this.removing.has(remote.meta.name)) continue;
|
|
7242
|
-
await this.updateOutbox(remote, remote.channel.outbox.latestOrdinal,
|
|
7295
|
+
await this.updateOutbox(remote, remote.channel.outbox.latestOrdinal, "batch-triggered");
|
|
7243
7296
|
}
|
|
7244
7297
|
await this.drainPrunes();
|
|
7245
7298
|
}
|
|
@@ -7281,7 +7334,7 @@ var SyncManager = class {
|
|
|
7281
7334
|
if (this.isShutdown) return;
|
|
7282
7335
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
7283
7336
|
this.logger.error("Failed to load operations from inbox (@remote, @documentId, @error)", remote.meta.name, syncOp.documentId, err.message);
|
|
7284
|
-
const channelError = new ChannelError(
|
|
7337
|
+
const channelError = new ChannelError("inbox", err);
|
|
7285
7338
|
syncOp.failed(channelError);
|
|
7286
7339
|
remote.channel.deadLetter.add(syncOp);
|
|
7287
7340
|
remote.channel.inbox.remove(syncOp);
|
|
@@ -7294,14 +7347,14 @@ var SyncManager = class {
|
|
|
7294
7347
|
if (this.isShutdown) return;
|
|
7295
7348
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
7296
7349
|
this.logger.error("Failed to wait for job completion (@remote, @documentId, @jobId, @error)", remote.meta.name, syncOp.documentId, jobInfo.id, err.message);
|
|
7297
|
-
const channelError = new ChannelError(
|
|
7350
|
+
const channelError = new ChannelError("inbox", err);
|
|
7298
7351
|
syncOp.failed(channelError);
|
|
7299
7352
|
remote.channel.deadLetter.add(syncOp);
|
|
7300
7353
|
remote.channel.inbox.remove(syncOp);
|
|
7301
7354
|
return;
|
|
7302
7355
|
}
|
|
7303
7356
|
if (this.isShutdown) return;
|
|
7304
|
-
if (completedJobInfo.status ===
|
|
7357
|
+
if (completedJobInfo.status === "FAILED") {
|
|
7305
7358
|
const errorMessage = completedJobInfo.error?.message || "Unknown error";
|
|
7306
7359
|
this.logger.error("Failed to apply operations from inbox (@remote, @documentId, @jobId, @error)", remote.meta.name, syncOp.documentId, completedJobInfo.id, errorMessage);
|
|
7307
7360
|
syncOp.failed(this.inboxFailure(completedJobInfo.error));
|
|
@@ -7344,7 +7397,7 @@ var SyncManager = class {
|
|
|
7344
7397
|
if (this.isShutdown) return;
|
|
7345
7398
|
for (const { remote, syncOp } of items) {
|
|
7346
7399
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
7347
|
-
syncOp.failed(new ChannelError(
|
|
7400
|
+
syncOp.failed(new ChannelError("inbox", err));
|
|
7348
7401
|
remote.channel.deadLetter.add(syncOp);
|
|
7349
7402
|
remote.channel.inbox.remove(syncOp);
|
|
7350
7403
|
}
|
|
@@ -7361,7 +7414,7 @@ var SyncManager = class {
|
|
|
7361
7414
|
for (const { remote, syncOp } of items) {
|
|
7362
7415
|
if (!(syncOp.jobId in result.jobs)) {
|
|
7363
7416
|
this.logger.error("Job key missing from batch load result (@remote, @documentId, @jobId)", remote.meta.name, syncOp.documentId, syncOp.jobId);
|
|
7364
|
-
const error = new ChannelError(
|
|
7417
|
+
const error = new ChannelError("inbox", /* @__PURE__ */ new Error(`Job key '${syncOp.jobId}' missing from batch load result`));
|
|
7365
7418
|
syncOp.failed(error);
|
|
7366
7419
|
remote.channel.deadLetter.add(syncOp);
|
|
7367
7420
|
remote.channel.inbox.remove(syncOp);
|
|
@@ -7374,13 +7427,13 @@ var SyncManager = class {
|
|
|
7374
7427
|
} catch (error) {
|
|
7375
7428
|
if (this.isShutdown) continue;
|
|
7376
7429
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
7377
|
-
syncOp.failed(new ChannelError(
|
|
7430
|
+
syncOp.failed(new ChannelError("inbox", err));
|
|
7378
7431
|
remote.channel.deadLetter.add(syncOp);
|
|
7379
7432
|
remote.channel.inbox.remove(syncOp);
|
|
7380
7433
|
continue;
|
|
7381
7434
|
}
|
|
7382
7435
|
if (this.isShutdown) return;
|
|
7383
|
-
if (completedJobInfo.status ===
|
|
7436
|
+
if (completedJobInfo.status === "FAILED") {
|
|
7384
7437
|
syncOp.failed(this.inboxFailure(completedJobInfo.error));
|
|
7385
7438
|
remote.channel.deadLetter.add(syncOp);
|
|
7386
7439
|
} else syncOp.executed();
|
|
@@ -7399,7 +7452,7 @@ var SyncManager = class {
|
|
|
7399
7452
|
*/
|
|
7400
7453
|
inboxFailure(error) {
|
|
7401
7454
|
const message = error?.message || "Unknown error";
|
|
7402
|
-
return new ChannelError(
|
|
7455
|
+
return new ChannelError("inbox", /* @__PURE__ */ new Error(`Failed to apply operations: ${message}`), classifyJobFailure(error?.name ?? "Error"));
|
|
7403
7456
|
}
|
|
7404
7457
|
/**
|
|
7405
7458
|
* Where the next outbox derivation starts: at the evicted floor when there is
|
|
@@ -7426,7 +7479,7 @@ var SyncManager = class {
|
|
|
7426
7479
|
*/
|
|
7427
7480
|
evictPastOutboxBound(remote) {
|
|
7428
7481
|
const cap = this.config.maxHeldOperationsPerRemote;
|
|
7429
|
-
const queued = remote.channel.outbox.items.filter((syncOp) => syncOp.status ===
|
|
7482
|
+
const queued = remote.channel.outbox.items.filter((syncOp) => syncOp.status === -1).sort((a, b) => firstOrdinalOf(a) - firstOrdinalOf(b));
|
|
7430
7483
|
let kept = 0;
|
|
7431
7484
|
let cut = queued.length;
|
|
7432
7485
|
for (let i = 0; i < queued.length; i++) {
|
|
@@ -7518,7 +7571,7 @@ var SyncManager = class {
|
|
|
7518
7571
|
* it marked; the count is what keeps that drain from removing the remote this
|
|
7519
7572
|
* call is still adding to.
|
|
7520
7573
|
*/
|
|
7521
|
-
async updateOutbox(remote, ackOrdinal, mode =
|
|
7574
|
+
async updateOutbox(remote, ackOrdinal, mode = "backfill", signal) {
|
|
7522
7575
|
this.derivingOutboxes++;
|
|
7523
7576
|
try {
|
|
7524
7577
|
await this.deriveOutbox(remote, ackOrdinal, mode, signal);
|
|
@@ -7546,11 +7599,11 @@ var SyncManager = class {
|
|
|
7546
7599
|
const prevJobId = lastJobByDoc.get(batch.documentId);
|
|
7547
7600
|
const deps = [];
|
|
7548
7601
|
if (prevJobId) deps.push(prevJobId);
|
|
7549
|
-
if (mode ===
|
|
7602
|
+
if (mode === "batch-triggered" && prevChainJobId && prevChainJobId !== prevJobId) deps.push(prevChainJobId);
|
|
7550
7603
|
const syncOp = new SyncOperation(crypto.randomUUID(), jobId, deps, remote.meta.name, batch.documentId, [batch.scope], batch.branch, batch.operations);
|
|
7551
7604
|
syncOps.push(syncOp);
|
|
7552
7605
|
lastJobByDoc.set(batch.documentId, jobId);
|
|
7553
|
-
if (mode ===
|
|
7606
|
+
if (mode === "batch-triggered") prevChainJobId = jobId;
|
|
7554
7607
|
}
|
|
7555
7608
|
remote.channel.outbox.add(...syncOps);
|
|
7556
7609
|
this.evictPastOutboxBound(remote);
|
|
@@ -7907,7 +7960,7 @@ var Reactor = class {
|
|
|
7907
7960
|
const jobInfo = {
|
|
7908
7961
|
id: jobId,
|
|
7909
7962
|
documentId: job.documentId,
|
|
7910
|
-
status:
|
|
7963
|
+
status: "PENDING",
|
|
7911
7964
|
createdAtUtcIso,
|
|
7912
7965
|
consistencyToken: {
|
|
7913
7966
|
version: 1,
|
|
@@ -7949,7 +8002,7 @@ var Reactor = class {
|
|
|
7949
8002
|
const jobInfo = {
|
|
7950
8003
|
id: jobId,
|
|
7951
8004
|
documentId: job.documentId,
|
|
7952
|
-
status:
|
|
8005
|
+
status: "PENDING",
|
|
7953
8006
|
createdAtUtcIso,
|
|
7954
8007
|
consistencyToken: {
|
|
7955
8008
|
version: 1,
|
|
@@ -7987,7 +8040,7 @@ var Reactor = class {
|
|
|
7987
8040
|
const jobInfo = {
|
|
7988
8041
|
id: jobId,
|
|
7989
8042
|
documentId: job.documentId,
|
|
7990
|
-
status:
|
|
8043
|
+
status: "PENDING",
|
|
7991
8044
|
createdAtUtcIso,
|
|
7992
8045
|
consistencyToken: {
|
|
7993
8046
|
version: 1,
|
|
@@ -8027,7 +8080,7 @@ var Reactor = class {
|
|
|
8027
8080
|
const jobInfo = {
|
|
8028
8081
|
id: jobId,
|
|
8029
8082
|
documentId: job.documentId,
|
|
8030
|
-
status:
|
|
8083
|
+
status: "PENDING",
|
|
8031
8084
|
createdAtUtcIso,
|
|
8032
8085
|
consistencyToken: {
|
|
8033
8086
|
version: 1,
|
|
@@ -8062,7 +8115,7 @@ var Reactor = class {
|
|
|
8062
8115
|
const jobInfo = {
|
|
8063
8116
|
id: planKeyToJobId.get(jobPlan.key),
|
|
8064
8117
|
documentId: jobPlan.documentId,
|
|
8065
|
-
status:
|
|
8118
|
+
status: "PENDING",
|
|
8066
8119
|
createdAtUtcIso,
|
|
8067
8120
|
consistencyToken: {
|
|
8068
8121
|
version: 1,
|
|
@@ -8132,7 +8185,7 @@ var Reactor = class {
|
|
|
8132
8185
|
const jobInfo = {
|
|
8133
8186
|
id: planKeyToJobId.get(jobPlan.key),
|
|
8134
8187
|
documentId: jobPlan.documentId,
|
|
8135
|
-
status:
|
|
8188
|
+
status: "PENDING",
|
|
8136
8189
|
createdAtUtcIso,
|
|
8137
8190
|
consistencyToken: {
|
|
8138
8191
|
version: 1,
|
|
@@ -8221,7 +8274,7 @@ var Reactor = class {
|
|
|
8221
8274
|
return Promise.resolve({
|
|
8222
8275
|
id: jobId,
|
|
8223
8276
|
documentId: "",
|
|
8224
|
-
status:
|
|
8277
|
+
status: "FAILED",
|
|
8225
8278
|
createdAtUtcIso: now,
|
|
8226
8279
|
completedAtUtcIso: now,
|
|
8227
8280
|
error: toErrorInfo$1("Job not found"),
|
|
@@ -8572,11 +8625,12 @@ var ReactorBuilder = class {
|
|
|
8572
8625
|
if (resolver instanceof DocumentModelResolver) resolver.setModelLoadedHook((documentType) => eventBus.emit(ReactorEventTypes.MODEL_LOADED, { documentType }));
|
|
8573
8626
|
const queue = this.queueInstance ?? new InMemoryQueue(eventBus, resolver);
|
|
8574
8627
|
const jobTracker = new InMemoryJobTracker(eventBus);
|
|
8575
|
-
const
|
|
8628
|
+
const cacheConfig = {
|
|
8576
8629
|
maxDocuments: this.writeCacheConfig?.maxDocuments ?? 100,
|
|
8577
8630
|
ringBufferSize: this.writeCacheConfig?.ringBufferSize ?? 10,
|
|
8578
8631
|
keyframeInterval: this.writeCacheConfig?.keyframeInterval ?? 10
|
|
8579
|
-
}
|
|
8632
|
+
};
|
|
8633
|
+
const writeCache = new KyselyWriteCache(keyframeStore, operationStore, documentModelRegistry, cacheConfig);
|
|
8580
8634
|
await writeCache.startup();
|
|
8581
8635
|
const operationIndex = new KyselyOperationIndex(database);
|
|
8582
8636
|
const documentMetaCache = new DocumentMetaCache(operationStore, { maxDocuments: 1e3 });
|
|
@@ -8585,22 +8639,24 @@ var ReactorBuilder = class {
|
|
|
8585
8639
|
const executionScope = new KyselyExecutionScope(database, operationStore, operationIndex, keyframeStore, writeCache, documentMetaCache, collectionMembershipCache);
|
|
8586
8640
|
let executorManager = this.executorManager;
|
|
8587
8641
|
let executorStartCount = this.executorConfig.maxConcurrency ?? 1;
|
|
8588
|
-
if (!executorManager)
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
if (
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8642
|
+
if (!executorManager) {
|
|
8643
|
+
if (this.workerPool) {
|
|
8644
|
+
const pool = this.workerPool;
|
|
8645
|
+
let factory = pool.factory;
|
|
8646
|
+
if (!factory) {
|
|
8647
|
+
if (pool.db === void 0) throw new Error("unreachable: worker pool configured without db or factory");
|
|
8648
|
+
if (this.signer && !this.workerSigner) this.logger.warn("Worker pool has no signer spec; pooled workers store synthesized operations unsigned");
|
|
8649
|
+
if (this.trustPolicy && !this.workerTrustPolicy) this.logger.warn("Worker pool has no trust policy spec; pooled workers apply the default trust policy");
|
|
8650
|
+
factory = await this.createDefaultWorkerFactory(pool.numWorkers, pool.db);
|
|
8651
|
+
}
|
|
8652
|
+
const poolManager = new WorkerPoolJobExecutorManager(factory, eventBus, queue, jobTracker, this.logger, resolver, operationIndex, this.executorConfig.jobTimeoutMs, this.executorConfig.deferredJobTtlMs);
|
|
8653
|
+
executorManager = poolManager;
|
|
8654
|
+
executorStartCount = pool.numWorkers;
|
|
8655
|
+
if (resolver instanceof DocumentModelResolver) resolver.setBroadcastHook((entry) => poolManager.loadModel(entry));
|
|
8656
|
+
} 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);
|
|
8657
|
+
}
|
|
8602
8658
|
await executorManager.start(executorStartCount);
|
|
8603
|
-
const callerReadModels = Array.from(new Set([...this.readModels]));
|
|
8659
|
+
const callerReadModels = Array.from(/* @__PURE__ */ new Set([...this.readModels]));
|
|
8604
8660
|
const degradedComponents = [];
|
|
8605
8661
|
const startDegraded = (component, error) => {
|
|
8606
8662
|
degradedComponents.push({
|
|
@@ -8614,7 +8670,7 @@ var ReactorBuilder = class {
|
|
|
8614
8670
|
yieldDeadlineMs: this.executorConfig.yieldDeadlineMs ?? 50
|
|
8615
8671
|
};
|
|
8616
8672
|
const documentViewConsistencyTracker = new ConsistencyTracker();
|
|
8617
|
-
const documentView = new KyselyDocumentView(database, operationStore, operationIndex, writeCache, documentViewConsistencyTracker, featureFlags.documentDecisions ?
|
|
8673
|
+
const documentView = new KyselyDocumentView(database, operationStore, operationIndex, writeCache, documentViewConsistencyTracker, featureFlags.documentDecisions ? "StateAtDeletion" : "NotFound", readModelIndexing);
|
|
8618
8674
|
try {
|
|
8619
8675
|
await documentView.init();
|
|
8620
8676
|
} catch (error) {
|
|
@@ -8670,7 +8726,7 @@ var ReactorBuilder = class {
|
|
|
8670
8726
|
const reactor = new Reactor(this.logger, documentModelRegistry, queue, jobTracker, readModelCoordinator, this.features, documentView, documentIndexer, operationStore, eventBus, executorManager);
|
|
8671
8727
|
let syncModule = void 0;
|
|
8672
8728
|
if (this.channelScheme) {
|
|
8673
|
-
const factory = this.channelScheme ===
|
|
8729
|
+
const factory = this.channelScheme === "connect" ? new GqlRequestChannelFactory(this.logger, this.jwtHandler, queue) : new GqlResponseChannelFactory(this.logger);
|
|
8674
8730
|
syncModule = new SyncBuilder().withChannelFactory(factory).buildModule(reactor, this.logger, operationIndex, eventBus, database, this.driveContainerTypes);
|
|
8675
8731
|
await syncModule.syncManager.startup();
|
|
8676
8732
|
} else if (this.syncBuilder) {
|
|
@@ -8771,7 +8827,7 @@ var ReactorBuilder = class {
|
|
|
8771
8827
|
poolInstrumentations.push(forwarder);
|
|
8772
8828
|
this.instrumentedPools.push(forwarder);
|
|
8773
8829
|
}
|
|
8774
|
-
const { ProjectionShardManager } = await import("./projection-shard-manager-
|
|
8830
|
+
const { ProjectionShardManager } = await import("./projection-shard-manager-B-j8VYzA.js");
|
|
8775
8831
|
const manager = new ProjectionShardManager({
|
|
8776
8832
|
shardCount: config.shardCount,
|
|
8777
8833
|
db,
|
|
@@ -8805,7 +8861,7 @@ var ReactorBuilder = class {
|
|
|
8805
8861
|
return manager;
|
|
8806
8862
|
}
|
|
8807
8863
|
async createDefaultProjectionWorkerFactory() {
|
|
8808
|
-
const [{ createProjectionThreadTransport }, { projectionWorkerEntryPath }] = await Promise.all([import("./transport-
|
|
8864
|
+
const [{ createProjectionThreadTransport }, { projectionWorkerEntryPath }] = await Promise.all([import("./transport-B3G50KVd.js"), import("./projection-worker-D8uNFdwX.js")]);
|
|
8809
8865
|
return () => createProjectionThreadTransport(projectionWorkerEntryPath);
|
|
8810
8866
|
}
|
|
8811
8867
|
/**
|
|
@@ -8815,9 +8871,9 @@ var ReactorBuilder = class {
|
|
|
8815
8871
|
*/
|
|
8816
8872
|
async createDefaultWorkerFactory(numWorkers, db) {
|
|
8817
8873
|
const [{ WorkerHandle }, { createThreadTransport }, { workerEntryPath }] = await Promise.all([
|
|
8818
|
-
import("./worker-handle-
|
|
8819
|
-
import("./transport-
|
|
8820
|
-
|
|
8874
|
+
import("./worker-handle-CwWNTpUg.js"),
|
|
8875
|
+
import("./transport-CZDHzfvy.js"),
|
|
8876
|
+
Promise.resolve().then(() => worker_exports)
|
|
8821
8877
|
]);
|
|
8822
8878
|
const poolConfig = {
|
|
8823
8879
|
enabled: true,
|
|
@@ -9291,6 +9347,23 @@ const SIGNATURE_REFUSAL_CODES = [
|
|
|
9291
9347
|
"SIGNER_UNAUTHORIZED"
|
|
9292
9348
|
];
|
|
9293
9349
|
//#endregion
|
|
9350
|
+
//#region src/executor/worker/index.ts
|
|
9351
|
+
var worker_exports = /* @__PURE__ */ __exportAll({
|
|
9352
|
+
createForwardingLogger: () => createForwardingLogger,
|
|
9353
|
+
errorToInfo: () => errorToInfo,
|
|
9354
|
+
sanitizeArg: () => sanitizeArg,
|
|
9355
|
+
workerEntryPath: () => workerEntryPath
|
|
9356
|
+
});
|
|
9357
|
+
function resolveWorkerEntryPath() {
|
|
9358
|
+
const url = new URL("./entry.js", import.meta.url);
|
|
9359
|
+
if (url.protocol !== "file:") return url.href;
|
|
9360
|
+
let pathname = decodeURIComponent(url.pathname);
|
|
9361
|
+
if (/^\/[A-Za-z]:[/\\]/.test(pathname)) pathname = pathname.slice(1);
|
|
9362
|
+
return pathname;
|
|
9363
|
+
}
|
|
9364
|
+
/** Absolute path to the worker entry script for use with `new Worker(workerEntryPath)`. */
|
|
9365
|
+
const workerEntryPath = resolveWorkerEntryPath();
|
|
9366
|
+
//#endregion
|
|
9294
9367
|
//#region src/decision/sync-scope-gate.ts
|
|
9295
9368
|
/** What a subject may read of a document that is not there to be read. */
|
|
9296
9369
|
const META_ONLY = (scope) => ALWAYS_READABLE_SCOPES.has(scope);
|
|
@@ -9302,6 +9375,9 @@ const META_ONLY = (scope) => ALWAYS_READABLE_SCOPES.has(scope);
|
|
|
9302
9375
|
* path's own job, and it is the only thing this adds to the gate it wraps.
|
|
9303
9376
|
*/
|
|
9304
9377
|
var SyncScopeGate = class {
|
|
9378
|
+
gate;
|
|
9379
|
+
documentView;
|
|
9380
|
+
logger;
|
|
9305
9381
|
constructor(gate, documentView, logger) {
|
|
9306
9382
|
this.gate = gate;
|
|
9307
9383
|
this.documentView = documentView;
|