@powerhousedao/reactor 6.2.2-dev.5 → 6.2.2-dev.50

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";
@@ -57,7 +57,14 @@ declare function updateRelationshipAction(sourceId: string, targetId: string, re
57
57
  declare function removeRelationshipAction(sourceId: string, targetId: string, relationshipType?: string): Action;
58
58
  //#endregion
59
59
  //#region src/queue/types.d.ts
60
- type JobKind = "mutation" | "load";
60
+ /**
61
+ * What a job carries: a mutation applies actions, a load imports synced
62
+ * operations, and a reevaluation re-judges a document's stored operations
63
+ * because a read-set stream elsewhere (a group document) changed. A
64
+ * reevaluation job carries no actions or operations; its work is derived
65
+ * from what is already stored.
66
+ */
67
+ type JobKind = "mutation" | "load" | "reevaluation";
61
68
  /**
62
69
  * State of a job in the queue
63
70
  */
@@ -69,6 +76,17 @@ declare enum JobQueueState {
69
76
  RUNNING = 3,
70
77
  RESOLVED = 4
71
78
  }
79
+ /**
80
+ * How a retry is accounted against the job's retry limit.
81
+ * - `CountAgainstLimit` (default): a fault; the job eventually exhausts its
82
+ * retries and fails terminally.
83
+ * - `ExemptFromLimit`: not a fault, so the attempt is not charged to the job.
84
+ * Used for concurrency conflicts, where the retry does new work.
85
+ */
86
+ declare enum RetryAccounting {
87
+ CountAgainstLimit = "count-against-limit",
88
+ ExemptFromLimit = "exempt-from-limit"
89
+ }
72
90
  /**
73
91
  * Interface for a job execution handle
74
92
  */
@@ -127,9 +145,14 @@ type JobAvailableEvent = {
127
145
  //#endregion
128
146
  //#region src/shared/types.d.ts
129
147
  /**
130
- * Information about an error including message and stack trace.
148
+ * Information about an error including its name, message and stack trace.
149
+ *
150
+ * The name is what survives the crossing out of the executor: a consumer that
151
+ * has to tell a terminal failure from a retryable one, or classify a dead
152
+ * letter, only ever sees this record rather than the thrown error.
131
153
  */
132
154
  type ErrorInfo$1 = {
155
+ name: string;
133
156
  message: string;
134
157
  stack: string;
135
158
  };
@@ -230,6 +253,11 @@ type ViewFilter = {
230
253
  branch?: string;
231
254
  scopes?: string[];
232
255
  revision?: number;
256
+ /**
257
+ * Read subject for the IReactorClient read gate; defaults to the client's
258
+ * signer. Set per request when serving many principals. Ignored by IReactor.
259
+ */
260
+ subject?: AuthSubject;
233
261
  };
234
262
  /**
235
263
  * Describes filter options for searching documents.
@@ -328,6 +356,16 @@ interface IReadModelCoordinator {
328
356
  */
329
357
  getChainDepth(): number;
330
358
  }
359
+ type ReadModelRegistrationStage = "pre_ready" | "post_ready";
360
+ /**
361
+ * Optional capability exposed by coordinators that support adding read models
362
+ * after construction. Custom and remote coordinators are not required to
363
+ * implement it.
364
+ */
365
+ interface ILiveReadModelCoordinator extends IReadModelCoordinator {
366
+ addReadModel(readModel: IReadModel, stage: ReadModelRegistrationStage): void;
367
+ }
368
+ declare function supportsLiveReadModelRegistration(coordinator: IReadModelCoordinator): coordinator is ILiveReadModelCoordinator;
331
369
  //#endregion
332
370
  //#region src/sync/types.d.ts
333
371
  declare enum ChannelScheme {
@@ -398,7 +436,13 @@ declare enum ChannelErrorSource {
398
436
  Inbox = "inbox",
399
437
  Outbox = "outbox"
400
438
  }
401
- type SyncOperationErrorType = "SIGNATURE_INVALID" | "HASH_MISMATCH" | "LIBRARY_ERROR" | "MISSING_OPERATIONS" | "EXCESSIVE_SHUFFLE" | "GRACEFUL_ABORT";
439
+ type SyncOperationErrorType = "SIGNATURE_INVALID" | "HASH_MISMATCH" | "LIBRARY_ERROR" | "MISSING_OPERATIONS" | "EXCESSIVE_SHUFFLE" | "GRACEFUL_ABORT"
440
+ /**
441
+ * An arriving auth operation did not exceed the local auth head. Exempt from
442
+ * quarantine, because reconciling the two policies needs the traffic a
443
+ * quarantine would stop.
444
+ */
445
+ | "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
446
  type ChannelHealth = {
403
447
  state: "idle" | "running" | "error";
404
448
  lastSuccessUtcMs?: number;
@@ -491,6 +535,7 @@ type DeadLetterAddedEvent = {
491
535
  remoteName: string;
492
536
  documentId: string;
493
537
  errorSource: ChannelErrorSource;
538
+ errorType: SyncOperationErrorType;
494
539
  };
495
540
  /**
496
541
  * Status of a sync operation result.
@@ -537,6 +582,36 @@ declare class OptimisticLockError extends Error {
537
582
  declare class RevisionMismatchError extends Error {
538
583
  constructor(expected: number, actual: number);
539
584
  }
585
+ /**
586
+ * One read-set stream and the highest operation index observed on it, or -1
587
+ * if it was observed empty.
588
+ */
589
+ type AppendConditionStream = {
590
+ documentId: string;
591
+ scope: string;
592
+ branch: string;
593
+ revision: number;
594
+ };
595
+ /**
596
+ * A read-set enforced by {@link IOperationStore.apply}: the append fails if
597
+ * any stream has operations past its recorded revision.
598
+ */
599
+ type AppendCondition = {
600
+ streams: AppendConditionStream[];
601
+ };
602
+ /** Error history keeps messages, not classes, so failures match by prefix. */
603
+ declare const APPEND_CONDITION_FAILED_PREFIX = "Append condition failed: ";
604
+ /**
605
+ * A read-set stream grew before the append committed. A concurrency
606
+ * conflict, not a fault: the caller retries against the new stream heads.
607
+ */
608
+ declare class AppendConditionFailedError extends Error {
609
+ readonly condition: AppendCondition;
610
+ constructor(condition: AppendCondition);
611
+ static isError(error: unknown): error is AppendConditionFailedError;
612
+ /** True when a recorded error message is an append-condition failure. */
613
+ static isFailureMessage(message: string): boolean;
614
+ }
540
615
  /**
541
616
  * A write transaction passed to {@link IOperationStore.apply}. Accumulates
542
617
  * operations that are committed atomically when the callback returns.
@@ -550,7 +625,7 @@ interface AtomicTxn {
550
625
  * revision field and lastModified timestamp.
551
626
  */
552
627
  type DocumentRevisions = {
553
- /** Map of scope to operation index for that scope */revision: Record<string, number>; /** Latest timestamp across revisions */
628
+ /** Map of scope to operation index for that scope */revision: Record<string, number>; /** The largest operation timestamp in the document, across every scope. */
554
629
  latestTimestamp: string;
555
630
  };
556
631
  /**
@@ -571,6 +646,12 @@ interface IOperationStore {
571
646
  * returned instead of throwing. If no matching stored row is found, the
572
647
  * original error is propagated unchanged.
573
648
  *
649
+ * With an {@link AppendCondition}, the append additionally fails with
650
+ * {@link AppendConditionFailedError} — writing nothing — if any read-set
651
+ * stream has operations past its recorded revision. The written and
652
+ * read-set streams are advisory-locked in sorted key order, so concurrent
653
+ * conditional appends on overlapping streams serialize.
654
+ *
574
655
  * @param documentId - The document id
575
656
  * @param documentType - The document type identifier
576
657
  * @param scope - The operation scope (e.g. "global", "local")
@@ -578,9 +659,10 @@ interface IOperationStore {
578
659
  * @param revision - Expected current revision (optimistic lock)
579
660
  * @param fn - Callback that stages operations via {@link AtomicTxn}
580
661
  * @param signal - Optional abort signal to cancel the request
662
+ * @param condition - Optional read-set to enforce at write time
581
663
  * @returns The stored operations; empty array when no operations were staged
582
664
  */
583
- apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal): Promise<Operation[]>;
665
+ apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal, condition?: AppendCondition): Promise<Operation[]>;
584
666
  /**
585
667
  * Returns operations for a document/scope/branch whose index is greater
586
668
  * than the given revision.
@@ -627,6 +709,16 @@ interface IOperationStore {
627
709
  * @returns Object containing revision map and latest timestamp
628
710
  */
629
711
  getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
712
+ /**
713
+ * The largest operation timestamp in one stream, or undefined when it is empty.
714
+ * Distinct from {@link DocumentRevisions.latestTimestamp}, which maxes over
715
+ * every scope.
716
+ *
717
+ * Must be a real maximum, not the last-indexed operation's timestamp: a
718
+ * re-evaluation pass re-appends at a fresh index while keeping the original
719
+ * timestamp, so a later timestamp can sit behind the last row.
720
+ */
721
+ getStreamLatestTimestamp(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
630
722
  }
631
723
  /**
632
724
  * Stores periodic document snapshots (keyframes) so that document state
@@ -1045,7 +1137,8 @@ type DeadLetterRecord = {
1045
1137
  branch: string;
1046
1138
  operations: OperationWithContext$1[];
1047
1139
  errorSource: ChannelErrorSource;
1048
- errorMessage: string;
1140
+ errorMessage: string; /** Why it failed, in the closed set sync classifies failures into. */
1141
+ errorType: SyncOperationErrorType;
1049
1142
  };
1050
1143
  /**
1051
1144
  * Persists dead-lettered sync operations so they survive reactor restarts.
@@ -1103,6 +1196,15 @@ interface IOperationIndexTxn {
1103
1196
  createCollection(collectionId: string): void;
1104
1197
  addToCollection(collectionId: string, documentId: string): void;
1105
1198
  removeFromCollection(collectionId: string, documentId: string): void;
1199
+ /**
1200
+ * Records the group documents an auth operation's input names, tied to the
1201
+ * last written operation like addToCollection. At commit each reference is
1202
+ * remembered permanently and the group joins every collection the
1203
+ * referencing document belongs to, keeping the earliest join and reopening
1204
+ * a closed membership, so sync serves the group's history to every remote
1205
+ * that can observe the referencing grant.
1206
+ */
1207
+ recordGroupReferences(documentId: string, groupIds: string[]): void;
1106
1208
  write(operations: OperationIndexEntry[]): void;
1107
1209
  }
1108
1210
  /**
@@ -1124,6 +1226,13 @@ interface IOperationIndex {
1124
1226
  * Returns a map of documentId to array of collection IDs.
1125
1227
  */
1126
1228
  getCollectionsForDocuments(documentIds: string[]): Promise<Record<string, string[]>>;
1229
+ /**
1230
+ * The documents whose auth history has ever referenced the group, from the
1231
+ * group-reference relation. This is the set a group-stream change owes a
1232
+ * re-evaluation pass to; it is complete because a group's auth scope cannot
1233
+ * reference other groups.
1234
+ */
1235
+ getGroupReferencers(groupId: string, signal?: AbortSignal): Promise<string[]>;
1127
1236
  }
1128
1237
  /**
1129
1238
  * Identifies the collection a remote synchronizes. Collections are drive-level
@@ -1152,6 +1261,51 @@ declare class DriveCollectionId {
1152
1261
  equals(other: DriveCollectionId): boolean;
1153
1262
  }
1154
1263
  //#endregion
1264
+ //#region src/cache/write-cache-types.d.ts
1265
+ /**
1266
+ * Configuration options for the write cache
1267
+ */
1268
+ type WriteCacheConfig = {
1269
+ /** 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 */
1270
+ ringBufferSize: number; /** Persist a keyframe snapshot every N revisions. Default: 10 */
1271
+ keyframeInterval: number;
1272
+ };
1273
+ /**
1274
+ * Unique identifier for a document stream
1275
+ */
1276
+ type DocumentStreamKey = {
1277
+ /** Document identifier */documentId: string; /** Operation scope */
1278
+ scope: string; /** Branch name */
1279
+ branch: string;
1280
+ };
1281
+ /**
1282
+ * Where a snapshot sits in its stream.
1283
+ *
1284
+ * - `Head`: the newest revision of the stream when it was stored. Only these
1285
+ * can answer a read that asks for the head.
1286
+ * - `Historical`: state at an earlier revision. Usable as a starting point to
1287
+ * replay forward from, and as an answer to a read for that same revision.
1288
+ */
1289
+ declare enum SnapshotPosition {
1290
+ Head = "head",
1291
+ Historical = "historical"
1292
+ }
1293
+ /**
1294
+ * A cached document snapshot at a specific revision
1295
+ */
1296
+ type CachedSnapshot = {
1297
+ /** The revision number of this snapshot */revision: number; /** The document state at this revision */
1298
+ document: PHDocument; /** Where this snapshot sat in the stream when it was stored */
1299
+ position: SnapshotPosition;
1300
+ };
1301
+ /**
1302
+ * Serialized keyframe snapshot for K/V store persistence
1303
+ */
1304
+ type KeyframeSnapshot = {
1305
+ /** The revision number of this keyframe */revision: number; /** Serialized document state */
1306
+ document: string;
1307
+ };
1308
+ //#endregion
1155
1309
  //#region src/cache/write/interfaces.d.ts
1156
1310
  /**
1157
1311
  * IWriteCache is a write-side projection that optimizes document state retrieval
@@ -1166,7 +1320,8 @@ interface IWriteCache {
1166
1320
  * @param documentId - The document identifier
1167
1321
  * @param scope - Operation scope
1168
1322
  * @param branch - Branch name
1169
- * @param targetRevision - The exact revision to retrieve (optional, defaults to latest)
1323
+ * @param targetRevision - Index of the last operation to apply, defaulting
1324
+ * to latest. An operation index, never `header.revision[scope]`.
1170
1325
  * @param signal - Optional abort signal to cancel the operation
1171
1326
  * @returns The complete document at the specified revision
1172
1327
  *
@@ -1192,15 +1347,19 @@ interface IWriteCache {
1192
1347
  * @param documentId - The document identifier
1193
1348
  * @param scope - Operation scope
1194
1349
  * @param branch - Branch name
1195
- * @param revision - The revision this document represents
1350
+ * @param revision - Index of the last operation this document reflects, so
1351
+ * `header.revision[scope]` is one greater. -1 for an empty scope.
1196
1352
  * @param document - The document to cache
1353
+ * @param position - Whether `revision` is the stream's head. Nothing checks
1354
+ * it: claiming `Head` for an earlier revision makes a getState() with no
1355
+ * target return stale state.
1197
1356
  *
1198
1357
  * @example
1199
1358
  * ```typescript
1200
- * cache.putState(docId, 'global', 'main', 42, document);
1359
+ * cache.putState(docId, 'global', 'main', 42, document, SnapshotPosition.Head);
1201
1360
  * ```
1202
1361
  */
1203
- putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument): void;
1362
+ putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, position: SnapshotPosition): void;
1204
1363
  /**
1205
1364
  * Invalidates (removes) cached entries for a document stream.
1206
1365
  *
@@ -1531,6 +1690,17 @@ type CreateDocumentOptions = {
1531
1690
  /** Optional "id" or "slug" of parent document */parentIdentifier?: string; /** Optional version of the document model to use (defaults to latest) */
1532
1691
  documentModelVersion?: number;
1533
1692
  };
1693
+ /**
1694
+ * Options for upgrading a document.
1695
+ */
1696
+ type UpgradeDocumentOptions = {
1697
+ /**
1698
+ * How many times to retry with a fresh read when the executor rejects the
1699
+ * upgrade because the document changed after it was read. Defaults to
1700
+ * {@link DEFAULT_UPGRADE_CONFLICT_RETRIES}.
1701
+ */
1702
+ maxConflictRetries?: number;
1703
+ };
1534
1704
  /**
1535
1705
  * Drive-aware operations grouped under `client.drives`.
1536
1706
  *
@@ -1646,7 +1816,7 @@ interface IReactorClient {
1646
1816
  * @param signal - Optional abort signal to cancel the request
1647
1817
  * @returns The canonical document id
1648
1818
  */
1649
- resolveIdOrSlug(identifier: string, signal?: AbortSignal): Promise<string>;
1819
+ resolveIdOrSlug(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<string>;
1650
1820
  /**
1651
1821
  * Retrieves operations for a document.
1652
1822
  *
@@ -1707,6 +1877,38 @@ interface IReactorClient {
1707
1877
  * @param signal - Optional abort signal to cancel the request
1708
1878
  */
1709
1879
  createEmpty<TDocument extends PHDocument>(documentModelType: string, options?: CreateDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
1880
+ /**
1881
+ * Retrieves the document model module matching the version a document is
1882
+ * stamped with. Use this instead of {@link getDocumentModelModule}
1883
+ * whenever a specific document is in hand: the latest-wins lookup feeds
1884
+ * not-yet-upgraded documents the wrong reducer, diverging from replay.
1885
+ *
1886
+ * @param document - The document whose stamped version selects the module
1887
+ * @returns The document model module registered for that version
1888
+ * @throws UnsupportedDocumentModelVersionError if no module is registered for the stamped version
1889
+ */
1890
+ getDocumentModelModuleForDocument(document: PHDocument): Promise<DocumentModelModule<any>>;
1891
+ /**
1892
+ * Upgrades a document to a newer document model version by dispatching an
1893
+ * UPGRADE_DOCUMENT action. When toVersion is omitted, upgrades to the
1894
+ * latest registered module version for the document's type. Returns the
1895
+ * document unchanged when it is already at the target version.
1896
+ *
1897
+ * The action carries a snapshot of the document's version and per-scope
1898
+ * revisions, which the executor validates before persisting. When an edit
1899
+ * lands between the read and the upgrade executing, the upgrade is
1900
+ * rejected and retried with a fresh read up to
1901
+ * {@link UpgradeDocumentOptions.maxConflictRetries} times before the
1902
+ * conflict is surfaced.
1903
+ *
1904
+ * @param documentIdentifier - Target document id or slug
1905
+ * @param toVersion - Optional target document model version; defaults to latest
1906
+ * @param options - Optional upgrade options (maxConflictRetries)
1907
+ * @param signal - Optional abort signal to cancel the request
1908
+ * @returns The upgraded document
1909
+ * @throws DowngradeNotSupportedError if toVersion is less than the document's current version
1910
+ */
1911
+ upgradeDocument<TDocument extends PHDocument = PHDocument>(documentIdentifier: string, toVersion?: number, options?: UpgradeDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
1710
1912
  /**
1711
1913
  * Creates an empty document in a drive as a single batched operation.
1712
1914
  * This is more efficient than createEmpty + addFile as it batches all
@@ -1863,222 +2065,255 @@ interface IReactorClient {
1863
2065
  subscribe(search: SearchFilter, callback: (event: DocumentChangeEvent) => void, view?: ViewFilter): () => void;
1864
2066
  }
1865
2067
  //#endregion
1866
- //#region src/client/reactor-client.d.ts
2068
+ //#region src/cache/collection-membership-cache.d.ts
2069
+ interface ICollectionMembershipCache {
2070
+ getCollectionsForDocuments(documentIds: string[]): Promise<Record<string, string[]>>;
2071
+ invalidate(documentId: string): void;
2072
+ }
2073
+ //#endregion
2074
+ //#region src/cache/document-meta-cache-types.d.ts
1867
2075
  /**
1868
- * ReactorClient implementation that wraps lower-level APIs to provide
1869
- * a simpler interface for document operations.
2076
+ * Cached document metadata from the "document" scope.
1870
2077
  *
1871
- * Features:
1872
- * - Wraps Jobs with Promises for easier async handling
1873
- * - Manages signing of submitted Action objects
1874
- * - Provides quality-of-life functions for common tasks
1875
- * - Wraps subscription interface with ViewFilters
2078
+ * This lightweight structure holds essential document information needed by
2079
+ * the job executor without fetching full scope state. It provides an explicit
2080
+ * cross-scope contract for accessing document scope metadata.
1876
2081
  */
1877
- declare class ReactorClient implements IReactorClient {
1878
- private logger;
1879
- private reactor;
1880
- private signer;
1881
- private subscriptionManager;
1882
- private jobAwaiter;
1883
- private documentIndexer;
1884
- private documentView;
1885
- readonly drives: IDriveClient;
1886
- constructor(logger: ILogger, reactor: IReactor, signer: ISigner, subscriptionManager: IReactorSubscriptionManager, jobAwaiter: IJobAwaiter, documentIndexer: IDocumentIndexer, documentView: IDocumentView);
1887
- /**
1888
- * Retrieves a list of document model modules.
1889
- */
1890
- getDocumentModelModules(namespace?: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentModelModule>>;
1891
- /**
1892
- * Retrieves a specific document model module by document type.
1893
- *
1894
- * @param documentType - The document type identifier
1895
- * @returns The document model module
1896
- */
1897
- getDocumentModelModule(documentType: string): Promise<DocumentModelModule<any>>;
1898
- /**
1899
- * Retrieves a specific PHDocument
1900
- */
1901
- get<TDocument extends PHDocument>(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<TDocument>;
1902
- /**
1903
- * Resolves an identifier (id or slug) to the canonical document id, using the
1904
- * same lookup as the data path. Resolves against the "main" branch. Throws if
1905
- * the identifier cannot be resolved or is ambiguous.
1906
- */
1907
- resolveIdOrSlug(identifier: string, signal?: AbortSignal): Promise<string>;
1908
- /**
1909
- * Retrieves operations for a document
1910
- */
1911
- getOperations(documentIdentifier: string, view?: ViewFilter, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
1912
- private getOperationsWithCompositeCursor;
1913
- /**
1914
- * Retrieves outgoing relationships of a given type from a source document.
1915
- */
1916
- getOutgoingRelationships(sourceIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
1917
- /**
1918
- * Retrieves incoming relationships of a given type to a target document.
1919
- */
1920
- getIncomingRelationships(targetIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
2082
+ type CachedDocumentMeta = {
1921
2083
  /**
1922
- * Filters documents by criteria and returns a list of them
2084
+ * The full PHDocumentState from document.state.document.
2085
+ * Contains version, hash, isDeleted, deletedAtUtcIso, etc.
1923
2086
  */
1924
- find(search: SearchFilter, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
2087
+ state: PHDocumentState;
1925
2088
  /**
1926
- * Creates a document and waits for completion
2089
+ * The document type (from header), cached for convenience.
1927
2090
  */
1928
- create<TDocument extends PHDocument = PHDocument>(document: PHDocument, parentIdentifier?: string, signal?: AbortSignal): Promise<TDocument>;
2091
+ documentType: string;
1929
2092
  /**
1930
- * Creates an empty document and waits for completion
2093
+ * The revision of the document scope when this metadata was captured.
2094
+ * Used for cache invalidation and consistency checks.
1931
2095
  */
1932
- createEmpty<TDocument extends PHDocument>(documentModelType: string, options?: CreateDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
2096
+ documentScopeRevision: number;
2097
+ };
2098
+ /**
2099
+ * Interface for the document metadata cache.
2100
+ *
2101
+ * This cache provides an explicit cross-scope contract for accessing document
2102
+ * scope metadata. It solves the problem where job execution in one scope (e.g.,
2103
+ * "global") needs access to document scope state (version, isDeleted, etc.)
2104
+ * which may be stale in scope-specific caches or keyframes.
2105
+ *
2106
+ * The cache supports:
2107
+ * - Latest metadata retrieval with LRU caching
2108
+ * - Historical metadata reconstruction for reshuffling scenarios
2109
+ * - Eager updates after document scope operations
2110
+ */
2111
+ interface IDocumentMetaCache {
1933
2112
  /**
1934
- * Creates an empty document in a drive as a single batched operation.
1935
- * Delegates to {@link IDriveClient.addFile}.
2113
+ * Retrieves the LATEST document metadata from cache or rebuilds from operations.
1936
2114
  *
1937
- * @deprecated Use `client.drives.addFile` instead. This method will be
1938
- * removed in a future release.
1939
- */
1940
- createDocumentInDrive<TDocument extends PHDocument>(driveId: string, document: PHDocument, parentFolder?: string, signal?: AbortSignal): Promise<TDocument>;
1941
- /**
1942
- * Applies a list of actions to a document and waits for completion
1943
- */
1944
- execute<TDocument extends PHDocument>(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal): Promise<TDocument>;
1945
- /**
1946
- * Submits a list of actions to a document
2115
+ * On cache miss, fetches all document scope operations and reconstructs the
2116
+ * current PHDocumentState by applying UPGRADE_DOCUMENT and DELETE_DOCUMENT
2117
+ * operations.
2118
+ *
2119
+ * @param documentId - The document identifier
2120
+ * @param branch - Branch name
2121
+ * @param signal - Optional abort signal to cancel the operation
2122
+ * @returns The cached or rebuilt document metadata
2123
+ * @throws {Error} "Operation aborted" if signal is aborted
2124
+ * @throws {Error} If document not found (no CREATE_DOCUMENT operation)
1947
2125
  */
1948
- executeAsync(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal): Promise<JobInfo>;
1949
- executeBatch(request: BatchExecutionRequest, signal?: AbortSignal): Promise<BatchExecutionResult>;
2126
+ getDocumentMeta(documentId: string, branch: string, signal?: AbortSignal): Promise<CachedDocumentMeta>;
1950
2127
  /**
1951
- * Renames a document and waits for completion
2128
+ * Rebuilds document metadata at a SPECIFIC revision (always rebuilds, no caching).
2129
+ *
2130
+ * Used during reshuffling when operations need to be inserted at a previous
2131
+ * revision and we need the document scope state as of that point in time.
2132
+ *
2133
+ * @param documentId - The document identifier
2134
+ * @param branch - Branch name
2135
+ * @param targetRevision - The document scope revision to reconstruct up to
2136
+ * @param signal - Optional abort signal to cancel the operation
2137
+ * @returns Document metadata as of the target revision
2138
+ * @throws {Error} "Operation aborted" if signal is aborted
2139
+ * @throws {Error} If document not found
1952
2140
  */
1953
- rename(documentIdentifier: string, name: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
2141
+ rebuildAtRevision(documentId: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<CachedDocumentMeta>;
1954
2142
  /**
1955
- * Updates the preferred editor recorded in the document header meta.
1956
- * Pass `null` to clear it.
2143
+ * Eagerly updates cached metadata after document scope operations.
2144
+ *
2145
+ * Called by the job executor after CREATE_DOCUMENT, UPGRADE_DOCUMENT, or
2146
+ * DELETE_DOCUMENT operations to keep the cache current.
2147
+ *
2148
+ * @param documentId - The document identifier
2149
+ * @param branch - Branch name
2150
+ * @param meta - The new metadata to cache
1957
2151
  */
1958
- setPreferredEditor(documentIdentifier: string, preferredEditor: string | null, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
2152
+ putDocumentMeta(documentId: string, branch: string, meta: CachedDocumentMeta): void;
1959
2153
  /**
1960
- * Adds multiple documents as children to another and waits for completion
2154
+ * Invalidates cached document metadata.
2155
+ *
2156
+ * Call before reshuffling operations that modify the document scope, or
2157
+ * when document state may have changed externally.
2158
+ *
2159
+ * @param documentId - The document identifier
2160
+ * @param branch - Optional branch to narrow invalidation (if omitted, all branches)
2161
+ * @returns Number of entries invalidated
1961
2162
  */
1962
- addRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
2163
+ invalidate(documentId: string, branch?: string): number;
1963
2164
  /**
1964
- * Removes a relationship between two documents and waits for completion.
2165
+ * Clears all cached document metadata.
1965
2166
  */
1966
- removeRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
2167
+ clear(): void;
1967
2168
  /**
1968
- * Moves a relationship from one source document to another and waits for completion.
2169
+ * Performs startup initialization.
1969
2170
  */
1970
- moveRelationship(sourceParentIdentifier: string, targetParentIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<{
1971
- source: PHDocument;
1972
- target: PHDocument;
1973
- }>;
1974
- loadBatch(request: BatchLoadRequest, signal?: AbortSignal): Promise<BatchLoadResult>;
2171
+ startup(): Promise<void>;
1975
2172
  /**
1976
- * Deletes a document and waits for completion
2173
+ * Performs graceful shutdown.
1977
2174
  */
1978
- deleteDocument(identifier: string, propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
1979
- /**
1980
- * Deletes documents and waits for completion
1981
- */
1982
- deleteDocuments(identifiers: string[], propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
1983
- /**
1984
- * Retrieves the status of a job
1985
- */
1986
- getJobStatus(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
1987
- /**
1988
- * Waits for a job to complete
1989
- */
1990
- waitForJob(jobId: string | JobInfo, signal?: AbortSignal): Promise<JobInfo>;
1991
- /**
1992
- * Subscribes to changes for documents matching specified filters
1993
- */
1994
- subscribe(search: SearchFilter, callback: (event: DocumentChangeEvent) => void, view?: ViewFilter): () => void;
1995
- private removeAllIncomingRelationships;
2175
+ shutdown(): Promise<void>;
1996
2176
  }
1997
2177
  //#endregion
1998
- //#region src/executor/types.d.ts
1999
- /**
2000
- * Represents the result of a job execution
2001
- */
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[];
2007
- /**
2008
- * Operations with context (includes ephemeral resultingState).
2009
- * Used for emitting to IDocumentView via event bus.
2010
- */
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
- };
2178
+ //#region src/storage/kysely/types.d.ts
2179
+ interface OperationTable {
2180
+ id: Generated<number>;
2181
+ jobId: string;
2182
+ opId: string;
2183
+ prevOpId: string;
2184
+ writeTimestampUtcMs: Generated<Date>;
2185
+ documentId: string;
2186
+ documentType: string;
2187
+ scope: string;
2188
+ branch: string;
2189
+ timestampUtcMs: Date;
2190
+ index: number;
2191
+ action: unknown;
2192
+ skip: number;
2193
+ error?: string | null;
2194
+ deniedReason?: string | null;
2195
+ hash: string;
2196
+ }
2197
+ interface KeyframeTable {
2198
+ id: Generated<number>;
2199
+ documentId: string;
2200
+ documentType: string;
2201
+ scope: string;
2202
+ branch: string;
2203
+ revision: number;
2204
+ document: unknown;
2205
+ createdAt: Generated<Date>;
2206
+ }
2207
+ interface DocumentCollectionTable {
2208
+ documentId: string;
2209
+ collectionId: string;
2210
+ joinedOrdinal: bigint;
2211
+ leftOrdinal: bigint | null;
2212
+ }
2213
+ interface OperationIndexOperationTable {
2214
+ ordinal: Generated<number>;
2215
+ opId: string;
2216
+ documentId: string;
2217
+ documentType: string;
2218
+ scope: string;
2219
+ branch: string;
2220
+ timestampUtcMs: string;
2221
+ writeTimestampUtcMs: Generated<Date>;
2222
+ index: number;
2223
+ skip: number;
2224
+ hash: string;
2225
+ action: unknown;
2226
+ deniedReason?: string | null;
2227
+ sourceRemote: Generated<string>;
2228
+ }
2229
+ interface SyncRemoteTable {
2230
+ name: string;
2231
+ collection_id: string;
2232
+ channel_type: string;
2233
+ channel_id: string;
2234
+ remote_name: string;
2235
+ channel_parameters: unknown;
2236
+ filter_document_ids: unknown;
2237
+ filter_scopes: unknown;
2238
+ filter_branch: string;
2239
+ push_state: string;
2240
+ push_last_success_utc_ms: string | null;
2241
+ push_last_failure_utc_ms: string | null;
2242
+ push_failure_count: number;
2243
+ pull_state: string;
2244
+ pull_last_success_utc_ms: string | null;
2245
+ pull_last_failure_utc_ms: string | null;
2246
+ pull_failure_count: number;
2247
+ created_at: Generated<Date>;
2248
+ updated_at: Generated<Date>;
2249
+ }
2250
+ interface SyncCursorTable {
2251
+ remote_name: string;
2252
+ cursor_type: string;
2253
+ cursor_ordinal: bigint;
2254
+ last_synced_at_utc_ms: string | null;
2255
+ updated_at: Generated<Date>;
2256
+ }
2039
2257
  /**
2040
- * Event data for job execution events
2258
+ * Kysely table definition for the `sync_dead_letters` table.
2041
2259
  */
2042
- type JobStartedEvent = {
2043
- job: Job;
2044
- startedAt: string;
2045
- /**
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.
2050
- */
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
- };
2260
+ interface SyncDeadLetterTable {
2261
+ ordinal: Generated<number>;
2262
+ id: string;
2263
+ job_id: string;
2264
+ job_dependencies: unknown;
2265
+ remote_name: string;
2266
+ document_id: string;
2267
+ scopes: unknown;
2268
+ branch: string;
2269
+ operations: unknown;
2270
+ error_source: string;
2271
+ error_message: string;
2272
+ error_type: Generated<string>;
2273
+ created_at: Generated<Date>;
2274
+ }
2073
2275
  /**
2074
- * Status information for the job executor manager
2276
+ * One (document, group) reference ever discovered from an auth operation's
2277
+ * input. Rows are never updated or deleted (see migration 017).
2075
2278
  */
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
- };
2279
+ interface GroupReferenceTable {
2280
+ documentId: string;
2281
+ groupId: string;
2282
+ }
2283
+ interface Database$1 {
2284
+ Operation: OperationTable;
2285
+ Keyframe: KeyframeTable;
2286
+ document_collections: DocumentCollectionTable;
2287
+ operation_index_operations: OperationIndexOperationTable;
2288
+ group_references: GroupReferenceTable;
2289
+ sync_remotes: SyncRemoteTable;
2290
+ sync_cursors: SyncCursorTable;
2291
+ sync_dead_letters: SyncDeadLetterTable;
2292
+ }
2293
+ interface DocumentTable {
2294
+ id: string;
2295
+ createdAt: Generated<Date>;
2296
+ updatedAt: Generated<Date>;
2297
+ }
2298
+ interface DocumentRelationshipTable {
2299
+ id: Generated<string>;
2300
+ sourceId: string;
2301
+ targetId: string;
2302
+ relationshipType: string;
2303
+ metadata: unknown;
2304
+ createdAt: Generated<Date>;
2305
+ updatedAt: Generated<Date>;
2306
+ }
2307
+ interface IndexerStateTable {
2308
+ id: Generated<number>;
2309
+ lastOperationId: number;
2310
+ lastOperationTimestamp: Generated<Date>;
2311
+ }
2312
+ interface DocumentIndexerDatabase {
2313
+ Document: DocumentTable;
2314
+ DocumentRelationship: DocumentRelationshipTable;
2315
+ IndexerState: IndexerStateTable;
2316
+ }
2082
2317
  //#endregion
2083
2318
  //#region src/executor/worker/protocol.d.ts
2084
2319
  /**
@@ -2244,7 +2479,8 @@ type InitMessage = {
2244
2479
  poolConfig: WorkerPoolConfig;
2245
2480
  db: DbConfig; /** Omitted = the worker performs no executor-side signature verification. */
2246
2481
  signatureVerifier?: SignatureVerifierSpec;
2247
- models: ModelManifestEntry[];
2482
+ models: ModelManifestEntry[]; /** Omitted = the worker builds its executor with the built-in defaults. */
2483
+ executorConfig?: JobExecutorConfig;
2248
2484
  };
2249
2485
  /**
2250
2486
  * Dispatches a job to the worker for execution.
@@ -2425,209 +2661,1213 @@ type PoolAcquireSamplesMessage = {
2425
2661
  */
2426
2662
  type WorkerMessage = ReadyMessage | ResultMessage | ModelLoadedMessage | ModelLoadFailedMessage | LogMessage | HeartbeatMessage | MetricsMessage | PoolAcquireSamplesMessage;
2427
2663
  //#endregion
2428
- //#region src/executor/interfaces.d.ts
2664
+ //#region src/core/model-sources.d.ts
2665
+ /** An importable file holding one or more document-model exports. */
2666
+ type FileModelSource = {
2667
+ filePath: string;
2668
+ exportName?: string;
2669
+ };
2670
+ /** An importable package specifier holding one or more document-model exports. */
2671
+ type PackageModelSource = {
2672
+ packageName: string;
2673
+ subpath?: string;
2674
+ exportName?: string;
2675
+ };
2429
2676
  /**
2430
- * Snapshot of the single in-flight slot maintained by an {@link IExecutorWorker}.
2677
+ * A source of document models: a live module, an importable file, or an
2678
+ * importable package. File and package sources can cross a worker-thread
2679
+ * boundary (workers re-import them); a live module cannot.
2431
2680
  */
2432
- type WorkerInFlightSnapshot = {
2433
- correlationId: string;
2434
- jobId: string;
2681
+ type DocumentModelSource = DocumentModelModule<any> | FileModelSource | PackageModelSource;
2682
+ //#endregion
2683
+ //#region src/registry/interfaces.d.ts
2684
+ type RegistrationResult<T> = {
2685
+ status: "success";
2686
+ item: T;
2687
+ } | {
2688
+ status: "error";
2689
+ item: T;
2690
+ error: Error;
2435
2691
  };
2436
2692
  /**
2437
- * Outcome of a worker-side job execution.
2438
- *
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.
2443
- */
2444
- type WorkerExecutionOutcome = {
2445
- result: JobResult;
2446
- writeReady?: JobWriteReadyPayload;
2447
- };
2448
- /**
2449
- * Parent-side handle for a single executor worker.
2693
+ * Loader that asynchronously resolves a document type to a
2694
+ * {@link DocumentModelSource}. Used by the queue to gate CREATE_DOCUMENT
2695
+ * jobs until the required model is available in the registry.
2450
2696
  *
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.
2697
+ * Return an importable source ({ filePath } or { packageName }) whenever
2698
+ * possible: the resolver registers the resolved models on the host registry
2699
+ * and broadcasts importable sources to executor workers. A live
2700
+ * DocumentModelModule is also valid but host-only it cannot cross a
2701
+ * worker-thread boundary, so worker pools will not receive it.
2457
2702
  */
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;
2463
- /**
2464
- * Spawn the worker (if not already started), send the `init` payload and
2465
- * resolve when the worker replies with `ready`.
2466
- */
2467
- start(): Promise<void>;
2468
- /**
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.
2474
- */
2475
- execute(job: Job, signal?: AbortSignal): Promise<WorkerExecutionOutcome>;
2476
- /**
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.
2480
- */
2481
- abort(correlationId: string, reason?: string): void;
2482
- /**
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.
2486
- */
2487
- shutdown(graceful: boolean, graceMs?: number): Promise<void>;
2488
- /**
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.
2492
- */
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;
2703
+ interface IDocumentModelLoader {
2704
+ load(documentType: string): Promise<DocumentModelSource>;
2498
2705
  }
2499
2706
  /**
2500
- * Simple interface for executing a job.
2501
- * A JobExecutor simply takes a job and executes it - nothing more.
2707
+ * Registry for managing document model modules.
2708
+ * Provides centralized access to document models' reducers, utils, and specifications.
2709
+ * Supports version-aware module storage and upgrade manifest management.
2502
2710
  */
2503
- interface IJobExecutor {
2711
+ interface IDocumentModelRegistry {
2504
2712
  /**
2505
- * Execute a single job.
2506
- * @param job - The job to execute
2507
- * @returns Promise that resolves to the job result
2713
+ * Register multiple modules at once.
2714
+ * Modules without a version field default to version 1.
2715
+ * Invalid or duplicate modules are skipped without breaking registration of the remaining modules.
2716
+ *
2717
+ * @param modules Document model modules to register
2718
+ * @returns Array of results, one per module, indicating success or failure
2508
2719
  */
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 {
2720
+ registerModules(...modules: DocumentModelModule<any>[]): RegistrationResult<DocumentModelModule<any>>[];
2517
2721
  /**
2518
- * Start the executor manager.
2519
- * Begins listening for 'jobAvailable' events and dispatching to executors.
2722
+ * Unregister all versions of the specified document types.
2520
2723
  *
2521
- * @param numExecutors - Number of executor instances to create
2522
- * @returns Promise that resolves when the manager is started
2724
+ * @param documentTypes The document types to unregister
2725
+ * @returns true if all modules were unregistered, false if any were not found
2523
2726
  */
2524
- start(numExecutors: number): Promise<void>;
2727
+ unregisterModules(...documentTypes: string[]): boolean;
2525
2728
  /**
2526
- * Stop the executor manager.
2729
+ * Get a specific document model module by document type and optional version.
2730
+ * If version is not specified, returns the latest version.
2527
2731
  *
2528
- * @param graceful - Whether to wait for current jobs to complete
2529
- * @returns Promise that resolves when the manager is stopped
2732
+ * @param documentType The document type identifier
2733
+ * @param version Optional version number to retrieve
2734
+ * @returns The document model module
2735
+ * @throws ModuleNotFoundError if the document type or version is not registered
2530
2736
  */
2531
- stop(graceful?: boolean): Promise<void>;
2737
+ getModule(documentType: string, version?: number): DocumentModelModule<any>;
2532
2738
  /**
2533
- * Get all managed executor instances.
2739
+ * Get all registered document model modules.
2534
2740
  *
2535
- * @returns Array of executor instances
2741
+ * @returns Array of all registered modules
2536
2742
  */
2537
- getExecutors(): IJobExecutor[];
2743
+ getAllModules(): DocumentModelModule<any>[];
2538
2744
  /**
2539
- * Get the current status of the manager.
2745
+ * Clear all registered modules and upgrade manifests.
2746
+ */
2747
+ clear(): void;
2748
+ /**
2749
+ * Get all supported versions for a document type, sorted in ascending order.
2540
2750
  *
2541
- * @returns The current manager status
2751
+ * @param documentType The document type identifier
2752
+ * @returns Array of version numbers sorted ascending
2753
+ * @throws ModuleNotFoundError if no modules are registered for the document type
2542
2754
  */
2543
- getStatus(): ExecutorManagerStatus;
2544
- }
2545
- //#endregion
2546
- //#region src/job-tracker/interfaces.d.ts
2547
- /**
2548
- * Interface for tracking job lifecycle status.
2549
- * Maintains job state throughout execution: PENDING → RUNNING → COMPLETED/FAILED.
2550
- */
2551
- interface IJobTracker {
2755
+ getSupportedVersions(documentType: string): number[];
2552
2756
  /**
2553
- * Register a new job with PENDING status.
2757
+ * Get the latest (highest) version number for a document type.
2554
2758
  *
2555
- * @param jobInfo - The job information to register
2759
+ * @param documentType The document type identifier
2760
+ * @returns The highest version number registered for this document type
2761
+ * @throws ModuleNotFoundError if no modules are registered for the document type
2556
2762
  */
2557
- registerJob(jobInfo: JobInfo): void;
2763
+ getLatestVersion(documentType: string): number;
2558
2764
  /**
2559
- * Update a job's status to RUNNING.
2765
+ * Register upgrade manifests that define upgrade paths between versions.
2766
+ * Invalid or duplicate manifests are skipped without breaking registration of the remaining manifests.
2560
2767
  *
2561
- * @param jobId - The job ID to mark as running
2768
+ * @param manifests Upgrade manifests to register
2769
+ * @returns Array of results, one per manifest, indicating success or failure
2562
2770
  */
2563
- markRunning(jobId: string): void;
2771
+ registerUpgradeManifests(...manifests: UpgradeManifest<readonly number[]>[]): RegistrationResult<UpgradeManifest<readonly number[]>>[];
2564
2772
  /**
2565
- * Mark a job as failed.
2773
+ * Unregister upgrade manifests for the specified document types.
2774
+ * @param documentTypes The document types whose upgrade manifests should be unregistered
2775
+ * @returns true if all modules were unregistered, false if any were not found
2776
+ **/
2777
+ unregisterUpgradeManifests(...documentTypes: string[]): boolean;
2778
+ /**
2779
+ * Get the upgrade manifest for a document type.
2566
2780
  *
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
2781
+ * @param documentType The document type identifier
2782
+ * @returns The upgrade manifest
2783
+ * @throws ManifestNotFoundError if no manifest is registered for the document type
2570
2784
  */
2571
- markFailed(jobId: string, error: ErrorInfo$1, job?: Job): void;
2785
+ getUpgradeManifest(documentType: string): UpgradeManifest<readonly number[]>;
2572
2786
  /**
2573
- * Retrieve the current status of a job.
2787
+ * Compute the upgrade path from one version to another.
2788
+ * Returns the sequence of upgrade transitions needed.
2574
2789
  *
2575
- * @param jobId - The job ID to query
2576
- * @returns The job information, or null if the job is not found
2790
+ * @param documentType The document type identifier
2791
+ * @param fromVersion The starting version
2792
+ * @param toVersion The target version
2793
+ * @returns Array of upgrade transitions in order
2794
+ * @throws DowngradeNotSupportedError if toVersion is less than fromVersion
2795
+ * @throws ManifestNotFoundError if no upgrade manifest is registered
2796
+ * @throws MissingUpgradeTransitionError if any transition in the path is missing
2577
2797
  */
2578
- getJobStatus(jobId: string): JobInfo | null;
2798
+ computeUpgradePath(documentType: string, fromVersion: number, toVersion: number): UpgradeTransition[];
2579
2799
  /**
2580
- * Shutdown the job tracker and clean up resources.
2581
- * Unsubscribes from all event bus subscriptions.
2800
+ * Get the upgrade reducer for a single-step version transition.
2801
+ *
2802
+ * @param documentType The document type identifier
2803
+ * @param fromVersion The starting version
2804
+ * @param toVersion The target version (must be fromVersion + 1)
2805
+ * @returns The upgrade reducer function
2806
+ * @throws InvalidUpgradeStepError if toVersion is not fromVersion + 1
2807
+ * @throws ManifestNotFoundError if no upgrade manifest is registered
2808
+ * @throws MissingUpgradeTransitionError if the transition is not found
2582
2809
  */
2583
- shutdown(): void;
2810
+ getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
2584
2811
  }
2585
2812
  //#endregion
2586
- //#region src/queue/interfaces.d.ts
2813
+ //#region src/cache/buffer/ring-buffer.d.ts
2587
2814
  /**
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.
2815
+ * RingBuffer is a generic circular buffer implementation that stores a fixed number
2816
+ * of items. When the buffer is full, new items overwrite the oldest items.
2817
+ *
2818
+ * This implementation maintains O(1) time complexity for push operations and provides
2819
+ * items in chronological order (oldest to newest) via getAll().
2820
+ *
2821
+ * @template T - The type of items stored in the buffer
2591
2822
  */
2592
- interface IQueue {
2823
+ declare class RingBuffer<T> {
2824
+ private buffer;
2825
+ private head;
2826
+ private size;
2827
+ private capacity;
2828
+ constructor(capacity: number);
2593
2829
  /**
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
2830
+ * Adds an item to the buffer. If the buffer is full, overwrites the oldest item.
2831
+ *
2832
+ * @param item - The item to add
2599
2833
  */
2600
- enqueue(job: Job): Promise<void>;
2834
+ push(item: T): void;
2601
2835
  /**
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
2836
+ * Returns all items in the buffer in chronological order (oldest to newest).
2837
+ *
2838
+ * @returns Array of items in insertion order
2608
2839
  */
2609
- dequeue(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
2840
+ getAll(): T[];
2610
2841
  /**
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
2842
+ * Clears all items from the buffer.
2614
2843
  */
2615
- dequeueNext(signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
2844
+ clear(): void;
2616
2845
  /**
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
2846
+ * Gets the current number of items in the buffer.
2626
2847
  */
2627
- dequeueNextMatching(predicate: (meta: JobRoutingMeta) => boolean, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
2628
- /**
2629
- * Get the current size of the queue for a specific document/scope/branch.
2630
- * @param documentId - The document ID
2848
+ get length(): number;
2849
+ }
2850
+ //#endregion
2851
+ //#region src/cache/kysely-write-cache.d.ts
2852
+ type DocumentStream = {
2853
+ key: string;
2854
+ ringBuffer: RingBuffer<CachedSnapshot>;
2855
+ };
2856
+ /**
2857
+ * In-memory write cache with keyframe persistence for PHDocuments.
2858
+ *
2859
+ * Caches document snapshots in ring buffers with LRU eviction. On cache miss,
2860
+ * rebuilds documents from nearest keyframe or full operation history.
2861
+ *
2862
+ * **Performance Characteristics:**
2863
+ * - Cache hit: O(1) lookup in ring buffer
2864
+ * - Cold miss: O(n) where n is total operation count, or O(k) where k is operations since keyframe
2865
+ * - Warm miss: O(m) where m is operations since cached revision
2866
+ * - Eviction: O(1) for LRU tracking and removal
2867
+ *
2868
+ * **Thread Safety:**
2869
+ * Not thread-safe. Designed for single-threaded job executor environment.
2870
+ * External synchronization required for concurrent access across multiple executors.
2871
+ *
2872
+ * **Example:**
2873
+ * ```typescript
2874
+ * const cache = new KyselyWriteCache(
2875
+ * keyframeStore,
2876
+ * operationStore,
2877
+ * registry,
2878
+ * { maxDocuments: 1000, ringBufferSize: 10, keyframeInterval: 10 }
2879
+ * );
2880
+ *
2881
+ * await cache.startup();
2882
+ *
2883
+ * // Retrieve or rebuild document
2884
+ * const doc = await cache.getState(docId, docType, scope, branch, revision);
2885
+ *
2886
+ * // Cache result after job execution
2887
+ * cache.putState(docId, docType, scope, branch, newRevision, updatedDoc);
2888
+ *
2889
+ * await cache.shutdown();
2890
+ * ```
2891
+ */
2892
+ declare class KyselyWriteCache implements IWriteCache {
2893
+ private streams;
2894
+ private lruTracker;
2895
+ private keyframeStore;
2896
+ private operationStore;
2897
+ private registry;
2898
+ private config;
2899
+ constructor(keyframeStore: IKeyframeStore, operationStore: IOperationStore, registry: IDocumentModelRegistry, config: WriteCacheConfig);
2900
+ withScopedStores(operationStore: IOperationStore, keyframeStore: IKeyframeStore): KyselyWriteCache;
2901
+ /**
2902
+ * Initializes the write cache.
2903
+ * Currently a no-op as keyframe store lifecycle is managed externally.
2904
+ */
2905
+ startup(): Promise<void>;
2906
+ /**
2907
+ * Shuts down the write cache.
2908
+ * Currently a no-op as keyframe store lifecycle is managed externally.
2909
+ */
2910
+ shutdown(): Promise<void>;
2911
+ /**
2912
+ * Retrieves document state at a specific revision from cache or rebuilds it.
2913
+ *
2914
+ * Note: this returns a _shallow_ copy of the document.
2915
+ *
2916
+ * Cache hit path: Returns cached snapshot if available (O(1))
2917
+ * Warm miss path: Rebuilds from cached base revision + incremental ops
2918
+ * Cold miss path: Rebuilds from keyframe or from scratch using all operations
2919
+ *
2920
+ * @param documentId - The document identifier
2921
+ * @param scope - The operation scope
2922
+ * @param branch - The operation branch
2923
+ * @param targetRevision - The target revision, or undefined for newest
2924
+ * @param signal - Optional abort signal to cancel the operation
2925
+ * @returns The document at the target revision
2926
+ * @throws {Error} "Operation aborted" if signal is aborted
2927
+ * @throws {ModuleNotFoundError} If document type not registered in registry
2928
+ * @throws {Error} "Failed to rebuild document" if operation store fails
2929
+ * @throws {Error} If reducer throws during operation application
2930
+ * @throws {Error} If document serialization fails
2931
+ */
2932
+ getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
2933
+ /**
2934
+ * Stores a document snapshot in the cache at a specific revision.
2935
+ *
2936
+ * The cached document is a shallow copy of the input with its operation history
2937
+ * truncated to the last operation per scope and its clipboard cleared. This keeps
2938
+ * memory use and copy costs constant regardless of operation count. Consumers of
2939
+ * getState() must not rely on the full operation history being present; the only
2940
+ * guaranteed invariant is that operations[scope].at(-1) reflects the latest
2941
+ * operation index for each scope.
2942
+ *
2943
+ * Updates LRU tracker and may evict least recently used stream if at capacity.
2944
+ * Asynchronously persists keyframes at configured intervals (fire-and-forget).
2945
+ *
2946
+ * @param documentId - The document identifier
2947
+ * @param scope - The operation scope
2948
+ * @param branch - The operation branch
2949
+ * @param revision - The revision number
2950
+ * @param document - The document to cache
2951
+ * @throws {Error} If document serialization fails
2952
+ */
2953
+ putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, position: SnapshotPosition): void;
2954
+ private store;
2955
+ /**
2956
+ * Invalidates cached document streams.
2957
+ *
2958
+ * Supports three invalidation scopes:
2959
+ * - Document-level: invalidate(documentId) - removes all streams for document
2960
+ * - Scope-level: invalidate(documentId, scope) - removes all branches for scope
2961
+ * - Stream-level: invalidate(documentId, scope, branch) - removes specific stream
2962
+ *
2963
+ * @param documentId - The document identifier
2964
+ * @param scope - Optional scope to narrow invalidation
2965
+ * @param branch - Optional branch to narrow invalidation (requires scope)
2966
+ * @returns The number of streams evicted
2967
+ */
2968
+ invalidate(documentId: string, scope?: string, branch?: string): number;
2969
+ /**
2970
+ * Clears the entire cache, removing all cached document streams.
2971
+ * Resets LRU tracking state. This operation always succeeds.
2972
+ */
2973
+ clear(): void;
2974
+ /**
2975
+ * Retrieves a specific stream for a document. Exposed on the implementation
2976
+ * for testing, but not on the interface.
2977
+ *
2978
+ * @internal
2979
+ */
2980
+ getStream(documentId: string, scope: string, branch: string): DocumentStream | undefined;
2981
+ private findNearestKeyframe;
2982
+ /**
2983
+ * Rebuilds a scope from a keyframe or from the whole operation history.
2984
+ *
2985
+ * The document scope is always rebuilt first, because it carries the type,
2986
+ * the upgrades and the deletion marker. Its version-changing upgrades are not
2987
+ * applied there though: an upgrade reducer must see the state the requested
2988
+ * scope has reached at that upgrade's boundary, so each one is held back and
2989
+ * applied when the replay below crosses the boundary that
2990
+ * resolveModuleVersionForOp derives from it. Upgrades whose boundary lies past
2991
+ * the last replayed operation are applied at the end. Creation-time 0->N seed
2992
+ * upgrades carry the initial state, so they still apply immediately.
2993
+ */
2994
+ private coldMissRebuild;
2995
+ /**
2996
+ * Applies and removes every held-back upgrade whose target version is at or
2997
+ * below `throughVersion`, in the order the document scope recorded them.
2998
+ */
2999
+ private applyPendingUpgrades;
3000
+ /**
3001
+ * Applies the remaining held-back upgrades after the requested scope's
3002
+ * replay has finished. A head read applies them all. A positional read
3003
+ * applies only those whose boundary for this scope lies at or before the
3004
+ * target position: applying a later one would label migrated state with a
3005
+ * pre-upgrade revision, and a keyframe stored from that poisons every
3006
+ * rebuild that resumes from it. Boundaries come from the upgrade's revision
3007
+ * snapshot; an upgrade without one records no position for this scope, and
3008
+ * the replay loop not having crossed it already places it past the target.
3009
+ */
3010
+ private applyTailPendingUpgrades;
3011
+ /**
3012
+ * Applies one held-back upgrade, then re-applies the deletes the document
3013
+ * scope recorded after it so the hold-back cannot invert their order.
3014
+ */
3015
+ private applyPendingUpgrade;
3016
+ /**
3017
+ * Copies the current document revisions onto the document. Overwrites the
3018
+ * requested scope revision with the target revision, if provided.
3019
+ */
3020
+ private stampRevisions;
3021
+ /** The stored operation at `index`, or undefined if it is no longer there. */
3022
+ private operationAt;
3023
+ /**
3024
+ * Resolves which module version to use for a given operation in phase 2.
3025
+ *
3026
+ * Uses the validated-upgrade boundary rules from D7:
3027
+ * - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary
3028
+ * - Otherwise: timestamp fallback
3029
+ * - Falls back to final module version when neither is decidable
3030
+ */
3031
+ private resolveModuleVersionForOp;
3032
+ private warmMissRebuild;
3033
+ private findNearestOlderSnapshot;
3034
+ private makeStreamKey;
3035
+ private getOrCreateStream;
3036
+ private isKeyframeRevision;
3037
+ }
3038
+ //#endregion
3039
+ //#region src/storage/kysely/store.d.ts
3040
+ declare class KyselyOperationStore implements IOperationStore {
3041
+ private db;
3042
+ private trx?;
3043
+ constructor(db: Kysely<Database$1>);
3044
+ private get queryExecutor();
3045
+ withTransaction(trx: Transaction<Database$1>): KyselyOperationStore;
3046
+ apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal, condition?: AppendCondition): Promise<Operation[]>;
3047
+ private resolveUniqueConstraint;
3048
+ private executeApply;
3049
+ /**
3050
+ * Locks the written stream and every read-set stream, in sorted key order
3051
+ * so that overlapping concurrent appends serialize rather than deadlock.
3052
+ * The locks are still taken one row at a time, so the query preserves that
3053
+ * order. It must stay separate from the guarded insert, which would
3054
+ * otherwise read a snapshot taken before the locks were held.
3055
+ */
3056
+ private acquireStreamLocks;
3057
+ /**
3058
+ * Inserts the staged operations with the condition compiled in as a WHERE
3059
+ * NOT EXISTS guard, making the check and the append one statement. Returns
3060
+ * the rows inserted; zero means the guard failed and nothing was written.
3061
+ */
3062
+ private insertGuarded;
3063
+ private findIdempotentReplay;
3064
+ getSince(documentId: string, scope: string, branch: string, revision: number, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
3065
+ getSinceId(id: number, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<OperationWithContext$1>>;
3066
+ getConflicting(documentId: string, scope: string, branch: string, minTimestamp: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
3067
+ getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
3068
+ getStreamLatestTimestamp(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
3069
+ private rowToOperation;
3070
+ private rowToOperationWithContext;
3071
+ }
3072
+ //#endregion
3073
+ //#region src/storage/kysely/keyframe-store.d.ts
3074
+ declare class KyselyKeyframeStore implements IKeyframeStore {
3075
+ private db;
3076
+ private trx?;
3077
+ constructor(db: Kysely<Database$1>);
3078
+ private get queryExecutor();
3079
+ withTransaction(trx: Transaction<Database$1>): KyselyKeyframeStore;
3080
+ putKeyframe(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, signal?: AbortSignal): Promise<void>;
3081
+ findNearestKeyframe(documentId: string, scope: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<{
3082
+ revision: number;
3083
+ document: PHDocument;
3084
+ } | undefined>;
3085
+ listKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<Array<{
3086
+ scope: string;
3087
+ branch: string;
3088
+ revision: number;
3089
+ document: PHDocument;
3090
+ }>>;
3091
+ deleteKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<number>;
3092
+ }
3093
+ //#endregion
3094
+ //#region src/executor/execution-scope.d.ts
3095
+ interface ExecutionStores {
3096
+ operationStore: IOperationStore;
3097
+ operationIndex: IOperationIndex;
3098
+ writeCache: IWriteCache;
3099
+ documentMetaCache: IDocumentMetaCache;
3100
+ collectionMembershipCache: ICollectionMembershipCache;
3101
+ }
3102
+ interface IExecutionScope {
3103
+ run<T>(fn: (stores: ExecutionStores) => Promise<T>, signal?: AbortSignal): Promise<T>;
3104
+ }
3105
+ //#endregion
3106
+ //#region src/executor/types.d.ts
3107
+ /**
3108
+ * Represents the result of a job execution
3109
+ */
3110
+ type JobResult = {
3111
+ /** The job that was executed */job: Job; /** Whether the job executed successfully */
3112
+ success: boolean; /** Error if the job failed */
3113
+ error?: Error; /** The operations generated from the actions (if successful) */
3114
+ operations?: Operation[];
3115
+ /**
3116
+ * Operations with context (includes ephemeral resultingState).
3117
+ * Used for emitting to IDocumentView via event bus.
3118
+ */
3119
+ operationsWithContext?: OperationWithContext$1[]; /** Timestamp when the job execution completed */
3120
+ completedAt?: string; /** Duration of job execution in milliseconds */
3121
+ duration?: number; /** Any additional metadata from the execution */
3122
+ metadata?: Record<string, any>;
3123
+ };
3124
+ /**
3125
+ * Enforcement the reactor performs, each off by default.
3126
+ *
3127
+ * An evaluation made while replaying is part of the document's history, so two
3128
+ * reactors that share documents and disagree on these diverge. A flag is turned
3129
+ * on for a set of reactors that sync with each other, not for one node.
3130
+ */
3131
+ type ReactorFeatureFlags = {
3132
+ /**
3133
+ * Decide whether an operation may be admitted by building a decision model
3134
+ * over the document stream, rather than reading the deleted flag from the
3135
+ * document meta cache. Deletion then takes effect from the deleting
3136
+ * operation's position rather than for the whole document.
3137
+ */
3138
+ documentDecisions: boolean;
3139
+ /**
3140
+ * Evaluate the auth policy by reading the auth scope as a second projection.
3141
+ * Requires documentDecisions.
3142
+ */
3143
+ authEnforcement: boolean;
3144
+ /**
3145
+ * Match { group } principals by folding the referenced PHGroup documents as
3146
+ * derived projections. Requires authEnforcement.
3147
+ */
3148
+ authGroups: boolean;
3149
+ /**
3150
+ * Evaluate `where` clauses and { match } principals against the executing
3151
+ * scope's state, the subject, and the action input. Requires authGroups.
3152
+ */
3153
+ authConditions: boolean;
3154
+ };
3155
+ /**
3156
+ * Configuration options for the job executor
3157
+ */
3158
+ type JobExecutorConfig = {
3159
+ /** Feature flags; anything unset is off. */featureFlags?: Partial<ReactorFeatureFlags>; /** Maximum number of conflicting operations to skip when reshuffling. */
3160
+ maxSkipThreshold?: number; /** Maximum number of concurrent jobs to execute */
3161
+ maxConcurrency?: number; /** Maximum time in milliseconds a job can run before being considered timed out */
3162
+ jobTimeoutMs?: number; /** Base delay in milliseconds for exponential backoff retries */
3163
+ retryBaseDelayMs?: number; /** Maximum delay in milliseconds for exponential backoff retries */
3164
+ retryMaxDelayMs?: number;
3165
+ /** Maximum elapsed milliseconds before yielding to the main thread between actions.
3166
+ * Keeps the UI responsive when processing large batches. */
3167
+ yieldDeadlineMs?: number;
3168
+ };
3169
+ /**
3170
+ * Event types for the job executor
3171
+ */
3172
+ declare const JobExecutorEventTypes: {
3173
+ readonly JOB_STARTED: 20000;
3174
+ readonly JOB_COMPLETED: 20001;
3175
+ readonly JOB_FAILED: 20002;
3176
+ readonly EXECUTOR_STARTED: 20003;
3177
+ readonly EXECUTOR_STOPPED: 20004;
3178
+ };
3179
+ /**
3180
+ * Event data for job execution events
3181
+ */
3182
+ type JobStartedEvent = {
3183
+ job: Job;
3184
+ startedAt: string;
3185
+ /**
3186
+ * Identifier of the executor that took the job. For the worker pool this is
3187
+ * the thread-worker id (e.g. "reactor-worker-3"); for the in-process simple
3188
+ * manager it is "in-process-<index>". Optional for backwards compatibility
3189
+ * with consumers built before the field was added.
3190
+ */
3191
+ workerId?: string;
3192
+ };
3193
+ type JobCompletedEvent = {
3194
+ job: Job;
3195
+ result: JobResult; /** See {@link JobStartedEvent.workerId}. */
3196
+ workerId?: string;
3197
+ };
3198
+ type JobFailedEvent = {
3199
+ job: Job;
3200
+ error: string;
3201
+ willRetry: boolean;
3202
+ retryCount: number; /** See {@link JobStartedEvent.workerId}. */
3203
+ workerId?: string;
3204
+ };
3205
+ type ExecutorStartedEvent = {
3206
+ config: JobExecutorConfig;
3207
+ startedAt: string;
3208
+ };
3209
+ type ExecutorStoppedEvent = {
3210
+ stoppedAt: string;
3211
+ graceful: boolean;
3212
+ };
3213
+ /**
3214
+ * Status information for the job executor manager
3215
+ */
3216
+ type ExecutorManagerStatus = {
3217
+ /** Whether the manager is currently running */isRunning: boolean; /** Number of executor instances managed */
3218
+ numExecutors: number; /** Number of jobs currently being processed */
3219
+ activeJobs: number; /** Total number of jobs processed since start */
3220
+ totalJobsProcessed: number;
3221
+ };
3222
+ //#endregion
3223
+ //#region src/decision/types.d.ts
3224
+ /** One operation stream. */
3225
+ type StreamQuery = {
3226
+ documentId: string;
3227
+ branch: string;
3228
+ scope: string;
3229
+ };
3230
+ /**
3231
+ * What building a decision model reads a stream's state through.
3232
+ *
3233
+ * `IWriteCache` satisfies this and is what the write paths pass. The read path
3234
+ * cannot: the write cache is a write-side projection invalidated by the process
3235
+ * that runs the executor, so a reactor whose executors live in worker processes
3236
+ * holds state in its parent that no commit ever invalidates. A read there would
3237
+ * decide against a policy arbitrarily far behind the one the write paths
3238
+ * enforce. Reads therefore pass a reader backed by the read side.
3239
+ */
3240
+ interface IStreamStateReader {
3241
+ getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
3242
+ }
3243
+ /** The document and branch a decision model is built for. */
3244
+ type DecisionTarget = {
3245
+ documentId: string;
3246
+ branch: string;
3247
+ };
3248
+ /**
3249
+ * What a decision's conditions may read beyond the projections: the executing
3250
+ * scope's own state and the attempted action's input. Populated only while
3251
+ * authConditions is on; otherwise both stay undefined and conditional grants
3252
+ * never apply.
3253
+ */
3254
+ type DecisionContext = {
3255
+ scopeState: unknown;
3256
+ actionInput?: unknown;
3257
+ };
3258
+ /** A statically-queried stream's operations, named after its projection. */
3259
+ type StreamHistory = {
3260
+ name: string;
3261
+ operations: Operation[];
3262
+ };
3263
+ /**
3264
+ * A named stream whose value in the model is that scope's state from the
3265
+ * document rebuild the reactor already performs. A derived query may read
3266
+ * only statically-queried projections, so composition is one layer deep.
3267
+ */
3268
+ type Projection<M> = {
3269
+ query: StreamQuery | ((model: Partial<M>) => StreamQuery[]);
3270
+ /**
3271
+ * For a derived projection, the streams it may read anywhere in an
3272
+ * evaluated range, derived from the statically-queried streams' operations
3273
+ * (including the operations under evaluation). A positional walk cannot use
3274
+ * `query`, because the folded state it depends on changes over the range;
3275
+ * this over-approximates by design, since a stream referenced at any
3276
+ * position stays readable when the earlier range is re-evaluated even if a
3277
+ * later operation removes the reference. Ignored on static projections.
3278
+ */
3279
+ queryOverHistory?: (reads: StreamHistory[]) => StreamQuery[];
3280
+ /**
3281
+ * Action types in this stream that can change an evaluation. Reads of the stream
3282
+ * are filtered to these, so anything left out is invisible to a decision.
3283
+ */
3284
+ decidingActions: string[]; /** Applies one of this stream's operations while deciding. */
3285
+ apply: (document: PHDocument, operation: Operation) => PHDocument;
3286
+ };
3287
+ /**
3288
+ * The outcome of evaluating one operation. A refusal carries the reason it is
3289
+ * recorded with, because a model has more than one way to refuse.
3290
+ */
3291
+ type Evaluation = {
3292
+ decision: "allow";
3293
+ } | {
3294
+ decision: "deny";
3295
+ reason: string;
3296
+ };
3297
+ /** Projections plus a decision function over the built model. */
3298
+ type DecisionModel<M> = {
3299
+ projections: { [K in keyof M]: Projection<M> };
3300
+ /**
3301
+ * Present when decide reads the executing scope's state through the
3302
+ * decision context. A positional walk then folds the evaluated stream with
3303
+ * this, from its base state through every effective operation, so
3304
+ * conditions read the state as it stood at each operation's position
3305
+ * rather than at the head.
3306
+ */
3307
+ foldEvaluatedScope?: (document: PHDocument, operation: Operation) => PHDocument;
3308
+ /**
3309
+ * Whether or not this model decides about operations in a given scope. That
3310
+ * is, a scope it reads is not necessarily one it evaluates, and vise-versa.
3311
+ */
3312
+ evaluatesScope(scope: string): boolean;
3313
+ decide(model: M, subject: AuthSubject, request: AuthRequest, ctx: DecisionContext): Evaluation;
3314
+ };
3315
+ /** A built model plus the read-set condition recording what the build read. */
3316
+ type BuiltDecisionModel<M> = {
3317
+ model: M;
3318
+ appendCondition: AppendCondition;
3319
+ };
3320
+ //#endregion
3321
+ //#region src/decision/document-decision-model.d.ts
3322
+ /** What the document decision model reads: the target's document scope. */
3323
+ type DocumentDecisionModel = {
3324
+ document: PHDocumentState;
3325
+ };
3326
+ /**
3327
+ * The simplest decision model: one projection over the document scope, which
3328
+ * rejects on a deleted document.
3329
+ */
3330
+ declare function documentDecisionModel(target: DecisionTarget): DecisionModel<DocumentDecisionModel>;
3331
+ //#endregion
3332
+ //#region src/decision/registered-model.d.ts
3333
+ /**
3334
+ * A model this reactor can register. Every one carries the document projection,
3335
+ * because admission reads the version and the deletion timestamp off it; a model
3336
+ * with more projections than that is still assignable here.
3337
+ */
3338
+ type RegisteredDecisionModel = (target: DecisionTarget) => DecisionModel<DocumentDecisionModel>;
3339
+ /** What admission needs out of a model built at the stream heads. */
3340
+ type AdmissionDecision = {
3341
+ evaluation: Evaluation;
3342
+ appendCondition: AppendCondition;
3343
+ documentVersion: number;
3344
+ deletedAtUtcIso: string | null;
3345
+ };
3346
+ /**
3347
+ * What decideAtHead resolves a condition context from: the action's input,
3348
+ * with the executing scope's state read at the head. Supplied only while
3349
+ * authConditions is on.
3350
+ */
3351
+ type AdmissionConditions = {
3352
+ actionInput?: unknown;
3353
+ };
3354
+ /**
3355
+ * Builds the model at the stream heads and decides one request against it. The
3356
+ * append condition it returns is the read-set the store enforces at write time.
3357
+ *
3358
+ * With `conditions` supplied, the executing scope's state is read at the head
3359
+ * for `doc.<scope>.*` paths. That read carries no append-condition entry of
3360
+ * its own: the written stream's expected-revision check already refuses a
3361
+ * write whose scope grew between the read and the append.
3362
+ */
3363
+ declare function decideAtHead(model: RegisteredDecisionModel, cache: IWriteCache, target: DecisionTarget, subject: AuthSubject, request: AuthRequest, signal?: AbortSignal, conditions?: AdmissionConditions): Promise<AdmissionDecision>;
3364
+ /**
3365
+ * The model this reactor enforces. With `authEnforcement` off the auth scope is
3366
+ * absent from every append condition and no load walks it; with `authGroups`
3367
+ * on, the group documents the grant list names join the read-set and the
3368
+ * registry supplies the reducer that folds them.
3369
+ */
3370
+ declare function selectDecisionModel(flags: ReactorFeatureFlags, registry: IDocumentModelRegistry): RegisteredDecisionModel;
3371
+ //#endregion
3372
+ //#region src/decision/read-gate.d.ts
3373
+ /**
3374
+ * Scopes every holder of a document may read, whatever the grants say. Denying
3375
+ * the policy itself would let a replica sync a document without it, read the
3376
+ * auth scope as uninitialized, and allow every operation it holds, so replicas
3377
+ * would diverge permanently. The document scope carries the metadata the same
3378
+ * argument covers. Grants gate domain-scope reads only.
3379
+ */
3380
+ declare const ALWAYS_READABLE_SCOPES: ReadonlySet<string>;
3381
+ /** Whether a subject may read each scope of one document. */
3382
+ interface IReadGate {
3383
+ /**
3384
+ * Resolves, for one document, which of its scopes the subject may read.
3385
+ *
3386
+ * The predicate is resolved up front rather than asked per scope so that the
3387
+ * filtering itself stays synchronous, and so that a model backing the answer
3388
+ * is built once per document instead of once per scope.
3389
+ */
3390
+ scopePredicate(document: PHDocument, subject: AuthSubject, branch: string, signal?: AbortSignal): Promise<(scope: string) => boolean>;
3391
+ }
3392
+ /**
3393
+ * The model reads enforce. Below `authEnforcement` there is no model to
3394
+ * enforce: the document-only model ignores the auth scope entirely, so reading
3395
+ * through it would serve every domain scope of a policied document to anyone.
3396
+ * Undefined therefore means "evaluate the policy alone", which is what the read
3397
+ * surface did before the model existed.
3398
+ */
3399
+ declare function readDecisionModel(flags: ReactorFeatureFlags, registry: IDocumentModelRegistry): RegisteredDecisionModel | undefined;
3400
+ /**
3401
+ * Evaluates the policy on its own, with no groups map and no condition context.
3402
+ * A `{ group }` or conditional grant therefore never applies: an allow that
3403
+ * does not apply withholds access, so this cannot widen a policy, but a policy
3404
+ * relying on a conditional deny is weaker here than it is written.
3405
+ */
3406
+ declare class BareReadGate implements IReadGate {
3407
+ scopePredicate(document: PHDocument, subject: AuthSubject): Promise<(scope: string) => boolean>;
3408
+ }
3409
+ /**
3410
+ * Evaluates a read against the registered decision model, built at the stream
3411
+ * heads. This is what makes `{ group }` principals and conditional grants apply
3412
+ * to a read: the model supplies the groups map and the scope's own state, the
3413
+ * same two things admission supplies.
3414
+ *
3415
+ * A read has no action, so a condition on `action.input.*` never holds for one.
3416
+ *
3417
+ * State is read through the read side rather than the write cache. The write
3418
+ * cache is invalidated by whichever process runs the executor, so a reactor
3419
+ * running its executors in worker processes would answer reads in the parent
3420
+ * from state no commit ever invalidates.
3421
+ */
3422
+ declare class ModelReadGate implements IReadGate {
3423
+ private readonly model;
3424
+ private readonly documentView;
3425
+ /**
3426
+ * Whether a group a policy names is served to that policy's audience. Only
3427
+ * meaningful with `authGroups`, which is what makes a `{ group }` grant
3428
+ * match at all; below it the grant fails closed, so serving the roster
3429
+ * would publish a member list no read grant can use.
3430
+ */
3431
+ private readonly servesGroups;
3432
+ private readonly operationIndex?;
3433
+ private readonly logger?;
3434
+ constructor(model: RegisteredDecisionModel, documentView: IDocumentView,
3435
+ /**
3436
+ * Whether a group a policy names is served to that policy's audience. Only
3437
+ * meaningful with `authGroups`, which is what makes a `{ group }` grant
3438
+ * match at all; below it the grant fails closed, so serving the roster
3439
+ * would publish a member list no read grant can use.
3440
+ */
3441
+
3442
+ servesGroups: boolean, operationIndex?: IOperationIndex | undefined, logger?: ILogger | undefined);
3443
+ /**
3444
+ * A served group yields its member list and nothing else. What the audience
3445
+ * is owed is the state it must fold to evaluate auth with the group; a
3446
+ * group's other scopes are its own business and stay behind its own grants.
3447
+ */
3448
+ scopePredicate(document: PHDocument, subject: AuthSubject, branch: string, signal?: AbortSignal): Promise<(scope: string) => boolean>;
3449
+ /**
3450
+ * Whether the subject is served this group because a policy names it.
3451
+ *
3452
+ * A replica must fold a group's membership to evaluate auth with it, so a
3453
+ * group a grant names is served to the audience of the document that names
3454
+ * it, whatever the group's own read grants say. Naming a group in a policy
3455
+ * publishes its roster to that policy's audience; a group whose membership
3456
+ * must stay confidential does not belong in a grant.
3457
+ *
3458
+ * The referencing document's own domain scopes are the test. Its `auth` and
3459
+ * `document` scopes are readable by every holder, so testing those would
3460
+ * serve every referenced group to everybody.
3461
+ *
3462
+ * One level only. A referencer that is itself a group is skipped, and a
3463
+ * referencer's own readability is decided from its policy alone, so a
3464
+ * reference cycle terminates. Cycles are reachable: the reference relation
3465
+ * is recorded from an operation's input, including one later stored denied,
3466
+ * so a refused grant naming a group from inside another group leaves a row
3467
+ * behind that validation never saw.
3468
+ *
3469
+ * The referencers are probed a few at a time and the walk stops at the first
3470
+ * that serves, because a subject outside the audience is the case that runs to
3471
+ * the bound, and it is the common one. A probe that failed decides only when
3472
+ * nothing served: serving rests on a real allow, so this cannot widen, and it
3473
+ * stops one unreachable referencer from turning an allow already in hand into
3474
+ * a denial. A read records no operation, so replicas differing over a
3475
+ * transient failure has no consensus consequence.
3476
+ *
3477
+ * The probes are awaited together rather than raced, so none is ever left
3478
+ * running with nobody awaiting it, which is where unhandled rejections come
3479
+ * from.
3480
+ */
3481
+ private servesGroupTo;
3482
+ /**
3483
+ * Whether one referencing document serves the subject any domain scope. A
3484
+ * referencer this replica does not hold serves nothing, which fails closed
3485
+ * the same way a group it does not hold does.
3486
+ */
3487
+ private servesThrough;
3488
+ private servesGroup;
3489
+ /**
3490
+ * What this document's own policy says, with no group serving applied.
3491
+ *
3492
+ * An unpoliced document is readable in full, which is the common case and the
3493
+ * one worth answering without building anything. The test is the one
3494
+ * `evaluate` makes: a legacy `{}` auth scope and version 0 both mean
3495
+ * uninitialized, and "no grants" does not, because a policy with a version and
3496
+ * an empty grant list denies everything.
3497
+ */
3498
+ private ownPolicyPredicate;
3499
+ }
3500
+ //#endregion
3501
+ //#region src/client/reactor-client.d.ts
3502
+ /**
3503
+ * ReactorClient implementation that wraps lower-level APIs to provide
3504
+ * a simpler interface for document operations.
3505
+ *
3506
+ * Features:
3507
+ * - Wraps Jobs with Promises for easier async handling
3508
+ * - Manages signing of submitted Action objects
3509
+ * - Provides quality-of-life functions for common tasks
3510
+ * - Wraps subscription interface with ViewFilters
3511
+ */
3512
+ declare class ReactorClient implements IReactorClient {
3513
+ private logger;
3514
+ private reactor;
3515
+ private signer;
3516
+ private subscriptionManager;
3517
+ private jobAwaiter;
3518
+ private documentIndexer;
3519
+ private documentView;
3520
+ private readGate;
3521
+ readonly drives: IDriveClient;
3522
+ constructor(logger: ILogger, reactor: IReactor, signer: ISigner, subscriptionManager: IReactorSubscriptionManager, jobAwaiter: IJobAwaiter, documentIndexer: IDocumentIndexer, documentView: IDocumentView, readGate?: IReadGate);
3523
+ private readSubject;
3524
+ /**
3525
+ * Which scopes of one document the subject may read. Resolved once per
3526
+ * document, so the gate builds its model once however many scopes are then
3527
+ * tested, and the filtering itself stays synchronous.
3528
+ */
3529
+ private readableScopes;
3530
+ /**
3531
+ * One document, filtered to the scopes the subject may read. Every method
3532
+ * that hands a document back goes through here, including the ones that
3533
+ * follow a write: a document returned from a mutation is a read like any
3534
+ * other, and returning it whole served scopes the same subject would be
3535
+ * refused by `get`. Its author still sees what it wrote, because an allow on
3536
+ * execute confers read of that scope.
3537
+ */
3538
+ private gateDocument;
3539
+ /**
3540
+ * Retrieves a list of document model modules.
3541
+ */
3542
+ getDocumentModelModules(namespace?: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentModelModule>>;
3543
+ /**
3544
+ * Retrieves a specific document model module by document type.
3545
+ *
3546
+ * @param documentType - The document type identifier
3547
+ * @returns The document model module
3548
+ */
3549
+ getDocumentModelModule(documentType: string): Promise<DocumentModelModule<any>>;
3550
+ /**
3551
+ * Retrieves the document model module matching the version the document is
3552
+ * stamped with, so not-yet-upgraded documents get the reducer their
3553
+ * history was written with rather than the latest.
3554
+ */
3555
+ getDocumentModelModuleForDocument(document: PHDocument): Promise<DocumentModelModule<any>>;
3556
+ /**
3557
+ * Retrieves a specific PHDocument
3558
+ */
3559
+ get<TDocument extends PHDocument>(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<TDocument>;
3560
+ /**
3561
+ * Resolves an identifier (id or slug) to the canonical document id, using the
3562
+ * same lookup as the data path. Resolves against the "main" branch. Throws if
3563
+ * the identifier cannot be resolved or is ambiguous.
3564
+ */
3565
+ resolveIdOrSlug(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<string>;
3566
+ /**
3567
+ * Retrieves operations for a document
3568
+ */
3569
+ getOperations(documentIdentifier: string, view?: ViewFilter, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
3570
+ private getOperationsWithCompositeCursor;
3571
+ /**
3572
+ * Retrieves outgoing relationships of a given type from a source document.
3573
+ */
3574
+ getOutgoingRelationships(sourceIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
3575
+ /**
3576
+ * Retrieves incoming relationships of a given type to a target document.
3577
+ */
3578
+ getIncomingRelationships(targetIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
3579
+ /**
3580
+ * Filters documents by criteria and returns a list of them
3581
+ */
3582
+ find(search: SearchFilter, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
3583
+ /**
3584
+ * Creates a document and waits for completion
3585
+ */
3586
+ create<TDocument extends PHDocument = PHDocument>(document: PHDocument, parentIdentifier?: string, signal?: AbortSignal): Promise<TDocument>;
3587
+ /**
3588
+ * Creates an empty document and waits for completion
3589
+ */
3590
+ createEmpty<TDocument extends PHDocument>(documentModelType: string, options?: CreateDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
3591
+ /**
3592
+ * Upgrades a document to a newer document model version by dispatching an
3593
+ * UPGRADE_DOCUMENT action. When toVersion is omitted, upgrades to the
3594
+ * latest registered module version for the document's type. Returns the
3595
+ * document unchanged when it is already at the target version.
3596
+ *
3597
+ * The executor validates the action's version and revision snapshot against
3598
+ * the state the migration actually runs on. When a concurrent edit
3599
+ * invalidates the snapshot, the upgrade is rebuilt from a fresh read and
3600
+ * retried up to maxConflictRetries times before the conflict is surfaced.
3601
+ */
3602
+ upgradeDocument<TDocument extends PHDocument = PHDocument>(documentIdentifier: string, toVersion?: number, options?: UpgradeDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
3603
+ /**
3604
+ * Creates an empty document in a drive as a single batched operation.
3605
+ * Delegates to {@link IDriveClient.addFile}.
3606
+ *
3607
+ * @deprecated Use `client.drives.addFile` instead. This method will be
3608
+ * removed in a future release.
3609
+ */
3610
+ createDocumentInDrive<TDocument extends PHDocument>(driveId: string, document: PHDocument, parentFolder?: string, signal?: AbortSignal): Promise<TDocument>;
3611
+ /**
3612
+ * Applies a list of actions to a document and waits for completion
3613
+ */
3614
+ execute<TDocument extends PHDocument>(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal): Promise<TDocument>;
3615
+ /**
3616
+ * Submits a list of actions to a document
3617
+ */
3618
+ executeAsync(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal): Promise<JobInfo>;
3619
+ executeBatch(request: BatchExecutionRequest, signal?: AbortSignal): Promise<BatchExecutionResult>;
3620
+ /**
3621
+ * Renames a document and waits for completion
3622
+ */
3623
+ rename(documentIdentifier: string, name: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
3624
+ /**
3625
+ * Updates the preferred editor recorded in the document header meta.
3626
+ * Pass `null` to clear it.
3627
+ */
3628
+ setPreferredEditor(documentIdentifier: string, preferredEditor: string | null, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
3629
+ /**
3630
+ * Adds multiple documents as children to another and waits for completion
3631
+ */
3632
+ addRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
3633
+ /**
3634
+ * Removes a relationship between two documents and waits for completion.
3635
+ */
3636
+ removeRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
3637
+ /**
3638
+ * Moves a relationship from one source document to another and waits for completion.
3639
+ */
3640
+ moveRelationship(sourceParentIdentifier: string, targetParentIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<{
3641
+ source: PHDocument;
3642
+ target: PHDocument;
3643
+ }>;
3644
+ loadBatch(request: BatchLoadRequest, signal?: AbortSignal): Promise<BatchLoadResult>;
3645
+ /**
3646
+ * Deletes a document and waits for completion
3647
+ */
3648
+ deleteDocument(identifier: string, propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
3649
+ /**
3650
+ * Deletes documents and waits for completion
3651
+ */
3652
+ deleteDocuments(identifiers: string[], propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
3653
+ /**
3654
+ * Retrieves the status of a job
3655
+ */
3656
+ getJobStatus(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
3657
+ /**
3658
+ * Waits for a job to complete
3659
+ */
3660
+ waitForJob(jobId: string | JobInfo, signal?: AbortSignal): Promise<JobInfo>;
3661
+ /**
3662
+ * Subscribes to changes for documents matching specified filters
3663
+ */
3664
+ subscribe(search: SearchFilter, callback: (event: DocumentChangeEvent) => void, view?: ViewFilter): () => void;
3665
+ private removeAllIncomingRelationships;
3666
+ }
3667
+ //#endregion
3668
+ //#region src/executor/interfaces.d.ts
3669
+ /**
3670
+ * Snapshot of the single in-flight slot maintained by an {@link IExecutorWorker}.
3671
+ */
3672
+ type WorkerInFlightSnapshot = {
3673
+ correlationId: string;
3674
+ jobId: string;
3675
+ };
3676
+ /**
3677
+ * Outcome of a worker-side job execution.
3678
+ *
3679
+ * `result` mirrors the in-process `JobResult` exactly. `writeReady` carries
3680
+ * the operations + jobMeta the parent needs to emit `JOB_WRITE_READY`, and is
3681
+ * present only when the worker produced operations. It is absent on failure
3682
+ * and on success-with-no-operations.
3683
+ */
3684
+ type WorkerExecutionOutcome = {
3685
+ result: JobResult;
3686
+ writeReady?: JobWriteReadyPayload;
3687
+ };
3688
+ /**
3689
+ * Parent-side handle for a single executor worker.
3690
+ *
3691
+ * Implementations wrap an IPC transport (worker_threads, child_process, or a
3692
+ * test fake) and expose a transport-agnostic surface that the worker-pool
3693
+ * manager uses to dispatch jobs. The handle owns one worker's lifecycle
3694
+ * (`start` -> `execute`* -> `shutdown`) and bounds its in-flight map to a
3695
+ * single entry; `SimpleJobExecutor` is single-threaded inside the worker, so
3696
+ * concurrent dispatches would race its caches.
3697
+ */
3698
+ interface IExecutorWorker {
3699
+ /** Stable identifier of the worker (mirrors `InitMessage.workerId`). */
3700
+ readonly workerId: string;
3701
+ /** Zero-based index within the pool, used for sticky routing. */
3702
+ readonly index: number;
3703
+ /**
3704
+ * Spawn the worker (if not already started), send the `init` payload and
3705
+ * resolve when the worker replies with `ready`.
3706
+ */
3707
+ start(): Promise<void>;
3708
+ /**
3709
+ * Dispatch a job to the worker and resolve with its outcome — the
3710
+ * `JobResult` and, on success-with-operations, a `writeReady` payload
3711
+ * the parent will enrich and re-emit. Rejects with a transport-level
3712
+ * error if the worker exits, aborts, or times out before producing a
3713
+ * result.
3714
+ */
3715
+ execute(job: Job, signal?: AbortSignal): Promise<WorkerExecutionOutcome>;
3716
+ /**
3717
+ * Request cancellation of the in-flight job (if any). The handle posts an
3718
+ * `abort` message; if the worker fails to reply within its grace window it
3719
+ * is force-terminated.
3720
+ */
3721
+ abort(correlationId: string, reason?: string): void;
3722
+ /**
3723
+ * Stop the worker. When `graceful` is true the handle waits for the
3724
+ * in-flight job to settle (up to `graceMs`) before terminating; otherwise
3725
+ * the worker is terminated immediately.
3726
+ */
3727
+ shutdown(graceful: boolean, graceMs?: number): Promise<void>;
3728
+ /**
3729
+ * Register an additional document model on the running worker. Resolves
3730
+ * when the worker replies with `model-loaded`; rejects when it replies
3731
+ * with `model-load-failed` or the worker exits before answering.
3732
+ */
3733
+ loadModel(entry: ModelManifestEntry, signal?: AbortSignal): Promise<void>;
3734
+ /** True when no job is currently in flight. */
3735
+ isIdle(): boolean;
3736
+ /** Snapshot of the in-flight slot, or null when idle. */
3737
+ getInFlight(): WorkerInFlightSnapshot | null;
3738
+ }
3739
+ /**
3740
+ * Simple interface for executing a job.
3741
+ * A JobExecutor simply takes a job and executes it - nothing more.
3742
+ */
3743
+ interface IJobExecutor {
3744
+ /**
3745
+ * Execute a single job.
3746
+ * @param job - The job to execute
3747
+ * @returns Promise that resolves to the job result
3748
+ */
3749
+ executeJob(job: Job, signal?: AbortSignal): Promise<JobResult>;
3750
+ }
3751
+ /**
3752
+ * Interface for managing multiple job executors.
3753
+ * Listens for 'jobAvailable' events from the event bus, pulls jobs from the queue,
3754
+ * and coordinates the distribution of jobs across multiple executor instances.
3755
+ */
3756
+ interface IJobExecutorManager {
3757
+ /**
3758
+ * Start the executor manager.
3759
+ * Begins listening for 'jobAvailable' events and dispatching to executors.
3760
+ *
3761
+ * @param numExecutors - Number of executor instances to create
3762
+ * @returns Promise that resolves when the manager is started
3763
+ */
3764
+ start(numExecutors: number): Promise<void>;
3765
+ /**
3766
+ * Stop the executor manager.
3767
+ *
3768
+ * @param graceful - Whether to wait for current jobs to complete
3769
+ * @returns Promise that resolves when the manager is stopped
3770
+ */
3771
+ stop(graceful?: boolean): Promise<void>;
3772
+ /**
3773
+ * Get all managed executor instances.
3774
+ *
3775
+ * @returns Array of executor instances
3776
+ */
3777
+ getExecutors(): IJobExecutor[];
3778
+ /**
3779
+ * Get the current status of the manager.
3780
+ *
3781
+ * @returns The current manager status
3782
+ */
3783
+ getStatus(): ExecutorManagerStatus;
3784
+ }
3785
+ //#endregion
3786
+ //#region src/job-tracker/interfaces.d.ts
3787
+ /**
3788
+ * Interface for tracking job lifecycle status.
3789
+ * Maintains job state throughout execution: PENDING → RUNNING → COMPLETED/FAILED.
3790
+ */
3791
+ interface IJobTracker {
3792
+ /**
3793
+ * Register a new job with PENDING status.
3794
+ *
3795
+ * @param jobInfo - The job information to register
3796
+ */
3797
+ registerJob(jobInfo: JobInfo): void;
3798
+ /**
3799
+ * Update a job's status to RUNNING.
3800
+ *
3801
+ * @param jobId - The job ID to mark as running
3802
+ */
3803
+ markRunning(jobId: string): void;
3804
+ /**
3805
+ * Mark a job as failed.
3806
+ *
3807
+ * @param jobId - The job ID to mark as failed
3808
+ * @param error - Error information including message and stack trace
3809
+ * @param job - Optional full job object for debugging purposes
3810
+ */
3811
+ markFailed(jobId: string, error: ErrorInfo$1, job?: Job): void;
3812
+ /**
3813
+ * Retrieve the current status of a job.
3814
+ *
3815
+ * @param jobId - The job ID to query
3816
+ * @returns The job information, or null if the job is not found
3817
+ */
3818
+ getJobStatus(jobId: string): JobInfo | null;
3819
+ /**
3820
+ * Shutdown the job tracker and clean up resources.
3821
+ * Unsubscribes from all event bus subscriptions.
3822
+ */
3823
+ shutdown(): void;
3824
+ }
3825
+ //#endregion
3826
+ //#region src/queue/interfaces.d.ts
3827
+ /**
3828
+ * Interface for a job queue that manages write operations.
3829
+ * Internally organizes jobs by documentId, scope, and branch to ensure proper ordering.
3830
+ * Emits events to the event bus when new jobs are available for consumption.
3831
+ */
3832
+ interface IQueue {
3833
+ /**
3834
+ * Add a new job to the queue.
3835
+ * Jobs are automatically organized by documentId, scope, and branch internally.
3836
+ * Emits a 'jobAvailable' event to the event bus when the job is queued.
3837
+ * @param job - The job to add to the queue
3838
+ * @returns Promise that resolves when the job is queued
3839
+ */
3840
+ enqueue(job: Job): Promise<void>;
3841
+ /**
3842
+ * Get the next job to execute for a specific document/scope/branch combination.
3843
+ * @param documentId - The document ID to get jobs for
3844
+ * @param scope - The scope to get jobs for
3845
+ * @param branch - The branch to get jobs for
3846
+ * @param signal - Optional abort signal to cancel the request
3847
+ * @returns Promise that resolves to the next job execution handle or null if no jobs available
3848
+ */
3849
+ dequeue(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
3850
+ /**
3851
+ * Get the next available job from any queue.
3852
+ * @param signal - Optional abort signal to cancel the request
3853
+ * @returns Promise that resolves to the next job execution handle or null if no jobs available
3854
+ */
3855
+ dequeueNext(signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
3856
+ /**
3857
+ * Get the next available job whose routing metadata satisfies the predicate.
3858
+ * Walks ready sub-queue heads in queue insertion order, skips heads whose document
3859
+ * is currently executing (same isDocumentExecuting gate as dequeueNext), and returns
3860
+ * the first head for which predicate returns true.
3861
+ * Returns null when paused, when nothing matches, or when the queue is empty.
3862
+ * Rejects if signal is already aborted.
3863
+ * @param predicate - Filter applied to JobRoutingMeta of each candidate head
3864
+ * @param signal - Optional abort signal to cancel the request
3865
+ * @returns Promise that resolves to the first matching job execution handle or null
3866
+ */
3867
+ dequeueNextMatching(predicate: (meta: JobRoutingMeta) => boolean, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
3868
+ /**
3869
+ * Get the current size of the queue for a specific document/scope/branch.
3870
+ * @param documentId - The document ID
2631
3871
  * @param scope - The scope
2632
3872
  * @param branch - The branch
2633
3873
  * @returns Promise that resolves to the number of jobs in the queue
@@ -2679,9 +3919,11 @@ interface IQueue {
2679
3919
  * Retry a failed job.
2680
3920
  * @param jobId - The ID of the job to retry
2681
3921
  * @param error - Optional error information from the failure
3922
+ * @param accounting - Whether the attempt counts against the job's retry
3923
+ * limit; defaults to {@link RetryAccounting.CountAgainstLimit}
2682
3924
  * @returns Promise that resolves when the job is requeued for retry
2683
3925
  */
2684
- retryJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
3926
+ retryJob(jobId: string, error?: ErrorInfo$1, accounting?: RetryAccounting): Promise<void>;
2685
3927
  /**
2686
3928
  * Returns true if and only if all jobs have been resolved.
2687
3929
  */
@@ -2690,213 +3932,88 @@ interface IQueue {
2690
3932
  * Blocks the queue from accepting new jobs.
2691
3933
  * @param onDrained - Optional callback to call when the queue is drained
2692
3934
  */
2693
- block(onDrained?: () => void): void;
2694
- /**
2695
- * Unblocks the queue from accepting new jobs.
2696
- */
2697
- unblock(): void;
2698
- }
2699
- //#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>;
2731
- }
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>;
2743
- }
2744
- interface DocumentViewDatabase {
2745
- ViewState: ViewStateTable;
2746
- DocumentSnapshot: DocumentSnapshotTable;
2747
- SlugMapping: SlugMappingTable;
2748
- ProcessorCursor: ProcessorCursorTable;
2749
- }
2750
- type InsertableDocumentSnapshot = Insertable<DocumentSnapshotTable>;
2751
- //#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
- };
2764
- /**
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.
2768
- */
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;
2779
- };
2780
- /**
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.
2784
- *
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.
2798
- */
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>;
2826
- /**
2827
- * Get all registered document model modules.
2828
- *
2829
- * @returns Array of all registered modules
2830
- */
2831
- getAllModules(): DocumentModelModule<any>[];
2832
- /**
2833
- * Clear all registered modules and upgrade manifests.
2834
- */
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
2842
- */
2843
- getSupportedVersions(documentType: string): number[];
2844
- /**
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
2850
- */
2851
- getLatestVersion(documentType: string): number;
2852
- /**
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
2858
- */
2859
- registerUpgradeManifests(...manifests: UpgradeManifest<readonly number[]>[]): RegistrationResult<UpgradeManifest<readonly number[]>>[];
2860
- /**
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;
2866
- /**
2867
- * Get the upgrade manifest for a document type.
2868
- *
2869
- * @param documentType The document type identifier
2870
- * @returns The upgrade manifest
2871
- * @throws ManifestNotFoundError if no manifest is registered for the document type
2872
- */
2873
- getUpgradeManifest(documentType: string): UpgradeManifest<readonly number[]>;
2874
- /**
2875
- * Compute the upgrade path from one version to another.
2876
- * Returns the sequence of upgrade transitions needed.
2877
- *
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
2885
- */
2886
- computeUpgradePath(documentType: string, fromVersion: number, toVersion: number): UpgradeTransition[];
3935
+ block(onDrained?: () => void): void;
2887
3936
  /**
2888
- * Get the upgrade reducer for a single-step version transition.
2889
- *
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
3937
+ * Unblocks the queue from accepting new jobs.
2897
3938
  */
2898
- getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
3939
+ unblock(): void;
3940
+ }
3941
+ //#endregion
3942
+ //#region src/core/group-reevaluation-trigger.d.ts
3943
+ /**
3944
+ * Watches committed writes for group membership changes and enqueues a
3945
+ * re-evaluation job for every document whose auth history references the
3946
+ * changed group, found through the reverse direction of the group-reference
3947
+ * relation. Each affected document is re-judged in its own job, so the work
3948
+ * runs under that document's execution slot rather than the group's.
3949
+ *
3950
+ * The job carries the earliest changed membership timestamp; the executor
3951
+ * skips the pass when everything the document holds sorts before it, which
3952
+ * keeps the common case (a membership write later than all history) free.
3953
+ */
3954
+ declare class GroupReevaluationTrigger {
3955
+ private logger;
3956
+ private eventBus;
3957
+ private queue;
3958
+ private operationIndex;
3959
+ private unsubscribe?;
3960
+ constructor(logger: ILogger, eventBus: IEventBus, queue: IQueue, operationIndex: IOperationIndex);
3961
+ startup(): void;
3962
+ shutdown(): void;
3963
+ private onWriteReady;
3964
+ }
3965
+ //#endregion
3966
+ //#region src/read-models/types.d.ts
3967
+ interface ViewStateTable {
3968
+ readModelId: string;
3969
+ lastOrdinal: number;
3970
+ lastOperationTimestamp: Generated<Date>;
3971
+ }
3972
+ interface DocumentSnapshotTable {
3973
+ id: Generated<string>;
3974
+ documentId: string;
3975
+ slug: string | null;
3976
+ name: string | null;
3977
+ scope: string;
3978
+ branch: string;
3979
+ content: unknown;
3980
+ documentType: string;
3981
+ lastOperationIndex: number;
3982
+ lastOperationHash: string;
3983
+ lastUpdatedAt: Generated<Date>;
3984
+ snapshotVersion: Generated<number>;
3985
+ identifiers: unknown;
3986
+ metadata: unknown;
3987
+ isDeleted: Generated<boolean>;
3988
+ deletedAt: Date | null;
3989
+ }
3990
+ interface SlugMappingTable {
3991
+ slug: string;
3992
+ documentId: string;
3993
+ scope: string;
3994
+ branch: string;
3995
+ createdAt: Generated<Date>;
3996
+ updatedAt: Generated<Date>;
3997
+ }
3998
+ interface ProcessorCursorTable {
3999
+ processorId: string;
4000
+ factoryId: string;
4001
+ driveId: string;
4002
+ processorIndex: number;
4003
+ lastOrdinal: Generated<number>;
4004
+ status: Generated<string>;
4005
+ lastError: string | null;
4006
+ lastErrorTimestamp: Date | null;
4007
+ createdAt: Generated<Date>;
4008
+ updatedAt: Generated<Date>;
4009
+ }
4010
+ interface DocumentViewDatabase {
4011
+ ViewState: ViewStateTable;
4012
+ DocumentSnapshot: DocumentSnapshotTable;
4013
+ SlugMapping: SlugMappingTable;
4014
+ ProcessorCursor: ProcessorCursorTable;
2899
4015
  }
4016
+ type InsertableDocumentSnapshot = Insertable<DocumentSnapshotTable>;
2900
4017
  //#endregion
2901
4018
  //#region src/shared/consistency-tracker.d.ts
2902
4019
  interface IConsistencyTracker {
@@ -2946,134 +4063,6 @@ declare class ConsistencyTracker implements IConsistencyTracker {
2946
4063
  private removeWaiter;
2947
4064
  }
2948
4065
  //#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
4066
  //#region src/storage/pool-instrumentation.d.ts
3078
4067
  /**
3079
4068
  * Snapshot of a pg.Pool's internal counters at a point in time.
@@ -3137,7 +4126,13 @@ declare class PollingChannelError extends Error {
3137
4126
  declare class ChannelError extends Error {
3138
4127
  source: ChannelErrorSource;
3139
4128
  error: Error;
3140
- constructor(source: ChannelErrorSource, error: Error);
4129
+ /**
4130
+ * The classification when something other than the error carries it. Absent
4131
+ * means derive it from `error.name`; a dead letter mirrored from a peer sets it,
4132
+ * because only the message crosses the wire.
4133
+ */
4134
+ readonly errorType?: SyncOperationErrorType;
4135
+ constructor(source: ChannelErrorSource, error: Error, errorType?: SyncOperationErrorType);
3141
4136
  }
3142
4137
  //#endregion
3143
4138
  //#region src/sync/sync-operation.d.ts
@@ -3736,6 +4731,12 @@ interface ReactorModule {
3736
4731
  * integration scenarios.
3737
4732
  */
3738
4733
  interface InProcessReactorModule extends ReactorModule {
4734
+ /**
4735
+ * The enforcement flags this reactor resolved, as plain booleans. Held on the
4736
+ * module because they select what a read enforces as well as what a write
4737
+ * does, and the read surface is composed outside the reactor.
4738
+ */
4739
+ featureFlags: ReactorFeatureFlags;
3739
4740
  queue: IQueue;
3740
4741
  jobTracker: IJobTracker;
3741
4742
  executorManager: IJobExecutorManager;
@@ -3754,6 +4755,12 @@ interface InProcessReactorModule extends ReactorModule {
3754
4755
  processorManagerConsistencyTracker: IConsistencyTracker;
3755
4756
  reactor: IReactor;
3756
4757
  syncModule: InProcessSyncModule | undefined;
4758
+ /**
4759
+ * Present when authGroups is on: enqueues re-evaluation jobs for the
4760
+ * documents a group membership change affects. Started by the builder;
4761
+ * hosts shut it down alongside the sync manager.
4762
+ */
4763
+ groupReevaluationTrigger: GroupReevaluationTrigger | undefined;
3757
4764
  /**
3758
4765
  * Instrumented pg.Pool handles registered with the builder, either by
3759
4766
  * createPostgresDatabase or by withInstrumentedPool. Empty when no pg
@@ -3815,12 +4822,6 @@ declare class DriveClient implements IDriveClient {
3815
4822
  private removeFileNode;
3816
4823
  }
3817
4824
  //#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
4825
  //#region src/registry/document-model-resolver.d.ts
3825
4826
  interface IDocumentModelResolver {
3826
4827
  ensureModelLoaded(documentType: string): Promise<void>;
@@ -3857,60 +4858,28 @@ declare class DocumentModelResolver implements IDocumentModelResolver {
3857
4858
  * peers (tabs) can load the same type via the event bus.
3858
4859
  */
3859
4860
  setModelLoadedHook(hook: (documentType: string) => Promise<void>): void;
3860
- ensureModelLoaded(documentType: string): Promise<void>;
3861
- private loadRegisterAndBroadcast;
3862
- private notifyPeersModelLoaded;
3863
- }
3864
- /**
3865
- * No-op resolver used when no document model loader is configured.
3866
- * Checks the registry for the model and returns if found; throws if not.
3867
- * Since there is no loader, missing models cannot be recovered.
3868
- */
3869
- declare class NullDocumentModelResolver implements IDocumentModelResolver {
3870
- private registry?;
3871
- constructor(registry?: IDocumentModelRegistry | undefined);
3872
- ensureModelLoaded(documentType: string): Promise<void>;
3873
- }
3874
- //#endregion
3875
- //#region src/executor/worker-pool-job-executor-manager.d.ts
3876
- /**
3877
- * Factory invoked once per worker at `start()` time. The index is the
3878
- * worker's position in the pool and the same value the manager will use
3879
- * for sticky routing (`bucketFor(documentId) === index`).
3880
- */
3881
- type WorkerFactory = (index: number) => IExecutorWorker;
3882
- //#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
- };
4861
+ ensureModelLoaded(documentType: string): Promise<void>;
4862
+ private loadRegisterAndBroadcast;
4863
+ private notifyPeersModelLoaded;
4864
+ }
3900
4865
  /**
3901
- * A cached document snapshot at a specific revision
4866
+ * No-op resolver used when no document model loader is configured.
4867
+ * Checks the registry for the model and returns if found; throws if not.
4868
+ * Since there is no loader, missing models cannot be recovered.
3902
4869
  */
3903
- type CachedSnapshot = {
3904
- /** The revision number of this snapshot */revision: number; /** The document state at this revision */
3905
- document: PHDocument;
3906
- };
4870
+ declare class NullDocumentModelResolver implements IDocumentModelResolver {
4871
+ private registry?;
4872
+ constructor(registry?: IDocumentModelRegistry | undefined);
4873
+ ensureModelLoaded(documentType: string): Promise<void>;
4874
+ }
4875
+ //#endregion
4876
+ //#region src/executor/worker-pool-job-executor-manager.d.ts
3907
4877
  /**
3908
- * Serialized keyframe snapshot for K/V store persistence
4878
+ * Factory invoked once per worker at `start()` time. The index is the
4879
+ * worker's position in the pool and the same value the manager will use
4880
+ * for sticky routing (`bucketFor(documentId) === index`).
3909
4881
  */
3910
- type KeyframeSnapshot = {
3911
- /** The revision number of this keyframe */revision: number; /** Serialized document state */
3912
- document: string;
3913
- };
4882
+ type WorkerFactory = (index: number) => IExecutorWorker;
3914
4883
  //#endregion
3915
4884
  //#region src/projection/protocol.d.ts
3916
4885
  /**
@@ -4162,6 +5131,7 @@ declare class SyncBuilder {
4162
5131
  * them (`BaseReadModel` subclasses, in particular).
4163
5132
  */
4164
5133
  interface ReadModelFactoryDeps {
5134
+ documentModelRegistry: IDocumentModelRegistry;
4165
5135
  operationIndex: IOperationIndex;
4166
5136
  writeCache: IWriteCache;
4167
5137
  processorManagerConsistencyTracker: IConsistencyTracker;
@@ -4383,6 +5353,7 @@ declare class ReactorClientBuilder {
4383
5353
  private subscriptionManager?;
4384
5354
  private jobAwaiter?;
4385
5355
  private documentModelLoader?;
5356
+ private readGate?;
4386
5357
  /**
4387
5358
  * Sets the logger for the ReactorClient.
4388
5359
  * @param logger - The logger to use.
@@ -4406,6 +5377,22 @@ declare class ReactorClientBuilder {
4406
5377
  withSubscriptionManager(subscriptionManager: IReactorSubscriptionManager): this;
4407
5378
  withJobAwaiter(jobAwaiter: IJobAwaiter): this;
4408
5379
  withDocumentModelLoader(loader: IDocumentModelLoader): this;
5380
+ /**
5381
+ * Overrides how reads are gated. A client built from a ReactorBuilder derives
5382
+ * this from that reactor's flags; one built from `withReactor` cannot, because
5383
+ * it is handed no flags and no registry, so it gates on the policy alone
5384
+ * unless a gate is supplied here.
5385
+ */
5386
+ withReadGate(readGate: IReadGate): this;
5387
+ /**
5388
+ * The gate this reactor's flags call for. Below authEnforcement there is no
5389
+ * model to enforce -- the registered one ignores the auth scope -- so the
5390
+ * policy is evaluated on its own, which is what reads did before the model
5391
+ * existed. Group serving turns on with authGroups, because below it a
5392
+ * `{ group }` grant does not match, so a served roster is one no grant can
5393
+ * use.
5394
+ */
5395
+ private resolveReadGate;
4409
5396
  build(): Promise<ReactorClient>;
4410
5397
  buildModule(): Promise<InProcessReactorClientModule>;
4411
5398
  }
@@ -4500,568 +5487,229 @@ type ParsedPaging = {
4500
5487
  */
4501
5488
  declare function parsePagingOptions(paging: PagingOptions | undefined, defaultLimit: number): ParsedPaging;
4502
5489
  //#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;
4537
- /**
4538
- * Notify subscribers about updated documents
4539
- */
4540
- notifyDocumentsUpdated(documents: PHDocument[]): void;
4541
- /**
4542
- * Notify subscribers about relationship changes
4543
- */
4544
- notifyRelationshipChanged(parentId: string, childId: string, changeType: RelationshipChangeType, childType?: string): void;
4545
- /**
4546
- * Clear all subscriptions
4547
- */
4548
- clearAll(): void;
4549
- private filterDocumentIds;
4550
- private filterDocuments;
4551
- private matchesRelationshipFilter;
4552
- }
4553
- //#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>;
4559
- }
4560
- //#endregion
4561
- //#region src/queue/queue.d.ts
4562
- /**
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.
4567
- */
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;
4582
- /**
4583
- * Creates a unique key for a document/scope/branch combination
4584
- */
4585
- private createQueueKey;
4586
- /**
4587
- * Gets or creates a queue for the given key
4588
- */
4589
- private getQueue;
4590
- /**
4591
- * Check if a document has any jobs currently executing
4592
- */
4593
- private isDocumentExecuting;
4594
- /**
4595
- * Mark a job as executing for its document
4596
- */
4597
- private markJobExecuting;
4598
- /**
4599
- * Mark a job as no longer executing for its document
4600
- */
4601
- private markJobComplete;
4602
- /**
4603
- * Check if all dependencies for a job have been completed
4604
- */
4605
- private areDependenciesMet;
4606
- /**
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>;
4631
- /**
4632
- * Check if the queue is drained and call the callback if it is
4633
- */
4634
- private checkDrained;
4635
- /**
4636
- * Returns true if and only if all jobs have been resolved.
4637
- */
4638
- get isDrained(): boolean;
4639
- /**
4640
- * Blocks the queue from accepting new jobs.
4641
- * @param onDrained - Optional callback to call when the queue is drained
4642
- */
4643
- block(onDrained?: () => void): void;
4644
- /**
4645
- * Unblocks the queue from accepting new jobs.
4646
- */
4647
- unblock(): void;
4648
- /**
4649
- * Pauses job dequeuing. Jobs can still be enqueued but dequeueNext() will return null.
4650
- */
4651
- pause(): void;
4652
- /**
4653
- * Resumes job dequeuing and emits JOB_AVAILABLE events for pending jobs to wake up executors.
4654
- */
4655
- resume(): Promise<void>;
4656
- /**
4657
- * Returns whether job dequeuing is paused.
4658
- */
4659
- get paused(): boolean;
4660
- /**
4661
- * Returns all pending jobs across all queues.
4662
- */
4663
- getPendingJobs(): Job[];
4664
- /**
4665
- * Returns a map of document IDs to sets of executing job IDs.
4666
- */
4667
- getExecutingJobIds(): Map<string, Set<string>>;
4668
- /**
4669
- * Returns a job by ID from the job index.
4670
- */
4671
- getJob(jobId: string): Job | undefined;
4672
- }
4673
- //#endregion
4674
- //#region src/job-tracker/in-memory-job-tracker.d.ts
4675
- /**
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.
4679
- */
4680
- declare class InMemoryJobTracker implements IJobTracker {
4681
- 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;
4694
- }
4695
- //#endregion
4696
- //#region src/executor/simple-job-executor-manager.d.ts
4697
- type JobExecutorFactory = () => IJobExecutor;
4698
- /**
4699
- * Manages multiple job executors and coordinates job distribution.
4700
- * Listens for job available events and dispatches jobs to executors.
4701
- */
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
- }
4727
- //#endregion
4728
- //#region src/cache/document-meta-cache-types.d.ts
5490
+ //#region src/subs/default-error-handler.d.ts
4729
5491
  /**
4730
- * Cached document metadata from the "document" scope.
4731
- *
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.
5492
+ * Default error handler that re-throws subscription errors.
5493
+ * This ensures that errors are not silently swallowed.
4735
5494
  */
4736
- type CachedDocumentMeta = {
5495
+ declare class DefaultSubscriptionErrorHandler implements ISubscriptionErrorHandler {
5496
+ handleError(error: unknown, context: SubscriptionErrorContext): void;
5497
+ }
5498
+ //#endregion
5499
+ //#region src/subs/react-subscription-manager.d.ts
5500
+ type DocumentCreatedCallback = (result: PagedResults<string>) => void;
5501
+ type DocumentDeletedCallback = (documentIds: string[]) => void;
5502
+ type DocumentStateUpdatedCallback = (result: PagedResults<PHDocument>) => void;
5503
+ type RelationshipChangedCallback = (parentId: string, childId: string, changeType: RelationshipChangeType) => void;
5504
+ declare class ReactorSubscriptionManager implements IReactorSubscriptionManager {
5505
+ private createdSubscriptions;
5506
+ private deletedSubscriptions;
5507
+ private updatedSubscriptions;
5508
+ private relationshipSubscriptions;
5509
+ private subscriptionCounter;
5510
+ private errorHandler;
5511
+ constructor(errorHandler: ISubscriptionErrorHandler);
5512
+ onDocumentCreated(callback: DocumentCreatedCallback, search?: SearchFilter): () => void;
5513
+ onDocumentDeleted(callback: DocumentDeletedCallback, search?: SearchFilter): () => void;
5514
+ onDocumentStateUpdated(callback: DocumentStateUpdatedCallback, search?: SearchFilter, view?: ViewFilter): () => void;
5515
+ onRelationshipChanged(callback: RelationshipChangedCallback, search?: SearchFilter): () => void;
4737
5516
  /**
4738
- * The full PHDocumentState from document.state.document.
4739
- * Contains version, hash, isDeleted, deletedAtUtcIso, etc.
5517
+ * Notify subscribers about created documents
4740
5518
  */
4741
- state: PHDocumentState;
5519
+ notifyDocumentsCreated(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
4742
5520
  /**
4743
- * The document type (from header), cached for convenience.
5521
+ * Notify subscribers about deleted documents
4744
5522
  */
4745
- documentType: string;
5523
+ notifyDocumentsDeleted(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
4746
5524
  /**
4747
- * The revision of the document scope when this metadata was captured.
4748
- * Used for cache invalidation and consistency checks.
5525
+ * Notify subscribers about updated documents
4749
5526
  */
4750
- documentScopeRevision: number;
4751
- };
4752
- /**
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
4764
- */
4765
- interface IDocumentMetaCache {
5527
+ notifyDocumentsUpdated(documents: PHDocument[]): void;
4766
5528
  /**
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)
5529
+ * Notify subscribers about relationship changes
4779
5530
  */
4780
- getDocumentMeta(documentId: string, branch: string, signal?: AbortSignal): Promise<CachedDocumentMeta>;
5531
+ notifyRelationshipChanged(parentId: string, childId: string, changeType: RelationshipChangeType, childType?: string): void;
4781
5532
  /**
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
5533
+ * Clear all subscriptions
4794
5534
  */
4795
- rebuildAtRevision(documentId: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<CachedDocumentMeta>;
5535
+ clearAll(): void;
5536
+ private filterDocumentIds;
5537
+ private filterDocuments;
5538
+ private matchesRelationshipFilter;
5539
+ }
5540
+ //#endregion
5541
+ //#region src/events/event-bus.d.ts
5542
+ declare class EventBus implements IEventBus {
5543
+ readonly eventTypeToSubscribers: Map<number, Subscriber[]>;
5544
+ subscribe<K>(type: number, subscriber: (type: number, event: K) => void | Promise<void>): Unsubscribe;
5545
+ emit(type: number, data: any): Promise<void>;
5546
+ }
5547
+ //#endregion
5548
+ //#region src/queue/queue.d.ts
5549
+ /**
5550
+ * In-memory implementation of the IQueue interface.
5551
+ * Organizes jobs by documentId, scope, and branch to ensure proper ordering.
5552
+ * Ensures serial execution per document by tracking executing jobs.
5553
+ * Implements dependency management through queue hints.
5554
+ */
5555
+ declare class InMemoryQueue implements IQueue {
5556
+ private eventBus;
5557
+ private resolver;
5558
+ private queues;
5559
+ private jobIdToQueueKey;
5560
+ private docIdToJobId;
5561
+ private jobIdToDocId;
5562
+ private completedJobs;
5563
+ private jobIndex;
5564
+ private isBlocked;
5565
+ private onDrainedCallback?;
5566
+ private isPausedFlag;
5567
+ constructor(eventBus: IEventBus, resolver: IDocumentModelResolver);
5568
+ private toErrorInfo;
4796
5569
  /**
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
5570
+ * Creates a unique key for a document/scope/branch combination
4805
5571
  */
4806
- putDocumentMeta(documentId: string, branch: string, meta: CachedDocumentMeta): void;
5572
+ private createQueueKey;
4807
5573
  /**
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
5574
+ * Gets or creates a queue for the given key
4816
5575
  */
4817
- invalidate(documentId: string, branch?: string): number;
5576
+ private getQueue;
4818
5577
  /**
4819
- * Clears all cached document metadata.
5578
+ * Check if a document has any jobs currently executing
4820
5579
  */
4821
- clear(): void;
5580
+ private isDocumentExecuting;
4822
5581
  /**
4823
- * Performs startup initialization.
5582
+ * Mark a job as executing for its document
4824
5583
  */
4825
- startup(): Promise<void>;
5584
+ private markJobExecuting;
4826
5585
  /**
4827
- * Performs graceful shutdown.
5586
+ * Mark a job as no longer executing for its document
4828
5587
  */
4829
- shutdown(): Promise<void>;
4830
- }
4831
- //#endregion
4832
- //#region src/cache/buffer/ring-buffer.d.ts
4833
- /**
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
4841
- */
4842
- declare class RingBuffer<T> {
4843
- private buffer;
4844
- private head;
4845
- private size;
4846
- private capacity;
4847
- constructor(capacity: number);
5588
+ private markJobComplete;
4848
5589
  /**
4849
- * Adds an item to the buffer. If the buffer is full, overwrites the oldest item.
4850
- *
4851
- * @param item - The item to add
5590
+ * Check if all dependencies for a job have been completed
4852
5591
  */
4853
- push(item: T): void;
5592
+ private areDependenciesMet;
4854
5593
  /**
4855
- * Returns all items in the buffer in chronological order (oldest to newest).
5594
+ * Returns the head of the sub-queue if its dependencies are met, or null.
4856
5595
  *
4857
- * @returns Array of items in insertion order
4858
- */
4859
- getAll(): T[];
4860
- /**
4861
- * Clears all items from the buffer.
4862
- */
4863
- clear(): void;
4864
- /**
4865
- * Gets the current number of items in the buffer.
5596
+ * The dispatcher only ever considers the head — a dep-blocked head holds
5597
+ * the rest of its sub-queue. This preserves per-(documentId, scope, branch)
5598
+ * FIFO regardless of how dependencies are authored, and makes the queue's
5599
+ * documented "serialized per document" invariant hold even when callers
5600
+ * omit queueHint dependencies on jobs that share a sub-queue.
4866
5601
  */
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;
5602
+ private getNextJobWithMetDependencies;
5603
+ private getCreateDocumentType;
5604
+ enqueue(job: Job): Promise<void>;
5605
+ dequeue(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
5606
+ dequeueNext(signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
5607
+ dequeueNextMatching(predicate: (meta: JobRoutingMeta) => boolean, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
5608
+ size(documentId: string, scope: string, branch: string): Promise<number>;
5609
+ totalSize(): Promise<number>;
5610
+ remove(jobId: string): Promise<boolean>;
5611
+ clear(documentId: string, scope: string, branch: string): Promise<void>;
5612
+ clearAll(): Promise<void>;
5613
+ hasJobs(): Promise<boolean>;
5614
+ completeJob(jobId: string): Promise<void>;
5615
+ failJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
5616
+ deferJob(jobId: string): void;
5617
+ retryJob(jobId: string, error?: ErrorInfo$1, accounting?: RetryAccounting): Promise<void>;
4920
5618
  /**
4921
- * Initializes the write cache.
4922
- * Currently a no-op as keyframe store lifecycle is managed externally.
5619
+ * Check if the queue is drained and call the callback if it is
4923
5620
  */
4924
- startup(): Promise<void>;
5621
+ private checkDrained;
4925
5622
  /**
4926
- * Shuts down the write cache.
4927
- * Currently a no-op as keyframe store lifecycle is managed externally.
5623
+ * Returns true if and only if all jobs have been resolved.
4928
5624
  */
4929
- shutdown(): Promise<void>;
5625
+ get isDrained(): boolean;
4930
5626
  /**
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
4936
- *
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
5627
+ * Blocks the queue from accepting new jobs.
5628
+ * @param onDrained - Optional callback to call when the queue is drained
4948
5629
  */
4949
- getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
5630
+ block(onDrained?: () => void): void;
4950
5631
  /**
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
5632
+ * Unblocks the queue from accepting new jobs.
4969
5633
  */
4970
- putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument): void;
5634
+ unblock(): void;
4971
5635
  /**
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
5636
+ * Pauses job dequeuing. Jobs can still be enqueued but dequeueNext() will return null.
4983
5637
  */
4984
- invalidate(documentId: string, scope?: string, branch?: string): number;
5638
+ pause(): void;
4985
5639
  /**
4986
- * Clears the entire cache, removing all cached document streams.
4987
- * Resets LRU tracking state. This operation always succeeds.
5640
+ * Resumes job dequeuing and emits JOB_AVAILABLE events for pending jobs to wake up executors.
4988
5641
  */
4989
- clear(): void;
5642
+ resume(): Promise<void>;
4990
5643
  /**
4991
- * Retrieves a specific stream for a document. Exposed on the implementation
4992
- * for testing, but not on the interface.
4993
- *
4994
- * @internal
5644
+ * Returns whether job dequeuing is paused.
4995
5645
  */
4996
- getStream(documentId: string, scope: string, branch: string): DocumentStream | undefined;
4997
- private findNearestKeyframe;
4998
- private coldMissRebuild;
5646
+ get paused(): boolean;
4999
5647
  /**
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
5648
+ * Returns all pending jobs across all queues.
5006
5649
  */
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;
5650
+ getPendingJobs(): Job[];
5651
+ /**
5652
+ * Returns a map of document IDs to sets of executing job IDs.
5653
+ */
5654
+ getExecutingJobIds(): Map<string, Set<string>>;
5655
+ /**
5656
+ * Returns a job by ID from the job index.
5657
+ */
5658
+ getJob(jobId: string): Job | undefined;
5032
5659
  }
5033
5660
  //#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>;
5661
+ //#region src/job-tracker/in-memory-job-tracker.d.ts
5662
+ /**
5663
+ * In-memory implementation of IJobTracker.
5664
+ * Maintains job status in a Map for synchronous access.
5665
+ * Subscribes to operation events to update job states.
5666
+ */
5667
+ declare class InMemoryJobTracker implements IJobTracker {
5668
+ private eventBus;
5669
+ private jobs;
5670
+ private unsubscribers;
5671
+ constructor(eventBus: IEventBus);
5672
+ private subscribeToEvents;
5673
+ private handleWriteReady;
5674
+ private handleReadReady;
5675
+ private handleJobFailed;
5676
+ shutdown(): void;
5677
+ registerJob(jobInfo: JobInfo): void;
5678
+ markRunning(jobId: string): void;
5679
+ markFailed(jobId: string, error: ErrorInfo$1, job?: Job): void;
5680
+ getJobStatus(jobId: string): JobInfo | null;
5053
5681
  }
5054
5682
  //#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>;
5683
+ //#region src/executor/simple-job-executor-manager.d.ts
5684
+ type JobExecutorFactory = () => IJobExecutor;
5685
+ /**
5686
+ * Manages multiple job executors and coordinates job distribution.
5687
+ * Listens for job available events and dispatches jobs to executors.
5688
+ */
5689
+ declare class SimpleJobExecutorManager implements IJobExecutorManager {
5690
+ private executorFactory;
5691
+ private eventBus;
5692
+ private queue;
5693
+ private jobTracker;
5694
+ private logger;
5695
+ private resolver;
5696
+ private executors;
5697
+ private isRunning;
5698
+ private activeJobs;
5699
+ private totalJobsProcessed;
5700
+ private unsubscribe?;
5701
+ private deferredJobs;
5702
+ private resultHandler;
5703
+ private jobTimeoutMs;
5704
+ constructor(executorFactory: JobExecutorFactory, eventBus: IEventBus, queue: IQueue, jobTracker: IJobTracker, logger: ILogger, resolver: IDocumentModelResolver, jobTimeoutMs?: number);
5705
+ start(numExecutors: number): Promise<void>;
5706
+ stop(graceful?: boolean): Promise<void>;
5707
+ getExecutors(): IJobExecutor[];
5708
+ getStatus(): ExecutorManagerStatus;
5709
+ private processNextJob;
5710
+ private checkForMoreJobs;
5711
+ private processExistingJobs;
5712
+ private flushDeferredJobs;
5065
5713
  }
5066
5714
  //#endregion
5067
5715
  //#region src/executor/simple-job-executor.d.ts
@@ -5079,6 +5727,8 @@ declare class SimpleJobExecutor implements IJobExecutor {
5079
5727
  private collectionMembershipCache;
5080
5728
  private driveContainerTypes;
5081
5729
  private config;
5730
+ private featureFlags;
5731
+ private decisionModel;
5082
5732
  private signatureVerifierModule;
5083
5733
  private documentActionHandler;
5084
5734
  private executionScope;
@@ -5091,6 +5741,69 @@ declare class SimpleJobExecutor implements IJobExecutor {
5091
5741
  private getCollectionMembershipsForOperations;
5092
5742
  private processActions;
5093
5743
  private executeRegularAction;
5744
+ /**
5745
+ * Orders a write by timestamp and decides it where it lands. The caller
5746
+ * supplies the timestamp, so a write can belong before operations already
5747
+ * stored; those are re-appended alongside it, the way a load reshuffles.
5748
+ *
5749
+ * Deciding a backdated write at the stream heads instead of at its position
5750
+ * would overwrite the verdict every other replica computes for it.
5751
+ */
5752
+ private positionByTimestamp;
5753
+ /**
5754
+ * Decides each operation where it lands and carries the verdict on it. A
5755
+ * refused submitted action is reported to the caller and nothing is stored; a
5756
+ * refused operation the reshuffle merely moved keeps its verdict, because it
5757
+ * already holds a position.
5758
+ *
5759
+ * The operations carry the indexes and skips they will be stored at, because
5760
+ * the walk resolves skips before it orders them.
5761
+ */
5762
+ private evaluatePositioned;
5763
+ /**
5764
+ * The scopes a re-evaluation pass visits, in a fixed order.
5765
+ *
5766
+ * The revisions map comes from a query with no ORDER BY, and the order is
5767
+ * load-bearing: each scope's pass re-reads the auth stream, and the walk skips
5768
+ * an operation by its stored denial, so a denial this pass just wrote is
5769
+ * visible to a later-visited scope and invisible to an earlier one. The model's
5770
+ * own projection order leads, then the rest sorted, so the pass is reproducible
5771
+ * across replicas and across runs.
5772
+ */
5773
+ private evaluationOrder;
5774
+ /**
5775
+ * The first timestamp in the batch that does not strictly exceed everything
5776
+ * ahead of it, or undefined when the whole batch is monotonic.
5777
+ *
5778
+ * The bound is carried forward rather than compared against one stored maximum,
5779
+ * because a single execute can carry several auth actions stamped in the same
5780
+ * millisecond. Letting a tie through would store a stream the position walk
5781
+ * then refuses to read, with no repair path.
5782
+ */
5783
+ private firstNonMonotonicTimestamp;
5784
+ /** The operations a batch of submitted actions appends at the scope's tail. */
5785
+ private appendedOperations;
5786
+ /**
5787
+ * Re-evaluates the document when a write meets both criteria: it was written
5788
+ * to a stream the model reads, and it is timestamped before an operation
5789
+ * already stored. The caller supplies the timestamp and the reactor does not replace
5790
+ * it, so a mutation job can write such an operation just as a load job can,
5791
+ * which is why both executeJob and executeLoadJob call this.
5792
+ */
5793
+ private reevaluateIfCriteriaMet;
5794
+ /**
5795
+ * Re-evaluates every scope the model evaluates. Where an operation's
5796
+ * evaluation differs from what is stored, the tail from that operation is
5797
+ * re-appended, carrying a skip that spans the indices it supersedes.
5798
+ */
5799
+ private reevaluateDocument;
5800
+ /**
5801
+ * Re-judges a document's stored operations because a read-set stream in
5802
+ * another document (a group) gained an operation. The trigger timestamp
5803
+ * bounds the work: an operation later than everything this document holds
5804
+ * cannot change any evaluation, so the pass is skipped.
5805
+ */
5806
+ private executeReevaluationJob;
5094
5807
  private executeLoadJob;
5095
5808
  private accumulateResultOrReturnError;
5096
5809
  }
@@ -5159,6 +5872,49 @@ declare class DocumentModelRegistry implements IDocumentModelRegistry {
5159
5872
  getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
5160
5873
  }
5161
5874
  //#endregion
5875
+ //#region src/decision/build-decision-model.d.ts
5876
+ /**
5877
+ * Reads each projection's stream through the supplied reader, recording the
5878
+ * revision observed. Static projections resolve first; derived projections
5879
+ * see only those and contribute a map from document id to state. Each
5880
+ * distinct stream is read once and yields one append condition entry.
5881
+ */
5882
+ declare function buildDecisionModel<M>(reader: IStreamStateReader, definition: (target: DecisionTarget) => DecisionModel<M>, target: DecisionTarget, signal?: AbortSignal): Promise<BuiltDecisionModel<M>>;
5883
+ //#endregion
5884
+ //#region src/decision/auth-decision-model.d.ts
5885
+ type AuthDecisionModel = {
5886
+ document: PHDocumentState;
5887
+ auth: PHAuthState;
5888
+ };
5889
+ /** This decision model uses both the document and the auth streams. */
5890
+ declare function authDecisionModel(target: DecisionTarget): DecisionModel<AuthDecisionModel>;
5891
+ //#endregion
5892
+ //#region src/decision/stream-order.d.ts
5893
+ /** Where a stream's stored order contradicts its timestamps. */
5894
+ type OutOfOrderPair = {
5895
+ previous: Operation;
5896
+ current: Operation;
5897
+ /**
5898
+ * `descending` cannot be walked at all. `tied` walks fine — the intra-stream
5899
+ * rule breaks the tie by index — but violates the monotonic auth rule, so a
5900
+ * stream holding one can never be replicated to a peer that lacks it.
5901
+ */
5902
+ kind: "descending" | "tied";
5903
+ };
5904
+ /**
5905
+ * The first pair of effective operations whose stored order contradicts their
5906
+ * timestamps, or undefined when the stream is in position order.
5907
+ *
5908
+ * Such a stream cannot be walked, and the auth stream is never reshuffled once
5909
+ * the monotonic rule is on, so run this before enabling enforcement on a fleet.
5910
+ *
5911
+ * `requireStrict` additionally rejects a tie, which is what the auth stream's
5912
+ * monotonic rule requires and what the walk alone does not care about.
5913
+ */
5914
+ declare function firstOutOfOrderPair(operations: Operation[], options?: {
5915
+ requireStrict?: boolean;
5916
+ }): OutOfOrderPair | undefined;
5917
+ //#endregion
5162
5918
  //#region src/read-models/base-read-model.d.ts
5163
5919
  type BaseReadModelConfig = {
5164
5920
  readModelId: string;
@@ -5243,7 +5999,7 @@ declare class KyselyDocumentIndexer extends BaseReadModel implements IDocumentIn
5243
5999
  * serialized so the executor can return to dispatch without holding ordering
5244
6000
  * implicitly.
5245
6001
  */
5246
- declare class ReadModelCoordinator implements IReadModelCoordinator {
6002
+ declare class ReadModelCoordinator implements ILiveReadModelCoordinator {
5247
6003
  private eventBus;
5248
6004
  readonly preReady: IReadModel[];
5249
6005
  readonly postReady: IReadModel[];
@@ -5262,6 +6018,7 @@ declare class ReadModelCoordinator implements IReadModelCoordinator {
5262
6018
  */
5263
6019
  drain(): Promise<void>;
5264
6020
  getChainDepth(): number;
6021
+ addReadModel(readModel: IReadModel, stage: ReadModelRegistrationStage): void;
5265
6022
  private handleWriteReady;
5266
6023
  private emitEmptyReadReady;
5267
6024
  private runChain;
@@ -5275,8 +6032,31 @@ declare class ReadModelCoordinator implements IReadModelCoordinator {
5275
6032
  type Database$2 = Database$1 & DocumentViewDatabase;
5276
6033
  declare class KyselyDocumentView extends BaseReadModel implements IDocumentView {
5277
6034
  private operationStore;
6035
+ /**
6036
+ * Whether a single-document read serves a deleted document's state as of the
6037
+ * deletion rather than hiding it. Only meaningful with `documentDecisions`,
6038
+ * which is what makes deletion positional. Listings omit it either way.
6039
+ */
6040
+ private readonly servesDeletionBoundary;
5278
6041
  private _db;
5279
- constructor(db: Kysely<Database$2>, operationStore: IOperationStore, operationIndex: IOperationIndex, writeCache: IWriteCache, consistencyTracker: IConsistencyTracker);
6042
+ constructor(db: Kysely<Database$2>, operationStore: IOperationStore, operationIndex: IOperationIndex, writeCache: IWriteCache, consistencyTracker: IConsistencyTracker,
6043
+ /**
6044
+ * Whether a single-document read serves a deleted document's state as of the
6045
+ * deletion rather than hiding it. Only meaningful with `documentDecisions`,
6046
+ * which is what makes deletion positional. Listings omit it either way.
6047
+ */
6048
+
6049
+ servesDeletionBoundary: boolean);
6050
+ /**
6051
+ * Indexes committed operations into DocumentSnapshot rows. CREATE_DOCUMENT
6052
+ * only seeds header/document/auth. UPGRADE_DOCUMENT reindexes every scope
6053
+ * present in resultingState when the operation vouches for them — a seed
6054
+ * carrying initialState or a migration stamped with the __migrated marker
6055
+ * — since the upgrade reducer may have reshaped any of them; upgrades
6056
+ * without either fall back to header/document/auth, because their sibling
6057
+ * echoes may be stale. All other action types index only header and their
6058
+ * own scope.
6059
+ */
5280
6060
  protected commitOperations(items: OperationWithContext$1[]): Promise<void>;
5281
6061
  exists(documentIds: string[], consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<boolean[]>;
5282
6062
  get<TDocument extends PHDocument>(documentId: string, view?: ViewFilter$1, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<TDocument>;
@@ -5408,6 +6188,8 @@ declare class GqlRequestChannel implements IChannel {
5408
6188
  private isPushing;
5409
6189
  private pendingDrain;
5410
6190
  private receivingPages;
6191
+ /** Cleared for good the first time the remote rejects {@link DECISION_FIELDS}. */
6192
+ private peerServesDecisionFields;
5411
6193
  private isRecovering;
5412
6194
  private connectionState;
5413
6195
  /** Latest unrecoverable error was an auth rejection; cleared on connect. */
@@ -5454,6 +6236,18 @@ declare class GqlRequestChannel implements IChannel {
5454
6236
  * Queries the remote GraphQL endpoint for sync envelopes.
5455
6237
  */
5456
6238
  private pollSyncEnvelopes;
6239
+ /**
6240
+ * True when the remote rejected the query for naming a field it does not
6241
+ * have. Selecting an unknown field fails validation for the whole query, so
6242
+ * an unhandled one takes the channel's polling down until the process
6243
+ * restarts rather than degrading.
6244
+ */
6245
+ private rejectsDecisionFields;
6246
+ /**
6247
+ * The poll query. `withDecisionFields` selects the two fields added with the
6248
+ * auth projection; a remote on the previous schema is polled without them.
6249
+ */
6250
+ private pollQuery;
5457
6251
  /**
5458
6252
  * Registers or updates this channel on the remote server via GraphQL mutation.
5459
6253
  * Returns the remote's ack ordinal so the client can trim its outbox.
@@ -5616,6 +6410,18 @@ declare function batchOperationsByDocument(operations: OperationWithContext$1[])
5616
6410
  * jobId; all other jobIds are remapped so external dependencies still resolve.
5617
6411
  */
5618
6412
  declare function consolidateSyncOperations(syncOps: SyncOperation[]): SyncOperation[];
6413
+ /**
6414
+ * Classifies a failure by error name rather than `instanceof`, because a failure
6415
+ * that crossed the pooled-worker boundary arrives as plain data.
6416
+ */
6417
+ declare function classifyJobFailure(errorName: string): SyncOperationErrorType;
6418
+ /** The explicit type when something else carried it, else derived by name. */
6419
+ declare function syncOperationErrorType(error: ChannelError | undefined): SyncOperationErrorType;
6420
+ /**
6421
+ * A held auth operation must not quarantine: reconciling the two policies needs
6422
+ * the traffic a quarantine would stop.
6423
+ */
6424
+ declare function quarantinesDocument(errorType: SyncOperationErrorType): boolean;
5619
6425
  //#endregion
5620
6426
  //#region src/admin/types.d.ts
5621
6427
  type KeyframeValidationIssue = {
@@ -5631,11 +6437,20 @@ type SnapshotValidationIssue = {
5631
6437
  snapshotHash: string;
5632
6438
  replayedHash: string;
5633
6439
  };
6440
+ /** Effective operations whose stored order contradicts their timestamps. */
6441
+ type StreamOrderIssue = {
6442
+ scope: string;
6443
+ branch: string;
6444
+ previous: Operation;
6445
+ current: Operation;
6446
+ kind: OutOfOrderPair["kind"];
6447
+ };
5634
6448
  type ValidationResult = {
5635
6449
  documentId: string;
5636
6450
  isConsistent: boolean;
5637
6451
  keyframeIssues: KeyframeValidationIssue[];
5638
6452
  snapshotIssues: SnapshotValidationIssue[];
6453
+ streamOrderIssues: StreamOrderIssue[];
5639
6454
  };
5640
6455
  type RebuildResult = {
5641
6456
  documentId: string;
@@ -5659,6 +6474,7 @@ declare class DocumentIntegrityService implements IDocumentIntegrityService {
5659
6474
  validateDocument(documentId: string, branch?: string, signal?: AbortSignal): Promise<ValidationResult>;
5660
6475
  rebuildKeyframes(documentId: string, branch?: string, signal?: AbortSignal): Promise<RebuildResult>;
5661
6476
  rebuildSnapshots(documentId: string, branch?: string, signal?: AbortSignal): Promise<RebuildResult>;
6477
+ private findStreamOrderIssues;
5662
6478
  private discoverScopes;
5663
6479
  }
5664
6480
  //#endregion
@@ -5707,5 +6523,5 @@ declare class ProcessorManager extends BaseReadModel implements IProcessorManage
5707
6523
  private deleteProcessorCursors;
5708
6524
  }
5709
6525
  //#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 };
6526
+ export { ALWAYS_READABLE_SCOPES, APPEND_CONDITION_FAILED_PREFIX, type AbortMessage, type AdmissionDecision, type AppendCondition, AppendConditionFailedError, type AppendConditionStream, type AtomicTxn, type AttachmentHash, type AttachmentRef, type AuthDecisionModel, BareReadGate, 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 IReadGate, type IReadModel, type IReadModelCoordinator, type IRelationalDb, type IStreamStateReader, 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, ModelReadGate, 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, readDecisionModel, removeRelationshipAction, runMigrations, sanitizeArg, selectDecisionModel, supportsLiveReadModelRegistration, syncOperationErrorType, trimMailboxFromAckOrdinal, updateRelationshipAction, upgradeDocumentAction, workerEntryPath };
5711
6527
  //# sourceMappingURL=index.d.ts.map