@powerhousedao/reactor 6.2.2-dev.4 → 6.2.2-dev.41

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Action, CreateDocumentActionInput, DocumentModelModule, ISigner, Operation, OperationContext, OperationWithContext, OperationWithContext as OperationWithContext$1, PHDocument, PHDocumentState, SignatureVerificationHandler, UpgradeDocumentActionInput, UpgradeManifest, UpgradeReducer, UpgradeTransition, actions as documentActions } from "@powerhousedao/shared/document-model";
1
+ import { Action, AuthRequest, AuthSubject, CreateDocumentActionInput, DocumentModelModule, ISigner, Operation, OperationContext, OperationWithContext, OperationWithContext as OperationWithContext$1, PHAuthState, PHDocument, PHDocumentState, SignatureVerificationHandler, UpgradeDocumentActionInput, UpgradeManifest, UpgradeReducer, UpgradeTransition, actions as documentActions } from "@powerhousedao/shared/document-model";
2
2
  import { DocumentDriveDocument, DriveInput, FolderNode, Node } from "@powerhousedao/shared/document-drive";
3
3
  import { ILogger } from "document-model";
4
4
  import * as kysely from "kysely";
@@ -69,6 +69,17 @@ declare enum JobQueueState {
69
69
  RUNNING = 3,
70
70
  RESOLVED = 4
71
71
  }
72
+ /**
73
+ * How a retry is accounted against the job's retry limit.
74
+ * - `CountAgainstLimit` (default): a fault; the job eventually exhausts its
75
+ * retries and fails terminally.
76
+ * - `ExemptFromLimit`: not a fault, so the attempt is not charged to the job.
77
+ * Used for concurrency conflicts, where the retry does new work.
78
+ */
79
+ declare enum RetryAccounting {
80
+ CountAgainstLimit = "count-against-limit",
81
+ ExemptFromLimit = "exempt-from-limit"
82
+ }
72
83
  /**
73
84
  * Interface for a job execution handle
74
85
  */
@@ -127,9 +138,14 @@ type JobAvailableEvent = {
127
138
  //#endregion
128
139
  //#region src/shared/types.d.ts
129
140
  /**
130
- * Information about an error including message and stack trace.
141
+ * Information about an error including its name, message and stack trace.
142
+ *
143
+ * The name is what survives the crossing out of the executor: a consumer that
144
+ * has to tell a terminal failure from a retryable one, or classify a dead
145
+ * letter, only ever sees this record rather than the thrown error.
131
146
  */
132
147
  type ErrorInfo$1 = {
148
+ name: string;
133
149
  message: string;
134
150
  stack: string;
135
151
  };
@@ -230,6 +246,11 @@ type ViewFilter = {
230
246
  branch?: string;
231
247
  scopes?: string[];
232
248
  revision?: number;
249
+ /**
250
+ * Read subject for the IReactorClient read gate; defaults to the client's
251
+ * signer. Set per request when serving many principals. Ignored by IReactor.
252
+ */
253
+ subject?: AuthSubject;
233
254
  };
234
255
  /**
235
256
  * Describes filter options for searching documents.
@@ -328,6 +349,16 @@ interface IReadModelCoordinator {
328
349
  */
329
350
  getChainDepth(): number;
330
351
  }
352
+ type ReadModelRegistrationStage = "pre_ready" | "post_ready";
353
+ /**
354
+ * Optional capability exposed by coordinators that support adding read models
355
+ * after construction. Custom and remote coordinators are not required to
356
+ * implement it.
357
+ */
358
+ interface ILiveReadModelCoordinator extends IReadModelCoordinator {
359
+ addReadModel(readModel: IReadModel, stage: ReadModelRegistrationStage): void;
360
+ }
361
+ declare function supportsLiveReadModelRegistration(coordinator: IReadModelCoordinator): coordinator is ILiveReadModelCoordinator;
331
362
  //#endregion
332
363
  //#region src/sync/types.d.ts
333
364
  declare enum ChannelScheme {
@@ -398,7 +429,13 @@ declare enum ChannelErrorSource {
398
429
  Inbox = "inbox",
399
430
  Outbox = "outbox"
400
431
  }
401
- type SyncOperationErrorType = "SIGNATURE_INVALID" | "HASH_MISMATCH" | "LIBRARY_ERROR" | "MISSING_OPERATIONS" | "EXCESSIVE_SHUFFLE" | "GRACEFUL_ABORT";
432
+ type SyncOperationErrorType = "SIGNATURE_INVALID" | "HASH_MISMATCH" | "LIBRARY_ERROR" | "MISSING_OPERATIONS" | "EXCESSIVE_SHUFFLE" | "GRACEFUL_ABORT"
433
+ /**
434
+ * An arriving auth operation did not exceed the local auth head. Exempt from
435
+ * quarantine, because reconciling the two policies needs the traffic a
436
+ * quarantine would stop.
437
+ */
438
+ | "AUTH_TIMESTAMP_NOT_MONOTONIC" /** An arriving operation carried a timestamp that is not an ISO-8601 instant. */ | "INVALID_TIMESTAMP" /** No classification applies, including rows written before the field. */ | "UNCLASSIFIED";
402
439
  type ChannelHealth = {
403
440
  state: "idle" | "running" | "error";
404
441
  lastSuccessUtcMs?: number;
@@ -491,6 +528,7 @@ type DeadLetterAddedEvent = {
491
528
  remoteName: string;
492
529
  documentId: string;
493
530
  errorSource: ChannelErrorSource;
531
+ errorType: SyncOperationErrorType;
494
532
  };
495
533
  /**
496
534
  * Status of a sync operation result.
@@ -537,6 +575,36 @@ declare class OptimisticLockError extends Error {
537
575
  declare class RevisionMismatchError extends Error {
538
576
  constructor(expected: number, actual: number);
539
577
  }
578
+ /**
579
+ * One read-set stream and the highest operation index observed on it, or -1
580
+ * if it was observed empty.
581
+ */
582
+ type AppendConditionStream = {
583
+ documentId: string;
584
+ scope: string;
585
+ branch: string;
586
+ revision: number;
587
+ };
588
+ /**
589
+ * A read-set enforced by {@link IOperationStore.apply}: the append fails if
590
+ * any stream has operations past its recorded revision.
591
+ */
592
+ type AppendCondition = {
593
+ streams: AppendConditionStream[];
594
+ };
595
+ /** Error history keeps messages, not classes, so failures match by prefix. */
596
+ declare const APPEND_CONDITION_FAILED_PREFIX = "Append condition failed: ";
597
+ /**
598
+ * A read-set stream grew before the append committed. A concurrency
599
+ * conflict, not a fault: the caller retries against the new stream heads.
600
+ */
601
+ declare class AppendConditionFailedError extends Error {
602
+ readonly condition: AppendCondition;
603
+ constructor(condition: AppendCondition);
604
+ static isError(error: unknown): error is AppendConditionFailedError;
605
+ /** True when a recorded error message is an append-condition failure. */
606
+ static isFailureMessage(message: string): boolean;
607
+ }
540
608
  /**
541
609
  * A write transaction passed to {@link IOperationStore.apply}. Accumulates
542
610
  * operations that are committed atomically when the callback returns.
@@ -550,7 +618,7 @@ interface AtomicTxn {
550
618
  * revision field and lastModified timestamp.
551
619
  */
552
620
  type DocumentRevisions = {
553
- /** Map of scope to operation index for that scope */revision: Record<string, number>; /** Latest timestamp across revisions */
621
+ /** Map of scope to operation index for that scope */revision: Record<string, number>; /** The largest operation timestamp in the document, across every scope. */
554
622
  latestTimestamp: string;
555
623
  };
556
624
  /**
@@ -571,6 +639,12 @@ interface IOperationStore {
571
639
  * returned instead of throwing. If no matching stored row is found, the
572
640
  * original error is propagated unchanged.
573
641
  *
642
+ * With an {@link AppendCondition}, the append additionally fails with
643
+ * {@link AppendConditionFailedError} — writing nothing — if any read-set
644
+ * stream has operations past its recorded revision. The written and
645
+ * read-set streams are advisory-locked in sorted key order, so concurrent
646
+ * conditional appends on overlapping streams serialize.
647
+ *
574
648
  * @param documentId - The document id
575
649
  * @param documentType - The document type identifier
576
650
  * @param scope - The operation scope (e.g. "global", "local")
@@ -578,9 +652,10 @@ interface IOperationStore {
578
652
  * @param revision - Expected current revision (optimistic lock)
579
653
  * @param fn - Callback that stages operations via {@link AtomicTxn}
580
654
  * @param signal - Optional abort signal to cancel the request
655
+ * @param condition - Optional read-set to enforce at write time
581
656
  * @returns The stored operations; empty array when no operations were staged
582
657
  */
583
- apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal): Promise<Operation[]>;
658
+ apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal, condition?: AppendCondition): Promise<Operation[]>;
584
659
  /**
585
660
  * Returns operations for a document/scope/branch whose index is greater
586
661
  * than the given revision.
@@ -627,6 +702,16 @@ interface IOperationStore {
627
702
  * @returns Object containing revision map and latest timestamp
628
703
  */
629
704
  getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
705
+ /**
706
+ * The largest operation timestamp in one stream, or undefined when it is empty.
707
+ * Distinct from {@link DocumentRevisions.latestTimestamp}, which maxes over
708
+ * every scope.
709
+ *
710
+ * Must be a real maximum, not the last-indexed operation's timestamp: a
711
+ * re-evaluation pass re-appends at a fresh index while keeping the original
712
+ * timestamp, so a later timestamp can sit behind the last row.
713
+ */
714
+ getStreamLatestTimestamp(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
630
715
  }
631
716
  /**
632
717
  * Stores periodic document snapshots (keyframes) so that document state
@@ -1045,7 +1130,8 @@ type DeadLetterRecord = {
1045
1130
  branch: string;
1046
1131
  operations: OperationWithContext$1[];
1047
1132
  errorSource: ChannelErrorSource;
1048
- errorMessage: string;
1133
+ errorMessage: string; /** Why it failed, in the closed set sync classifies failures into. */
1134
+ errorType: SyncOperationErrorType;
1049
1135
  };
1050
1136
  /**
1051
1137
  * Persists dead-lettered sync operations so they survive reactor restarts.
@@ -1152,6 +1238,51 @@ declare class DriveCollectionId {
1152
1238
  equals(other: DriveCollectionId): boolean;
1153
1239
  }
1154
1240
  //#endregion
1241
+ //#region src/cache/write-cache-types.d.ts
1242
+ /**
1243
+ * Configuration options for the write cache
1244
+ */
1245
+ type WriteCacheConfig = {
1246
+ /** Maximum number of document streams to cache (LRU eviction). Default: 1000 */maxDocuments: number; /** Number of snapshots to keep in each document's ring buffer. Default: 10 */
1247
+ ringBufferSize: number; /** Persist a keyframe snapshot every N revisions. Default: 10 */
1248
+ keyframeInterval: number;
1249
+ };
1250
+ /**
1251
+ * Unique identifier for a document stream
1252
+ */
1253
+ type DocumentStreamKey = {
1254
+ /** Document identifier */documentId: string; /** Operation scope */
1255
+ scope: string; /** Branch name */
1256
+ branch: string;
1257
+ };
1258
+ /**
1259
+ * Where a snapshot sits in its stream.
1260
+ *
1261
+ * - `Head`: the newest revision of the stream when it was stored. Only these
1262
+ * can answer a read that asks for the head.
1263
+ * - `Historical`: state at an earlier revision. Usable as a starting point to
1264
+ * replay forward from, and as an answer to a read for that same revision.
1265
+ */
1266
+ declare enum SnapshotPosition {
1267
+ Head = "head",
1268
+ Historical = "historical"
1269
+ }
1270
+ /**
1271
+ * A cached document snapshot at a specific revision
1272
+ */
1273
+ type CachedSnapshot = {
1274
+ /** The revision number of this snapshot */revision: number; /** The document state at this revision */
1275
+ document: PHDocument; /** Where this snapshot sat in the stream when it was stored */
1276
+ position: SnapshotPosition;
1277
+ };
1278
+ /**
1279
+ * Serialized keyframe snapshot for K/V store persistence
1280
+ */
1281
+ type KeyframeSnapshot = {
1282
+ /** The revision number of this keyframe */revision: number; /** Serialized document state */
1283
+ document: string;
1284
+ };
1285
+ //#endregion
1155
1286
  //#region src/cache/write/interfaces.d.ts
1156
1287
  /**
1157
1288
  * IWriteCache is a write-side projection that optimizes document state retrieval
@@ -1166,7 +1297,8 @@ interface IWriteCache {
1166
1297
  * @param documentId - The document identifier
1167
1298
  * @param scope - Operation scope
1168
1299
  * @param branch - Branch name
1169
- * @param targetRevision - The exact revision to retrieve (optional, defaults to latest)
1300
+ * @param targetRevision - Index of the last operation to apply, defaulting
1301
+ * to latest. An operation index, never `header.revision[scope]`.
1170
1302
  * @param signal - Optional abort signal to cancel the operation
1171
1303
  * @returns The complete document at the specified revision
1172
1304
  *
@@ -1192,15 +1324,19 @@ interface IWriteCache {
1192
1324
  * @param documentId - The document identifier
1193
1325
  * @param scope - Operation scope
1194
1326
  * @param branch - Branch name
1195
- * @param revision - The revision this document represents
1327
+ * @param revision - Index of the last operation this document reflects, so
1328
+ * `header.revision[scope]` is one greater. -1 for an empty scope.
1196
1329
  * @param document - The document to cache
1330
+ * @param position - Whether `revision` is the stream's head. Nothing checks
1331
+ * it: claiming `Head` for an earlier revision makes a getState() with no
1332
+ * target return stale state.
1197
1333
  *
1198
1334
  * @example
1199
1335
  * ```typescript
1200
- * cache.putState(docId, 'global', 'main', 42, document);
1336
+ * cache.putState(docId, 'global', 'main', 42, document, SnapshotPosition.Head);
1201
1337
  * ```
1202
1338
  */
1203
- putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument): void;
1339
+ putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, position: SnapshotPosition): void;
1204
1340
  /**
1205
1341
  * Invalidates (removes) cached entries for a document stream.
1206
1342
  *
@@ -1646,7 +1782,7 @@ interface IReactorClient {
1646
1782
  * @param signal - Optional abort signal to cancel the request
1647
1783
  * @returns The canonical document id
1648
1784
  */
1649
- resolveIdOrSlug(identifier: string, signal?: AbortSignal): Promise<string>;
1785
+ resolveIdOrSlug(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<string>;
1650
1786
  /**
1651
1787
  * Retrieves operations for a document.
1652
1788
  *
@@ -1884,6 +2020,7 @@ declare class ReactorClient implements IReactorClient {
1884
2020
  private documentView;
1885
2021
  readonly drives: IDriveClient;
1886
2022
  constructor(logger: ILogger, reactor: IReactor, signer: ISigner, subscriptionManager: IReactorSubscriptionManager, jobAwaiter: IJobAwaiter, documentIndexer: IDocumentIndexer, documentView: IDocumentView);
2023
+ private readSubject;
1887
2024
  /**
1888
2025
  * Retrieves a list of document model modules.
1889
2026
  */
@@ -1904,7 +2041,7 @@ declare class ReactorClient implements IReactorClient {
1904
2041
  * same lookup as the data path. Resolves against the "main" branch. Throws if
1905
2042
  * the identifier cannot be resolved or is ambiguous.
1906
2043
  */
1907
- resolveIdOrSlug(identifier: string, signal?: AbortSignal): Promise<string>;
2044
+ resolveIdOrSlug(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<string>;
1908
2045
  /**
1909
2046
  * Retrieves operations for a document
1910
2047
  */
@@ -1995,244 +2132,400 @@ declare class ReactorClient implements IReactorClient {
1995
2132
  private removeAllIncomingRelationships;
1996
2133
  }
1997
2134
  //#endregion
1998
- //#region src/executor/types.d.ts
2135
+ //#region src/cache/collection-membership-cache.d.ts
2136
+ interface ICollectionMembershipCache {
2137
+ getCollectionsForDocuments(documentIds: string[]): Promise<Record<string, string[]>>;
2138
+ invalidate(documentId: string): void;
2139
+ }
2140
+ //#endregion
2141
+ //#region src/cache/document-meta-cache-types.d.ts
1999
2142
  /**
2000
- * Represents the result of a job execution
2143
+ * Cached document metadata from the "document" scope.
2144
+ *
2145
+ * This lightweight structure holds essential document information needed by
2146
+ * the job executor without fetching full scope state. It provides an explicit
2147
+ * cross-scope contract for accessing document scope metadata.
2001
2148
  */
2002
- type JobResult = {
2003
- /** The job that was executed */job: Job; /** Whether the job executed successfully */
2004
- success: boolean; /** Error if the job failed */
2005
- error?: Error; /** The operations generated from the actions (if successful) */
2006
- operations?: Operation[];
2149
+ type CachedDocumentMeta = {
2007
2150
  /**
2008
- * Operations with context (includes ephemeral resultingState).
2009
- * Used for emitting to IDocumentView via event bus.
2151
+ * The full PHDocumentState from document.state.document.
2152
+ * Contains version, hash, isDeleted, deletedAtUtcIso, etc.
2010
2153
  */
2011
- operationsWithContext?: OperationWithContext$1[]; /** Timestamp when the job execution completed */
2012
- completedAt?: string; /** Duration of job execution in milliseconds */
2013
- duration?: number; /** Any additional metadata from the execution */
2014
- metadata?: Record<string, any>;
2015
- };
2016
- /**
2017
- * Configuration options for the job executor
2018
- */
2019
- type JobExecutorConfig = {
2020
- /** Maximum number of conflicting operations to skip when reshuffling. */maxSkipThreshold?: number; /** Maximum number of concurrent jobs to execute */
2021
- maxConcurrency?: number; /** Maximum time in milliseconds a job can run before being considered timed out */
2022
- jobTimeoutMs?: number; /** Base delay in milliseconds for exponential backoff retries */
2023
- retryBaseDelayMs?: number; /** Maximum delay in milliseconds for exponential backoff retries */
2024
- retryMaxDelayMs?: number;
2025
- /** Maximum elapsed milliseconds before yielding to the main thread between actions.
2026
- * Keeps the UI responsive when processing large batches. */
2027
- yieldDeadlineMs?: number;
2028
- };
2029
- /**
2030
- * Event types for the job executor
2031
- */
2032
- declare const JobExecutorEventTypes: {
2033
- readonly JOB_STARTED: 20000;
2034
- readonly JOB_COMPLETED: 20001;
2035
- readonly JOB_FAILED: 20002;
2036
- readonly EXECUTOR_STARTED: 20003;
2037
- readonly EXECUTOR_STOPPED: 20004;
2038
- };
2039
- /**
2040
- * Event data for job execution events
2041
- */
2042
- type JobStartedEvent = {
2043
- job: Job;
2044
- startedAt: string;
2154
+ state: PHDocumentState;
2045
2155
  /**
2046
- * Identifier of the executor that took the job. For the worker pool this is
2047
- * the thread-worker id (e.g. "reactor-worker-3"); for the in-process simple
2048
- * manager it is "in-process-<index>". Optional for backwards compatibility
2049
- * with consumers built before the field was added.
2156
+ * The document type (from header), cached for convenience.
2050
2157
  */
2051
- workerId?: string;
2052
- };
2053
- type JobCompletedEvent = {
2054
- job: Job;
2055
- result: JobResult; /** See {@link JobStartedEvent.workerId}. */
2056
- workerId?: string;
2057
- };
2058
- type JobFailedEvent = {
2059
- job: Job;
2060
- error: string;
2061
- willRetry: boolean;
2062
- retryCount: number; /** See {@link JobStartedEvent.workerId}. */
2063
- workerId?: string;
2064
- };
2065
- type ExecutorStartedEvent = {
2066
- config: JobExecutorConfig;
2067
- startedAt: string;
2068
- };
2069
- type ExecutorStoppedEvent = {
2070
- stoppedAt: string;
2071
- graceful: boolean;
2072
- };
2073
- /**
2074
- * Status information for the job executor manager
2075
- */
2076
- type ExecutorManagerStatus = {
2077
- /** Whether the manager is currently running */isRunning: boolean; /** Number of executor instances managed */
2078
- numExecutors: number; /** Number of jobs currently being processed */
2079
- activeJobs: number; /** Total number of jobs processed since start */
2080
- totalJobsProcessed: number;
2081
- };
2082
- //#endregion
2083
- //#region src/executor/worker/protocol.d.ts
2084
- /**
2085
- * A JSON-clonable value safe to send across the worker IPC boundary.
2086
- *
2087
- * The shape mirrors the structured-clone subset used by the parent's
2088
- * sanitizer: primitives, arrays, plain objects, plus the explicit
2089
- * {@link ErrorInfo} shape for marshalled Errors.
2090
- *
2091
- * @see Wire Protocol Reference wiki page
2092
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2093
- */
2094
- type SanitizedArg = null | boolean | number | string | ErrorInfo | SanitizedArg[] | {
2095
- [key: string]: SanitizedArg;
2096
- };
2097
- /**
2098
- * Structured representation of an Error for IPC transport.
2099
- *
2100
- * Class instances cannot be structured-cloned across worker boundaries,
2101
- * so Errors are flattened into this shape on the worker side and
2102
- * reconstructed on the parent side.
2103
- *
2104
- * @see Wire Protocol Reference wiki page
2105
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2106
- */
2107
- type ErrorInfo = {
2108
- name: string;
2109
- message: string;
2110
- stack?: string;
2111
- cause?: ErrorInfo;
2112
- };
2113
- /**
2114
- * Reference to a module that the worker should `import()` at runtime,
2115
- * along with the named export to pluck out as the factory.
2116
- *
2117
- * Exactly one of `packageName` or `filePath` is provided.
2118
- *
2119
- * @see Wire Protocol Reference wiki page
2120
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2121
- */
2122
- type ModuleRef = {
2123
- /** Bare-specifier package name (resolved by the worker's module loader). */packageName: string; /** Named export within the module to invoke as the factory. */
2124
- exportName: string;
2125
- } | {
2126
- /** Absolute or worker-resolvable file path to import. */filePath: string; /** Named export within the module to invoke as the factory. */
2127
- exportName: string;
2128
- };
2129
- /**
2130
- * Factory specification shared by the signature verifier and document
2131
- * model spec channels. The worker imports `module.exportName` and invokes
2132
- * it with `initArgs` to obtain the actual instance.
2133
- *
2134
- * `initArgs` must be JSON-clonable.
2135
- *
2136
- * @see Wire Protocol Reference wiki page
2137
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2138
- */
2139
- type FactorySpec = {
2140
- module: ModuleRef;
2141
- initArgs?: SanitizedArg;
2158
+ documentType: string;
2159
+ /**
2160
+ * The revision of the document scope when this metadata was captured.
2161
+ * Used for cache invalidation and consistency checks.
2162
+ */
2163
+ documentScopeRevision: number;
2142
2164
  };
2143
2165
  /**
2144
- * Factory spec for the signature verifier the worker should instantiate.
2145
- *
2146
- * Structurally identical to {@link FactorySpec}; the alias exists so call
2147
- * sites read intent-fully.
2148
- *
2149
- * @see Wire Protocol Reference wiki page
2150
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2151
- */
2152
- type SignatureVerifierSpec = FactorySpec;
2153
- /**
2154
- * Factory spec for a document model module the worker should instantiate.
2155
- *
2156
- * Structurally identical to {@link FactorySpec}; the alias exists so call
2157
- * sites read intent-fully.
2166
+ * Interface for the document metadata cache.
2158
2167
  *
2159
- * @see Wire Protocol Reference wiki page
2160
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2161
- */
2162
- type DocumentModelSpec = FactorySpec;
2163
- /**
2164
- * One entry in the document model manifest the worker materializes on
2165
- * startup (or extends lazily via `load-model`).
2168
+ * This cache provides an explicit cross-scope contract for accessing document
2169
+ * scope metadata. It solves the problem where job execution in one scope (e.g.,
2170
+ * "global") needs access to document scope state (version, isDeleted, etc.)
2171
+ * which may be stale in scope-specific caches or keyframes.
2166
2172
  *
2167
- * @see Wire Protocol Reference wiki page
2168
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2173
+ * The cache supports:
2174
+ * - Latest metadata retrieval with LRU caching
2175
+ * - Historical metadata reconstruction for reshuffling scenarios
2176
+ * - Eager updates after document scope operations
2169
2177
  */
2170
- type ModelManifestEntry = {
2171
- /** Document type identifier (e.g. "ph/account"). */documentType: string; /** Document model version this entry registers. */
2172
- version: string; /** Factory spec the worker imports and invokes to obtain the model. */
2173
- spec: DocumentModelSpec;
2174
- };
2175
- /**
2176
- * JSON-clonable Postgres connection info passed to the worker so it can
2177
- * open its own pool. Storage-specific wiring may extend this shape in
2178
- * later phases.
2179
- *
2180
- * @see Wire Protocol Reference wiki page
2181
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2182
- */
2183
- type DbConfig = {
2184
- host: string;
2185
- port: number;
2186
- database: string;
2187
- user: string;
2188
- password: string;
2189
- ssl?: boolean;
2190
- applicationName?: string;
2191
- poolSize?: number;
2178
+ interface IDocumentMetaCache {
2192
2179
  /**
2193
- * Maximum time (ms) a caller will wait to acquire a connection from the
2194
- * pool before pg.Pool throws. When omitted, pg defaults to 0 (unlimited
2195
- * wait), which hides acquire-starvation as silent latency.
2180
+ * Retrieves the LATEST document metadata from cache or rebuilds from operations.
2181
+ *
2182
+ * On cache miss, fetches all document scope operations and reconstructs the
2183
+ * current PHDocumentState by applying UPGRADE_DOCUMENT and DELETE_DOCUMENT
2184
+ * operations.
2185
+ *
2186
+ * @param documentId - The document identifier
2187
+ * @param branch - Branch name
2188
+ * @param signal - Optional abort signal to cancel the operation
2189
+ * @returns The cached or rebuilt document metadata
2190
+ * @throws {Error} "Operation aborted" if signal is aborted
2191
+ * @throws {Error} If document not found (no CREATE_DOCUMENT operation)
2196
2192
  */
2197
- connectionTimeoutMillis?: number;
2193
+ getDocumentMeta(documentId: string, branch: string, signal?: AbortSignal): Promise<CachedDocumentMeta>;
2198
2194
  /**
2199
- * How long (ms) an idle connection stays open before pg closes it. When
2200
- * omitted, pg defaults to 10000.
2195
+ * Rebuilds document metadata at a SPECIFIC revision (always rebuilds, no caching).
2196
+ *
2197
+ * Used during reshuffling when operations need to be inserted at a previous
2198
+ * revision and we need the document scope state as of that point in time.
2199
+ *
2200
+ * @param documentId - The document identifier
2201
+ * @param branch - Branch name
2202
+ * @param targetRevision - The document scope revision to reconstruct up to
2203
+ * @param signal - Optional abort signal to cancel the operation
2204
+ * @returns Document metadata as of the target revision
2205
+ * @throws {Error} "Operation aborted" if signal is aborted
2206
+ * @throws {Error} If document not found
2201
2207
  */
2202
- idleTimeoutMillis?: number;
2203
- };
2208
+ rebuildAtRevision(documentId: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<CachedDocumentMeta>;
2209
+ /**
2210
+ * Eagerly updates cached metadata after document scope operations.
2211
+ *
2212
+ * Called by the job executor after CREATE_DOCUMENT, UPGRADE_DOCUMENT, or
2213
+ * DELETE_DOCUMENT operations to keep the cache current.
2214
+ *
2215
+ * @param documentId - The document identifier
2216
+ * @param branch - Branch name
2217
+ * @param meta - The new metadata to cache
2218
+ */
2219
+ putDocumentMeta(documentId: string, branch: string, meta: CachedDocumentMeta): void;
2220
+ /**
2221
+ * Invalidates cached document metadata.
2222
+ *
2223
+ * Call before reshuffling operations that modify the document scope, or
2224
+ * when document state may have changed externally.
2225
+ *
2226
+ * @param documentId - The document identifier
2227
+ * @param branch - Optional branch to narrow invalidation (if omitted, all branches)
2228
+ * @returns Number of entries invalidated
2229
+ */
2230
+ invalidate(documentId: string, branch?: string): number;
2231
+ /**
2232
+ * Clears all cached document metadata.
2233
+ */
2234
+ clear(): void;
2235
+ /**
2236
+ * Performs startup initialization.
2237
+ */
2238
+ startup(): Promise<void>;
2239
+ /**
2240
+ * Performs graceful shutdown.
2241
+ */
2242
+ shutdown(): Promise<void>;
2243
+ }
2244
+ //#endregion
2245
+ //#region src/storage/kysely/types.d.ts
2246
+ interface OperationTable {
2247
+ id: Generated<number>;
2248
+ jobId: string;
2249
+ opId: string;
2250
+ prevOpId: string;
2251
+ writeTimestampUtcMs: Generated<Date>;
2252
+ documentId: string;
2253
+ documentType: string;
2254
+ scope: string;
2255
+ branch: string;
2256
+ timestampUtcMs: Date;
2257
+ index: number;
2258
+ action: unknown;
2259
+ skip: number;
2260
+ error?: string | null;
2261
+ deniedReason?: string | null;
2262
+ hash: string;
2263
+ }
2264
+ interface KeyframeTable {
2265
+ id: Generated<number>;
2266
+ documentId: string;
2267
+ documentType: string;
2268
+ scope: string;
2269
+ branch: string;
2270
+ revision: number;
2271
+ document: unknown;
2272
+ createdAt: Generated<Date>;
2273
+ }
2274
+ interface DocumentCollectionTable {
2275
+ documentId: string;
2276
+ collectionId: string;
2277
+ joinedOrdinal: bigint;
2278
+ leftOrdinal: bigint | null;
2279
+ }
2280
+ interface OperationIndexOperationTable {
2281
+ ordinal: Generated<number>;
2282
+ opId: string;
2283
+ documentId: string;
2284
+ documentType: string;
2285
+ scope: string;
2286
+ branch: string;
2287
+ timestampUtcMs: string;
2288
+ writeTimestampUtcMs: Generated<Date>;
2289
+ index: number;
2290
+ skip: number;
2291
+ hash: string;
2292
+ action: unknown;
2293
+ deniedReason?: string | null;
2294
+ sourceRemote: Generated<string>;
2295
+ }
2296
+ interface SyncRemoteTable {
2297
+ name: string;
2298
+ collection_id: string;
2299
+ channel_type: string;
2300
+ channel_id: string;
2301
+ remote_name: string;
2302
+ channel_parameters: unknown;
2303
+ filter_document_ids: unknown;
2304
+ filter_scopes: unknown;
2305
+ filter_branch: string;
2306
+ push_state: string;
2307
+ push_last_success_utc_ms: string | null;
2308
+ push_last_failure_utc_ms: string | null;
2309
+ push_failure_count: number;
2310
+ pull_state: string;
2311
+ pull_last_success_utc_ms: string | null;
2312
+ pull_last_failure_utc_ms: string | null;
2313
+ pull_failure_count: number;
2314
+ created_at: Generated<Date>;
2315
+ updated_at: Generated<Date>;
2316
+ }
2317
+ interface SyncCursorTable {
2318
+ remote_name: string;
2319
+ cursor_type: string;
2320
+ cursor_ordinal: bigint;
2321
+ last_synced_at_utc_ms: string | null;
2322
+ updated_at: Generated<Date>;
2323
+ }
2204
2324
  /**
2205
- * Configuration for the executor worker pool.
2325
+ * Kysely table definition for the `sync_dead_letters` table.
2326
+ */
2327
+ interface SyncDeadLetterTable {
2328
+ ordinal: Generated<number>;
2329
+ id: string;
2330
+ job_id: string;
2331
+ job_dependencies: unknown;
2332
+ remote_name: string;
2333
+ document_id: string;
2334
+ scopes: unknown;
2335
+ branch: string;
2336
+ operations: unknown;
2337
+ error_source: string;
2338
+ error_message: string;
2339
+ error_type: Generated<string>;
2340
+ created_at: Generated<Date>;
2341
+ }
2342
+ interface Database$1 {
2343
+ Operation: OperationTable;
2344
+ Keyframe: KeyframeTable;
2345
+ document_collections: DocumentCollectionTable;
2346
+ operation_index_operations: OperationIndexOperationTable;
2347
+ sync_remotes: SyncRemoteTable;
2348
+ sync_cursors: SyncCursorTable;
2349
+ sync_dead_letters: SyncDeadLetterTable;
2350
+ }
2351
+ interface DocumentTable {
2352
+ id: string;
2353
+ createdAt: Generated<Date>;
2354
+ updatedAt: Generated<Date>;
2355
+ }
2356
+ interface DocumentRelationshipTable {
2357
+ id: Generated<string>;
2358
+ sourceId: string;
2359
+ targetId: string;
2360
+ relationshipType: string;
2361
+ metadata: unknown;
2362
+ createdAt: Generated<Date>;
2363
+ updatedAt: Generated<Date>;
2364
+ }
2365
+ interface IndexerStateTable {
2366
+ id: Generated<number>;
2367
+ lastOperationId: number;
2368
+ lastOperationTimestamp: Generated<Date>;
2369
+ }
2370
+ interface DocumentIndexerDatabase {
2371
+ Document: DocumentTable;
2372
+ DocumentRelationship: DocumentRelationshipTable;
2373
+ IndexerState: IndexerStateTable;
2374
+ }
2375
+ //#endregion
2376
+ //#region src/executor/worker/protocol.d.ts
2377
+ /**
2378
+ * A JSON-clonable value safe to send across the worker IPC boundary.
2206
2379
  *
2207
- * Mirrors the `workerPool` sub-config on {@link JobExecutorConfig};
2208
- * a later card wires this into the executor config.
2380
+ * The shape mirrors the structured-clone subset used by the parent's
2381
+ * sanitizer: primitives, arrays, plain objects, plus the explicit
2382
+ * {@link ErrorInfo} shape for marshalled Errors.
2209
2383
  *
2210
2384
  * @see Wire Protocol Reference wiki page
2211
2385
  * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2212
2386
  */
2213
- type WorkerPoolConfig = {
2214
- /** Whether the worker pool is active; when false the executor runs in-process. */enabled: boolean; /** Number of worker instances to spawn. */
2215
- numWorkers: number; /** Worker isolation mode. */
2216
- workerType: "thread" | "process"; /** Optional heartbeat interval in milliseconds. */
2217
- heartbeatMs?: number; /** Optional per-worker Postgres pool size override. */
2218
- workerPgPoolSize?: number;
2387
+ type SanitizedArg = null | boolean | number | string | ErrorInfo | SanitizedArg[] | {
2388
+ [key: string]: SanitizedArg;
2219
2389
  };
2220
2390
  /**
2221
- * Payload the worker reports back when a job's write phase is complete.
2391
+ * Structured representation of an Error for IPC transport.
2222
2392
  *
2223
- * Parent fills `collectionMemberships` at emission time, so it is
2224
- * intentionally absent from the worker -> parent message.
2393
+ * Class instances cannot be structured-cloned across worker boundaries,
2394
+ * so Errors are flattened into this shape on the worker side and
2395
+ * reconstructed on the parent side.
2225
2396
  *
2226
2397
  * @see Wire Protocol Reference wiki page
2227
2398
  * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2228
2399
  */
2229
- type JobWriteReadyPayload = {
2230
- operations: OperationWithContext$1[];
2231
- jobMeta: JobMeta;
2400
+ type ErrorInfo = {
2401
+ name: string;
2402
+ message: string;
2403
+ stack?: string;
2404
+ cause?: ErrorInfo;
2232
2405
  };
2233
2406
  /**
2234
- * Initializes a freshly spawned worker with the configuration and
2235
- * factories it needs to start executing jobs.
2407
+ * Reference to a module that the worker should `import()` at runtime,
2408
+ * along with the named export to pluck out as the factory.
2409
+ *
2410
+ * Exactly one of `packageName` or `filePath` is provided.
2411
+ *
2412
+ * @see Wire Protocol Reference wiki page
2413
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2414
+ */
2415
+ type ModuleRef = {
2416
+ /** Bare-specifier package name (resolved by the worker's module loader). */packageName: string; /** Named export within the module to invoke as the factory. */
2417
+ exportName: string;
2418
+ } | {
2419
+ /** Absolute or worker-resolvable file path to import. */filePath: string; /** Named export within the module to invoke as the factory. */
2420
+ exportName: string;
2421
+ };
2422
+ /**
2423
+ * Factory specification shared by the signature verifier and document
2424
+ * model spec channels. The worker imports `module.exportName` and invokes
2425
+ * it with `initArgs` to obtain the actual instance.
2426
+ *
2427
+ * `initArgs` must be JSON-clonable.
2428
+ *
2429
+ * @see Wire Protocol Reference wiki page
2430
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2431
+ */
2432
+ type FactorySpec = {
2433
+ module: ModuleRef;
2434
+ initArgs?: SanitizedArg;
2435
+ };
2436
+ /**
2437
+ * Factory spec for the signature verifier the worker should instantiate.
2438
+ *
2439
+ * Structurally identical to {@link FactorySpec}; the alias exists so call
2440
+ * sites read intent-fully.
2441
+ *
2442
+ * @see Wire Protocol Reference wiki page
2443
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2444
+ */
2445
+ type SignatureVerifierSpec = FactorySpec;
2446
+ /**
2447
+ * Factory spec for a document model module the worker should instantiate.
2448
+ *
2449
+ * Structurally identical to {@link FactorySpec}; the alias exists so call
2450
+ * sites read intent-fully.
2451
+ *
2452
+ * @see Wire Protocol Reference wiki page
2453
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2454
+ */
2455
+ type DocumentModelSpec = FactorySpec;
2456
+ /**
2457
+ * One entry in the document model manifest the worker materializes on
2458
+ * startup (or extends lazily via `load-model`).
2459
+ *
2460
+ * @see Wire Protocol Reference wiki page
2461
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2462
+ */
2463
+ type ModelManifestEntry = {
2464
+ /** Document type identifier (e.g. "ph/account"). */documentType: string; /** Document model version this entry registers. */
2465
+ version: string; /** Factory spec the worker imports and invokes to obtain the model. */
2466
+ spec: DocumentModelSpec;
2467
+ };
2468
+ /**
2469
+ * JSON-clonable Postgres connection info passed to the worker so it can
2470
+ * open its own pool. Storage-specific wiring may extend this shape in
2471
+ * later phases.
2472
+ *
2473
+ * @see Wire Protocol Reference wiki page
2474
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2475
+ */
2476
+ type DbConfig = {
2477
+ host: string;
2478
+ port: number;
2479
+ database: string;
2480
+ user: string;
2481
+ password: string;
2482
+ ssl?: boolean;
2483
+ applicationName?: string;
2484
+ poolSize?: number;
2485
+ /**
2486
+ * Maximum time (ms) a caller will wait to acquire a connection from the
2487
+ * pool before pg.Pool throws. When omitted, pg defaults to 0 (unlimited
2488
+ * wait), which hides acquire-starvation as silent latency.
2489
+ */
2490
+ connectionTimeoutMillis?: number;
2491
+ /**
2492
+ * How long (ms) an idle connection stays open before pg closes it. When
2493
+ * omitted, pg defaults to 10000.
2494
+ */
2495
+ idleTimeoutMillis?: number;
2496
+ };
2497
+ /**
2498
+ * Configuration for the executor worker pool.
2499
+ *
2500
+ * Mirrors the `workerPool` sub-config on {@link JobExecutorConfig};
2501
+ * a later card wires this into the executor config.
2502
+ *
2503
+ * @see Wire Protocol Reference wiki page
2504
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2505
+ */
2506
+ type WorkerPoolConfig = {
2507
+ /** Whether the worker pool is active; when false the executor runs in-process. */enabled: boolean; /** Number of worker instances to spawn. */
2508
+ numWorkers: number; /** Worker isolation mode. */
2509
+ workerType: "thread" | "process"; /** Optional heartbeat interval in milliseconds. */
2510
+ heartbeatMs?: number; /** Optional per-worker Postgres pool size override. */
2511
+ workerPgPoolSize?: number;
2512
+ };
2513
+ /**
2514
+ * Payload the worker reports back when a job's write phase is complete.
2515
+ *
2516
+ * Parent fills `collectionMemberships` at emission time, so it is
2517
+ * intentionally absent from the worker -> parent message.
2518
+ *
2519
+ * @see Wire Protocol Reference wiki page
2520
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2521
+ */
2522
+ type JobWriteReadyPayload = {
2523
+ operations: OperationWithContext$1[];
2524
+ jobMeta: JobMeta;
2525
+ };
2526
+ /**
2527
+ * Initializes a freshly spawned worker with the configuration and
2528
+ * factories it needs to start executing jobs.
2236
2529
  *
2237
2530
  * @see Wire Protocol Reference wiki page
2238
2531
  * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
@@ -2244,7 +2537,8 @@ type InitMessage = {
2244
2537
  poolConfig: WorkerPoolConfig;
2245
2538
  db: DbConfig; /** Omitted = the worker performs no executor-side signature verification. */
2246
2539
  signatureVerifier?: SignatureVerifierSpec;
2247
- models: ModelManifestEntry[];
2540
+ models: ModelManifestEntry[]; /** Omitted = the worker builds its executor with the built-in defaults. */
2541
+ executorConfig?: JobExecutorConfig;
2248
2542
  };
2249
2543
  /**
2250
2544
  * Dispatches a job to the worker for execution.
@@ -2425,504 +2719,873 @@ type PoolAcquireSamplesMessage = {
2425
2719
  */
2426
2720
  type WorkerMessage = ReadyMessage | ResultMessage | ModelLoadedMessage | ModelLoadFailedMessage | LogMessage | HeartbeatMessage | MetricsMessage | PoolAcquireSamplesMessage;
2427
2721
  //#endregion
2428
- //#region src/executor/interfaces.d.ts
2722
+ //#region src/core/model-sources.d.ts
2723
+ /** An importable file holding one or more document-model exports. */
2724
+ type FileModelSource = {
2725
+ filePath: string;
2726
+ exportName?: string;
2727
+ };
2728
+ /** An importable package specifier holding one or more document-model exports. */
2729
+ type PackageModelSource = {
2730
+ packageName: string;
2731
+ subpath?: string;
2732
+ exportName?: string;
2733
+ };
2429
2734
  /**
2430
- * Snapshot of the single in-flight slot maintained by an {@link IExecutorWorker}.
2735
+ * A source of document models: a live module, an importable file, or an
2736
+ * importable package. File and package sources can cross a worker-thread
2737
+ * boundary (workers re-import them); a live module cannot.
2431
2738
  */
2432
- type WorkerInFlightSnapshot = {
2433
- correlationId: string;
2434
- jobId: string;
2739
+ type DocumentModelSource = DocumentModelModule<any> | FileModelSource | PackageModelSource;
2740
+ //#endregion
2741
+ //#region src/registry/interfaces.d.ts
2742
+ type RegistrationResult<T> = {
2743
+ status: "success";
2744
+ item: T;
2745
+ } | {
2746
+ status: "error";
2747
+ item: T;
2748
+ error: Error;
2435
2749
  };
2436
2750
  /**
2437
- * Outcome of a worker-side job execution.
2751
+ * Loader that asynchronously resolves a document type to a
2752
+ * {@link DocumentModelSource}. Used by the queue to gate CREATE_DOCUMENT
2753
+ * jobs until the required model is available in the registry.
2438
2754
  *
2439
- * `result` mirrors the in-process `JobResult` exactly. `writeReady` carries
2440
- * the operations + jobMeta the parent needs to emit `JOB_WRITE_READY`, and is
2441
- * present only when the worker produced operations. It is absent on failure
2442
- * and on success-with-no-operations.
2755
+ * Return an importable source ({ filePath } or { packageName }) whenever
2756
+ * possible: the resolver registers the resolved models on the host registry
2757
+ * and broadcasts importable sources to executor workers. A live
2758
+ * DocumentModelModule is also valid but host-only — it cannot cross a
2759
+ * worker-thread boundary, so worker pools will not receive it.
2443
2760
  */
2444
- type WorkerExecutionOutcome = {
2445
- result: JobResult;
2446
- writeReady?: JobWriteReadyPayload;
2447
- };
2761
+ interface IDocumentModelLoader {
2762
+ load(documentType: string): Promise<DocumentModelSource>;
2763
+ }
2448
2764
  /**
2449
- * Parent-side handle for a single executor worker.
2450
- *
2451
- * Implementations wrap an IPC transport (worker_threads, child_process, or a
2452
- * test fake) and expose a transport-agnostic surface that the worker-pool
2453
- * manager uses to dispatch jobs. The handle owns one worker's lifecycle
2454
- * (`start` -> `execute`* -> `shutdown`) and bounds its in-flight map to a
2455
- * single entry; `SimpleJobExecutor` is single-threaded inside the worker, so
2456
- * concurrent dispatches would race its caches.
2765
+ * Registry for managing document model modules.
2766
+ * Provides centralized access to document models' reducers, utils, and specifications.
2767
+ * Supports version-aware module storage and upgrade manifest management.
2457
2768
  */
2458
- interface IExecutorWorker {
2459
- /** Stable identifier of the worker (mirrors `InitMessage.workerId`). */
2460
- readonly workerId: string;
2461
- /** Zero-based index within the pool, used for sticky routing. */
2462
- readonly index: number;
2769
+ interface IDocumentModelRegistry {
2463
2770
  /**
2464
- * Spawn the worker (if not already started), send the `init` payload and
2465
- * resolve when the worker replies with `ready`.
2771
+ * Register multiple modules at once.
2772
+ * Modules without a version field default to version 1.
2773
+ * Invalid or duplicate modules are skipped without breaking registration of the remaining modules.
2774
+ *
2775
+ * @param modules Document model modules to register
2776
+ * @returns Array of results, one per module, indicating success or failure
2466
2777
  */
2467
- start(): Promise<void>;
2778
+ registerModules(...modules: DocumentModelModule<any>[]): RegistrationResult<DocumentModelModule<any>>[];
2468
2779
  /**
2469
- * Dispatch a job to the worker and resolve with its outcome — the
2470
- * `JobResult` and, on success-with-operations, a `writeReady` payload
2471
- * the parent will enrich and re-emit. Rejects with a transport-level
2472
- * error if the worker exits, aborts, or times out before producing a
2473
- * result.
2780
+ * Unregister all versions of the specified document types.
2781
+ *
2782
+ * @param documentTypes The document types to unregister
2783
+ * @returns true if all modules were unregistered, false if any were not found
2474
2784
  */
2475
- execute(job: Job, signal?: AbortSignal): Promise<WorkerExecutionOutcome>;
2785
+ unregisterModules(...documentTypes: string[]): boolean;
2476
2786
  /**
2477
- * Request cancellation of the in-flight job (if any). The handle posts an
2478
- * `abort` message; if the worker fails to reply within its grace window it
2479
- * is force-terminated.
2787
+ * Get a specific document model module by document type and optional version.
2788
+ * If version is not specified, returns the latest version.
2789
+ *
2790
+ * @param documentType The document type identifier
2791
+ * @param version Optional version number to retrieve
2792
+ * @returns The document model module
2793
+ * @throws ModuleNotFoundError if the document type or version is not registered
2480
2794
  */
2481
- abort(correlationId: string, reason?: string): void;
2795
+ getModule(documentType: string, version?: number): DocumentModelModule<any>;
2482
2796
  /**
2483
- * Stop the worker. When `graceful` is true the handle waits for the
2484
- * in-flight job to settle (up to `graceMs`) before terminating; otherwise
2485
- * the worker is terminated immediately.
2797
+ * Get all registered document model modules.
2798
+ *
2799
+ * @returns Array of all registered modules
2486
2800
  */
2487
- shutdown(graceful: boolean, graceMs?: number): Promise<void>;
2801
+ getAllModules(): DocumentModelModule<any>[];
2488
2802
  /**
2489
- * Register an additional document model on the running worker. Resolves
2490
- * when the worker replies with `model-loaded`; rejects when it replies
2491
- * with `model-load-failed` or the worker exits before answering.
2803
+ * Clear all registered modules and upgrade manifests.
2492
2804
  */
2493
- loadModel(entry: ModelManifestEntry, signal?: AbortSignal): Promise<void>;
2494
- /** True when no job is currently in flight. */
2495
- isIdle(): boolean;
2496
- /** Snapshot of the in-flight slot, or null when idle. */
2497
- getInFlight(): WorkerInFlightSnapshot | null;
2498
- }
2499
- /**
2500
- * Simple interface for executing a job.
2501
- * A JobExecutor simply takes a job and executes it - nothing more.
2502
- */
2503
- interface IJobExecutor {
2805
+ clear(): void;
2504
2806
  /**
2505
- * Execute a single job.
2506
- * @param job - The job to execute
2507
- * @returns Promise that resolves to the job result
2807
+ * Get all supported versions for a document type, sorted in ascending order.
2808
+ *
2809
+ * @param documentType The document type identifier
2810
+ * @returns Array of version numbers sorted ascending
2811
+ * @throws ModuleNotFoundError if no modules are registered for the document type
2508
2812
  */
2509
- executeJob(job: Job, signal?: AbortSignal): Promise<JobResult>;
2510
- }
2511
- /**
2512
- * Interface for managing multiple job executors.
2513
- * Listens for 'jobAvailable' events from the event bus, pulls jobs from the queue,
2514
- * and coordinates the distribution of jobs across multiple executor instances.
2515
- */
2516
- interface IJobExecutorManager {
2813
+ getSupportedVersions(documentType: string): number[];
2517
2814
  /**
2518
- * Start the executor manager.
2519
- * Begins listening for 'jobAvailable' events and dispatching to executors.
2815
+ * Get the latest (highest) version number for a document type.
2520
2816
  *
2521
- * @param numExecutors - Number of executor instances to create
2522
- * @returns Promise that resolves when the manager is started
2817
+ * @param documentType The document type identifier
2818
+ * @returns The highest version number registered for this document type
2819
+ * @throws ModuleNotFoundError if no modules are registered for the document type
2523
2820
  */
2524
- start(numExecutors: number): Promise<void>;
2821
+ getLatestVersion(documentType: string): number;
2525
2822
  /**
2526
- * Stop the executor manager.
2823
+ * Register upgrade manifests that define upgrade paths between versions.
2824
+ * Invalid or duplicate manifests are skipped without breaking registration of the remaining manifests.
2527
2825
  *
2528
- * @param graceful - Whether to wait for current jobs to complete
2529
- * @returns Promise that resolves when the manager is stopped
2826
+ * @param manifests Upgrade manifests to register
2827
+ * @returns Array of results, one per manifest, indicating success or failure
2530
2828
  */
2531
- stop(graceful?: boolean): Promise<void>;
2829
+ registerUpgradeManifests(...manifests: UpgradeManifest<readonly number[]>[]): RegistrationResult<UpgradeManifest<readonly number[]>>[];
2532
2830
  /**
2533
- * Get all managed executor instances.
2831
+ * Unregister upgrade manifests for the specified document types.
2832
+ * @param documentTypes The document types whose upgrade manifests should be unregistered
2833
+ * @returns true if all modules were unregistered, false if any were not found
2834
+ **/
2835
+ unregisterUpgradeManifests(...documentTypes: string[]): boolean;
2836
+ /**
2837
+ * Get the upgrade manifest for a document type.
2534
2838
  *
2535
- * @returns Array of executor instances
2839
+ * @param documentType The document type identifier
2840
+ * @returns The upgrade manifest
2841
+ * @throws ManifestNotFoundError if no manifest is registered for the document type
2536
2842
  */
2537
- getExecutors(): IJobExecutor[];
2843
+ getUpgradeManifest(documentType: string): UpgradeManifest<readonly number[]>;
2538
2844
  /**
2539
- * Get the current status of the manager.
2845
+ * Compute the upgrade path from one version to another.
2846
+ * Returns the sequence of upgrade transitions needed.
2540
2847
  *
2541
- * @returns The current manager status
2848
+ * @param documentType The document type identifier
2849
+ * @param fromVersion The starting version
2850
+ * @param toVersion The target version
2851
+ * @returns Array of upgrade transitions in order
2852
+ * @throws DowngradeNotSupportedError if toVersion is less than fromVersion
2853
+ * @throws ManifestNotFoundError if no upgrade manifest is registered
2854
+ * @throws MissingUpgradeTransitionError if any transition in the path is missing
2542
2855
  */
2543
- getStatus(): ExecutorManagerStatus;
2856
+ computeUpgradePath(documentType: string, fromVersion: number, toVersion: number): UpgradeTransition[];
2857
+ /**
2858
+ * Get the upgrade reducer for a single-step version transition.
2859
+ *
2860
+ * @param documentType The document type identifier
2861
+ * @param fromVersion The starting version
2862
+ * @param toVersion The target version (must be fromVersion + 1)
2863
+ * @returns The upgrade reducer function
2864
+ * @throws InvalidUpgradeStepError if toVersion is not fromVersion + 1
2865
+ * @throws ManifestNotFoundError if no upgrade manifest is registered
2866
+ * @throws MissingUpgradeTransitionError if the transition is not found
2867
+ */
2868
+ getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
2544
2869
  }
2545
2870
  //#endregion
2546
- //#region src/job-tracker/interfaces.d.ts
2871
+ //#region src/cache/buffer/ring-buffer.d.ts
2547
2872
  /**
2548
- * Interface for tracking job lifecycle status.
2549
- * Maintains job state throughout execution: PENDING RUNNING COMPLETED/FAILED.
2873
+ * RingBuffer is a generic circular buffer implementation that stores a fixed number
2874
+ * of items. When the buffer is full, new items overwrite the oldest items.
2875
+ *
2876
+ * This implementation maintains O(1) time complexity for push operations and provides
2877
+ * items in chronological order (oldest to newest) via getAll().
2878
+ *
2879
+ * @template T - The type of items stored in the buffer
2550
2880
  */
2551
- interface IJobTracker {
2552
- /**
2553
- * Register a new job with PENDING status.
2554
- *
2555
- * @param jobInfo - The job information to register
2556
- */
2557
- registerJob(jobInfo: JobInfo): void;
2881
+ declare class RingBuffer<T> {
2882
+ private buffer;
2883
+ private head;
2884
+ private size;
2885
+ private capacity;
2886
+ constructor(capacity: number);
2558
2887
  /**
2559
- * Update a job's status to RUNNING.
2888
+ * Adds an item to the buffer. If the buffer is full, overwrites the oldest item.
2560
2889
  *
2561
- * @param jobId - The job ID to mark as running
2890
+ * @param item - The item to add
2562
2891
  */
2563
- markRunning(jobId: string): void;
2892
+ push(item: T): void;
2564
2893
  /**
2565
- * Mark a job as failed.
2894
+ * Returns all items in the buffer in chronological order (oldest to newest).
2566
2895
  *
2567
- * @param jobId - The job ID to mark as failed
2568
- * @param error - Error information including message and stack trace
2569
- * @param job - Optional full job object for debugging purposes
2896
+ * @returns Array of items in insertion order
2570
2897
  */
2571
- markFailed(jobId: string, error: ErrorInfo$1, job?: Job): void;
2898
+ getAll(): T[];
2572
2899
  /**
2573
- * Retrieve the current status of a job.
2574
- *
2575
- * @param jobId - The job ID to query
2576
- * @returns The job information, or null if the job is not found
2900
+ * Clears all items from the buffer.
2577
2901
  */
2578
- getJobStatus(jobId: string): JobInfo | null;
2902
+ clear(): void;
2579
2903
  /**
2580
- * Shutdown the job tracker and clean up resources.
2581
- * Unsubscribes from all event bus subscriptions.
2904
+ * Gets the current number of items in the buffer.
2582
2905
  */
2583
- shutdown(): void;
2906
+ get length(): number;
2584
2907
  }
2585
2908
  //#endregion
2586
- //#region src/queue/interfaces.d.ts
2909
+ //#region src/cache/kysely-write-cache.d.ts
2910
+ type DocumentStream = {
2911
+ key: string;
2912
+ ringBuffer: RingBuffer<CachedSnapshot>;
2913
+ };
2587
2914
  /**
2588
- * Interface for a job queue that manages write operations.
2589
- * Internally organizes jobs by documentId, scope, and branch to ensure proper ordering.
2590
- * Emits events to the event bus when new jobs are available for consumption.
2915
+ * In-memory write cache with keyframe persistence for PHDocuments.
2916
+ *
2917
+ * Caches document snapshots in ring buffers with LRU eviction. On cache miss,
2918
+ * rebuilds documents from nearest keyframe or full operation history.
2919
+ *
2920
+ * **Performance Characteristics:**
2921
+ * - Cache hit: O(1) lookup in ring buffer
2922
+ * - Cold miss: O(n) where n is total operation count, or O(k) where k is operations since keyframe
2923
+ * - Warm miss: O(m) where m is operations since cached revision
2924
+ * - Eviction: O(1) for LRU tracking and removal
2925
+ *
2926
+ * **Thread Safety:**
2927
+ * Not thread-safe. Designed for single-threaded job executor environment.
2928
+ * External synchronization required for concurrent access across multiple executors.
2929
+ *
2930
+ * **Example:**
2931
+ * ```typescript
2932
+ * const cache = new KyselyWriteCache(
2933
+ * keyframeStore,
2934
+ * operationStore,
2935
+ * registry,
2936
+ * { maxDocuments: 1000, ringBufferSize: 10, keyframeInterval: 10 }
2937
+ * );
2938
+ *
2939
+ * await cache.startup();
2940
+ *
2941
+ * // Retrieve or rebuild document
2942
+ * const doc = await cache.getState(docId, docType, scope, branch, revision);
2943
+ *
2944
+ * // Cache result after job execution
2945
+ * cache.putState(docId, docType, scope, branch, newRevision, updatedDoc);
2946
+ *
2947
+ * await cache.shutdown();
2948
+ * ```
2591
2949
  */
2592
- interface IQueue {
2950
+ declare class KyselyWriteCache implements IWriteCache {
2951
+ private streams;
2952
+ private lruTracker;
2953
+ private keyframeStore;
2954
+ private operationStore;
2955
+ private registry;
2956
+ private config;
2957
+ constructor(keyframeStore: IKeyframeStore, operationStore: IOperationStore, registry: IDocumentModelRegistry, config: WriteCacheConfig);
2958
+ withScopedStores(operationStore: IOperationStore, keyframeStore: IKeyframeStore): KyselyWriteCache;
2593
2959
  /**
2594
- * Add a new job to the queue.
2595
- * Jobs are automatically organized by documentId, scope, and branch internally.
2596
- * Emits a 'jobAvailable' event to the event bus when the job is queued.
2597
- * @param job - The job to add to the queue
2598
- * @returns Promise that resolves when the job is queued
2960
+ * Initializes the write cache.
2961
+ * Currently a no-op as keyframe store lifecycle is managed externally.
2599
2962
  */
2600
- enqueue(job: Job): Promise<void>;
2963
+ startup(): Promise<void>;
2601
2964
  /**
2602
- * Get the next job to execute for a specific document/scope/branch combination.
2603
- * @param documentId - The document ID to get jobs for
2604
- * @param scope - The scope to get jobs for
2605
- * @param branch - The branch to get jobs for
2606
- * @param signal - Optional abort signal to cancel the request
2607
- * @returns Promise that resolves to the next job execution handle or null if no jobs available
2965
+ * Shuts down the write cache.
2966
+ * Currently a no-op as keyframe store lifecycle is managed externally.
2608
2967
  */
2609
- dequeue(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
2968
+ shutdown(): Promise<void>;
2610
2969
  /**
2611
- * Get the next available job from any queue.
2612
- * @param signal - Optional abort signal to cancel the request
2613
- * @returns Promise that resolves to the next job execution handle or null if no jobs available
2970
+ * Retrieves document state at a specific revision from cache or rebuilds it.
2971
+ *
2972
+ * Note: this returns a _shallow_ copy of the document.
2973
+ *
2974
+ * Cache hit path: Returns cached snapshot if available (O(1))
2975
+ * Warm miss path: Rebuilds from cached base revision + incremental ops
2976
+ * Cold miss path: Rebuilds from keyframe or from scratch using all operations
2977
+ *
2978
+ * @param documentId - The document identifier
2979
+ * @param scope - The operation scope
2980
+ * @param branch - The operation branch
2981
+ * @param targetRevision - The target revision, or undefined for newest
2982
+ * @param signal - Optional abort signal to cancel the operation
2983
+ * @returns The document at the target revision
2984
+ * @throws {Error} "Operation aborted" if signal is aborted
2985
+ * @throws {ModuleNotFoundError} If document type not registered in registry
2986
+ * @throws {Error} "Failed to rebuild document" if operation store fails
2987
+ * @throws {Error} If reducer throws during operation application
2988
+ * @throws {Error} If document serialization fails
2614
2989
  */
2615
- dequeueNext(signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
2990
+ getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
2616
2991
  /**
2617
- * Get the next available job whose routing metadata satisfies the predicate.
2618
- * Walks ready sub-queue heads in queue insertion order, skips heads whose document
2619
- * is currently executing (same isDocumentExecuting gate as dequeueNext), and returns
2620
- * the first head for which predicate returns true.
2621
- * Returns null when paused, when nothing matches, or when the queue is empty.
2622
- * Rejects if signal is already aborted.
2623
- * @param predicate - Filter applied to JobRoutingMeta of each candidate head
2624
- * @param signal - Optional abort signal to cancel the request
2625
- * @returns Promise that resolves to the first matching job execution handle or null
2992
+ * Stores a document snapshot in the cache at a specific revision.
2993
+ *
2994
+ * The cached document is a shallow copy of the input with its operation history
2995
+ * truncated to the last operation per scope and its clipboard cleared. This keeps
2996
+ * memory use and copy costs constant regardless of operation count. Consumers of
2997
+ * getState() must not rely on the full operation history being present; the only
2998
+ * guaranteed invariant is that operations[scope].at(-1) reflects the latest
2999
+ * operation index for each scope.
3000
+ *
3001
+ * Updates LRU tracker and may evict least recently used stream if at capacity.
3002
+ * Asynchronously persists keyframes at configured intervals (fire-and-forget).
3003
+ *
3004
+ * @param documentId - The document identifier
3005
+ * @param scope - The operation scope
3006
+ * @param branch - The operation branch
3007
+ * @param revision - The revision number
3008
+ * @param document - The document to cache
3009
+ * @throws {Error} If document serialization fails
2626
3010
  */
2627
- dequeueNextMatching(predicate: (meta: JobRoutingMeta) => boolean, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
3011
+ putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, position: SnapshotPosition): void;
3012
+ private store;
2628
3013
  /**
2629
- * Get the current size of the queue for a specific document/scope/branch.
2630
- * @param documentId - The document ID
2631
- * @param scope - The scope
2632
- * @param branch - The branch
2633
- * @returns Promise that resolves to the number of jobs in the queue
3014
+ * Invalidates cached document streams.
3015
+ *
3016
+ * Supports three invalidation scopes:
3017
+ * - Document-level: invalidate(documentId) - removes all streams for document
3018
+ * - Scope-level: invalidate(documentId, scope) - removes all branches for scope
3019
+ * - Stream-level: invalidate(documentId, scope, branch) - removes specific stream
3020
+ *
3021
+ * @param documentId - The document identifier
3022
+ * @param scope - Optional scope to narrow invalidation
3023
+ * @param branch - Optional branch to narrow invalidation (requires scope)
3024
+ * @returns The number of streams evicted
2634
3025
  */
2635
- size(documentId: string, scope: string, branch: string): Promise<number>;
3026
+ invalidate(documentId: string, scope?: string, branch?: string): number;
2636
3027
  /**
2637
- * Get the total size of all queues.
2638
- * @returns Promise that resolves to the total number of jobs across all queues
2639
- */
2640
- totalSize(): Promise<number>;
2641
- /**
2642
- * Remove a specific job from the queue.
2643
- * @param jobId - The ID of the job to remove
2644
- * @returns Promise that resolves to true if job was removed, false if not found
2645
- */
2646
- remove(jobId: string): Promise<boolean>;
2647
- /**
2648
- * Clear all jobs for a specific document/scope/branch combination.
2649
- * @param documentId - The document ID
2650
- * @param scope - The scope
2651
- * @param branch - The branch
2652
- * @returns Promise that resolves when the queue is cleared
2653
- */
2654
- clear(documentId: string, scope: string, branch: string): Promise<void>;
2655
- /**
2656
- * Clear all jobs from all queues.
2657
- * @returns Promise that resolves when all queues are cleared
2658
- */
2659
- clearAll(): Promise<void>;
2660
- /**
2661
- * Check if there are any jobs in the queue.
2662
- * @returns Promise that resolves to true if there are jobs, false otherwise
2663
- */
2664
- hasJobs(): Promise<boolean>;
2665
- /**
2666
- * Mark a job as completed.
2667
- * @param jobId - The ID of the job to mark as completed
2668
- * @returns Promise that resolves when the job is marked as completed
3028
+ * Clears the entire cache, removing all cached document streams.
3029
+ * Resets LRU tracking state. This operation always succeeds.
2669
3030
  */
2670
- completeJob(jobId: string): Promise<void>;
3031
+ clear(): void;
2671
3032
  /**
2672
- * Mark a job as failed.
2673
- * @param jobId - The ID of the job to mark as failed
2674
- * @param error - Optional error information
2675
- * @returns Promise that resolves when the job is marked as failed
3033
+ * Retrieves a specific stream for a document. Exposed on the implementation
3034
+ * for testing, but not on the interface.
3035
+ *
3036
+ * @internal
2676
3037
  */
2677
- failJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
3038
+ getStream(documentId: string, scope: string, branch: string): DocumentStream | undefined;
3039
+ private findNearestKeyframe;
3040
+ private coldMissRebuild;
2678
3041
  /**
2679
- * Retry a failed job.
2680
- * @param jobId - The ID of the job to retry
2681
- * @param error - Optional error information from the failure
2682
- * @returns Promise that resolves when the job is requeued for retry
3042
+ * Copies the current document revisions onto the document. Overwrites the
3043
+ * requested scope revision with the target revision, if provided.
2683
3044
  */
2684
- retryJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
3045
+ private stampRevisions;
3046
+ /** The stored operation at `index`, or undefined if it is no longer there. */
3047
+ private operationAt;
2685
3048
  /**
2686
- * Returns true if and only if all jobs have been resolved.
3049
+ * Resolves which module version to use for a given operation in phase 2.
3050
+ *
3051
+ * Uses the validated-upgrade boundary rules from D7:
3052
+ * - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary
3053
+ * - Otherwise: timestamp fallback
3054
+ * - Falls back to final module version when neither is decidable
2687
3055
  */
2688
- get isDrained(): boolean;
3056
+ private resolveModuleVersionForOp;
3057
+ private warmMissRebuild;
3058
+ private findNearestOlderSnapshot;
3059
+ private makeStreamKey;
3060
+ private getOrCreateStream;
3061
+ private isKeyframeRevision;
3062
+ }
3063
+ //#endregion
3064
+ //#region src/storage/kysely/store.d.ts
3065
+ declare class KyselyOperationStore implements IOperationStore {
3066
+ private db;
3067
+ private trx?;
3068
+ constructor(db: Kysely<Database$1>);
3069
+ private get queryExecutor();
3070
+ withTransaction(trx: Transaction<Database$1>): KyselyOperationStore;
3071
+ apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal, condition?: AppendCondition): Promise<Operation[]>;
3072
+ private resolveUniqueConstraint;
3073
+ private executeApply;
2689
3074
  /**
2690
- * Blocks the queue from accepting new jobs.
2691
- * @param onDrained - Optional callback to call when the queue is drained
3075
+ * Locks the written stream and every read-set stream, in sorted key order
3076
+ * so that overlapping concurrent appends serialize rather than deadlock.
3077
+ * The locks are still taken one row at a time, so the query preserves that
3078
+ * order. It must stay separate from the guarded insert, which would
3079
+ * otherwise read a snapshot taken before the locks were held.
2692
3080
  */
2693
- block(onDrained?: () => void): void;
3081
+ private acquireStreamLocks;
2694
3082
  /**
2695
- * Unblocks the queue from accepting new jobs.
3083
+ * Inserts the staged operations with the condition compiled in as a WHERE
3084
+ * NOT EXISTS guard, making the check and the append one statement. Returns
3085
+ * the rows inserted; zero means the guard failed and nothing was written.
2696
3086
  */
2697
- unblock(): void;
3087
+ private insertGuarded;
3088
+ private findIdempotentReplay;
3089
+ getSince(documentId: string, scope: string, branch: string, revision: number, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
3090
+ getSinceId(id: number, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<OperationWithContext$1>>;
3091
+ getConflicting(documentId: string, scope: string, branch: string, minTimestamp: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
3092
+ getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
3093
+ getStreamLatestTimestamp(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
3094
+ private rowToOperation;
3095
+ private rowToOperationWithContext;
2698
3096
  }
2699
3097
  //#endregion
2700
- //#region src/read-models/types.d.ts
2701
- interface ViewStateTable {
2702
- readModelId: string;
2703
- lastOrdinal: number;
2704
- lastOperationTimestamp: Generated<Date>;
2705
- }
2706
- interface DocumentSnapshotTable {
2707
- id: Generated<string>;
2708
- documentId: string;
2709
- slug: string | null;
2710
- name: string | null;
2711
- scope: string;
2712
- branch: string;
2713
- content: unknown;
2714
- documentType: string;
2715
- lastOperationIndex: number;
2716
- lastOperationHash: string;
2717
- lastUpdatedAt: Generated<Date>;
2718
- snapshotVersion: Generated<number>;
2719
- identifiers: unknown;
2720
- metadata: unknown;
2721
- isDeleted: Generated<boolean>;
2722
- deletedAt: Date | null;
2723
- }
2724
- interface SlugMappingTable {
2725
- slug: string;
2726
- documentId: string;
2727
- scope: string;
2728
- branch: string;
2729
- createdAt: Generated<Date>;
2730
- updatedAt: Generated<Date>;
3098
+ //#region src/storage/kysely/keyframe-store.d.ts
3099
+ declare class KyselyKeyframeStore implements IKeyframeStore {
3100
+ private db;
3101
+ private trx?;
3102
+ constructor(db: Kysely<Database$1>);
3103
+ private get queryExecutor();
3104
+ withTransaction(trx: Transaction<Database$1>): KyselyKeyframeStore;
3105
+ putKeyframe(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, signal?: AbortSignal): Promise<void>;
3106
+ findNearestKeyframe(documentId: string, scope: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<{
3107
+ revision: number;
3108
+ document: PHDocument;
3109
+ } | undefined>;
3110
+ listKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<Array<{
3111
+ scope: string;
3112
+ branch: string;
3113
+ revision: number;
3114
+ document: PHDocument;
3115
+ }>>;
3116
+ deleteKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<number>;
2731
3117
  }
2732
- interface ProcessorCursorTable {
2733
- processorId: string;
2734
- factoryId: string;
2735
- driveId: string;
2736
- processorIndex: number;
2737
- lastOrdinal: Generated<number>;
2738
- status: Generated<string>;
2739
- lastError: string | null;
2740
- lastErrorTimestamp: Date | null;
2741
- createdAt: Generated<Date>;
2742
- updatedAt: Generated<Date>;
3118
+ //#endregion
3119
+ //#region src/executor/execution-scope.d.ts
3120
+ interface ExecutionStores {
3121
+ operationStore: IOperationStore;
3122
+ operationIndex: IOperationIndex;
3123
+ writeCache: IWriteCache;
3124
+ documentMetaCache: IDocumentMetaCache;
3125
+ collectionMembershipCache: ICollectionMembershipCache;
2743
3126
  }
2744
- interface DocumentViewDatabase {
2745
- ViewState: ViewStateTable;
2746
- DocumentSnapshot: DocumentSnapshotTable;
2747
- SlugMapping: SlugMappingTable;
2748
- ProcessorCursor: ProcessorCursorTable;
3127
+ interface IExecutionScope {
3128
+ run<T>(fn: (stores: ExecutionStores) => Promise<T>, signal?: AbortSignal): Promise<T>;
2749
3129
  }
2750
- type InsertableDocumentSnapshot = Insertable<DocumentSnapshotTable>;
2751
3130
  //#endregion
2752
- //#region src/core/model-sources.d.ts
2753
- /** An importable file holding one or more document-model exports. */
2754
- type FileModelSource = {
2755
- filePath: string;
2756
- exportName?: string;
2757
- };
2758
- /** An importable package specifier holding one or more document-model exports. */
2759
- type PackageModelSource = {
2760
- packageName: string;
2761
- subpath?: string;
2762
- exportName?: string;
2763
- };
3131
+ //#region src/executor/types.d.ts
2764
3132
  /**
2765
- * A source of document models: a live module, an importable file, or an
2766
- * importable package. File and package sources can cross a worker-thread
2767
- * boundary (workers re-import them); a live module cannot.
3133
+ * Represents the result of a job execution
2768
3134
  */
2769
- type DocumentModelSource = DocumentModelModule<any> | FileModelSource | PackageModelSource;
2770
- //#endregion
2771
- //#region src/registry/interfaces.d.ts
2772
- type RegistrationResult<T> = {
2773
- status: "success";
2774
- item: T;
2775
- } | {
2776
- status: "error";
2777
- item: T;
2778
- error: Error;
3135
+ type JobResult = {
3136
+ /** The job that was executed */job: Job; /** Whether the job executed successfully */
3137
+ success: boolean; /** Error if the job failed */
3138
+ error?: Error; /** The operations generated from the actions (if successful) */
3139
+ operations?: Operation[];
3140
+ /**
3141
+ * Operations with context (includes ephemeral resultingState).
3142
+ * Used for emitting to IDocumentView via event bus.
3143
+ */
3144
+ operationsWithContext?: OperationWithContext$1[]; /** Timestamp when the job execution completed */
3145
+ completedAt?: string; /** Duration of job execution in milliseconds */
3146
+ duration?: number; /** Any additional metadata from the execution */
3147
+ metadata?: Record<string, any>;
2779
3148
  };
2780
3149
  /**
2781
- * Loader that asynchronously resolves a document type to a
2782
- * {@link DocumentModelSource}. Used by the queue to gate CREATE_DOCUMENT
2783
- * jobs until the required model is available in the registry.
3150
+ * Enforcement the reactor performs, each off by default.
2784
3151
  *
2785
- * Return an importable source ({ filePath } or { packageName }) whenever
2786
- * possible: the resolver registers the resolved models on the host registry
2787
- * and broadcasts importable sources to executor workers. A live
2788
- * DocumentModelModule is also valid but host-only — it cannot cross a
2789
- * worker-thread boundary, so worker pools will not receive it.
2790
- */
2791
- interface IDocumentModelLoader {
2792
- load(documentType: string): Promise<DocumentModelSource>;
2793
- }
2794
- /**
2795
- * Registry for managing document model modules.
2796
- * Provides centralized access to document models' reducers, utils, and specifications.
2797
- * Supports version-aware module storage and upgrade manifest management.
3152
+ * An evaluation made while replaying is part of the document's history, so two
3153
+ * reactors that share documents and disagree on these diverge. A flag is turned
3154
+ * on for a set of reactors that sync with each other, not for one node.
2798
3155
  */
2799
- interface IDocumentModelRegistry {
2800
- /**
2801
- * Register multiple modules at once.
2802
- * Modules without a version field default to version 1.
2803
- * Invalid or duplicate modules are skipped without breaking registration of the remaining modules.
2804
- *
2805
- * @param modules Document model modules to register
2806
- * @returns Array of results, one per module, indicating success or failure
2807
- */
2808
- registerModules(...modules: DocumentModelModule<any>[]): RegistrationResult<DocumentModelModule<any>>[];
2809
- /**
2810
- * Unregister all versions of the specified document types.
2811
- *
2812
- * @param documentTypes The document types to unregister
2813
- * @returns true if all modules were unregistered, false if any were not found
2814
- */
2815
- unregisterModules(...documentTypes: string[]): boolean;
2816
- /**
2817
- * Get a specific document model module by document type and optional version.
2818
- * If version is not specified, returns the latest version.
2819
- *
2820
- * @param documentType The document type identifier
2821
- * @param version Optional version number to retrieve
2822
- * @returns The document model module
2823
- * @throws ModuleNotFoundError if the document type or version is not registered
2824
- */
2825
- getModule(documentType: string, version?: number): DocumentModelModule<any>;
3156
+ type ReactorFeatureFlags = {
2826
3157
  /**
2827
- * Get all registered document model modules.
2828
- *
2829
- * @returns Array of all registered modules
3158
+ * Decide whether an operation may be admitted by building a decision model
3159
+ * over the document stream, rather than reading the deleted flag from the
3160
+ * document meta cache. Deletion then takes effect from the deleting
3161
+ * operation's position rather than for the whole document.
2830
3162
  */
2831
- getAllModules(): DocumentModelModule<any>[];
3163
+ documentDecisions: boolean;
2832
3164
  /**
2833
- * Clear all registered modules and upgrade manifests.
3165
+ * Evaluate the auth policy by reading the auth scope as a second projection.
3166
+ * Requires documentDecisions.
2834
3167
  */
2835
- clear(): void;
2836
- /**
2837
- * Get all supported versions for a document type, sorted in ascending order.
2838
- *
2839
- * @param documentType The document type identifier
2840
- * @returns Array of version numbers sorted ascending
2841
- * @throws ModuleNotFoundError if no modules are registered for the document type
3168
+ authEnforcement: boolean;
3169
+ };
3170
+ /**
3171
+ * Configuration options for the job executor
3172
+ */
3173
+ type JobExecutorConfig = {
3174
+ /** Feature flags; anything unset is off. */featureFlags?: Partial<ReactorFeatureFlags>; /** Maximum number of conflicting operations to skip when reshuffling. */
3175
+ maxSkipThreshold?: number; /** Maximum number of concurrent jobs to execute */
3176
+ maxConcurrency?: number; /** Maximum time in milliseconds a job can run before being considered timed out */
3177
+ jobTimeoutMs?: number; /** Base delay in milliseconds for exponential backoff retries */
3178
+ retryBaseDelayMs?: number; /** Maximum delay in milliseconds for exponential backoff retries */
3179
+ retryMaxDelayMs?: number;
3180
+ /** Maximum elapsed milliseconds before yielding to the main thread between actions.
3181
+ * Keeps the UI responsive when processing large batches. */
3182
+ yieldDeadlineMs?: number;
3183
+ };
3184
+ /**
3185
+ * Event types for the job executor
3186
+ */
3187
+ declare const JobExecutorEventTypes: {
3188
+ readonly JOB_STARTED: 20000;
3189
+ readonly JOB_COMPLETED: 20001;
3190
+ readonly JOB_FAILED: 20002;
3191
+ readonly EXECUTOR_STARTED: 20003;
3192
+ readonly EXECUTOR_STOPPED: 20004;
3193
+ };
3194
+ /**
3195
+ * Event data for job execution events
3196
+ */
3197
+ type JobStartedEvent = {
3198
+ job: Job;
3199
+ startedAt: string;
3200
+ /**
3201
+ * Identifier of the executor that took the job. For the worker pool this is
3202
+ * the thread-worker id (e.g. "reactor-worker-3"); for the in-process simple
3203
+ * manager it is "in-process-<index>". Optional for backwards compatibility
3204
+ * with consumers built before the field was added.
2842
3205
  */
2843
- getSupportedVersions(documentType: string): number[];
3206
+ workerId?: string;
3207
+ };
3208
+ type JobCompletedEvent = {
3209
+ job: Job;
3210
+ result: JobResult; /** See {@link JobStartedEvent.workerId}. */
3211
+ workerId?: string;
3212
+ };
3213
+ type JobFailedEvent = {
3214
+ job: Job;
3215
+ error: string;
3216
+ willRetry: boolean;
3217
+ retryCount: number; /** See {@link JobStartedEvent.workerId}. */
3218
+ workerId?: string;
3219
+ };
3220
+ type ExecutorStartedEvent = {
3221
+ config: JobExecutorConfig;
3222
+ startedAt: string;
3223
+ };
3224
+ type ExecutorStoppedEvent = {
3225
+ stoppedAt: string;
3226
+ graceful: boolean;
3227
+ };
3228
+ /**
3229
+ * Status information for the job executor manager
3230
+ */
3231
+ type ExecutorManagerStatus = {
3232
+ /** Whether the manager is currently running */isRunning: boolean; /** Number of executor instances managed */
3233
+ numExecutors: number; /** Number of jobs currently being processed */
3234
+ activeJobs: number; /** Total number of jobs processed since start */
3235
+ totalJobsProcessed: number;
3236
+ };
3237
+ //#endregion
3238
+ //#region src/executor/interfaces.d.ts
3239
+ /**
3240
+ * Snapshot of the single in-flight slot maintained by an {@link IExecutorWorker}.
3241
+ */
3242
+ type WorkerInFlightSnapshot = {
3243
+ correlationId: string;
3244
+ jobId: string;
3245
+ };
3246
+ /**
3247
+ * Outcome of a worker-side job execution.
3248
+ *
3249
+ * `result` mirrors the in-process `JobResult` exactly. `writeReady` carries
3250
+ * the operations + jobMeta the parent needs to emit `JOB_WRITE_READY`, and is
3251
+ * present only when the worker produced operations. It is absent on failure
3252
+ * and on success-with-no-operations.
3253
+ */
3254
+ type WorkerExecutionOutcome = {
3255
+ result: JobResult;
3256
+ writeReady?: JobWriteReadyPayload;
3257
+ };
3258
+ /**
3259
+ * Parent-side handle for a single executor worker.
3260
+ *
3261
+ * Implementations wrap an IPC transport (worker_threads, child_process, or a
3262
+ * test fake) and expose a transport-agnostic surface that the worker-pool
3263
+ * manager uses to dispatch jobs. The handle owns one worker's lifecycle
3264
+ * (`start` -> `execute`* -> `shutdown`) and bounds its in-flight map to a
3265
+ * single entry; `SimpleJobExecutor` is single-threaded inside the worker, so
3266
+ * concurrent dispatches would race its caches.
3267
+ */
3268
+ interface IExecutorWorker {
3269
+ /** Stable identifier of the worker (mirrors `InitMessage.workerId`). */
3270
+ readonly workerId: string;
3271
+ /** Zero-based index within the pool, used for sticky routing. */
3272
+ readonly index: number;
2844
3273
  /**
2845
- * Get the latest (highest) version number for a document type.
2846
- *
2847
- * @param documentType The document type identifier
2848
- * @returns The highest version number registered for this document type
2849
- * @throws ModuleNotFoundError if no modules are registered for the document type
3274
+ * Spawn the worker (if not already started), send the `init` payload and
3275
+ * resolve when the worker replies with `ready`.
2850
3276
  */
2851
- getLatestVersion(documentType: string): number;
3277
+ start(): Promise<void>;
2852
3278
  /**
2853
- * Register upgrade manifests that define upgrade paths between versions.
2854
- * Invalid or duplicate manifests are skipped without breaking registration of the remaining manifests.
2855
- *
2856
- * @param manifests Upgrade manifests to register
2857
- * @returns Array of results, one per manifest, indicating success or failure
3279
+ * Dispatch a job to the worker and resolve with its outcome — the
3280
+ * `JobResult` and, on success-with-operations, a `writeReady` payload
3281
+ * the parent will enrich and re-emit. Rejects with a transport-level
3282
+ * error if the worker exits, aborts, or times out before producing a
3283
+ * result.
2858
3284
  */
2859
- registerUpgradeManifests(...manifests: UpgradeManifest<readonly number[]>[]): RegistrationResult<UpgradeManifest<readonly number[]>>[];
3285
+ execute(job: Job, signal?: AbortSignal): Promise<WorkerExecutionOutcome>;
2860
3286
  /**
2861
- * Unregister upgrade manifests for the specified document types.
2862
- * @param documentTypes The document types whose upgrade manifests should be unregistered
2863
- * @returns true if all modules were unregistered, false if any were not found
2864
- **/
2865
- unregisterUpgradeManifests(...documentTypes: string[]): boolean;
3287
+ * Request cancellation of the in-flight job (if any). The handle posts an
3288
+ * `abort` message; if the worker fails to reply within its grace window it
3289
+ * is force-terminated.
3290
+ */
3291
+ abort(correlationId: string, reason?: string): void;
2866
3292
  /**
2867
- * Get the upgrade manifest for a document type.
3293
+ * Stop the worker. When `graceful` is true the handle waits for the
3294
+ * in-flight job to settle (up to `graceMs`) before terminating; otherwise
3295
+ * the worker is terminated immediately.
3296
+ */
3297
+ shutdown(graceful: boolean, graceMs?: number): Promise<void>;
3298
+ /**
3299
+ * Register an additional document model on the running worker. Resolves
3300
+ * when the worker replies with `model-loaded`; rejects when it replies
3301
+ * with `model-load-failed` or the worker exits before answering.
3302
+ */
3303
+ loadModel(entry: ModelManifestEntry, signal?: AbortSignal): Promise<void>;
3304
+ /** True when no job is currently in flight. */
3305
+ isIdle(): boolean;
3306
+ /** Snapshot of the in-flight slot, or null when idle. */
3307
+ getInFlight(): WorkerInFlightSnapshot | null;
3308
+ }
3309
+ /**
3310
+ * Simple interface for executing a job.
3311
+ * A JobExecutor simply takes a job and executes it - nothing more.
3312
+ */
3313
+ interface IJobExecutor {
3314
+ /**
3315
+ * Execute a single job.
3316
+ * @param job - The job to execute
3317
+ * @returns Promise that resolves to the job result
3318
+ */
3319
+ executeJob(job: Job, signal?: AbortSignal): Promise<JobResult>;
3320
+ }
3321
+ /**
3322
+ * Interface for managing multiple job executors.
3323
+ * Listens for 'jobAvailable' events from the event bus, pulls jobs from the queue,
3324
+ * and coordinates the distribution of jobs across multiple executor instances.
3325
+ */
3326
+ interface IJobExecutorManager {
3327
+ /**
3328
+ * Start the executor manager.
3329
+ * Begins listening for 'jobAvailable' events and dispatching to executors.
2868
3330
  *
2869
- * @param documentType The document type identifier
2870
- * @returns The upgrade manifest
2871
- * @throws ManifestNotFoundError if no manifest is registered for the document type
3331
+ * @param numExecutors - Number of executor instances to create
3332
+ * @returns Promise that resolves when the manager is started
2872
3333
  */
2873
- getUpgradeManifest(documentType: string): UpgradeManifest<readonly number[]>;
3334
+ start(numExecutors: number): Promise<void>;
2874
3335
  /**
2875
- * Compute the upgrade path from one version to another.
2876
- * Returns the sequence of upgrade transitions needed.
3336
+ * Stop the executor manager.
2877
3337
  *
2878
- * @param documentType The document type identifier
2879
- * @param fromVersion The starting version
2880
- * @param toVersion The target version
2881
- * @returns Array of upgrade transitions in order
2882
- * @throws DowngradeNotSupportedError if toVersion is less than fromVersion
2883
- * @throws ManifestNotFoundError if no upgrade manifest is registered
2884
- * @throws MissingUpgradeTransitionError if any transition in the path is missing
3338
+ * @param graceful - Whether to wait for current jobs to complete
3339
+ * @returns Promise that resolves when the manager is stopped
2885
3340
  */
2886
- computeUpgradePath(documentType: string, fromVersion: number, toVersion: number): UpgradeTransition[];
3341
+ stop(graceful?: boolean): Promise<void>;
2887
3342
  /**
2888
- * Get the upgrade reducer for a single-step version transition.
3343
+ * Get all managed executor instances.
2889
3344
  *
2890
- * @param documentType The document type identifier
2891
- * @param fromVersion The starting version
2892
- * @param toVersion The target version (must be fromVersion + 1)
2893
- * @returns The upgrade reducer function
2894
- * @throws InvalidUpgradeStepError if toVersion is not fromVersion + 1
2895
- * @throws ManifestNotFoundError if no upgrade manifest is registered
2896
- * @throws MissingUpgradeTransitionError if the transition is not found
3345
+ * @returns Array of executor instances
2897
3346
  */
2898
- getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
3347
+ getExecutors(): IJobExecutor[];
3348
+ /**
3349
+ * Get the current status of the manager.
3350
+ *
3351
+ * @returns The current manager status
3352
+ */
3353
+ getStatus(): ExecutorManagerStatus;
2899
3354
  }
2900
3355
  //#endregion
2901
- //#region src/shared/consistency-tracker.d.ts
2902
- interface IConsistencyTracker {
3356
+ //#region src/job-tracker/interfaces.d.ts
3357
+ /**
3358
+ * Interface for tracking job lifecycle status.
3359
+ * Maintains job state throughout execution: PENDING → RUNNING → COMPLETED/FAILED.
3360
+ */
3361
+ interface IJobTracker {
2903
3362
  /**
2904
- * Updates the tracker with new operation indexes.
2905
- * When multiple coordinates have the same key, keeps the highest operationIndex.
2906
- * Resolves any pending waiters whose coordinates are now satisfied.
3363
+ * Register a new job with PENDING status.
3364
+ *
3365
+ * @param jobInfo - The job information to register
2907
3366
  */
2908
- update(coordinates: ConsistencyCoordinate[]): void;
3367
+ registerJob(jobInfo: JobInfo): void;
2909
3368
  /**
2910
- * Returns the latest operation index for a given key, or undefined if not tracked.
3369
+ * Update a job's status to RUNNING.
3370
+ *
3371
+ * @param jobId - The job ID to mark as running
2911
3372
  */
2912
- getLatest(key: ConsistencyKey): number | undefined;
3373
+ markRunning(jobId: string): void;
2913
3374
  /**
2914
- * Returns a promise that resolves when all coordinates are satisfied.
2915
- * Rejects if the timeout is reached or the signal is aborted.
3375
+ * Mark a job as failed.
3376
+ *
3377
+ * @param jobId - The job ID to mark as failed
3378
+ * @param error - Error information including message and stack trace
3379
+ * @param job - Optional full job object for debugging purposes
2916
3380
  */
2917
- waitFor(coordinates: ConsistencyCoordinate[], timeoutMs?: number, signal?: AbortSignal): Promise<void>;
3381
+ markFailed(jobId: string, error: ErrorInfo$1, job?: Job): void;
2918
3382
  /**
2919
- * Returns a serializable snapshot of the current state.
3383
+ * Retrieve the current status of a job.
3384
+ *
3385
+ * @param jobId - The job ID to query
3386
+ * @returns The job information, or null if the job is not found
2920
3387
  */
2921
- serialize(): Array<[ConsistencyKey, number]>;
3388
+ getJobStatus(jobId: string): JobInfo | null;
2922
3389
  /**
2923
- * Restores state from a serialized snapshot.
3390
+ * Shutdown the job tracker and clean up resources.
3391
+ * Unsubscribes from all event bus subscriptions.
2924
3392
  */
2925
- hydrate(entries: Array<[ConsistencyKey, number]>): void;
3393
+ shutdown(): void;
3394
+ }
3395
+ //#endregion
3396
+ //#region src/queue/interfaces.d.ts
3397
+ /**
3398
+ * Interface for a job queue that manages write operations.
3399
+ * Internally organizes jobs by documentId, scope, and branch to ensure proper ordering.
3400
+ * Emits events to the event bus when new jobs are available for consumption.
3401
+ */
3402
+ interface IQueue {
3403
+ /**
3404
+ * Add a new job to the queue.
3405
+ * Jobs are automatically organized by documentId, scope, and branch internally.
3406
+ * Emits a 'jobAvailable' event to the event bus when the job is queued.
3407
+ * @param job - The job to add to the queue
3408
+ * @returns Promise that resolves when the job is queued
3409
+ */
3410
+ enqueue(job: Job): Promise<void>;
3411
+ /**
3412
+ * Get the next job to execute for a specific document/scope/branch combination.
3413
+ * @param documentId - The document ID to get jobs for
3414
+ * @param scope - The scope to get jobs for
3415
+ * @param branch - The branch to get jobs for
3416
+ * @param signal - Optional abort signal to cancel the request
3417
+ * @returns Promise that resolves to the next job execution handle or null if no jobs available
3418
+ */
3419
+ dequeue(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
3420
+ /**
3421
+ * Get the next available job from any queue.
3422
+ * @param signal - Optional abort signal to cancel the request
3423
+ * @returns Promise that resolves to the next job execution handle or null if no jobs available
3424
+ */
3425
+ dequeueNext(signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
3426
+ /**
3427
+ * Get the next available job whose routing metadata satisfies the predicate.
3428
+ * Walks ready sub-queue heads in queue insertion order, skips heads whose document
3429
+ * is currently executing (same isDocumentExecuting gate as dequeueNext), and returns
3430
+ * the first head for which predicate returns true.
3431
+ * Returns null when paused, when nothing matches, or when the queue is empty.
3432
+ * Rejects if signal is already aborted.
3433
+ * @param predicate - Filter applied to JobRoutingMeta of each candidate head
3434
+ * @param signal - Optional abort signal to cancel the request
3435
+ * @returns Promise that resolves to the first matching job execution handle or null
3436
+ */
3437
+ dequeueNextMatching(predicate: (meta: JobRoutingMeta) => boolean, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
3438
+ /**
3439
+ * Get the current size of the queue for a specific document/scope/branch.
3440
+ * @param documentId - The document ID
3441
+ * @param scope - The scope
3442
+ * @param branch - The branch
3443
+ * @returns Promise that resolves to the number of jobs in the queue
3444
+ */
3445
+ size(documentId: string, scope: string, branch: string): Promise<number>;
3446
+ /**
3447
+ * Get the total size of all queues.
3448
+ * @returns Promise that resolves to the total number of jobs across all queues
3449
+ */
3450
+ totalSize(): Promise<number>;
3451
+ /**
3452
+ * Remove a specific job from the queue.
3453
+ * @param jobId - The ID of the job to remove
3454
+ * @returns Promise that resolves to true if job was removed, false if not found
3455
+ */
3456
+ remove(jobId: string): Promise<boolean>;
3457
+ /**
3458
+ * Clear all jobs for a specific document/scope/branch combination.
3459
+ * @param documentId - The document ID
3460
+ * @param scope - The scope
3461
+ * @param branch - The branch
3462
+ * @returns Promise that resolves when the queue is cleared
3463
+ */
3464
+ clear(documentId: string, scope: string, branch: string): Promise<void>;
3465
+ /**
3466
+ * Clear all jobs from all queues.
3467
+ * @returns Promise that resolves when all queues are cleared
3468
+ */
3469
+ clearAll(): Promise<void>;
3470
+ /**
3471
+ * Check if there are any jobs in the queue.
3472
+ * @returns Promise that resolves to true if there are jobs, false otherwise
3473
+ */
3474
+ hasJobs(): Promise<boolean>;
3475
+ /**
3476
+ * Mark a job as completed.
3477
+ * @param jobId - The ID of the job to mark as completed
3478
+ * @returns Promise that resolves when the job is marked as completed
3479
+ */
3480
+ completeJob(jobId: string): Promise<void>;
3481
+ /**
3482
+ * Mark a job as failed.
3483
+ * @param jobId - The ID of the job to mark as failed
3484
+ * @param error - Optional error information
3485
+ * @returns Promise that resolves when the job is marked as failed
3486
+ */
3487
+ failJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
3488
+ /**
3489
+ * Retry a failed job.
3490
+ * @param jobId - The ID of the job to retry
3491
+ * @param error - Optional error information from the failure
3492
+ * @param accounting - Whether the attempt counts against the job's retry
3493
+ * limit; defaults to {@link RetryAccounting.CountAgainstLimit}
3494
+ * @returns Promise that resolves when the job is requeued for retry
3495
+ */
3496
+ retryJob(jobId: string, error?: ErrorInfo$1, accounting?: RetryAccounting): Promise<void>;
3497
+ /**
3498
+ * Returns true if and only if all jobs have been resolved.
3499
+ */
3500
+ get isDrained(): boolean;
3501
+ /**
3502
+ * Blocks the queue from accepting new jobs.
3503
+ * @param onDrained - Optional callback to call when the queue is drained
3504
+ */
3505
+ block(onDrained?: () => void): void;
3506
+ /**
3507
+ * Unblocks the queue from accepting new jobs.
3508
+ */
3509
+ unblock(): void;
3510
+ }
3511
+ //#endregion
3512
+ //#region src/read-models/types.d.ts
3513
+ interface ViewStateTable {
3514
+ readModelId: string;
3515
+ lastOrdinal: number;
3516
+ lastOperationTimestamp: Generated<Date>;
3517
+ }
3518
+ interface DocumentSnapshotTable {
3519
+ id: Generated<string>;
3520
+ documentId: string;
3521
+ slug: string | null;
3522
+ name: string | null;
3523
+ scope: string;
3524
+ branch: string;
3525
+ content: unknown;
3526
+ documentType: string;
3527
+ lastOperationIndex: number;
3528
+ lastOperationHash: string;
3529
+ lastUpdatedAt: Generated<Date>;
3530
+ snapshotVersion: Generated<number>;
3531
+ identifiers: unknown;
3532
+ metadata: unknown;
3533
+ isDeleted: Generated<boolean>;
3534
+ deletedAt: Date | null;
3535
+ }
3536
+ interface SlugMappingTable {
3537
+ slug: string;
3538
+ documentId: string;
3539
+ scope: string;
3540
+ branch: string;
3541
+ createdAt: Generated<Date>;
3542
+ updatedAt: Generated<Date>;
3543
+ }
3544
+ interface ProcessorCursorTable {
3545
+ processorId: string;
3546
+ factoryId: string;
3547
+ driveId: string;
3548
+ processorIndex: number;
3549
+ lastOrdinal: Generated<number>;
3550
+ status: Generated<string>;
3551
+ lastError: string | null;
3552
+ lastErrorTimestamp: Date | null;
3553
+ createdAt: Generated<Date>;
3554
+ updatedAt: Generated<Date>;
3555
+ }
3556
+ interface DocumentViewDatabase {
3557
+ ViewState: ViewStateTable;
3558
+ DocumentSnapshot: DocumentSnapshotTable;
3559
+ SlugMapping: SlugMappingTable;
3560
+ ProcessorCursor: ProcessorCursorTable;
3561
+ }
3562
+ type InsertableDocumentSnapshot = Insertable<DocumentSnapshotTable>;
3563
+ //#endregion
3564
+ //#region src/shared/consistency-tracker.d.ts
3565
+ interface IConsistencyTracker {
3566
+ /**
3567
+ * Updates the tracker with new operation indexes.
3568
+ * When multiple coordinates have the same key, keeps the highest operationIndex.
3569
+ * Resolves any pending waiters whose coordinates are now satisfied.
3570
+ */
3571
+ update(coordinates: ConsistencyCoordinate[]): void;
3572
+ /**
3573
+ * Returns the latest operation index for a given key, or undefined if not tracked.
3574
+ */
3575
+ getLatest(key: ConsistencyKey): number | undefined;
3576
+ /**
3577
+ * Returns a promise that resolves when all coordinates are satisfied.
3578
+ * Rejects if the timeout is reached or the signal is aborted.
3579
+ */
3580
+ waitFor(coordinates: ConsistencyCoordinate[], timeoutMs?: number, signal?: AbortSignal): Promise<void>;
3581
+ /**
3582
+ * Returns a serializable snapshot of the current state.
3583
+ */
3584
+ serialize(): Array<[ConsistencyKey, number]>;
3585
+ /**
3586
+ * Restores state from a serialized snapshot.
3587
+ */
3588
+ hydrate(entries: Array<[ConsistencyKey, number]>): void;
2926
3589
  }
2927
3590
  /**
2928
3591
  * Creates a consistency key from documentId, scope, and branch.
@@ -2946,134 +3609,6 @@ declare class ConsistencyTracker implements IConsistencyTracker {
2946
3609
  private removeWaiter;
2947
3610
  }
2948
3611
  //#endregion
2949
- //#region src/storage/kysely/types.d.ts
2950
- interface OperationTable {
2951
- id: Generated<number>;
2952
- jobId: string;
2953
- opId: string;
2954
- prevOpId: string;
2955
- writeTimestampUtcMs: Generated<Date>;
2956
- documentId: string;
2957
- documentType: string;
2958
- scope: string;
2959
- branch: string;
2960
- timestampUtcMs: Date;
2961
- index: number;
2962
- action: unknown;
2963
- skip: number;
2964
- error?: string | null;
2965
- hash: string;
2966
- }
2967
- interface KeyframeTable {
2968
- id: Generated<number>;
2969
- documentId: string;
2970
- documentType: string;
2971
- scope: string;
2972
- branch: string;
2973
- revision: number;
2974
- document: unknown;
2975
- createdAt: Generated<Date>;
2976
- }
2977
- interface DocumentCollectionTable {
2978
- documentId: string;
2979
- collectionId: string;
2980
- joinedOrdinal: bigint;
2981
- leftOrdinal: bigint | null;
2982
- }
2983
- interface OperationIndexOperationTable {
2984
- ordinal: Generated<number>;
2985
- opId: string;
2986
- documentId: string;
2987
- documentType: string;
2988
- scope: string;
2989
- branch: string;
2990
- timestampUtcMs: string;
2991
- writeTimestampUtcMs: Generated<Date>;
2992
- index: number;
2993
- skip: number;
2994
- hash: string;
2995
- action: unknown;
2996
- sourceRemote: Generated<string>;
2997
- }
2998
- interface SyncRemoteTable {
2999
- name: string;
3000
- collection_id: string;
3001
- channel_type: string;
3002
- channel_id: string;
3003
- remote_name: string;
3004
- channel_parameters: unknown;
3005
- filter_document_ids: unknown;
3006
- filter_scopes: unknown;
3007
- filter_branch: string;
3008
- push_state: string;
3009
- push_last_success_utc_ms: string | null;
3010
- push_last_failure_utc_ms: string | null;
3011
- push_failure_count: number;
3012
- pull_state: string;
3013
- pull_last_success_utc_ms: string | null;
3014
- pull_last_failure_utc_ms: string | null;
3015
- pull_failure_count: number;
3016
- created_at: Generated<Date>;
3017
- updated_at: Generated<Date>;
3018
- }
3019
- interface SyncCursorTable {
3020
- remote_name: string;
3021
- cursor_type: string;
3022
- cursor_ordinal: bigint;
3023
- last_synced_at_utc_ms: string | null;
3024
- updated_at: Generated<Date>;
3025
- }
3026
- /**
3027
- * Kysely table definition for the `sync_dead_letters` table.
3028
- */
3029
- interface SyncDeadLetterTable {
3030
- ordinal: Generated<number>;
3031
- id: string;
3032
- job_id: string;
3033
- job_dependencies: unknown;
3034
- remote_name: string;
3035
- document_id: string;
3036
- scopes: unknown;
3037
- branch: string;
3038
- operations: unknown;
3039
- error_source: string;
3040
- error_message: string;
3041
- created_at: Generated<Date>;
3042
- }
3043
- interface Database$1 {
3044
- Operation: OperationTable;
3045
- Keyframe: KeyframeTable;
3046
- document_collections: DocumentCollectionTable;
3047
- operation_index_operations: OperationIndexOperationTable;
3048
- sync_remotes: SyncRemoteTable;
3049
- sync_cursors: SyncCursorTable;
3050
- sync_dead_letters: SyncDeadLetterTable;
3051
- }
3052
- interface DocumentTable {
3053
- id: string;
3054
- createdAt: Generated<Date>;
3055
- updatedAt: Generated<Date>;
3056
- }
3057
- interface DocumentRelationshipTable {
3058
- id: Generated<string>;
3059
- sourceId: string;
3060
- targetId: string;
3061
- relationshipType: string;
3062
- metadata: unknown;
3063
- createdAt: Generated<Date>;
3064
- updatedAt: Generated<Date>;
3065
- }
3066
- interface IndexerStateTable {
3067
- id: Generated<number>;
3068
- lastOperationId: number;
3069
- lastOperationTimestamp: Generated<Date>;
3070
- }
3071
- interface DocumentIndexerDatabase {
3072
- Document: DocumentTable;
3073
- DocumentRelationship: DocumentRelationshipTable;
3074
- IndexerState: IndexerStateTable;
3075
- }
3076
- //#endregion
3077
3612
  //#region src/storage/pool-instrumentation.d.ts
3078
3613
  /**
3079
3614
  * Snapshot of a pg.Pool's internal counters at a point in time.
@@ -3137,7 +3672,13 @@ declare class PollingChannelError extends Error {
3137
3672
  declare class ChannelError extends Error {
3138
3673
  source: ChannelErrorSource;
3139
3674
  error: Error;
3140
- constructor(source: ChannelErrorSource, error: Error);
3675
+ /**
3676
+ * The classification when something other than the error carries it. Absent
3677
+ * means derive it from `error.name`; a dead letter mirrored from a peer sets it,
3678
+ * because only the message crosses the wire.
3679
+ */
3680
+ readonly errorType?: SyncOperationErrorType;
3681
+ constructor(source: ChannelErrorSource, error: Error, errorType?: SyncOperationErrorType);
3141
3682
  }
3142
3683
  //#endregion
3143
3684
  //#region src/sync/sync-operation.d.ts
@@ -3815,12 +4356,6 @@ declare class DriveClient implements IDriveClient {
3815
4356
  private removeFileNode;
3816
4357
  }
3817
4358
  //#endregion
3818
- //#region src/cache/collection-membership-cache.d.ts
3819
- interface ICollectionMembershipCache {
3820
- getCollectionsForDocuments(documentIds: string[]): Promise<Record<string, string[]>>;
3821
- invalidate(documentId: string): void;
3822
- }
3823
- //#endregion
3824
4359
  //#region src/registry/document-model-resolver.d.ts
3825
4360
  interface IDocumentModelResolver {
3826
4361
  ensureModelLoaded(documentType: string): Promise<void>;
@@ -3880,38 +4415,6 @@ declare class NullDocumentModelResolver implements IDocumentModelResolver {
3880
4415
  */
3881
4416
  type WorkerFactory = (index: number) => IExecutorWorker;
3882
4417
  //#endregion
3883
- //#region src/cache/write-cache-types.d.ts
3884
- /**
3885
- * Configuration options for the write cache
3886
- */
3887
- type WriteCacheConfig = {
3888
- /** Maximum number of document streams to cache (LRU eviction). Default: 1000 */maxDocuments: number; /** Number of snapshots to keep in each document's ring buffer. Default: 10 */
3889
- ringBufferSize: number; /** Persist a keyframe snapshot every N revisions. Default: 10 */
3890
- keyframeInterval: number;
3891
- };
3892
- /**
3893
- * Unique identifier for a document stream
3894
- */
3895
- type DocumentStreamKey = {
3896
- /** Document identifier */documentId: string; /** Operation scope */
3897
- scope: string; /** Branch name */
3898
- branch: string;
3899
- };
3900
- /**
3901
- * A cached document snapshot at a specific revision
3902
- */
3903
- type CachedSnapshot = {
3904
- /** The revision number of this snapshot */revision: number; /** The document state at this revision */
3905
- document: PHDocument;
3906
- };
3907
- /**
3908
- * Serialized keyframe snapshot for K/V store persistence
3909
- */
3910
- type KeyframeSnapshot = {
3911
- /** The revision number of this keyframe */revision: number; /** Serialized document state */
3912
- document: string;
3913
- };
3914
- //#endregion
3915
4418
  //#region src/projection/protocol.d.ts
3916
4419
  /**
3917
4420
  * Identifier for a built-in read model the projection worker materializes
@@ -4095,973 +4598,635 @@ type ProjectionShardManagerConfig = {
4095
4598
  shardCount: number;
4096
4599
  db: DbConfig;
4097
4600
  models: ModelManifestEntry[];
4098
- preReadyKinds: BuiltInReadModelKind[];
4099
- postReadyKinds: BuiltInReadModelKind[];
4100
- factory: ProjectionWorkerFactory;
4101
- logger: ILogger;
4102
- hostBus: IEventBus;
4103
- initTimeoutMs?: number;
4104
- shutdownGraceMs?: number;
4105
- drainTimeoutMs?: number;
4106
- chainDepthReportIntervalMs?: number;
4107
- /**
4108
- * Host-side forwarding instrumentations indexed by shard index. The
4109
- * manager routes each shard's `pool-acquire-samples` message to the
4110
- * matching forwarder so the host's OpenTelemetry instrumentation records
4111
- * acquire-wait latencies as if each shard's pg.Pool were local.
4112
- */
4113
- poolInstrumentations?: ForwardingPoolInstrumentation[];
4114
- };
4115
- //#endregion
4116
- //#region src/signer/types.d.ts
4117
- /**
4118
- * Configuration for signing and verification.
4119
- */
4120
- type SignerConfig = {
4121
- /**
4122
- * The signer used to sign actions before submission.
4123
- */
4124
- signer: ISigner;
4125
- /**
4126
- * Optional handler for verifying signatures on incoming operations.
4127
- * If not provided, signature verification will be skipped.
4128
- */
4129
- verifier?: SignatureVerificationHandler;
4130
- };
4131
- //#endregion
4132
- //#region src/storage/migrations/types.d.ts
4133
- type MigrationStrategy = "auto" | "manual" | "none";
4134
- interface MigrationResult {
4135
- success: boolean;
4136
- migrationsExecuted: string[];
4137
- error?: Error;
4138
- }
4139
- //#endregion
4140
- //#region src/sync/sync-builder.d.ts
4141
- declare class SyncBuilder {
4142
- private channelFactory?;
4143
- private remoteStorage?;
4144
- private cursorStorage?;
4145
- private deadLetterStorage?;
4146
- private config;
4147
- withChannelFactory(factory: IChannelFactory): this;
4148
- withRemoteStorage(storage: ISyncRemoteStorage): this;
4149
- withCursorStorage(storage: ISyncCursorStorage): this;
4150
- withDeadLetterStorage(storage: ISyncDeadLetterStorage): this;
4151
- withMaxDeadLettersPerRemote(limit: number): this;
4152
- withMaxInboxBatchSize(limit: number): this;
4153
- build(reactor: IReactor, logger: ILogger, operationIndex: IOperationIndex, eventBus: IEventBus, db: Kysely<Database$1>, driveContainerTypes: ReadonlySet<string>): ISyncManager;
4154
- buildModule(reactor: IReactor, logger: ILogger, operationIndex: IOperationIndex, eventBus: IEventBus, db: Kysely<Database$1>, driveContainerTypes: ReadonlySet<string>): InProcessSyncModule;
4155
- }
4156
- //#endregion
4157
- //#region src/core/reactor-builder.d.ts
4158
- /**
4159
- * Dependencies provided to read-model factories registered via
4160
- * `withReadModelFactory`. These are constructed inside `buildModule()`, which
4161
- * is why factory-based registration is needed for read models that depend on
4162
- * them (`BaseReadModel` subclasses, in particular).
4163
- */
4164
- interface ReadModelFactoryDeps {
4165
- operationIndex: IOperationIndex;
4166
- writeCache: IWriteCache;
4167
- processorManagerConsistencyTracker: IConsistencyTracker;
4168
- }
4169
- /**
4170
- * Factory that builds a pre-ready read model from internal reactor
4171
- * dependencies once they are available. Awaited during `buildModule()`.
4172
- */
4173
- type ReadModelFactory = (deps: ReadModelFactoryDeps) => IReadModel | Promise<IReadModel>;
4174
- type WorkerPoolBase = {
4175
- /** Number of worker threads to spawn; also the sticky-routing modulus. */numWorkers: number;
4176
- /**
4177
- * Factory spec the default transport's workers import to instantiate
4178
- * their signature verifier. Omitted = no executor-side verification,
4179
- * parity with the in-process executor's default.
4180
- */
4181
- verifier?: SignatureVerifierSpec;
4182
- };
4183
- /**
4184
- * Executor worker-pool configuration. Either `db` (default thread
4185
- * transport; each worker opens its own Postgres pool) or a custom
4186
- * `factory` transport is required by construction — an enabled pool
4187
- * without connection info is unrepresentable.
4188
- */
4189
- type WorkerPoolOptions = (WorkerPoolBase & {
4190
- db: DbConfig;
4191
- factory?: WorkerFactory;
4192
- }) | (WorkerPoolBase & {
4193
- db?: DbConfig;
4194
- factory: WorkerFactory;
4195
- });
4196
- /**
4197
- * Caller-facing config for {@link ReactorBuilder.withProjectionShards}.
4198
- * When set, the builder replaces the in-process
4199
- * {@link ReadModelCoordinator} with a {@link ProjectionShardManager} that
4200
- * fans JOB_WRITE_READY events to N projection workers sharded by
4201
- * documentId.
4202
- *
4203
- * @see Sharded projection workers sub-feature brief
4204
- * (Powerhouse board wiki id: eb26f01f-8f68-4918-a6f6-ac7a4679b533)
4205
- */
4206
- type ProjectionShardBuilderConfig = {
4207
- shardCount: number;
4208
- preReadyKinds: BuiltInReadModelKind[];
4209
- postReadyKinds: BuiltInReadModelKind[];
4210
- /**
4211
- * Connection info for the projection workers' own pools. Falls back to
4212
- * the executor worker pool's `db` when {@link ReactorBuilder.withWorkerPool}
4213
- * is configured with one.
4214
- */
4215
- db?: DbConfig;
4216
- poolSize?: number;
4217
- initTimeoutMs?: number;
4218
- shutdownGraceMs?: number;
4219
- drainTimeoutMs?: number;
4220
- chainDepthReportIntervalMs?: number;
4221
- };
4222
- declare class ReactorBuilder {
4223
- private logger?;
4224
- private documentModelSources;
4225
- private upgradeManifests;
4226
- private features;
4227
- private readModels;
4228
- private readModelFactories;
4229
- private executorManager;
4230
- private executorConfig;
4231
- private writeCacheConfig?;
4232
- private migrationStrategy;
4233
- private syncBuilder?;
4234
- private eventBus?;
4235
- private readModelCoordinator?;
4236
- private signatureVerifier?;
4237
- private kyselyInstance?;
4238
- private signalHandlersEnabled;
4239
- private queueInstance?;
4240
- private channelScheme?;
4241
- private jwtHandler?;
4242
- private documentModelLoader?;
4243
- private shutdownHooks;
4244
- private driveContainerTypes;
4245
- private workerPool?;
4246
- private resolvedModelManifest?;
4247
- private projectionShardConfig?;
4248
- private projectionWorkerFactory?;
4249
- private instrumentedPools;
4250
- withLogger(logger: ILogger): this;
4251
- /**
4252
- * Register document-model sources: live modules, importable files, or
4253
- * importable packages. Appends across calls. At `buildModule()` every
4254
- * source is resolved host-side and registered on the registry; file and
4255
- * package sources additionally form the worker manifest when the worker
4256
- * pool is enabled (live modules cannot cross a thread boundary).
4257
- */
4258
- withDocumentModelSources(sources: DocumentModelSource[]): this;
4259
- withUpgradeManifests(manifests: UpgradeManifest<readonly number[]>[]): this;
4260
- withFeatures(features: ReactorFeatures): this;
4261
- withReadModel(readModel: IReadModel): this;
4262
- /**
4263
- * Register a factory that builds a pre-ready read model after the reactor's
4264
- * internal `operationIndex`, `writeCache`, and processor-manager consistency
4265
- * tracker are constructed. Use this for read models (e.g. `BaseReadModel`
4266
- * subclasses) that need those dependencies and therefore cannot be built
4267
- * before calling `buildModule()`.
4268
- */
4269
- withReadModelFactory(factory: ReadModelFactory): this;
4270
- withReadModelCoordinator(readModelCoordinator: IReadModelCoordinator): this;
4271
- withExecutor(executor: IJobExecutorManager): this;
4272
- withExecutorConfig(config: Partial<JobExecutorConfig>): this;
4273
- withWriteCacheConfig(config: Partial<WriteCacheConfig>): this;
4274
- withDriveContainerTypes(types: string[]): this;
4275
- withMigrationStrategy(strategy: MigrationStrategy): this;
4276
- withSync(syncBuilder: SyncBuilder): this;
4277
- withEventBus(eventBus: IEventBus): this;
4278
- withSignatureVerifier(verifier: SignatureVerificationHandler): this;
4279
- withKysely(kysely: Kysely<Database>): this;
4280
- /**
4281
- * Register an externally-constructed pg.Pool's {@link PoolInstrumentation}
4282
- * so it surfaces through {@link ReactorModule.pools}. Use this when the
4283
- * caller built the pool itself (e.g. the in-process bench host wiring) so
4284
- * pool acquire-wait and pool-stat metrics still emit. The builder also
4285
- * registers any pool it constructs internally via {@link createPostgresDatabase}.
4286
- */
4287
- withInstrumentedPool(instrumentation: PoolInstrumentation): this;
4288
- withQueue(queue: IQueue): this;
4289
- withChannelScheme(scheme: ChannelScheme): this;
4290
- withJwtHandler(handler: JwtHandler): this;
4291
- withDocumentModelLoader(loader: IDocumentModelLoader): this;
4292
- withSignalHandlers(): this;
4293
- /**
4294
- * Register an async cleanup hook to run during graceful shutdown. Hooks fire
4295
- * after `reactor.kill()` resolves and before `database.destroy()`, so callers
4296
- * that depend on the reactor (e.g. an HTTP API layered on top) can drain
4297
- * cleanly before the underlying kysely instance is torn down. Hook errors are
4298
- * logged and otherwise ignored — one bad hook cannot strand the rest of the
4299
- * shutdown chain.
4300
- */
4301
- withShutdownHook(hook: () => Promise<void>): this;
4302
- /**
4303
- * Enable the executor worker pool: N `node:worker_threads` workers with
4304
- * sticky per-document routing, replacing the in-process executor. Calling
4305
- * this enables the pool — there is no `enabled` flag. Provide `db`
4306
- * (each worker opens its own Postgres pool; the parent database is built
4307
- * from it too unless {@link withKysely} is set) or a custom `factory`
4308
- * transport. `verifier` is imported by the default transport's workers;
4309
- * omitted = no executor-side signature verification.
4310
- */
4311
- withWorkerPool(options: WorkerPoolOptions): this;
4312
- /**
4313
- * Configure N sharded projection workers. When set, the builder replaces
4314
- * the default in-process {@link ReadModelCoordinator} with a
4315
- * {@link ProjectionShardManager}.
4316
- *
4317
- * Projection workers open their own Postgres pools from `config.db`,
4318
- * falling back to the executor worker pool's `db` when
4319
- * {@link withWorkerPool} is configured with one; only the `poolSize` is
4320
- * overridden by {@link ProjectionShardBuilderConfig.poolSize}. The same
4321
- * model manifest resolved from {@link withDocumentModelSources} is
4322
- * forwarded.
4323
- */
4324
- withProjectionShards(config: ProjectionShardBuilderConfig): this;
4325
- /**
4326
- * Inject a custom {@link ProjectionWorkerFactory}. When set, the builder
4327
- * skips default thread-transport wiring for the projection shards and
4328
- * hands the factory directly to {@link ProjectionShardManager}.
4329
- */
4330
- withProjectionWorkerFactory(factory: ProjectionWorkerFactory): this;
4331
- getResolvedModelManifest(): ModelManifestEntry[] | undefined;
4332
- build(): Promise<IReactor>;
4333
- buildModule(): Promise<InProcessReactorModule>;
4334
- /**
4335
- * The single Postgres config for the parent, executor workers, and
4336
- * projection shards. They must share one physical database (the parent
4337
- * writes operations; workers and shards read them), so divergent
4338
- * worker/shard targets throw. `withKysely` overrides the parent and is not
4339
- * validated against a worker/shard `db`.
4340
- */
4341
- private resolveReactorDbConfig;
4342
- /**
4343
- * Constructs a {@link ProjectionShardManager} bound to the host event
4344
- * bus. Builds the default thread-transport factory unless one was
4345
- * injected via {@link withProjectionWorkerFactory}. Calls
4346
- * `manager.startup()` so all N workers reach READY before the reactor
4347
- * is returned to the caller.
4348
- */
4349
- private createProjectionShardManager;
4350
- private createDefaultProjectionWorkerFactory;
4351
- /**
4352
- * Default {@link WorkerFactory} used when the pool options carry no
4353
- * custom `factory`. Each worker spawns a real `node:worker_threads`
4354
- * Worker pointing at the compiled `worker/entry.js`.
4355
- */
4356
- private createDefaultWorkerFactory;
4357
- /**
4358
- * Builds the parent Kysely instance against a real Postgres server using
4359
- * the same {@link DbConfig} the workers receive at init. Used in the
4360
- * worker-pool path so the parent reactor and each worker thread share
4361
- * storage; PGlite cannot be shared across threads. The constructed pool
4362
- * is wrapped with {@link instrumentPgPool} and the resulting
4363
- * {@link PoolInstrumentation} is pushed onto {@link instrumentedPools} so
4364
- * the reactor module exposes acquire-wait and pool-stat surfaces.
4365
- */
4366
- private createPostgresDatabase;
4367
- private attachSignalHandlers;
4368
- }
4369
- //#endregion
4370
- //#region src/core/reactor-client-builder.d.ts
4371
- /**
4372
- * Builder class for constructing ReactorClient instances with proper configuration
4373
- */
4374
- declare class ReactorClientBuilder {
4375
- private logger?;
4376
- private reactorBuilder?;
4377
- private reactor?;
4378
- private eventBus?;
4379
- private documentIndexer?;
4380
- private documentView?;
4381
- private signer?;
4382
- private signatureVerifier?;
4383
- private subscriptionManager?;
4384
- private jobAwaiter?;
4385
- private documentModelLoader?;
4386
- /**
4387
- * Sets the logger for the ReactorClient.
4388
- * @param logger - The logger to use.
4389
- * @returns The ReactorClientBuilder instance.
4390
- */
4391
- withLogger(logger: ILogger): this;
4392
- /**
4393
- * Either this or withReactor must be set.
4394
- */
4395
- withReactorBuilder(reactorBuilder: ReactorBuilder): this;
4396
- /**
4397
- * Either this or withReactorBuilder must be set.
4398
- */
4399
- withReactor(reactor: IReactor, eventBus: IEventBus, documentIndexer: IDocumentIndexer, documentView: IDocumentView): this;
4400
- /**
4401
- * Sets the signer configuration for signing and verifying actions.
4402
- *
4403
- * @param config - Either an ISigner for signing only, or a SignerConfig for both signing and verification
4404
- */
4405
- withSigner(config: ISigner | SignerConfig): this;
4406
- withSubscriptionManager(subscriptionManager: IReactorSubscriptionManager): this;
4407
- withJobAwaiter(jobAwaiter: IJobAwaiter): this;
4408
- withDocumentModelLoader(loader: IDocumentModelLoader): this;
4409
- build(): Promise<ReactorClient>;
4410
- buildModule(): Promise<InProcessReactorClientModule>;
4411
- }
4412
- //#endregion
4413
- //#region src/core/drive-container-types.d.ts
4414
- declare const DEFAULT_DRIVE_CONTAINER_TYPES: ReadonlySet<string>;
4415
- //#endregion
4416
- //#region src/core/reactor.d.ts
4417
- /**
4418
- * This class implements the IReactor interface and serves as the main entry point
4419
- * for the new Reactor architecture.
4420
- */
4421
- declare class Reactor implements IReactor {
4422
- private logger;
4423
- private documentModelRegistry;
4424
- private shutdownStatus;
4425
- private setShutdown;
4426
- private setCompleted;
4427
- private queue;
4428
- private jobTracker;
4429
- private readModelCoordinator;
4430
- private features;
4431
- private documentView;
4432
- private documentIndexer;
4433
- private operationStore;
4434
- private eventBus;
4435
- private executorManager;
4436
- constructor(logger: ILogger, documentModelRegistry: IDocumentModelRegistry, queue: IQueue, jobTracker: IJobTracker, readModelCoordinator: IReadModelCoordinator, features: ReactorFeatures, documentView: IDocumentView, documentIndexer: IDocumentIndexer, operationStore: IOperationStore, eventBus: IEventBus, executorManager: IJobExecutorManager);
4437
- kill(): ShutdownStatus;
4438
- getDocumentModels(namespace?: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentModelModule>>;
4439
- get<TDocument extends PHDocument>(id: string, view?: ViewFilter, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<TDocument>;
4440
- getBySlug<TDocument extends PHDocument>(slug: string, view?: ViewFilter, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<TDocument>;
4441
- getByIdOrSlug<TDocument extends PHDocument>(identifier: string, view?: ViewFilter, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<TDocument>;
4442
- getOutgoingRelationships(sourceId: string, relationshipType: string, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<string[]>;
4443
- getIncomingRelationships(targetId: string, relationshipType: string, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<string[]>;
4444
- getOperations(documentId: string, view?: ViewFilter, filter?: OperationFilter, paging?: PagingOptions, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<Record<string, PagedResults<Operation>>>;
4445
- find(search: SearchFilter, view?: ViewFilter, paging?: PagingOptions, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
4446
- create(document: PHDocument, signer?: ISigner, signal?: AbortSignal, meta?: Record<string, unknown>): Promise<JobInfo>;
4447
- deleteDocument(id: string, signer?: ISigner, signal?: AbortSignal, meta?: Record<string, unknown>): Promise<JobInfo>;
4448
- execute(docId: string, branch: string, actions: Action[], signal?: AbortSignal, meta?: Record<string, unknown>): Promise<JobInfo>;
4449
- load(docId: string, branch: string, operations: Operation[], signal?: AbortSignal, meta?: Record<string, unknown>): Promise<JobInfo>;
4450
- executeBatch(request: BatchExecutionRequest, signal?: AbortSignal, meta?: Record<string, unknown>): Promise<BatchExecutionResult>;
4451
- loadBatch(request: BatchLoadRequest, signal?: AbortSignal, meta?: Record<string, unknown>): Promise<BatchLoadResult>;
4452
- addRelationship(sourceId: string, targetId: string, relationshipType: string, branch?: string, signer?: ISigner, signal?: AbortSignal): Promise<JobInfo>;
4453
- removeRelationship(sourceId: string, targetId: string, relationshipType: string, branch?: string, signer?: ISigner, signal?: AbortSignal): Promise<JobInfo>;
4454
- getJobStatus(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
4455
- private findByIds;
4456
- private findBySlugs;
4457
- private findByParentId;
4458
- private findByType;
4459
- private emitJobPending;
4460
- }
4461
- //#endregion
4462
- //#region src/shared/drive-url.d.ts
4463
- interface ParsedDriveUrl {
4464
- url: string;
4465
- driveId: string;
4466
- graphqlEndpoint: string;
4467
- }
4468
- /**
4469
- * Parse a drive URL to extract drive ID and construct GraphQL endpoint.
4470
- * Preserves any subpath prefix so the result is correct when the reactor is
4471
- * served behind a proxy at a non-root path.
4472
- * e.g., "http://localhost:4001/d/abc123" -> { driveId: "abc123", graphqlEndpoint: "http://localhost:4001/graphql/r" }
4473
- * e.g., "https://example.com/api/reactor/d/abc123" -> { ..., graphqlEndpoint: "https://example.com/api/reactor/graphql/r" }
4474
- */
4475
- declare function parseDriveUrl(url: string): ParsedDriveUrl;
4476
- /**
4477
- * Extract drive ID from a drive URL.
4478
- */
4479
- declare function driveIdFromUrl(url: string): string;
4480
- //#endregion
4481
- //#region src/shared/factories.d.ts
4482
- /**
4483
- * Factory method to create a ShutdownStatus that can be updated
4484
- *
4485
- * @param initialState - Initial shutdown state (default: false)
4486
- * @returns A tuple of [ShutdownStatus, setShutdown function, setCompleted function]
4487
- */
4488
- declare function createMutableShutdownStatus(initialState?: boolean): [ShutdownStatus, (value: boolean) => void, (completed: Promise<void>) => void];
4489
- //#endregion
4490
- //#region src/shared/utils.d.ts
4491
- type ParsedPaging = {
4492
- offset: number;
4493
- limit: number;
4494
- };
4495
- /**
4496
- * Validates PagingOptions and returns a normalized offset and limit.
4497
- * Throws if the cursor is not empty and not a non-negative integer, or if
4498
- * limit is less than 1. When `paging` is undefined, returns offset 0 and
4499
- * the caller-supplied `defaultLimit`.
4500
- */
4501
- declare function parsePagingOptions(paging: PagingOptions | undefined, defaultLimit: number): ParsedPaging;
4502
- //#endregion
4503
- //#region src/subs/default-error-handler.d.ts
4504
- /**
4505
- * Default error handler that re-throws subscription errors.
4506
- * This ensures that errors are not silently swallowed.
4507
- */
4508
- declare class DefaultSubscriptionErrorHandler implements ISubscriptionErrorHandler {
4509
- handleError(error: unknown, context: SubscriptionErrorContext): void;
4510
- }
4511
- //#endregion
4512
- //#region src/subs/react-subscription-manager.d.ts
4513
- type DocumentCreatedCallback = (result: PagedResults<string>) => void;
4514
- type DocumentDeletedCallback = (documentIds: string[]) => void;
4515
- type DocumentStateUpdatedCallback = (result: PagedResults<PHDocument>) => void;
4516
- type RelationshipChangedCallback = (parentId: string, childId: string, changeType: RelationshipChangeType) => void;
4517
- declare class ReactorSubscriptionManager implements IReactorSubscriptionManager {
4518
- private createdSubscriptions;
4519
- private deletedSubscriptions;
4520
- private updatedSubscriptions;
4521
- private relationshipSubscriptions;
4522
- private subscriptionCounter;
4523
- private errorHandler;
4524
- constructor(errorHandler: ISubscriptionErrorHandler);
4525
- onDocumentCreated(callback: DocumentCreatedCallback, search?: SearchFilter): () => void;
4526
- onDocumentDeleted(callback: DocumentDeletedCallback, search?: SearchFilter): () => void;
4527
- onDocumentStateUpdated(callback: DocumentStateUpdatedCallback, search?: SearchFilter, view?: ViewFilter): () => void;
4528
- onRelationshipChanged(callback: RelationshipChangedCallback, search?: SearchFilter): () => void;
4529
- /**
4530
- * Notify subscribers about created documents
4531
- */
4532
- notifyDocumentsCreated(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
4533
- /**
4534
- * Notify subscribers about deleted documents
4535
- */
4536
- notifyDocumentsDeleted(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
4601
+ preReadyKinds: BuiltInReadModelKind[];
4602
+ postReadyKinds: BuiltInReadModelKind[];
4603
+ factory: ProjectionWorkerFactory;
4604
+ logger: ILogger;
4605
+ hostBus: IEventBus;
4606
+ initTimeoutMs?: number;
4607
+ shutdownGraceMs?: number;
4608
+ drainTimeoutMs?: number;
4609
+ chainDepthReportIntervalMs?: number;
4537
4610
  /**
4538
- * Notify subscribers about updated documents
4611
+ * Host-side forwarding instrumentations indexed by shard index. The
4612
+ * manager routes each shard's `pool-acquire-samples` message to the
4613
+ * matching forwarder so the host's OpenTelemetry instrumentation records
4614
+ * acquire-wait latencies as if each shard's pg.Pool were local.
4539
4615
  */
4540
- notifyDocumentsUpdated(documents: PHDocument[]): void;
4616
+ poolInstrumentations?: ForwardingPoolInstrumentation[];
4617
+ };
4618
+ //#endregion
4619
+ //#region src/signer/types.d.ts
4620
+ /**
4621
+ * Configuration for signing and verification.
4622
+ */
4623
+ type SignerConfig = {
4541
4624
  /**
4542
- * Notify subscribers about relationship changes
4625
+ * The signer used to sign actions before submission.
4543
4626
  */
4544
- notifyRelationshipChanged(parentId: string, childId: string, changeType: RelationshipChangeType, childType?: string): void;
4627
+ signer: ISigner;
4545
4628
  /**
4546
- * Clear all subscriptions
4629
+ * Optional handler for verifying signatures on incoming operations.
4630
+ * If not provided, signature verification will be skipped.
4547
4631
  */
4548
- clearAll(): void;
4549
- private filterDocumentIds;
4550
- private filterDocuments;
4551
- private matchesRelationshipFilter;
4632
+ verifier?: SignatureVerificationHandler;
4633
+ };
4634
+ //#endregion
4635
+ //#region src/storage/migrations/types.d.ts
4636
+ type MigrationStrategy = "auto" | "manual" | "none";
4637
+ interface MigrationResult {
4638
+ success: boolean;
4639
+ migrationsExecuted: string[];
4640
+ error?: Error;
4552
4641
  }
4553
4642
  //#endregion
4554
- //#region src/events/event-bus.d.ts
4555
- declare class EventBus implements IEventBus {
4556
- readonly eventTypeToSubscribers: Map<number, Subscriber[]>;
4557
- subscribe<K>(type: number, subscriber: (type: number, event: K) => void | Promise<void>): Unsubscribe;
4558
- emit(type: number, data: any): Promise<void>;
4643
+ //#region src/sync/sync-builder.d.ts
4644
+ declare class SyncBuilder {
4645
+ private channelFactory?;
4646
+ private remoteStorage?;
4647
+ private cursorStorage?;
4648
+ private deadLetterStorage?;
4649
+ private config;
4650
+ withChannelFactory(factory: IChannelFactory): this;
4651
+ withRemoteStorage(storage: ISyncRemoteStorage): this;
4652
+ withCursorStorage(storage: ISyncCursorStorage): this;
4653
+ withDeadLetterStorage(storage: ISyncDeadLetterStorage): this;
4654
+ withMaxDeadLettersPerRemote(limit: number): this;
4655
+ withMaxInboxBatchSize(limit: number): this;
4656
+ build(reactor: IReactor, logger: ILogger, operationIndex: IOperationIndex, eventBus: IEventBus, db: Kysely<Database$1>, driveContainerTypes: ReadonlySet<string>): ISyncManager;
4657
+ buildModule(reactor: IReactor, logger: ILogger, operationIndex: IOperationIndex, eventBus: IEventBus, db: Kysely<Database$1>, driveContainerTypes: ReadonlySet<string>): InProcessSyncModule;
4559
4658
  }
4560
4659
  //#endregion
4561
- //#region src/queue/queue.d.ts
4660
+ //#region src/core/reactor-builder.d.ts
4562
4661
  /**
4563
- * In-memory implementation of the IQueue interface.
4564
- * Organizes jobs by documentId, scope, and branch to ensure proper ordering.
4565
- * Ensures serial execution per document by tracking executing jobs.
4566
- * Implements dependency management through queue hints.
4662
+ * Dependencies provided to read-model factories registered via
4663
+ * `withReadModelFactory`. These are constructed inside `buildModule()`, which
4664
+ * is why factory-based registration is needed for read models that depend on
4665
+ * them (`BaseReadModel` subclasses, in particular).
4567
4666
  */
4568
- declare class InMemoryQueue implements IQueue {
4569
- private eventBus;
4570
- private resolver;
4571
- private queues;
4572
- private jobIdToQueueKey;
4573
- private docIdToJobId;
4574
- private jobIdToDocId;
4575
- private completedJobs;
4576
- private jobIndex;
4577
- private isBlocked;
4578
- private onDrainedCallback?;
4579
- private isPausedFlag;
4580
- constructor(eventBus: IEventBus, resolver: IDocumentModelResolver);
4581
- private toErrorInfo;
4667
+ interface ReadModelFactoryDeps {
4668
+ documentModelRegistry: IDocumentModelRegistry;
4669
+ operationIndex: IOperationIndex;
4670
+ writeCache: IWriteCache;
4671
+ processorManagerConsistencyTracker: IConsistencyTracker;
4672
+ }
4673
+ /**
4674
+ * Factory that builds a pre-ready read model from internal reactor
4675
+ * dependencies once they are available. Awaited during `buildModule()`.
4676
+ */
4677
+ type ReadModelFactory = (deps: ReadModelFactoryDeps) => IReadModel | Promise<IReadModel>;
4678
+ type WorkerPoolBase = {
4679
+ /** Number of worker threads to spawn; also the sticky-routing modulus. */numWorkers: number;
4582
4680
  /**
4583
- * Creates a unique key for a document/scope/branch combination
4681
+ * Factory spec the default transport's workers import to instantiate
4682
+ * their signature verifier. Omitted = no executor-side verification,
4683
+ * parity with the in-process executor's default.
4584
4684
  */
4585
- private createQueueKey;
4685
+ verifier?: SignatureVerifierSpec;
4686
+ };
4687
+ /**
4688
+ * Executor worker-pool configuration. Either `db` (default thread
4689
+ * transport; each worker opens its own Postgres pool) or a custom
4690
+ * `factory` transport is required by construction — an enabled pool
4691
+ * without connection info is unrepresentable.
4692
+ */
4693
+ type WorkerPoolOptions = (WorkerPoolBase & {
4694
+ db: DbConfig;
4695
+ factory?: WorkerFactory;
4696
+ }) | (WorkerPoolBase & {
4697
+ db?: DbConfig;
4698
+ factory: WorkerFactory;
4699
+ });
4700
+ /**
4701
+ * Caller-facing config for {@link ReactorBuilder.withProjectionShards}.
4702
+ * When set, the builder replaces the in-process
4703
+ * {@link ReadModelCoordinator} with a {@link ProjectionShardManager} that
4704
+ * fans JOB_WRITE_READY events to N projection workers sharded by
4705
+ * documentId.
4706
+ *
4707
+ * @see Sharded projection workers sub-feature brief
4708
+ * (Powerhouse board wiki id: eb26f01f-8f68-4918-a6f6-ac7a4679b533)
4709
+ */
4710
+ type ProjectionShardBuilderConfig = {
4711
+ shardCount: number;
4712
+ preReadyKinds: BuiltInReadModelKind[];
4713
+ postReadyKinds: BuiltInReadModelKind[];
4586
4714
  /**
4587
- * Gets or creates a queue for the given key
4715
+ * Connection info for the projection workers' own pools. Falls back to
4716
+ * the executor worker pool's `db` when {@link ReactorBuilder.withWorkerPool}
4717
+ * is configured with one.
4588
4718
  */
4589
- private getQueue;
4719
+ db?: DbConfig;
4720
+ poolSize?: number;
4721
+ initTimeoutMs?: number;
4722
+ shutdownGraceMs?: number;
4723
+ drainTimeoutMs?: number;
4724
+ chainDepthReportIntervalMs?: number;
4725
+ };
4726
+ declare class ReactorBuilder {
4727
+ private logger?;
4728
+ private documentModelSources;
4729
+ private upgradeManifests;
4730
+ private features;
4731
+ private readModels;
4732
+ private readModelFactories;
4733
+ private executorManager;
4734
+ private executorConfig;
4735
+ private writeCacheConfig?;
4736
+ private migrationStrategy;
4737
+ private syncBuilder?;
4738
+ private eventBus?;
4739
+ private readModelCoordinator?;
4740
+ private signatureVerifier?;
4741
+ private kyselyInstance?;
4742
+ private signalHandlersEnabled;
4743
+ private queueInstance?;
4744
+ private channelScheme?;
4745
+ private jwtHandler?;
4746
+ private documentModelLoader?;
4747
+ private shutdownHooks;
4748
+ private driveContainerTypes;
4749
+ private workerPool?;
4750
+ private resolvedModelManifest?;
4751
+ private projectionShardConfig?;
4752
+ private projectionWorkerFactory?;
4753
+ private instrumentedPools;
4754
+ withLogger(logger: ILogger): this;
4590
4755
  /**
4591
- * Check if a document has any jobs currently executing
4756
+ * Register document-model sources: live modules, importable files, or
4757
+ * importable packages. Appends across calls. At `buildModule()` every
4758
+ * source is resolved host-side and registered on the registry; file and
4759
+ * package sources additionally form the worker manifest when the worker
4760
+ * pool is enabled (live modules cannot cross a thread boundary).
4592
4761
  */
4593
- private isDocumentExecuting;
4762
+ withDocumentModelSources(sources: DocumentModelSource[]): this;
4763
+ withUpgradeManifests(manifests: UpgradeManifest<readonly number[]>[]): this;
4764
+ withFeatures(features: ReactorFeatures): this;
4765
+ withReadModel(readModel: IReadModel): this;
4594
4766
  /**
4595
- * Mark a job as executing for its document
4767
+ * Register a factory that builds a pre-ready read model after the reactor's
4768
+ * internal `operationIndex`, `writeCache`, and processor-manager consistency
4769
+ * tracker are constructed. Use this for read models (e.g. `BaseReadModel`
4770
+ * subclasses) that need those dependencies and therefore cannot be built
4771
+ * before calling `buildModule()`.
4596
4772
  */
4597
- private markJobExecuting;
4773
+ withReadModelFactory(factory: ReadModelFactory): this;
4774
+ withReadModelCoordinator(readModelCoordinator: IReadModelCoordinator): this;
4775
+ withExecutor(executor: IJobExecutorManager): this;
4776
+ withExecutorConfig(config: Partial<JobExecutorConfig>): this;
4777
+ withWriteCacheConfig(config: Partial<WriteCacheConfig>): this;
4778
+ withDriveContainerTypes(types: string[]): this;
4779
+ withMigrationStrategy(strategy: MigrationStrategy): this;
4780
+ withSync(syncBuilder: SyncBuilder): this;
4781
+ withEventBus(eventBus: IEventBus): this;
4782
+ withSignatureVerifier(verifier: SignatureVerificationHandler): this;
4783
+ withKysely(kysely: Kysely<Database>): this;
4598
4784
  /**
4599
- * Mark a job as no longer executing for its document
4785
+ * Register an externally-constructed pg.Pool's {@link PoolInstrumentation}
4786
+ * so it surfaces through {@link ReactorModule.pools}. Use this when the
4787
+ * caller built the pool itself (e.g. the in-process bench host wiring) so
4788
+ * pool acquire-wait and pool-stat metrics still emit. The builder also
4789
+ * registers any pool it constructs internally via {@link createPostgresDatabase}.
4600
4790
  */
4601
- private markJobComplete;
4791
+ withInstrumentedPool(instrumentation: PoolInstrumentation): this;
4792
+ withQueue(queue: IQueue): this;
4793
+ withChannelScheme(scheme: ChannelScheme): this;
4794
+ withJwtHandler(handler: JwtHandler): this;
4795
+ withDocumentModelLoader(loader: IDocumentModelLoader): this;
4796
+ withSignalHandlers(): this;
4602
4797
  /**
4603
- * Check if all dependencies for a job have been completed
4798
+ * Register an async cleanup hook to run during graceful shutdown. Hooks fire
4799
+ * after `reactor.kill()` resolves and before `database.destroy()`, so callers
4800
+ * that depend on the reactor (e.g. an HTTP API layered on top) can drain
4801
+ * cleanly before the underlying kysely instance is torn down. Hook errors are
4802
+ * logged and otherwise ignored — one bad hook cannot strand the rest of the
4803
+ * shutdown chain.
4604
4804
  */
4605
- private areDependenciesMet;
4805
+ withShutdownHook(hook: () => Promise<void>): this;
4606
4806
  /**
4607
- * Returns the head of the sub-queue if its dependencies are met, or null.
4608
- *
4609
- * The dispatcher only ever considers the head a dep-blocked head holds
4610
- * the rest of its sub-queue. This preserves per-(documentId, scope, branch)
4611
- * FIFO regardless of how dependencies are authored, and makes the queue's
4612
- * documented "serialized per document" invariant hold even when callers
4613
- * omit queueHint dependencies on jobs that share a sub-queue.
4614
- */
4615
- private getNextJobWithMetDependencies;
4616
- private getCreateDocumentType;
4617
- enqueue(job: Job): Promise<void>;
4618
- dequeue(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
4619
- dequeueNext(signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
4620
- dequeueNextMatching(predicate: (meta: JobRoutingMeta) => boolean, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
4621
- size(documentId: string, scope: string, branch: string): Promise<number>;
4622
- totalSize(): Promise<number>;
4623
- remove(jobId: string): Promise<boolean>;
4624
- clear(documentId: string, scope: string, branch: string): Promise<void>;
4625
- clearAll(): Promise<void>;
4626
- hasJobs(): Promise<boolean>;
4627
- completeJob(jobId: string): Promise<void>;
4628
- failJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
4629
- deferJob(jobId: string): void;
4630
- retryJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
4807
+ * Enable the executor worker pool: N `node:worker_threads` workers with
4808
+ * sticky per-document routing, replacing the in-process executor. Calling
4809
+ * this enables the pool there is no `enabled` flag. Provide `db`
4810
+ * (each worker opens its own Postgres pool; the parent database is built
4811
+ * from it too unless {@link withKysely} is set) or a custom `factory`
4812
+ * transport. `verifier` is imported by the default transport's workers;
4813
+ * omitted = no executor-side signature verification.
4814
+ */
4815
+ withWorkerPool(options: WorkerPoolOptions): this;
4631
4816
  /**
4632
- * Check if the queue is drained and call the callback if it is
4817
+ * Configure N sharded projection workers. When set, the builder replaces
4818
+ * the default in-process {@link ReadModelCoordinator} with a
4819
+ * {@link ProjectionShardManager}.
4820
+ *
4821
+ * Projection workers open their own Postgres pools from `config.db`,
4822
+ * falling back to the executor worker pool's `db` when
4823
+ * {@link withWorkerPool} is configured with one; only the `poolSize` is
4824
+ * overridden by {@link ProjectionShardBuilderConfig.poolSize}. The same
4825
+ * model manifest resolved from {@link withDocumentModelSources} is
4826
+ * forwarded.
4633
4827
  */
4634
- private checkDrained;
4828
+ withProjectionShards(config: ProjectionShardBuilderConfig): this;
4635
4829
  /**
4636
- * Returns true if and only if all jobs have been resolved.
4830
+ * Inject a custom {@link ProjectionWorkerFactory}. When set, the builder
4831
+ * skips default thread-transport wiring for the projection shards and
4832
+ * hands the factory directly to {@link ProjectionShardManager}.
4637
4833
  */
4638
- get isDrained(): boolean;
4834
+ withProjectionWorkerFactory(factory: ProjectionWorkerFactory): this;
4835
+ getResolvedModelManifest(): ModelManifestEntry[] | undefined;
4836
+ build(): Promise<IReactor>;
4837
+ buildModule(): Promise<InProcessReactorModule>;
4639
4838
  /**
4640
- * Blocks the queue from accepting new jobs.
4641
- * @param onDrained - Optional callback to call when the queue is drained
4839
+ * The single Postgres config for the parent, executor workers, and
4840
+ * projection shards. They must share one physical database (the parent
4841
+ * writes operations; workers and shards read them), so divergent
4842
+ * worker/shard targets throw. `withKysely` overrides the parent and is not
4843
+ * validated against a worker/shard `db`.
4642
4844
  */
4643
- block(onDrained?: () => void): void;
4845
+ private resolveReactorDbConfig;
4644
4846
  /**
4645
- * Unblocks the queue from accepting new jobs.
4847
+ * Constructs a {@link ProjectionShardManager} bound to the host event
4848
+ * bus. Builds the default thread-transport factory unless one was
4849
+ * injected via {@link withProjectionWorkerFactory}. Calls
4850
+ * `manager.startup()` so all N workers reach READY before the reactor
4851
+ * is returned to the caller.
4646
4852
  */
4647
- unblock(): void;
4853
+ private createProjectionShardManager;
4854
+ private createDefaultProjectionWorkerFactory;
4648
4855
  /**
4649
- * Pauses job dequeuing. Jobs can still be enqueued but dequeueNext() will return null.
4856
+ * Default {@link WorkerFactory} used when the pool options carry no
4857
+ * custom `factory`. Each worker spawns a real `node:worker_threads`
4858
+ * Worker pointing at the compiled `worker/entry.js`.
4650
4859
  */
4651
- pause(): void;
4860
+ private createDefaultWorkerFactory;
4652
4861
  /**
4653
- * Resumes job dequeuing and emits JOB_AVAILABLE events for pending jobs to wake up executors.
4862
+ * Builds the parent Kysely instance against a real Postgres server using
4863
+ * the same {@link DbConfig} the workers receive at init. Used in the
4864
+ * worker-pool path so the parent reactor and each worker thread share
4865
+ * storage; PGlite cannot be shared across threads. The constructed pool
4866
+ * is wrapped with {@link instrumentPgPool} and the resulting
4867
+ * {@link PoolInstrumentation} is pushed onto {@link instrumentedPools} so
4868
+ * the reactor module exposes acquire-wait and pool-stat surfaces.
4654
4869
  */
4655
- resume(): Promise<void>;
4870
+ private createPostgresDatabase;
4871
+ private attachSignalHandlers;
4872
+ }
4873
+ //#endregion
4874
+ //#region src/core/reactor-client-builder.d.ts
4875
+ /**
4876
+ * Builder class for constructing ReactorClient instances with proper configuration
4877
+ */
4878
+ declare class ReactorClientBuilder {
4879
+ private logger?;
4880
+ private reactorBuilder?;
4881
+ private reactor?;
4882
+ private eventBus?;
4883
+ private documentIndexer?;
4884
+ private documentView?;
4885
+ private signer?;
4886
+ private signatureVerifier?;
4887
+ private subscriptionManager?;
4888
+ private jobAwaiter?;
4889
+ private documentModelLoader?;
4656
4890
  /**
4657
- * Returns whether job dequeuing is paused.
4891
+ * Sets the logger for the ReactorClient.
4892
+ * @param logger - The logger to use.
4893
+ * @returns The ReactorClientBuilder instance.
4658
4894
  */
4659
- get paused(): boolean;
4895
+ withLogger(logger: ILogger): this;
4660
4896
  /**
4661
- * Returns all pending jobs across all queues.
4897
+ * Either this or withReactor must be set.
4662
4898
  */
4663
- getPendingJobs(): Job[];
4899
+ withReactorBuilder(reactorBuilder: ReactorBuilder): this;
4664
4900
  /**
4665
- * Returns a map of document IDs to sets of executing job IDs.
4901
+ * Either this or withReactorBuilder must be set.
4666
4902
  */
4667
- getExecutingJobIds(): Map<string, Set<string>>;
4903
+ withReactor(reactor: IReactor, eventBus: IEventBus, documentIndexer: IDocumentIndexer, documentView: IDocumentView): this;
4668
4904
  /**
4669
- * Returns a job by ID from the job index.
4905
+ * Sets the signer configuration for signing and verifying actions.
4906
+ *
4907
+ * @param config - Either an ISigner for signing only, or a SignerConfig for both signing and verification
4670
4908
  */
4671
- getJob(jobId: string): Job | undefined;
4909
+ withSigner(config: ISigner | SignerConfig): this;
4910
+ withSubscriptionManager(subscriptionManager: IReactorSubscriptionManager): this;
4911
+ withJobAwaiter(jobAwaiter: IJobAwaiter): this;
4912
+ withDocumentModelLoader(loader: IDocumentModelLoader): this;
4913
+ build(): Promise<ReactorClient>;
4914
+ buildModule(): Promise<InProcessReactorClientModule>;
4672
4915
  }
4673
4916
  //#endregion
4674
- //#region src/job-tracker/in-memory-job-tracker.d.ts
4917
+ //#region src/core/drive-container-types.d.ts
4918
+ declare const DEFAULT_DRIVE_CONTAINER_TYPES: ReadonlySet<string>;
4919
+ //#endregion
4920
+ //#region src/core/reactor.d.ts
4675
4921
  /**
4676
- * In-memory implementation of IJobTracker.
4677
- * Maintains job status in a Map for synchronous access.
4678
- * Subscribes to operation events to update job states.
4922
+ * This class implements the IReactor interface and serves as the main entry point
4923
+ * for the new Reactor architecture.
4679
4924
  */
4680
- declare class InMemoryJobTracker implements IJobTracker {
4925
+ declare class Reactor implements IReactor {
4926
+ private logger;
4927
+ private documentModelRegistry;
4928
+ private shutdownStatus;
4929
+ private setShutdown;
4930
+ private setCompleted;
4931
+ private queue;
4932
+ private jobTracker;
4933
+ private readModelCoordinator;
4934
+ private features;
4935
+ private documentView;
4936
+ private documentIndexer;
4937
+ private operationStore;
4681
4938
  private eventBus;
4682
- private jobs;
4683
- private unsubscribers;
4684
- constructor(eventBus: IEventBus);
4685
- private subscribeToEvents;
4686
- private handleWriteReady;
4687
- private handleReadReady;
4688
- private handleJobFailed;
4689
- shutdown(): void;
4690
- registerJob(jobInfo: JobInfo): void;
4691
- markRunning(jobId: string): void;
4692
- markFailed(jobId: string, error: ErrorInfo$1, job?: Job): void;
4693
- getJobStatus(jobId: string): JobInfo | null;
4939
+ private executorManager;
4940
+ constructor(logger: ILogger, documentModelRegistry: IDocumentModelRegistry, queue: IQueue, jobTracker: IJobTracker, readModelCoordinator: IReadModelCoordinator, features: ReactorFeatures, documentView: IDocumentView, documentIndexer: IDocumentIndexer, operationStore: IOperationStore, eventBus: IEventBus, executorManager: IJobExecutorManager);
4941
+ kill(): ShutdownStatus;
4942
+ getDocumentModels(namespace?: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentModelModule>>;
4943
+ get<TDocument extends PHDocument>(id: string, view?: ViewFilter, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<TDocument>;
4944
+ getBySlug<TDocument extends PHDocument>(slug: string, view?: ViewFilter, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<TDocument>;
4945
+ getByIdOrSlug<TDocument extends PHDocument>(identifier: string, view?: ViewFilter, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<TDocument>;
4946
+ getOutgoingRelationships(sourceId: string, relationshipType: string, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<string[]>;
4947
+ getIncomingRelationships(targetId: string, relationshipType: string, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<string[]>;
4948
+ getOperations(documentId: string, view?: ViewFilter, filter?: OperationFilter, paging?: PagingOptions, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<Record<string, PagedResults<Operation>>>;
4949
+ find(search: SearchFilter, view?: ViewFilter, paging?: PagingOptions, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
4950
+ create(document: PHDocument, signer?: ISigner, signal?: AbortSignal, meta?: Record<string, unknown>): Promise<JobInfo>;
4951
+ deleteDocument(id: string, signer?: ISigner, signal?: AbortSignal, meta?: Record<string, unknown>): Promise<JobInfo>;
4952
+ execute(docId: string, branch: string, actions: Action[], signal?: AbortSignal, meta?: Record<string, unknown>): Promise<JobInfo>;
4953
+ load(docId: string, branch: string, operations: Operation[], signal?: AbortSignal, meta?: Record<string, unknown>): Promise<JobInfo>;
4954
+ executeBatch(request: BatchExecutionRequest, signal?: AbortSignal, meta?: Record<string, unknown>): Promise<BatchExecutionResult>;
4955
+ loadBatch(request: BatchLoadRequest, signal?: AbortSignal, meta?: Record<string, unknown>): Promise<BatchLoadResult>;
4956
+ addRelationship(sourceId: string, targetId: string, relationshipType: string, branch?: string, signer?: ISigner, signal?: AbortSignal): Promise<JobInfo>;
4957
+ removeRelationship(sourceId: string, targetId: string, relationshipType: string, branch?: string, signer?: ISigner, signal?: AbortSignal): Promise<JobInfo>;
4958
+ getJobStatus(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
4959
+ private findByIds;
4960
+ private findBySlugs;
4961
+ private findByParentId;
4962
+ private findByType;
4963
+ private emitJobPending;
4694
4964
  }
4695
4965
  //#endregion
4696
- //#region src/executor/simple-job-executor-manager.d.ts
4697
- type JobExecutorFactory = () => IJobExecutor;
4966
+ //#region src/shared/drive-url.d.ts
4967
+ interface ParsedDriveUrl {
4968
+ url: string;
4969
+ driveId: string;
4970
+ graphqlEndpoint: string;
4971
+ }
4698
4972
  /**
4699
- * Manages multiple job executors and coordinates job distribution.
4700
- * Listens for job available events and dispatches jobs to executors.
4973
+ * Parse a drive URL to extract drive ID and construct GraphQL endpoint.
4974
+ * Preserves any subpath prefix so the result is correct when the reactor is
4975
+ * served behind a proxy at a non-root path.
4976
+ * e.g., "http://localhost:4001/d/abc123" -> { driveId: "abc123", graphqlEndpoint: "http://localhost:4001/graphql/r" }
4977
+ * e.g., "https://example.com/api/reactor/d/abc123" -> { ..., graphqlEndpoint: "https://example.com/api/reactor/graphql/r" }
4701
4978
  */
4702
- declare class SimpleJobExecutorManager implements IJobExecutorManager {
4703
- private executorFactory;
4704
- private eventBus;
4705
- private queue;
4706
- private jobTracker;
4707
- private logger;
4708
- private resolver;
4709
- private executors;
4710
- private isRunning;
4711
- private activeJobs;
4712
- private totalJobsProcessed;
4713
- private unsubscribe?;
4714
- private deferredJobs;
4715
- private resultHandler;
4716
- private jobTimeoutMs;
4717
- constructor(executorFactory: JobExecutorFactory, eventBus: IEventBus, queue: IQueue, jobTracker: IJobTracker, logger: ILogger, resolver: IDocumentModelResolver, jobTimeoutMs?: number);
4718
- start(numExecutors: number): Promise<void>;
4719
- stop(graceful?: boolean): Promise<void>;
4720
- getExecutors(): IJobExecutor[];
4721
- getStatus(): ExecutorManagerStatus;
4722
- private processNextJob;
4723
- private checkForMoreJobs;
4724
- private processExistingJobs;
4725
- private flushDeferredJobs;
4726
- }
4979
+ declare function parseDriveUrl(url: string): ParsedDriveUrl;
4980
+ /**
4981
+ * Extract drive ID from a drive URL.
4982
+ */
4983
+ declare function driveIdFromUrl(url: string): string;
4727
4984
  //#endregion
4728
- //#region src/cache/document-meta-cache-types.d.ts
4985
+ //#region src/shared/factories.d.ts
4729
4986
  /**
4730
- * Cached document metadata from the "document" scope.
4987
+ * Factory method to create a ShutdownStatus that can be updated
4731
4988
  *
4732
- * This lightweight structure holds essential document information needed by
4733
- * the job executor without fetching full scope state. It provides an explicit
4734
- * cross-scope contract for accessing document scope metadata.
4989
+ * @param initialState - Initial shutdown state (default: false)
4990
+ * @returns A tuple of [ShutdownStatus, setShutdown function, setCompleted function]
4735
4991
  */
4736
- type CachedDocumentMeta = {
4737
- /**
4738
- * The full PHDocumentState from document.state.document.
4739
- * Contains version, hash, isDeleted, deletedAtUtcIso, etc.
4740
- */
4741
- state: PHDocumentState;
4742
- /**
4743
- * The document type (from header), cached for convenience.
4744
- */
4745
- documentType: string;
4746
- /**
4747
- * The revision of the document scope when this metadata was captured.
4748
- * Used for cache invalidation and consistency checks.
4749
- */
4750
- documentScopeRevision: number;
4992
+ declare function createMutableShutdownStatus(initialState?: boolean): [ShutdownStatus, (value: boolean) => void, (completed: Promise<void>) => void];
4993
+ //#endregion
4994
+ //#region src/shared/utils.d.ts
4995
+ type ParsedPaging = {
4996
+ offset: number;
4997
+ limit: number;
4751
4998
  };
4752
4999
  /**
4753
- * Interface for the document metadata cache.
4754
- *
4755
- * This cache provides an explicit cross-scope contract for accessing document
4756
- * scope metadata. It solves the problem where job execution in one scope (e.g.,
4757
- * "global") needs access to document scope state (version, isDeleted, etc.)
4758
- * which may be stale in scope-specific caches or keyframes.
4759
- *
4760
- * The cache supports:
4761
- * - Latest metadata retrieval with LRU caching
4762
- * - Historical metadata reconstruction for reshuffling scenarios
4763
- * - Eager updates after document scope operations
5000
+ * Validates PagingOptions and returns a normalized offset and limit.
5001
+ * Throws if the cursor is not empty and not a non-negative integer, or if
5002
+ * limit is less than 1. When `paging` is undefined, returns offset 0 and
5003
+ * the caller-supplied `defaultLimit`.
5004
+ */
5005
+ declare function parsePagingOptions(paging: PagingOptions | undefined, defaultLimit: number): ParsedPaging;
5006
+ //#endregion
5007
+ //#region src/subs/default-error-handler.d.ts
5008
+ /**
5009
+ * Default error handler that re-throws subscription errors.
5010
+ * This ensures that errors are not silently swallowed.
4764
5011
  */
4765
- interface IDocumentMetaCache {
4766
- /**
4767
- * Retrieves the LATEST document metadata from cache or rebuilds from operations.
4768
- *
4769
- * On cache miss, fetches all document scope operations and reconstructs the
4770
- * current PHDocumentState by applying UPGRADE_DOCUMENT and DELETE_DOCUMENT
4771
- * operations.
4772
- *
4773
- * @param documentId - The document identifier
4774
- * @param branch - Branch name
4775
- * @param signal - Optional abort signal to cancel the operation
4776
- * @returns The cached or rebuilt document metadata
4777
- * @throws {Error} "Operation aborted" if signal is aborted
4778
- * @throws {Error} If document not found (no CREATE_DOCUMENT operation)
4779
- */
4780
- getDocumentMeta(documentId: string, branch: string, signal?: AbortSignal): Promise<CachedDocumentMeta>;
4781
- /**
4782
- * Rebuilds document metadata at a SPECIFIC revision (always rebuilds, no caching).
4783
- *
4784
- * Used during reshuffling when operations need to be inserted at a previous
4785
- * revision and we need the document scope state as of that point in time.
4786
- *
4787
- * @param documentId - The document identifier
4788
- * @param branch - Branch name
4789
- * @param targetRevision - The document scope revision to reconstruct up to
4790
- * @param signal - Optional abort signal to cancel the operation
4791
- * @returns Document metadata as of the target revision
4792
- * @throws {Error} "Operation aborted" if signal is aborted
4793
- * @throws {Error} If document not found
4794
- */
4795
- rebuildAtRevision(documentId: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<CachedDocumentMeta>;
5012
+ declare class DefaultSubscriptionErrorHandler implements ISubscriptionErrorHandler {
5013
+ handleError(error: unknown, context: SubscriptionErrorContext): void;
5014
+ }
5015
+ //#endregion
5016
+ //#region src/subs/react-subscription-manager.d.ts
5017
+ type DocumentCreatedCallback = (result: PagedResults<string>) => void;
5018
+ type DocumentDeletedCallback = (documentIds: string[]) => void;
5019
+ type DocumentStateUpdatedCallback = (result: PagedResults<PHDocument>) => void;
5020
+ type RelationshipChangedCallback = (parentId: string, childId: string, changeType: RelationshipChangeType) => void;
5021
+ declare class ReactorSubscriptionManager implements IReactorSubscriptionManager {
5022
+ private createdSubscriptions;
5023
+ private deletedSubscriptions;
5024
+ private updatedSubscriptions;
5025
+ private relationshipSubscriptions;
5026
+ private subscriptionCounter;
5027
+ private errorHandler;
5028
+ constructor(errorHandler: ISubscriptionErrorHandler);
5029
+ onDocumentCreated(callback: DocumentCreatedCallback, search?: SearchFilter): () => void;
5030
+ onDocumentDeleted(callback: DocumentDeletedCallback, search?: SearchFilter): () => void;
5031
+ onDocumentStateUpdated(callback: DocumentStateUpdatedCallback, search?: SearchFilter, view?: ViewFilter): () => void;
5032
+ onRelationshipChanged(callback: RelationshipChangedCallback, search?: SearchFilter): () => void;
4796
5033
  /**
4797
- * Eagerly updates cached metadata after document scope operations.
4798
- *
4799
- * Called by the job executor after CREATE_DOCUMENT, UPGRADE_DOCUMENT, or
4800
- * DELETE_DOCUMENT operations to keep the cache current.
4801
- *
4802
- * @param documentId - The document identifier
4803
- * @param branch - Branch name
4804
- * @param meta - The new metadata to cache
5034
+ * Notify subscribers about created documents
4805
5035
  */
4806
- putDocumentMeta(documentId: string, branch: string, meta: CachedDocumentMeta): void;
5036
+ notifyDocumentsCreated(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
4807
5037
  /**
4808
- * Invalidates cached document metadata.
4809
- *
4810
- * Call before reshuffling operations that modify the document scope, or
4811
- * when document state may have changed externally.
4812
- *
4813
- * @param documentId - The document identifier
4814
- * @param branch - Optional branch to narrow invalidation (if omitted, all branches)
4815
- * @returns Number of entries invalidated
5038
+ * Notify subscribers about deleted documents
4816
5039
  */
4817
- invalidate(documentId: string, branch?: string): number;
5040
+ notifyDocumentsDeleted(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
4818
5041
  /**
4819
- * Clears all cached document metadata.
5042
+ * Notify subscribers about updated documents
4820
5043
  */
4821
- clear(): void;
5044
+ notifyDocumentsUpdated(documents: PHDocument[]): void;
4822
5045
  /**
4823
- * Performs startup initialization.
5046
+ * Notify subscribers about relationship changes
4824
5047
  */
4825
- startup(): Promise<void>;
5048
+ notifyRelationshipChanged(parentId: string, childId: string, changeType: RelationshipChangeType, childType?: string): void;
4826
5049
  /**
4827
- * Performs graceful shutdown.
5050
+ * Clear all subscriptions
4828
5051
  */
4829
- shutdown(): Promise<void>;
5052
+ clearAll(): void;
5053
+ private filterDocumentIds;
5054
+ private filterDocuments;
5055
+ private matchesRelationshipFilter;
4830
5056
  }
4831
5057
  //#endregion
4832
- //#region src/cache/buffer/ring-buffer.d.ts
5058
+ //#region src/events/event-bus.d.ts
5059
+ declare class EventBus implements IEventBus {
5060
+ readonly eventTypeToSubscribers: Map<number, Subscriber[]>;
5061
+ subscribe<K>(type: number, subscriber: (type: number, event: K) => void | Promise<void>): Unsubscribe;
5062
+ emit(type: number, data: any): Promise<void>;
5063
+ }
5064
+ //#endregion
5065
+ //#region src/queue/queue.d.ts
4833
5066
  /**
4834
- * RingBuffer is a generic circular buffer implementation that stores a fixed number
4835
- * of items. When the buffer is full, new items overwrite the oldest items.
4836
- *
4837
- * This implementation maintains O(1) time complexity for push operations and provides
4838
- * items in chronological order (oldest to newest) via getAll().
4839
- *
4840
- * @template T - The type of items stored in the buffer
5067
+ * In-memory implementation of the IQueue interface.
5068
+ * Organizes jobs by documentId, scope, and branch to ensure proper ordering.
5069
+ * Ensures serial execution per document by tracking executing jobs.
5070
+ * Implements dependency management through queue hints.
4841
5071
  */
4842
- declare class RingBuffer<T> {
4843
- private buffer;
4844
- private head;
4845
- private size;
4846
- private capacity;
4847
- constructor(capacity: number);
5072
+ declare class InMemoryQueue implements IQueue {
5073
+ private eventBus;
5074
+ private resolver;
5075
+ private queues;
5076
+ private jobIdToQueueKey;
5077
+ private docIdToJobId;
5078
+ private jobIdToDocId;
5079
+ private completedJobs;
5080
+ private jobIndex;
5081
+ private isBlocked;
5082
+ private onDrainedCallback?;
5083
+ private isPausedFlag;
5084
+ constructor(eventBus: IEventBus, resolver: IDocumentModelResolver);
5085
+ private toErrorInfo;
4848
5086
  /**
4849
- * Adds an item to the buffer. If the buffer is full, overwrites the oldest item.
4850
- *
4851
- * @param item - The item to add
5087
+ * Creates a unique key for a document/scope/branch combination
4852
5088
  */
4853
- push(item: T): void;
5089
+ private createQueueKey;
4854
5090
  /**
4855
- * Returns all items in the buffer in chronological order (oldest to newest).
4856
- *
4857
- * @returns Array of items in insertion order
5091
+ * Gets or creates a queue for the given key
4858
5092
  */
4859
- getAll(): T[];
5093
+ private getQueue;
4860
5094
  /**
4861
- * Clears all items from the buffer.
5095
+ * Check if a document has any jobs currently executing
4862
5096
  */
4863
- clear(): void;
5097
+ private isDocumentExecuting;
4864
5098
  /**
4865
- * Gets the current number of items in the buffer.
5099
+ * Mark a job as executing for its document
4866
5100
  */
4867
- get length(): number;
4868
- }
4869
- //#endregion
4870
- //#region src/cache/kysely-write-cache.d.ts
4871
- type DocumentStream = {
4872
- key: string;
4873
- ringBuffer: RingBuffer<CachedSnapshot>;
4874
- };
4875
- /**
4876
- * In-memory write cache with keyframe persistence for PHDocuments.
4877
- *
4878
- * Caches document snapshots in ring buffers with LRU eviction. On cache miss,
4879
- * rebuilds documents from nearest keyframe or full operation history.
4880
- *
4881
- * **Performance Characteristics:**
4882
- * - Cache hit: O(1) lookup in ring buffer
4883
- * - Cold miss: O(n) where n is total operation count, or O(k) where k is operations since keyframe
4884
- * - Warm miss: O(m) where m is operations since cached revision
4885
- * - Eviction: O(1) for LRU tracking and removal
4886
- *
4887
- * **Thread Safety:**
4888
- * Not thread-safe. Designed for single-threaded job executor environment.
4889
- * External synchronization required for concurrent access across multiple executors.
4890
- *
4891
- * **Example:**
4892
- * ```typescript
4893
- * const cache = new KyselyWriteCache(
4894
- * keyframeStore,
4895
- * operationStore,
4896
- * registry,
4897
- * { maxDocuments: 1000, ringBufferSize: 10, keyframeInterval: 10 }
4898
- * );
4899
- *
4900
- * await cache.startup();
4901
- *
4902
- * // Retrieve or rebuild document
4903
- * const doc = await cache.getState(docId, docType, scope, branch, revision);
4904
- *
4905
- * // Cache result after job execution
4906
- * cache.putState(docId, docType, scope, branch, newRevision, updatedDoc);
4907
- *
4908
- * await cache.shutdown();
4909
- * ```
4910
- */
4911
- declare class KyselyWriteCache implements IWriteCache {
4912
- private streams;
4913
- private lruTracker;
4914
- private keyframeStore;
4915
- private operationStore;
4916
- private registry;
4917
- private config;
4918
- constructor(keyframeStore: IKeyframeStore, operationStore: IOperationStore, registry: IDocumentModelRegistry, config: WriteCacheConfig);
4919
- withScopedStores(operationStore: IOperationStore, keyframeStore: IKeyframeStore): KyselyWriteCache;
5101
+ private markJobExecuting;
4920
5102
  /**
4921
- * Initializes the write cache.
4922
- * Currently a no-op as keyframe store lifecycle is managed externally.
5103
+ * Mark a job as no longer executing for its document
4923
5104
  */
4924
- startup(): Promise<void>;
5105
+ private markJobComplete;
4925
5106
  /**
4926
- * Shuts down the write cache.
4927
- * Currently a no-op as keyframe store lifecycle is managed externally.
5107
+ * Check if all dependencies for a job have been completed
4928
5108
  */
4929
- shutdown(): Promise<void>;
5109
+ private areDependenciesMet;
4930
5110
  /**
4931
- * Retrieves document state at a specific revision from cache or rebuilds it.
4932
- *
4933
- * Cache hit path: Returns cached snapshot if available (O(1))
4934
- * Warm miss path: Rebuilds from cached base revision + incremental ops
4935
- * Cold miss path: Rebuilds from keyframe or from scratch using all operations
5111
+ * Returns the head of the sub-queue if its dependencies are met, or null.
4936
5112
  *
4937
- * @param documentId - The document identifier
4938
- * @param scope - The operation scope
4939
- * @param branch - The operation branch
4940
- * @param targetRevision - The target revision, or undefined for newest
4941
- * @param signal - Optional abort signal to cancel the operation
4942
- * @returns The document at the target revision
4943
- * @throws {Error} "Operation aborted" if signal is aborted
4944
- * @throws {ModuleNotFoundError} If document type not registered in registry
4945
- * @throws {Error} "Failed to rebuild document" if operation store fails
4946
- * @throws {Error} If reducer throws during operation application
4947
- * @throws {Error} If document serialization fails
5113
+ * The dispatcher only ever considers the head — a dep-blocked head holds
5114
+ * the rest of its sub-queue. This preserves per-(documentId, scope, branch)
5115
+ * FIFO regardless of how dependencies are authored, and makes the queue's
5116
+ * documented "serialized per document" invariant hold even when callers
5117
+ * omit queueHint dependencies on jobs that share a sub-queue.
5118
+ */
5119
+ private getNextJobWithMetDependencies;
5120
+ private getCreateDocumentType;
5121
+ enqueue(job: Job): Promise<void>;
5122
+ dequeue(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
5123
+ dequeueNext(signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
5124
+ dequeueNextMatching(predicate: (meta: JobRoutingMeta) => boolean, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
5125
+ size(documentId: string, scope: string, branch: string): Promise<number>;
5126
+ totalSize(): Promise<number>;
5127
+ remove(jobId: string): Promise<boolean>;
5128
+ clear(documentId: string, scope: string, branch: string): Promise<void>;
5129
+ clearAll(): Promise<void>;
5130
+ hasJobs(): Promise<boolean>;
5131
+ completeJob(jobId: string): Promise<void>;
5132
+ failJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
5133
+ deferJob(jobId: string): void;
5134
+ retryJob(jobId: string, error?: ErrorInfo$1, accounting?: RetryAccounting): Promise<void>;
5135
+ /**
5136
+ * Check if the queue is drained and call the callback if it is
5137
+ */
5138
+ private checkDrained;
5139
+ /**
5140
+ * Returns true if and only if all jobs have been resolved.
4948
5141
  */
4949
- getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
5142
+ get isDrained(): boolean;
4950
5143
  /**
4951
- * Stores a document snapshot in the cache at a specific revision.
4952
- *
4953
- * The cached document is a shallow copy of the input with its operation history
4954
- * truncated to the last operation per scope and its clipboard cleared. This keeps
4955
- * memory use and copy costs constant regardless of operation count. Consumers of
4956
- * getState() must not rely on the full operation history being present; the only
4957
- * guaranteed invariant is that operations[scope].at(-1) reflects the latest
4958
- * operation index for each scope.
4959
- *
4960
- * Updates LRU tracker and may evict least recently used stream if at capacity.
4961
- * Asynchronously persists keyframes at configured intervals (fire-and-forget).
4962
- *
4963
- * @param documentId - The document identifier
4964
- * @param scope - The operation scope
4965
- * @param branch - The operation branch
4966
- * @param revision - The revision number
4967
- * @param document - The document to cache
4968
- * @throws {Error} If document serialization fails
5144
+ * Blocks the queue from accepting new jobs.
5145
+ * @param onDrained - Optional callback to call when the queue is drained
4969
5146
  */
4970
- putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument): void;
5147
+ block(onDrained?: () => void): void;
4971
5148
  /**
4972
- * Invalidates cached document streams.
4973
- *
4974
- * Supports three invalidation scopes:
4975
- * - Document-level: invalidate(documentId) - removes all streams for document
4976
- * - Scope-level: invalidate(documentId, scope) - removes all branches for scope
4977
- * - Stream-level: invalidate(documentId, scope, branch) - removes specific stream
4978
- *
4979
- * @param documentId - The document identifier
4980
- * @param scope - Optional scope to narrow invalidation
4981
- * @param branch - Optional branch to narrow invalidation (requires scope)
4982
- * @returns The number of streams evicted
5149
+ * Unblocks the queue from accepting new jobs.
4983
5150
  */
4984
- invalidate(documentId: string, scope?: string, branch?: string): number;
5151
+ unblock(): void;
4985
5152
  /**
4986
- * Clears the entire cache, removing all cached document streams.
4987
- * Resets LRU tracking state. This operation always succeeds.
5153
+ * Pauses job dequeuing. Jobs can still be enqueued but dequeueNext() will return null.
4988
5154
  */
4989
- clear(): void;
5155
+ pause(): void;
4990
5156
  /**
4991
- * Retrieves a specific stream for a document. Exposed on the implementation
4992
- * for testing, but not on the interface.
4993
- *
4994
- * @internal
5157
+ * Resumes job dequeuing and emits JOB_AVAILABLE events for pending jobs to wake up executors.
4995
5158
  */
4996
- getStream(documentId: string, scope: string, branch: string): DocumentStream | undefined;
4997
- private findNearestKeyframe;
4998
- private coldMissRebuild;
5159
+ resume(): Promise<void>;
4999
5160
  /**
5000
- * Resolves which module version to use for a given operation in phase 2.
5001
- *
5002
- * Uses the validated-upgrade boundary rules from D7:
5003
- * - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary
5004
- * - Otherwise: timestamp fallback
5005
- * - Falls back to final module version when neither is decidable
5161
+ * Returns whether job dequeuing is paused.
5006
5162
  */
5007
- private resolveModuleVersionForOp;
5008
- private warmMissRebuild;
5009
- private findNearestOlderSnapshot;
5010
- private makeStreamKey;
5011
- private getOrCreateStream;
5012
- private isKeyframeRevision;
5013
- }
5014
- //#endregion
5015
- //#region src/storage/kysely/store.d.ts
5016
- declare class KyselyOperationStore implements IOperationStore {
5017
- private db;
5018
- private trx?;
5019
- constructor(db: Kysely<Database$1>);
5020
- private get queryExecutor();
5021
- withTransaction(trx: Transaction<Database$1>): KyselyOperationStore;
5022
- apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal): Promise<Operation[]>;
5023
- private resolveUniqueConstraint;
5024
- private executeApply;
5025
- private findIdempotentReplay;
5026
- getSince(documentId: string, scope: string, branch: string, revision: number, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
5027
- getSinceId(id: number, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<OperationWithContext$1>>;
5028
- getConflicting(documentId: string, scope: string, branch: string, minTimestamp: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
5029
- getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
5030
- private rowToOperation;
5031
- private rowToOperationWithContext;
5163
+ get paused(): boolean;
5164
+ /**
5165
+ * Returns all pending jobs across all queues.
5166
+ */
5167
+ getPendingJobs(): Job[];
5168
+ /**
5169
+ * Returns a map of document IDs to sets of executing job IDs.
5170
+ */
5171
+ getExecutingJobIds(): Map<string, Set<string>>;
5172
+ /**
5173
+ * Returns a job by ID from the job index.
5174
+ */
5175
+ getJob(jobId: string): Job | undefined;
5032
5176
  }
5033
5177
  //#endregion
5034
- //#region src/storage/kysely/keyframe-store.d.ts
5035
- declare class KyselyKeyframeStore implements IKeyframeStore {
5036
- private db;
5037
- private trx?;
5038
- constructor(db: Kysely<Database$1>);
5039
- private get queryExecutor();
5040
- withTransaction(trx: Transaction<Database$1>): KyselyKeyframeStore;
5041
- putKeyframe(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, signal?: AbortSignal): Promise<void>;
5042
- findNearestKeyframe(documentId: string, scope: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<{
5043
- revision: number;
5044
- document: PHDocument;
5045
- } | undefined>;
5046
- listKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<Array<{
5047
- scope: string;
5048
- branch: string;
5049
- revision: number;
5050
- document: PHDocument;
5051
- }>>;
5052
- deleteKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<number>;
5178
+ //#region src/job-tracker/in-memory-job-tracker.d.ts
5179
+ /**
5180
+ * In-memory implementation of IJobTracker.
5181
+ * Maintains job status in a Map for synchronous access.
5182
+ * Subscribes to operation events to update job states.
5183
+ */
5184
+ declare class InMemoryJobTracker implements IJobTracker {
5185
+ private eventBus;
5186
+ private jobs;
5187
+ private unsubscribers;
5188
+ constructor(eventBus: IEventBus);
5189
+ private subscribeToEvents;
5190
+ private handleWriteReady;
5191
+ private handleReadReady;
5192
+ private handleJobFailed;
5193
+ shutdown(): void;
5194
+ registerJob(jobInfo: JobInfo): void;
5195
+ markRunning(jobId: string): void;
5196
+ markFailed(jobId: string, error: ErrorInfo$1, job?: Job): void;
5197
+ getJobStatus(jobId: string): JobInfo | null;
5053
5198
  }
5054
5199
  //#endregion
5055
- //#region src/executor/execution-scope.d.ts
5056
- interface ExecutionStores {
5057
- operationStore: IOperationStore;
5058
- operationIndex: IOperationIndex;
5059
- writeCache: IWriteCache;
5060
- documentMetaCache: IDocumentMetaCache;
5061
- collectionMembershipCache: ICollectionMembershipCache;
5062
- }
5063
- interface IExecutionScope {
5064
- run<T>(fn: (stores: ExecutionStores) => Promise<T>, signal?: AbortSignal): Promise<T>;
5200
+ //#region src/executor/simple-job-executor-manager.d.ts
5201
+ type JobExecutorFactory = () => IJobExecutor;
5202
+ /**
5203
+ * Manages multiple job executors and coordinates job distribution.
5204
+ * Listens for job available events and dispatches jobs to executors.
5205
+ */
5206
+ declare class SimpleJobExecutorManager implements IJobExecutorManager {
5207
+ private executorFactory;
5208
+ private eventBus;
5209
+ private queue;
5210
+ private jobTracker;
5211
+ private logger;
5212
+ private resolver;
5213
+ private executors;
5214
+ private isRunning;
5215
+ private activeJobs;
5216
+ private totalJobsProcessed;
5217
+ private unsubscribe?;
5218
+ private deferredJobs;
5219
+ private resultHandler;
5220
+ private jobTimeoutMs;
5221
+ constructor(executorFactory: JobExecutorFactory, eventBus: IEventBus, queue: IQueue, jobTracker: IJobTracker, logger: ILogger, resolver: IDocumentModelResolver, jobTimeoutMs?: number);
5222
+ start(numExecutors: number): Promise<void>;
5223
+ stop(graceful?: boolean): Promise<void>;
5224
+ getExecutors(): IJobExecutor[];
5225
+ getStatus(): ExecutorManagerStatus;
5226
+ private processNextJob;
5227
+ private checkForMoreJobs;
5228
+ private processExistingJobs;
5229
+ private flushDeferredJobs;
5065
5230
  }
5066
5231
  //#endregion
5067
5232
  //#region src/executor/simple-job-executor.d.ts
@@ -5079,6 +5244,8 @@ declare class SimpleJobExecutor implements IJobExecutor {
5079
5244
  private collectionMembershipCache;
5080
5245
  private driveContainerTypes;
5081
5246
  private config;
5247
+ private featureFlags;
5248
+ private decisionModel;
5082
5249
  private signatureVerifierModule;
5083
5250
  private documentActionHandler;
5084
5251
  private executionScope;
@@ -5091,6 +5258,62 @@ declare class SimpleJobExecutor implements IJobExecutor {
5091
5258
  private getCollectionMembershipsForOperations;
5092
5259
  private processActions;
5093
5260
  private executeRegularAction;
5261
+ /**
5262
+ * Orders a write by timestamp and decides it where it lands. The caller
5263
+ * supplies the timestamp, so a write can belong before operations already
5264
+ * stored; those are re-appended alongside it, the way a load reshuffles.
5265
+ *
5266
+ * Deciding a backdated write at the stream heads instead of at its position
5267
+ * would overwrite the verdict every other replica computes for it.
5268
+ */
5269
+ private positionByTimestamp;
5270
+ /**
5271
+ * Decides each operation where it lands and carries the verdict on it. A
5272
+ * refused submitted action is reported to the caller and nothing is stored; a
5273
+ * refused operation the reshuffle merely moved keeps its verdict, because it
5274
+ * already holds a position.
5275
+ *
5276
+ * The operations carry the indexes and skips they will be stored at, because
5277
+ * the walk resolves skips before it orders them.
5278
+ */
5279
+ private evaluatePositioned;
5280
+ /**
5281
+ * The scopes a re-evaluation pass visits, in a fixed order.
5282
+ *
5283
+ * The revisions map comes from a query with no ORDER BY, and the order is
5284
+ * load-bearing: each scope's pass re-reads the auth stream, and the walk skips
5285
+ * an operation by its stored denial, so a denial this pass just wrote is
5286
+ * visible to a later-visited scope and invisible to an earlier one. The model's
5287
+ * own projection order leads, then the rest sorted, so the pass is reproducible
5288
+ * across replicas and across runs.
5289
+ */
5290
+ private evaluationOrder;
5291
+ /**
5292
+ * The first timestamp in the batch that does not strictly exceed everything
5293
+ * ahead of it, or undefined when the whole batch is monotonic.
5294
+ *
5295
+ * The bound is carried forward rather than compared against one stored maximum,
5296
+ * because a single execute can carry several auth actions stamped in the same
5297
+ * millisecond. Letting a tie through would store a stream the position walk
5298
+ * then refuses to read, with no repair path.
5299
+ */
5300
+ private firstNonMonotonicTimestamp;
5301
+ /** The operations a batch of submitted actions appends at the scope's tail. */
5302
+ private appendedOperations;
5303
+ /**
5304
+ * Re-evaluates the document when a write meets both criteria: it was written
5305
+ * to a stream the model reads, and it is timestamped before an operation
5306
+ * already stored. The caller supplies the timestamp and the reactor does not replace
5307
+ * it, so a mutation job can write such an operation just as a load job can,
5308
+ * which is why both executeJob and executeLoadJob call this.
5309
+ */
5310
+ private reevaluateIfCriteriaMet;
5311
+ /**
5312
+ * Re-evaluates every scope the model evaluates. Where an operation's
5313
+ * evaluation differs from what is stored, the tail from that operation is
5314
+ * re-appended, carrying a skip that spans the indices it supersedes.
5315
+ */
5316
+ private reevaluateDocument;
5094
5317
  private executeLoadJob;
5095
5318
  private accumulateResultOrReturnError;
5096
5319
  }
@@ -5159,6 +5382,141 @@ declare class DocumentModelRegistry implements IDocumentModelRegistry {
5159
5382
  getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
5160
5383
  }
5161
5384
  //#endregion
5385
+ //#region src/decision/types.d.ts
5386
+ /** One operation stream. */
5387
+ type StreamQuery = {
5388
+ documentId: string;
5389
+ branch: string;
5390
+ scope: string;
5391
+ };
5392
+ /** The document and branch a decision model is built for. */
5393
+ type DecisionTarget = {
5394
+ documentId: string;
5395
+ branch: string;
5396
+ };
5397
+ /** The executing scope's own state, for conditions that read it. */
5398
+ type DecisionContext = {
5399
+ scopeState: unknown;
5400
+ };
5401
+ /**
5402
+ * A named stream whose value in the model is that scope's state from the
5403
+ * document rebuild the reactor already performs. A derived query may read
5404
+ * only statically-queried projections, so composition is one layer deep.
5405
+ */
5406
+ type Projection<M> = {
5407
+ query: StreamQuery | ((model: Partial<M>) => StreamQuery[]);
5408
+ /**
5409
+ * Action types in this stream that can change an evaluation. Reads of the stream
5410
+ * are filtered to these, so anything left out is invisible to a decision.
5411
+ */
5412
+ decidingActions: string[]; /** Applies one of this stream's operations while deciding. */
5413
+ apply: (document: PHDocument, operation: Operation) => PHDocument;
5414
+ };
5415
+ /**
5416
+ * The outcome of evaluating one operation. A refusal carries the reason it is
5417
+ * recorded with, because a model has more than one way to refuse.
5418
+ */
5419
+ type Evaluation = {
5420
+ decision: "allow";
5421
+ } | {
5422
+ decision: "deny";
5423
+ reason: string;
5424
+ };
5425
+ /** Projections plus a decision function over the built model. */
5426
+ type DecisionModel<M> = {
5427
+ projections: { [K in keyof M]: Projection<M> };
5428
+ /**
5429
+ * Whether or not this model decides about operations in a given scope. That
5430
+ * is, a scope it reads is not necessarily one it evaluates, and vise-versa.
5431
+ */
5432
+ evaluatesScope(scope: string): boolean;
5433
+ decide(model: M, subject: AuthSubject, request: AuthRequest, ctx: DecisionContext): Evaluation;
5434
+ };
5435
+ /** A built model plus the read-set condition recording what the build read. */
5436
+ type BuiltDecisionModel<M> = {
5437
+ model: M;
5438
+ appendCondition: AppendCondition;
5439
+ };
5440
+ //#endregion
5441
+ //#region src/decision/build-decision-model.d.ts
5442
+ /**
5443
+ * Reads each projection's stream through the write cache, recording the
5444
+ * revision observed. Static projections resolve first; derived projections
5445
+ * see only those and contribute a map from document id to state. Each
5446
+ * distinct stream is read once and yields one append condition entry.
5447
+ */
5448
+ declare function buildDecisionModel<M>(cache: IWriteCache, definition: (target: DecisionTarget) => DecisionModel<M>, target: DecisionTarget, signal?: AbortSignal): Promise<BuiltDecisionModel<M>>;
5449
+ //#endregion
5450
+ //#region src/decision/auth-decision-model.d.ts
5451
+ type AuthDecisionModel = {
5452
+ document: PHDocumentState;
5453
+ auth: PHAuthState;
5454
+ };
5455
+ /** This decision model uses both the document and the auth streams. */
5456
+ declare function authDecisionModel(target: DecisionTarget): DecisionModel<AuthDecisionModel>;
5457
+ //#endregion
5458
+ //#region src/decision/document-decision-model.d.ts
5459
+ /** What the document decision model reads: the target's document scope. */
5460
+ type DocumentDecisionModel = {
5461
+ document: PHDocumentState;
5462
+ };
5463
+ /**
5464
+ * The simplest decision model: one projection over the document scope, which
5465
+ * rejects on a deleted document.
5466
+ */
5467
+ declare function documentDecisionModel(target: DecisionTarget): DecisionModel<DocumentDecisionModel>;
5468
+ //#endregion
5469
+ //#region src/decision/registered-model.d.ts
5470
+ /**
5471
+ * A model this reactor can register. Every one carries the document projection,
5472
+ * because admission reads the version and the deletion timestamp off it; a model
5473
+ * with more projections than that is still assignable here.
5474
+ */
5475
+ type RegisteredDecisionModel = (target: DecisionTarget) => DecisionModel<DocumentDecisionModel>;
5476
+ /** What admission needs out of a model built at the stream heads. */
5477
+ type AdmissionDecision = {
5478
+ evaluation: Evaluation;
5479
+ appendCondition: AppendCondition;
5480
+ documentVersion: number;
5481
+ deletedAtUtcIso: string | null;
5482
+ };
5483
+ /**
5484
+ * Builds the model at the stream heads and decides one request against it. The
5485
+ * append condition it returns is the read-set the store enforces at write time.
5486
+ */
5487
+ declare function decideAtHead(model: RegisteredDecisionModel, cache: IWriteCache, target: DecisionTarget, subject: AuthSubject, request: AuthRequest, signal?: AbortSignal): Promise<AdmissionDecision>;
5488
+ /**
5489
+ * The model this reactor enforces. With `authEnforcement` off the auth scope is
5490
+ * absent from every append condition and no load walks it.
5491
+ */
5492
+ declare function selectDecisionModel(flags: ReactorFeatureFlags): RegisteredDecisionModel;
5493
+ //#endregion
5494
+ //#region src/decision/stream-order.d.ts
5495
+ /** Where a stream's stored order contradicts its timestamps. */
5496
+ type OutOfOrderPair = {
5497
+ previous: Operation;
5498
+ current: Operation;
5499
+ /**
5500
+ * `descending` cannot be walked at all. `tied` walks fine — the intra-stream
5501
+ * rule breaks the tie by index — but violates the monotonic auth rule, so a
5502
+ * stream holding one can never be replicated to a peer that lacks it.
5503
+ */
5504
+ kind: "descending" | "tied";
5505
+ };
5506
+ /**
5507
+ * The first pair of effective operations whose stored order contradicts their
5508
+ * timestamps, or undefined when the stream is in position order.
5509
+ *
5510
+ * Such a stream cannot be walked, and the auth stream is never reshuffled once
5511
+ * the monotonic rule is on, so run this before enabling enforcement on a fleet.
5512
+ *
5513
+ * `requireStrict` additionally rejects a tie, which is what the auth stream's
5514
+ * monotonic rule requires and what the walk alone does not care about.
5515
+ */
5516
+ declare function firstOutOfOrderPair(operations: Operation[], options?: {
5517
+ requireStrict?: boolean;
5518
+ }): OutOfOrderPair | undefined;
5519
+ //#endregion
5162
5520
  //#region src/read-models/base-read-model.d.ts
5163
5521
  type BaseReadModelConfig = {
5164
5522
  readModelId: string;
@@ -5243,7 +5601,7 @@ declare class KyselyDocumentIndexer extends BaseReadModel implements IDocumentIn
5243
5601
  * serialized so the executor can return to dispatch without holding ordering
5244
5602
  * implicitly.
5245
5603
  */
5246
- declare class ReadModelCoordinator implements IReadModelCoordinator {
5604
+ declare class ReadModelCoordinator implements ILiveReadModelCoordinator {
5247
5605
  private eventBus;
5248
5606
  readonly preReady: IReadModel[];
5249
5607
  readonly postReady: IReadModel[];
@@ -5262,6 +5620,7 @@ declare class ReadModelCoordinator implements IReadModelCoordinator {
5262
5620
  */
5263
5621
  drain(): Promise<void>;
5264
5622
  getChainDepth(): number;
5623
+ addReadModel(readModel: IReadModel, stage: ReadModelRegistrationStage): void;
5265
5624
  private handleWriteReady;
5266
5625
  private emitEmptyReadReady;
5267
5626
  private runChain;
@@ -5275,8 +5634,21 @@ declare class ReadModelCoordinator implements IReadModelCoordinator {
5275
5634
  type Database$2 = Database$1 & DocumentViewDatabase;
5276
5635
  declare class KyselyDocumentView extends BaseReadModel implements IDocumentView {
5277
5636
  private operationStore;
5637
+ /**
5638
+ * Whether a single-document read serves a deleted document's state as of the
5639
+ * deletion rather than hiding it. Only meaningful with `documentDecisions`,
5640
+ * which is what makes deletion positional. Listings omit it either way.
5641
+ */
5642
+ private readonly servesDeletionBoundary;
5278
5643
  private _db;
5279
- constructor(db: Kysely<Database$2>, operationStore: IOperationStore, operationIndex: IOperationIndex, writeCache: IWriteCache, consistencyTracker: IConsistencyTracker);
5644
+ constructor(db: Kysely<Database$2>, operationStore: IOperationStore, operationIndex: IOperationIndex, writeCache: IWriteCache, consistencyTracker: IConsistencyTracker,
5645
+ /**
5646
+ * Whether a single-document read serves a deleted document's state as of the
5647
+ * deletion rather than hiding it. Only meaningful with `documentDecisions`,
5648
+ * which is what makes deletion positional. Listings omit it either way.
5649
+ */
5650
+
5651
+ servesDeletionBoundary: boolean);
5280
5652
  protected commitOperations(items: OperationWithContext$1[]): Promise<void>;
5281
5653
  exists(documentIds: string[], consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<boolean[]>;
5282
5654
  get<TDocument extends PHDocument>(documentId: string, view?: ViewFilter$1, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<TDocument>;
@@ -5408,6 +5780,8 @@ declare class GqlRequestChannel implements IChannel {
5408
5780
  private isPushing;
5409
5781
  private pendingDrain;
5410
5782
  private receivingPages;
5783
+ /** Cleared for good the first time the remote rejects {@link DECISION_FIELDS}. */
5784
+ private peerServesDecisionFields;
5411
5785
  private isRecovering;
5412
5786
  private connectionState;
5413
5787
  /** Latest unrecoverable error was an auth rejection; cleared on connect. */
@@ -5454,6 +5828,18 @@ declare class GqlRequestChannel implements IChannel {
5454
5828
  * Queries the remote GraphQL endpoint for sync envelopes.
5455
5829
  */
5456
5830
  private pollSyncEnvelopes;
5831
+ /**
5832
+ * True when the remote rejected the query for naming a field it does not
5833
+ * have. Selecting an unknown field fails validation for the whole query, so
5834
+ * an unhandled one takes the channel's polling down until the process
5835
+ * restarts rather than degrading.
5836
+ */
5837
+ private rejectsDecisionFields;
5838
+ /**
5839
+ * The poll query. `withDecisionFields` selects the two fields added with the
5840
+ * auth projection; a remote on the previous schema is polled without them.
5841
+ */
5842
+ private pollQuery;
5457
5843
  /**
5458
5844
  * Registers or updates this channel on the remote server via GraphQL mutation.
5459
5845
  * Returns the remote's ack ordinal so the client can trim its outbox.
@@ -5616,6 +6002,18 @@ declare function batchOperationsByDocument(operations: OperationWithContext$1[])
5616
6002
  * jobId; all other jobIds are remapped so external dependencies still resolve.
5617
6003
  */
5618
6004
  declare function consolidateSyncOperations(syncOps: SyncOperation[]): SyncOperation[];
6005
+ /**
6006
+ * Classifies a failure by error name rather than `instanceof`, because a failure
6007
+ * that crossed the pooled-worker boundary arrives as plain data.
6008
+ */
6009
+ declare function classifyJobFailure(errorName: string): SyncOperationErrorType;
6010
+ /** The explicit type when something else carried it, else derived by name. */
6011
+ declare function syncOperationErrorType(error: ChannelError | undefined): SyncOperationErrorType;
6012
+ /**
6013
+ * A held auth operation must not quarantine: reconciling the two policies needs
6014
+ * the traffic a quarantine would stop.
6015
+ */
6016
+ declare function quarantinesDocument(errorType: SyncOperationErrorType): boolean;
5619
6017
  //#endregion
5620
6018
  //#region src/admin/types.d.ts
5621
6019
  type KeyframeValidationIssue = {
@@ -5631,11 +6029,20 @@ type SnapshotValidationIssue = {
5631
6029
  snapshotHash: string;
5632
6030
  replayedHash: string;
5633
6031
  };
6032
+ /** Effective operations whose stored order contradicts their timestamps. */
6033
+ type StreamOrderIssue = {
6034
+ scope: string;
6035
+ branch: string;
6036
+ previous: Operation;
6037
+ current: Operation;
6038
+ kind: OutOfOrderPair["kind"];
6039
+ };
5634
6040
  type ValidationResult = {
5635
6041
  documentId: string;
5636
6042
  isConsistent: boolean;
5637
6043
  keyframeIssues: KeyframeValidationIssue[];
5638
6044
  snapshotIssues: SnapshotValidationIssue[];
6045
+ streamOrderIssues: StreamOrderIssue[];
5639
6046
  };
5640
6047
  type RebuildResult = {
5641
6048
  documentId: string;
@@ -5659,6 +6066,7 @@ declare class DocumentIntegrityService implements IDocumentIntegrityService {
5659
6066
  validateDocument(documentId: string, branch?: string, signal?: AbortSignal): Promise<ValidationResult>;
5660
6067
  rebuildKeyframes(documentId: string, branch?: string, signal?: AbortSignal): Promise<RebuildResult>;
5661
6068
  rebuildSnapshots(documentId: string, branch?: string, signal?: AbortSignal): Promise<RebuildResult>;
6069
+ private findStreamOrderIssues;
5662
6070
  private discoverScopes;
5663
6071
  }
5664
6072
  //#endregion
@@ -5707,5 +6115,5 @@ declare class ProcessorManager extends BaseReadModel implements IProcessorManage
5707
6115
  private deleteProcessorCursors;
5708
6116
  }
5709
6117
  //#endregion
5710
- export { type AbortMessage, type AtomicTxn, type AttachmentHash, type AttachmentRef, BaseReadModel, type BatchExecutionRequest, type BatchExecutionResult, type BatchLoadRequest, type BatchLoadResult, type BuiltInReadModelKind, type CachedSnapshot, type ChannelConfig, ChannelError, ChannelErrorSource, type ChannelHealth, type ChannelMeta, ChannelScheme, type ConnectionState, type ConnectionStateChangeCallback, type ConnectionStateChangedEvent, type ConnectionStateSnapshot, type ConsistencyCoordinate, type ConsistencyKey, type ConsistencyToken, ConsistencyTracker, DEFAULT_DRIVE_CONTAINER_TYPES, DRIVE_AUTH_ERROR_MESSAGES, type Database, type DbConfig, type DeadLetterAddedEvent, DefaultSubscriptionErrorHandler, type DocumentChangeEvent, DocumentChangeType, type DocumentGraphEdge, type DocumentIndexerDatabase, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, type DocumentModelSource, type DocumentModelSpec, type DocumentRelationship, type DocumentRevisions, type DocumentStreamKey, type DocumentViewDatabase, DriveClient, DriveCollectionId, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, EventBus, EventBusAggregateError, type ExecuteMessage, type ExecutionJobPlan, type ExecutorStartedEvent, type ExecutorStoppedEvent, type FactorySpec, type FileModelSource, type GqlChannelConfig, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, type HeartbeatMessage, type IChannel, type IChannelFactory, type IConsistencyTracker, type IDocumentGraph, type IDocumentIndexer, type IDocumentIntegrityService, type IDocumentModelLoader, type IDocumentModelRegistry, type IDocumentModelResolver, type IDocumentView, type IDriveClient, type IEventBus, type IJobAwaiter, type IJobExecutor, type IJobExecutorManager, type IJobTracker, type IKeyframeStore, type IMailbox, type IOperationIndex, type IOperationStore, type IPollTimer, type IProcessor, type IProcessorHostModule, type IProcessorManager, type IProjectionTransport, type IQueue, type IReactor, type IReactorClient, type IReactorSubscriptionManager, type IReadModel, type IReadModelCoordinator, type IRelationalDb, type ISubscriptionErrorHandler, type ISyncCursorStorage, type ISyncManager, type ISyncRemoteStorage, type ISyncStatusTracker, type IWriteCache, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, type InProcessReactorClientModule, type InProcessReactorModule, type InProcessSyncModule, type InitMessage, type InsertableDocumentSnapshot, IntervalPollTimer, InvalidModuleError, type Job, type JobAvailableEvent, JobAwaiter, type JobCompletedEvent, type JobExecutorConfig, JobExecutorEventTypes, type JobExecutorFactory, type JobFailedEvent, type JobInfo, type JobPendingEvent, type JobReadReadyEvent, type JobResult, type JobRunningEvent, type JobStartedEvent, JobStatus, type JobWriteReadyEvent, type JobWriteReadyPayload, type JwtHandler, type KeyframeSnapshot, type KeyframeValidationIssue, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, type LoadJobPlan, type LoadModelMessage, type LogMessage, Mailbox, type MetricsMessage, type ModelLoadFailedMessage, type ModelLoadedEvent, type ModelLoadedMessage, type ModelManifestEntry, ModuleNotFoundError, type ModuleRef, NullDocumentModelResolver, type OperationBatch, type OperationContext, type OperationFilter, type OperationIndexEntry, type OperationTable, type OperationWithContext, OptimisticLockError, type PackageModelSource, type PagedResults, type PagingOptions, type ParentMessage, type ParsedDriveUrl, type ParsedPaging, PollBehavior, PollingChannelError, type PoolInstrumentation, type PoolStats, type ProcessorApp, type ProcessorFactory, type ProcessorFactoryBuilder, type ProcessorFilter, ProcessorManager, type ProcessorRecord, type ProcessorStatus, type ProjectionShardBuilderConfig, type ProjectionShardManagerConfig, type ProjectionWorkerFactory, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, type ReactorClientModule, ReactorEventTypes, type ReactorFeatures, type JobFailedEvent$1 as ReactorJobFailedEvent, type ReactorModule, ReactorSubscriptionManager, type ReadModelBatchCompletedEvent, ReadModelCoordinator, type ReadModelFactory, type ReadModelFactoryDeps, type ReadModelIndexedEvent, type ReadModelIndexingStage, type ReadModelStage, type ReadyMessage, type RebuildResult, RelationalDbProcessor, RelationshipChangeType, type Remote, type RemoteCursor, type RemoteFilter, type RemoteMeta, type RemoteOptions, type RemoteRecord, type RemoteStatus, type ResultMessage, RevisionMismatchError, type SanitizedArg, type SearchFilter, type ShutdownMessage, type ShutdownStatus, type SignatureVerificationHandler, type SignatureVerifierSpec, type SignerConfig, SimpleJobExecutorManager, type SnapshotValidationIssue, type Database$1 as StorageDatabase, type SubscriptionErrorContext, SyncBuilder, type SyncEnvelope, type SyncEnvelopeType, SyncEventTypes, type SyncFailedEvent, type SyncModule, SyncOperation, SyncOperationAggregateError, type SyncOperationErrorType, SyncOperationStatus, type SyncPendingEvent, SyncStatus, type SyncStatusChangeCallback, SyncStatusTracker, type SyncSucceededEvent, type TrackedProcessor, type Unsubscribe, type ValidationResult, type ViewFilter, type ErrorInfo as WorkerErrorInfo, type WorkerMessage, type WorkerPoolConfig, type WorkerPoolOptions, type WriteCacheConfig, addRelationshipAction, batchOperationsByDocument, consolidateSyncOperations, createDocumentAction, createForwardingLogger, createMutableShutdownStatus, createRelationalDb, deleteDocumentAction, documentActions, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, getMigrationStatus, instrumentPgPool, isDriveAuthError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, removeRelationshipAction, runMigrations, sanitizeArg, trimMailboxFromAckOrdinal, updateRelationshipAction, upgradeDocumentAction, workerEntryPath };
6118
+ export { APPEND_CONDITION_FAILED_PREFIX, type AbortMessage, type AdmissionDecision, type AppendCondition, AppendConditionFailedError, type AppendConditionStream, type AtomicTxn, type AttachmentHash, type AttachmentRef, type AuthDecisionModel, BaseReadModel, type BatchExecutionRequest, type BatchExecutionResult, type BatchLoadRequest, type BatchLoadResult, type BuiltDecisionModel, type BuiltInReadModelKind, type CachedSnapshot, type ChannelConfig, ChannelError, ChannelErrorSource, type ChannelHealth, type ChannelMeta, ChannelScheme, type ConnectionState, type ConnectionStateChangeCallback, type ConnectionStateChangedEvent, type ConnectionStateSnapshot, type ConsistencyCoordinate, type ConsistencyKey, type ConsistencyToken, ConsistencyTracker, DEFAULT_DRIVE_CONTAINER_TYPES, DRIVE_AUTH_ERROR_MESSAGES, type Database, type DbConfig, type DeadLetterAddedEvent, type DecisionContext, type DecisionModel, type DecisionTarget, DefaultSubscriptionErrorHandler, type DocumentChangeEvent, DocumentChangeType, type DocumentDecisionModel, type DocumentGraphEdge, type DocumentIndexerDatabase, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, type DocumentModelSource, type DocumentModelSpec, type DocumentRelationship, type DocumentRevisions, type DocumentStreamKey, type DocumentViewDatabase, DriveClient, DriveCollectionId, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, type Evaluation, EventBus, EventBusAggregateError, type ExecuteMessage, type ExecutionJobPlan, type ExecutorStartedEvent, type ExecutorStoppedEvent, type FactorySpec, type FileModelSource, type GqlChannelConfig, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, type HeartbeatMessage, type IChannel, type IChannelFactory, type IConsistencyTracker, type IDocumentGraph, type IDocumentIndexer, type IDocumentIntegrityService, type IDocumentModelLoader, type IDocumentModelRegistry, type IDocumentModelResolver, type IDocumentView, type IDriveClient, type IEventBus, type IJobAwaiter, type IJobExecutor, type IJobExecutorManager, type IJobTracker, type IKeyframeStore, type ILiveReadModelCoordinator, type IMailbox, type IOperationIndex, type IOperationStore, type IPollTimer, type IProcessor, type IProcessorHostModule, type IProcessorManager, type IProjectionTransport, type IQueue, type IReactor, type IReactorClient, type IReactorSubscriptionManager, type IReadModel, type IReadModelCoordinator, type IRelationalDb, type ISubscriptionErrorHandler, type ISyncCursorStorage, type ISyncManager, type ISyncRemoteStorage, type ISyncStatusTracker, type IWriteCache, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, type InProcessReactorClientModule, type InProcessReactorModule, type InProcessSyncModule, type InitMessage, type InsertableDocumentSnapshot, IntervalPollTimer, InvalidModuleError, type Job, type JobAvailableEvent, JobAwaiter, type JobCompletedEvent, type JobExecutorConfig, JobExecutorEventTypes, type JobExecutorFactory, type JobFailedEvent, type JobInfo, type JobPendingEvent, type JobReadReadyEvent, type JobResult, type JobRunningEvent, type JobStartedEvent, JobStatus, type JobWriteReadyEvent, type JobWriteReadyPayload, type JwtHandler, type KeyframeSnapshot, type KeyframeValidationIssue, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, type LoadJobPlan, type LoadModelMessage, type LogMessage, Mailbox, type MetricsMessage, type ModelLoadFailedMessage, type ModelLoadedEvent, type ModelLoadedMessage, type ModelManifestEntry, ModuleNotFoundError, type ModuleRef, NullDocumentModelResolver, type OperationBatch, type OperationContext, type OperationFilter, type OperationIndexEntry, type OperationTable, type OperationWithContext, OptimisticLockError, type OutOfOrderPair, type PackageModelSource, type PagedResults, type PagingOptions, type ParentMessage, type ParsedDriveUrl, type ParsedPaging, PollBehavior, PollingChannelError, type PoolInstrumentation, type PoolStats, type ProcessorApp, type ProcessorFactory, type ProcessorFactoryBuilder, type ProcessorFilter, ProcessorManager, type ProcessorRecord, type ProcessorStatus, type Projection, type ProjectionShardBuilderConfig, type ProjectionShardManagerConfig, type ProjectionWorkerFactory, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, type ReactorClientModule, ReactorEventTypes, type ReactorFeatureFlags, type ReactorFeatures, type JobFailedEvent$1 as ReactorJobFailedEvent, type ReactorModule, ReactorSubscriptionManager, type ReadModelBatchCompletedEvent, ReadModelCoordinator, type ReadModelFactory, type ReadModelFactoryDeps, type ReadModelIndexedEvent, type ReadModelIndexingStage, type ReadModelRegistrationStage, type ReadModelStage, type ReadyMessage, type RebuildResult, type RegisteredDecisionModel, RelationalDbProcessor, RelationshipChangeType, type Remote, type RemoteCursor, type RemoteFilter, type RemoteMeta, type RemoteOptions, type RemoteRecord, type RemoteStatus, type ResultMessage, RetryAccounting, RevisionMismatchError, type SanitizedArg, type SearchFilter, type ShutdownMessage, type ShutdownStatus, type SignatureVerificationHandler, type SignatureVerifierSpec, type SignerConfig, SimpleJobExecutorManager, type SnapshotValidationIssue, type Database$1 as StorageDatabase, type StreamOrderIssue, type StreamQuery, type SubscriptionErrorContext, SyncBuilder, type SyncEnvelope, type SyncEnvelopeType, SyncEventTypes, type SyncFailedEvent, type SyncModule, SyncOperation, SyncOperationAggregateError, type SyncOperationErrorType, SyncOperationStatus, type SyncPendingEvent, SyncStatus, type SyncStatusChangeCallback, SyncStatusTracker, type SyncSucceededEvent, type TrackedProcessor, type Unsubscribe, type ValidationResult, type ViewFilter, type ErrorInfo as WorkerErrorInfo, type WorkerMessage, type WorkerPoolConfig, type WorkerPoolOptions, type WriteCacheConfig, addRelationshipAction, authDecisionModel, batchOperationsByDocument, buildDecisionModel, classifyJobFailure, consolidateSyncOperations, createDocumentAction, createForwardingLogger, createMutableShutdownStatus, createRelationalDb, decideAtHead, deleteDocumentAction, documentActions, documentDecisionModel, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, firstOutOfOrderPair, getMigrationStatus, instrumentPgPool, isDriveAuthError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, quarantinesDocument, removeRelationshipAction, runMigrations, sanitizeArg, selectDecisionModel, supportsLiveReadModelRegistration, syncOperationErrorType, trimMailboxFromAckOrdinal, updateRelationshipAction, upgradeDocumentAction, workerEntryPath };
5711
6119
  //# sourceMappingURL=index.d.ts.map