@powerhousedao/reactor 6.2.3-dev.22 → 6.2.3-dev.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/{build-worker-executor-DUjyF4NM.js → build-worker-executor-DxmDJ4QQ.js} +24 -8
  2. package/dist/build-worker-executor-DxmDJ4QQ.js.map +1 -0
  3. package/dist/{document-indexer-C1oY6CaR.js → document-indexer-Dn9RB0sg.js} +6 -5
  4. package/dist/document-indexer-Dn9RB0sg.js.map +1 -0
  5. package/dist/{drive-container-types-CS5IxDiA.js → drive-container-types-Be5-EY9W.js} +843 -144
  6. package/dist/drive-container-types-Be5-EY9W.js.map +1 -0
  7. package/dist/entry.js +10 -5
  8. package/dist/entry.js.map +1 -1
  9. package/dist/index.d.ts +1985 -1826
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +716 -302
  12. package/dist/index.js.map +1 -1
  13. package/dist/projection-entry.js +4 -4
  14. package/dist/{projection-shard-manager-CUo4bF4O.js → projection-shard-manager-mQhfVipO.js} +2 -2
  15. package/dist/{projection-shard-manager-CUo4bF4O.js.map → projection-shard-manager-mQhfVipO.js.map} +1 -1
  16. package/dist/{types-DMKLa0Ok.js → types-DxDCmtId.js} +3 -2
  17. package/dist/types-DxDCmtId.js.map +1 -0
  18. package/dist/{worker-g03lNM42.js → worker-BDVzCtuf.js} +2 -2
  19. package/dist/{worker-g03lNM42.js.map → worker-BDVzCtuf.js.map} +1 -1
  20. package/dist/{worker-handle-CrERzl8s.js → worker-handle-B3p-nuqG.js} +14 -9
  21. package/dist/worker-handle-B3p-nuqG.js.map +1 -0
  22. package/package.json +9 -7
  23. package/dist/build-worker-executor-DUjyF4NM.js.map +0 -1
  24. package/dist/document-indexer-C1oY6CaR.js.map +0 -1
  25. package/dist/drive-container-types-CS5IxDiA.js.map +0 -1
  26. package/dist/types-DMKLa0Ok.js.map +0 -1
  27. package/dist/worker-handle-CrERzl8s.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { Action, AuthRequest, AuthSubject, CreateDocumentActionInput, DocumentModelModule, ISigner, Operation, OperationContext, OperationOutcome, OperationWithContext, OperationWithContext as OperationWithContext$1, PHAuthState, PHDocument, PHDocumentState, SignatureVerificationHandler, UpgradeDocumentActionInput, UpgradeManifest, UpgradeReducer, UpgradeTransition, actions as documentActions } from "@powerhousedao/shared/document-model";
1
+ import { Action, ActionSigner, AuthRequest, AuthSubject, CreateDocumentActionInput, DocumentModelModule, ISigner, Operation, OperationContext, OperationOutcome, OperationWithContext, OperationWithContext as OperationWithContext$1, PHAuthState, PHDocument, PHDocumentState, SignaturePolicy, 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";
5
5
  import { Generated, Insertable, Kysely, Transaction } from "kysely";
6
- import { IProcessor, IProcessorHostModuleBase, IProcessorHostModuleBase as IProcessorHostModuleBase$1, IProcessorManager, IProcessorManager as IProcessorManager$1, IRelationalDb, ProcessorApp, ProcessorFactory, ProcessorFactory as ProcessorFactory$1, ProcessorFactoryBuilder, ProcessorFilter, ProcessorRecord, ProcessorStatus, RelationalDbProcessor, TrackedProcessor, TrackedProcessor as TrackedProcessor$1, createRelationalDb } from "@powerhousedao/shared/processors";
6
+ import { IProcessor, IProcessorHostModuleBase, IProcessorHostModuleBase as IProcessorHostModuleBase$1, IProcessorManager, IProcessorManager as IProcessorManager$1, IRelationalDb, ProcessorApp, ProcessorFactory, ProcessorFactory as ProcessorFactory$1, ProcessorFactoryBuilder, ProcessorFilter, ProcessorRecord, ProcessorRecord as ProcessorRecord$1, ProcessorStatus, RelationalDbProcessor, TrackedProcessor, TrackedProcessor as TrackedProcessor$1, createRelationalDb } from "@powerhousedao/shared/processors";
7
7
  import { Pool } from "pg";
8
8
 
9
9
  //#region src/attachments/types.d.ts
@@ -784,6 +784,13 @@ interface IOperationStore {
784
784
  * timestamp, so a later timestamp can sit behind the last row.
785
785
  */
786
786
  getStreamLatestTimestamp(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
787
+ /**
788
+ * The subset of `opIds` stored anywhere in one stream, retracted rows
789
+ * included.
790
+ */
791
+ findOperationIds(documentId: string, scope: string, branch: string, opIds: string[], signal?: AbortSignal): Promise<Set<string>>;
792
+ /** The latest row of each of `opIds` stored in one stream. */
793
+ getOperationsByIds(documentId: string, scope: string, branch: string, opIds: string[], signal?: AbortSignal): Promise<Operation[]>;
787
794
  }
788
795
  /**
789
796
  * Stores periodic document snapshots (keyframes) so that document state
@@ -1332,6 +1339,8 @@ interface IOperationIndex {
1332
1339
  * reference other groups.
1333
1340
  */
1334
1341
  getGroupReferencers(groupId: string, signal?: AbortSignal): Promise<string[]>;
1342
+ /** The latest ordinal of each of `opIds` indexed in one stream. */
1343
+ getOrdinalsByOpIds(documentId: string, scope: string, branch: string, opIds: string[], signal?: AbortSignal): Promise<Map<string, number>>;
1335
1344
  }
1336
1345
  /**
1337
1346
  * Identifies the collection a remote synchronizes. Collections are drive-level
@@ -1524,2105 +1533,2188 @@ interface IWriteCache {
1524
1533
  shutdown(): Promise<void>;
1525
1534
  }
1526
1535
  //#endregion
1527
- //#region src/events/types.d.ts
1528
- /**
1529
- * Describes a function to unsubscribe from an event.
1530
- */
1531
- type Unsubscribe = () => void;
1532
- /**
1533
- * A subscriber is a function that is called when an event is emitted.
1534
- *
1535
- * It is passed the event type and the data.
1536
- * It can return a promise or a value.
1537
- * If it returns a promise, the event bus will wait for the promise to resolve before calling the next subscriber.
1538
- * If it throws an error, the event bus will reject with an aggregate error of all errors.
1539
- *
1540
- * @param type - The type of event to emit.
1541
- * @param data - The data to pass to the subscriber.
1542
- */
1543
- type Subscriber = (type: number, data: any) => void | Promise<void>;
1544
- /**
1545
- * Custom error class that aggregates multiple errors from event subscribers.
1546
- */
1547
- declare class EventBusAggregateError extends Error {
1548
- readonly errors: any[];
1549
- constructor(errors: unknown[]);
1536
+ //#region src/cache/collection-membership-cache.d.ts
1537
+ interface ICollectionMembershipCache {
1538
+ getCollectionsForDocuments(documentIds: string[]): Promise<Record<string, string[]>>;
1539
+ invalidate(documentId: string): void;
1550
1540
  }
1541
+ //#endregion
1542
+ //#region src/cache/document-meta-cache-types.d.ts
1551
1543
  /**
1552
- * Event types for reactor lifecycle events.
1553
- */
1554
- declare const ReactorEventTypes: {
1555
- readonly JOB_PENDING: 10001;
1556
- readonly JOB_RUNNING: 10002;
1557
- readonly JOB_WRITE_READY: 10003;
1558
- readonly JOB_READ_READY: 10004;
1559
- readonly JOB_FAILED: 10005;
1560
- readonly READMODEL_BATCH_COMPLETED: 10006;
1561
- readonly READMODEL_INDEXED: 10007;
1562
- readonly MODEL_LOADED: 10008;
1563
- };
1564
- /**
1565
- * Stage within ReadModelCoordinator.runChain. Used as a dimension on
1566
- * stage-attribution events and histograms.
1567
- */
1568
- type ReadModelStage = "pre_ready" | "emit" | "post_ready";
1569
- /**
1570
- * Stage in which an individual read model ran. The emit stage does not
1571
- * involve a read model so it is excluded from this discriminant.
1572
- */
1573
- type ReadModelIndexingStage = "pre_ready" | "post_ready";
1574
- /**
1575
- * Emitted after the resolver loads a model on demand, so peers load it too.
1576
- */
1577
- type ModelLoadedEvent = {
1578
- documentType: string;
1579
- };
1580
- /**
1581
- * Event emitted when a job is registered and waiting to be executed.
1582
- */
1583
- type JobPendingEvent = {
1584
- jobId: string;
1585
- jobMeta: JobMeta;
1586
- };
1587
- /**
1588
- * Event emitted when a job starts executing.
1589
- */
1590
- type JobRunningEvent = {
1591
- jobId: string;
1592
- jobMeta: JobMeta;
1593
- };
1594
- /**
1595
- * Event emitted when operations are written to IOperationStore.
1596
- * Contains the operations directly to avoid round-trip queries.
1544
+ * Cached document metadata from the "document" scope.
1545
+ *
1546
+ * This lightweight structure holds essential document information needed by
1547
+ * the job executor without fetching full scope state. It provides an explicit
1548
+ * cross-scope contract for accessing document scope metadata.
1597
1549
  */
1598
- type JobWriteReadyEvent = {
1599
- jobId: string;
1600
- operations: OperationWithContext$1[];
1601
- jobMeta: JobMeta;
1550
+ type CachedDocumentMeta = {
1602
1551
  /**
1603
- * The ids of the actions the caller submitted with this job. `operations`
1604
- * can also carry operations the job merely moved into a new position, so a
1605
- * consumer reporting back to the caller needs this to tell the two apart.
1606
- * Absent on jobs that carry no submitted actions.
1552
+ * The full PHDocumentState from document.state.document.
1553
+ * Contains version, hash, isDeleted, deletedAtUtcIso, etc.
1607
1554
  */
1608
- submittedActionIds?: string[];
1555
+ state: PHDocumentState;
1609
1556
  /**
1610
- * Maps documentId to the collection IDs it belongs to.
1611
- * Used by SyncManager to route operations only to remotes
1612
- * whose collection contains the document.
1557
+ * The document type (from header), cached for convenience.
1613
1558
  */
1614
- collectionMemberships?: Record<string, string[]>;
1559
+ documentType: string; /** From the CREATE_DOCUMENT input, which fixes them for the document's life. */
1560
+ protocolVersions: {
1561
+ [protocol: string]: number;
1562
+ } | undefined;
1563
+ /**
1564
+ * The revision of the document scope when this metadata was captured.
1565
+ * Used for cache invalidation and consistency checks.
1566
+ */
1567
+ documentScopeRevision: number;
1615
1568
  };
1616
1569
  /**
1617
- * Event emitted after all read models have finished processing operations.
1618
- * This event fires after JOB_WRITE_READY and guarantees that:
1619
- * - All read models (DocumentView, DocumentIndexer, etc.) have indexed the operations
1620
- * - All consistency trackers have been updated with the new operation indices
1621
- * - Queries without consistency tokens will now see the updated data
1570
+ * Interface for the document metadata cache.
1622
1571
  *
1623
- * This event is useful for:
1624
- * - Test synchronization (knowing when read models are ready)
1625
- * - Observability (measuring read model latency)
1626
- * - Event-driven workflows (triggering downstream processes)
1627
- */
1628
- type JobReadReadyEvent = {
1629
- jobId: string;
1630
- operations: OperationWithContext$1[];
1631
- };
1632
- /**
1633
- * Event emitted when a job fails with an unrecoverable error.
1634
- * This event allows the JobAwaiter and other subscribers to react to job failures
1635
- * without polling.
1636
- */
1637
- type JobFailedEvent$1 = {
1638
- jobId: string;
1639
- error: Error;
1640
- job?: Job;
1641
- };
1642
- /**
1643
- * Event emitted once per batch processed by ReadModelCoordinator.runChain,
1644
- * after all three projection stages complete. Carries per-stage wall times,
1645
- * the chain wait time, and the batch size so projection cost can be
1646
- * attributed by an observer.
1647
- */
1648
- type ReadModelBatchCompletedEvent = {
1649
- jobId: string;
1650
- batchSize: number;
1651
- chainWaitDurationMs: number;
1652
- preReadyDurationMs: number;
1653
- emitDurationMs: number;
1654
- postReadyDurationMs: number;
1655
- };
1656
- /**
1657
- * Event emitted once per individual read model per batch and stage, after
1658
- * that read model's indexOperations call resolves (or rejects). Lets
1659
- * observers attribute projection cost to a specific read model.
1660
- */
1661
- type ReadModelIndexedEvent = {
1662
- jobId: string;
1663
- readModelName: string;
1664
- stage: ReadModelIndexingStage;
1665
- durationMs: number;
1666
- operationCount: number;
1667
- success: boolean;
1668
- };
1669
- //#endregion
1670
- //#region src/events/interfaces.d.ts
1671
- /**
1672
- * Describes an object that manages event subscriptions and emissions.
1572
+ * This cache provides an explicit cross-scope contract for accessing document
1573
+ * scope metadata. It solves the problem where job execution in one scope (e.g.,
1574
+ * "global") needs access to document scope state (version, isDeleted, etc.)
1575
+ * which may be stale in scope-specific caches or keyframes.
1576
+ *
1577
+ * The cache supports:
1578
+ * - Latest metadata retrieval with LRU caching
1579
+ * - Historical metadata reconstruction for reshuffling scenarios
1580
+ * - Eager updates after document scope operations
1673
1581
  */
1674
- interface IEventBus {
1582
+ interface IDocumentMetaCache {
1675
1583
  /**
1676
- * Register a new subscriber.
1677
- * Order is preserved by pushing to the end of the per-type array.
1584
+ * Retrieves the LATEST document metadata from cache or rebuilds from operations.
1678
1585
  *
1679
- * @param type - The type of event to subscribe to.
1680
- * @param subscriber - The subscriber function to call when the event is emitted.
1586
+ * On cache miss, fetches all document scope operations and reconstructs the
1587
+ * current PHDocumentState by applying UPGRADE_DOCUMENT and DELETE_DOCUMENT
1588
+ * operations.
1681
1589
  *
1682
- * @returns A function to unsubscribe from the event.
1590
+ * @param documentId - The document identifier
1591
+ * @param branch - Branch name
1592
+ * @param signal - Optional abort signal to cancel the operation
1593
+ * @returns The cached or rebuilt document metadata
1594
+ * @throws {Error} "Operation aborted" if signal is aborted
1595
+ * @throws {Error} If document not found (no CREATE_DOCUMENT operation)
1683
1596
  */
1684
- subscribe<K>(type: number, subscriber: (type: number, event: K) => void | Promise<void>): Unsubscribe;
1597
+ getDocumentMeta(documentId: string, branch: string, signal?: AbortSignal): Promise<CachedDocumentMeta>;
1685
1598
  /**
1686
- * Emits an event and waits until **all** subscribers finish.
1687
- * - Every subscriber present at emit-start is called, in registration order.
1688
- * - Calls are invoked and settled sequentially.
1689
- * - If subscribers throw/reject, `emit` rejects with an aggregate error of all errors.
1599
+ * Rebuilds document metadata at a SPECIFIC revision (always rebuilds, no caching).
1690
1600
  *
1691
- * @param type - The type of event to emit.
1692
- * @param data - The data to pass to the subscribers.
1601
+ * Used during reshuffling when operations need to be inserted at a previous
1602
+ * revision and we need the document scope state as of that point in time.
1603
+ *
1604
+ * @param documentId - The document identifier
1605
+ * @param branch - Branch name
1606
+ * @param targetRevision - The document scope revision to reconstruct up to
1607
+ * @param signal - Optional abort signal to cancel the operation
1608
+ * @returns Document metadata as of the target revision
1609
+ * @throws {Error} "Operation aborted" if signal is aborted
1610
+ * @throws {Error} If document not found
1693
1611
  */
1694
- emit(type: number, data: any): Promise<void>;
1695
- }
1696
- //#endregion
1697
- //#region src/shared/awaiter.d.ts
1698
- interface IJobAwaiter {
1612
+ rebuildAtRevision(documentId: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<CachedDocumentMeta>;
1699
1613
  /**
1700
- * Waits for a job to complete: turns a job into a promise.
1614
+ * Eagerly updates cached metadata after document scope operations.
1701
1615
  *
1702
- * @param jobId - The job id or job object
1703
- * @param signal - Optional abort signal to cancel the request
1704
- * @returns The result of the job
1616
+ * Called by the job executor after CREATE_DOCUMENT, UPGRADE_DOCUMENT, or
1617
+ * DELETE_DOCUMENT operations to keep the cache current.
1618
+ *
1619
+ * @param documentId - The document identifier
1620
+ * @param branch - Branch name
1621
+ * @param meta - The new metadata to cache
1705
1622
  */
1706
- waitForJob(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
1623
+ putDocumentMeta(documentId: string, branch: string, meta: CachedDocumentMeta): void;
1707
1624
  /**
1708
- * Shuts down the job awaiter. This will synchronously reject all pending jobs.
1625
+ * Invalidates cached document metadata.
1626
+ *
1627
+ * Call before reshuffling operations that modify the document scope, or
1628
+ * when document state may have changed externally.
1629
+ *
1630
+ * @param documentId - The document identifier
1631
+ * @param branch - Optional branch to narrow invalidation (if omitted, all branches)
1632
+ * @returns Number of entries invalidated
1709
1633
  */
1710
- shutdown(): void;
1711
- }
1712
- /**
1713
- * Event-driven implementation of IJobAwaiter.
1714
- * Subscribes to operation events to detect job completion without polling.
1715
- */
1716
- declare class JobAwaiter implements IJobAwaiter {
1717
- private eventBus;
1718
- private getJobStatus;
1719
- private pendingJobs;
1720
- private unsubscribers;
1721
- constructor(eventBus: IEventBus, getJobStatus: (jobId: string, signal?: AbortSignal) => Promise<JobInfo>);
1722
- private subscribeToEvents;
1723
- shutdown(): void;
1724
- waitForJob(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
1725
- private handleWriteReady;
1726
- private handleReadReady;
1727
- private handleJobFailed;
1728
- private checkAndResolveWaiters;
1634
+ invalidate(documentId: string, branch?: string): number;
1635
+ /**
1636
+ * Clears all cached document metadata.
1637
+ */
1638
+ clear(): void;
1639
+ /**
1640
+ * Performs startup initialization.
1641
+ */
1642
+ startup(): Promise<void>;
1643
+ /**
1644
+ * Performs graceful shutdown.
1645
+ */
1646
+ shutdown(): Promise<void>;
1729
1647
  }
1730
1648
  //#endregion
1731
- //#region src/subs/types.d.ts
1649
+ //#region src/storage/kysely/types.d.ts
1650
+ interface OperationTable {
1651
+ id: Generated<number>;
1652
+ jobId: string;
1653
+ opId: string;
1654
+ prevOpId: string;
1655
+ writeTimestampUtcMs: Generated<Date>;
1656
+ documentId: string;
1657
+ documentType: string;
1658
+ scope: string;
1659
+ branch: string;
1660
+ timestampUtcMs: Date;
1661
+ index: number;
1662
+ action: unknown;
1663
+ skip: number;
1664
+ error?: string | null;
1665
+ deniedReason?: string | null;
1666
+ hash: string;
1667
+ }
1668
+ interface KeyframeTable {
1669
+ id: Generated<number>;
1670
+ documentId: string;
1671
+ documentType: string;
1672
+ scope: string;
1673
+ branch: string;
1674
+ revision: number;
1675
+ document: unknown;
1676
+ createdAt: Generated<Date>;
1677
+ }
1678
+ interface DocumentCollectionTable {
1679
+ documentId: string;
1680
+ collectionId: string;
1681
+ joinedOrdinal: bigint;
1682
+ leftOrdinal: bigint | null;
1683
+ }
1684
+ interface OperationIndexOperationTable {
1685
+ ordinal: Generated<number>;
1686
+ opId: string;
1687
+ documentId: string;
1688
+ documentType: string;
1689
+ scope: string;
1690
+ branch: string;
1691
+ timestampUtcMs: string;
1692
+ writeTimestampUtcMs: Generated<Date>;
1693
+ index: number;
1694
+ skip: number;
1695
+ hash: string;
1696
+ action: unknown;
1697
+ deniedReason?: string | null;
1698
+ sourceRemote: Generated<string>;
1699
+ }
1700
+ interface SyncRemoteTable {
1701
+ name: string;
1702
+ collection_id: string;
1703
+ channel_type: string;
1704
+ channel_id: string;
1705
+ remote_name: string;
1706
+ channel_parameters: unknown;
1707
+ filter_document_ids: unknown;
1708
+ filter_scopes: unknown;
1709
+ filter_branch: string;
1710
+ push_state: string;
1711
+ push_last_success_utc_ms: string | null;
1712
+ push_last_failure_utc_ms: string | null;
1713
+ push_failure_count: number;
1714
+ pull_state: string;
1715
+ pull_last_success_utc_ms: string | null;
1716
+ pull_last_failure_utc_ms: string | null;
1717
+ pull_failure_count: number;
1718
+ bound_address: string | null;
1719
+ created_at: Generated<Date>;
1720
+ updated_at: Generated<Date>;
1721
+ }
1722
+ interface SyncCursorTable {
1723
+ remote_name: string;
1724
+ cursor_type: string;
1725
+ cursor_ordinal: bigint;
1726
+ last_synced_at_utc_ms: string | null;
1727
+ updated_at: Generated<Date>;
1728
+ }
1732
1729
  /**
1733
- * Error handler for subscription callback errors
1730
+ * Kysely table definition for the `sync_dead_letters` table.
1734
1731
  */
1735
- interface ISubscriptionErrorHandler {
1736
- /**
1737
- * Called when a subscription callback throws an error
1738
- * @param error - The error that was thrown
1739
- * @param context - Context about which subscription failed
1740
- */
1741
- handleError(error: unknown, context: SubscriptionErrorContext): void;
1732
+ interface SyncDeadLetterTable {
1733
+ ordinal: Generated<number>;
1734
+ id: string;
1735
+ job_id: string;
1736
+ job_dependencies: unknown;
1737
+ remote_name: string;
1738
+ document_id: string;
1739
+ scopes: unknown;
1740
+ branch: string;
1741
+ operations: unknown;
1742
+ error_source: string;
1743
+ error_message: string;
1744
+ error_type: Generated<string>;
1745
+ created_at: Generated<Date>;
1742
1746
  }
1743
1747
  /**
1744
- * Context information about a subscription error
1748
+ * One (document, group) reference ever discovered from an auth operation's
1749
+ * input. Rows are never updated or deleted (see migration 017).
1745
1750
  */
1746
- interface SubscriptionErrorContext {
1747
- /** The type of event that was being processed */
1748
- eventType: "created" | "deleted" | "updated" | "relationshipChanged";
1749
- /** The subscription ID that failed */
1750
- subscriptionId: string;
1751
- /** Optional additional data about the event */
1752
- eventData?: unknown;
1751
+ interface GroupReferenceTable {
1752
+ documentId: string;
1753
+ groupId: string;
1754
+ }
1755
+ interface Database$1 {
1756
+ Operation: OperationTable;
1757
+ Keyframe: KeyframeTable;
1758
+ document_collections: DocumentCollectionTable;
1759
+ operation_index_operations: OperationIndexOperationTable;
1760
+ group_references: GroupReferenceTable;
1761
+ sync_remotes: SyncRemoteTable;
1762
+ sync_cursors: SyncCursorTable;
1763
+ sync_dead_letters: SyncDeadLetterTable;
1764
+ }
1765
+ interface DocumentTable {
1766
+ id: string;
1767
+ createdAt: Generated<Date>;
1768
+ updatedAt: Generated<Date>;
1769
+ }
1770
+ interface DocumentRelationshipTable {
1771
+ id: Generated<string>;
1772
+ sourceId: string;
1773
+ targetId: string;
1774
+ relationshipType: string;
1775
+ metadata: unknown;
1776
+ createdAt: Generated<Date>;
1777
+ updatedAt: Generated<Date>;
1778
+ }
1779
+ interface IndexerStateTable {
1780
+ id: Generated<number>;
1781
+ lastOperationId: number;
1782
+ lastOperationTimestamp: Generated<Date>;
1783
+ }
1784
+ interface DocumentIndexerDatabase {
1785
+ Document: DocumentTable;
1786
+ DocumentRelationship: DocumentRelationshipTable;
1787
+ IndexerState: IndexerStateTable;
1753
1788
  }
1789
+ //#endregion
1790
+ //#region src/core/model-sources.d.ts
1791
+ /** An importable file holding one or more document-model exports. */
1792
+ type FileModelSource = {
1793
+ filePath: string;
1794
+ exportName?: string;
1795
+ };
1796
+ /** An importable package specifier holding one or more document-model exports. */
1797
+ type PackageModelSource = {
1798
+ packageName: string;
1799
+ subpath?: string;
1800
+ exportName?: string;
1801
+ };
1754
1802
  /**
1755
- * Interface for subscribing to document events in the reactor.
1803
+ * A source of document models: a live module, an importable file, or an
1804
+ * importable package. File and package sources can cross a worker-thread
1805
+ * boundary (workers re-import them); a live module cannot.
1756
1806
  */
1757
- interface IReactorSubscriptionManager {
1807
+ type DocumentModelSource = DocumentModelModule<any> | FileModelSource | PackageModelSource;
1808
+ //#endregion
1809
+ //#region src/registry/interfaces.d.ts
1810
+ type RegistrationResult<T> = {
1811
+ status: "success";
1812
+ item: T;
1813
+ } | {
1814
+ status: "error";
1815
+ item: T;
1816
+ error: Error;
1817
+ };
1818
+ /**
1819
+ * Loader that asynchronously resolves a document type to a
1820
+ * {@link DocumentModelSource}. Used by the queue to gate CREATE_DOCUMENT
1821
+ * jobs until the required model is available in the registry.
1822
+ *
1823
+ * Return an importable source ({ filePath } or { packageName }) whenever
1824
+ * possible: the resolver registers the resolved models on the host registry
1825
+ * and broadcasts importable sources to executor workers. A live
1826
+ * DocumentModelModule is also valid but host-only — it cannot cross a
1827
+ * worker-thread boundary, so worker pools will not receive it.
1828
+ */
1829
+ interface IDocumentModelLoader {
1830
+ load(documentType: string): Promise<DocumentModelSource>;
1831
+ }
1832
+ /**
1833
+ * Registry for managing document model modules.
1834
+ * Provides centralized access to document models' reducers, utils, and specifications.
1835
+ * Supports version-aware module storage and upgrade manifest management.
1836
+ */
1837
+ interface IDocumentModelRegistry {
1758
1838
  /**
1759
- * Subscribes to document creation events
1839
+ * Register multiple modules at once.
1840
+ * Modules without a version field default to version 1.
1841
+ * Invalid or duplicate modules are skipped without breaking registration of the remaining modules.
1760
1842
  *
1761
- * @param callback - Function called when documents are created
1762
- * @param search - Optional search filter to limit which documents trigger events
1763
- * @param view - Optional filter containing branch and scopes information
1764
- * @returns A function that unsubscribes from the events
1843
+ * @param modules Document model modules to register
1844
+ * @returns Array of results, one per module, indicating success or failure
1765
1845
  */
1766
- onDocumentCreated(callback: (result: PagedResults<string>) => void, search?: SearchFilter): () => void;
1846
+ registerModules(...modules: DocumentModelModule<any>[]): RegistrationResult<DocumentModelModule<any>>[];
1767
1847
  /**
1768
- * Subscribes to document deletion events
1848
+ * Unregister all versions of the specified document types.
1769
1849
  *
1770
- * @param callback - Function called when documents are deleted
1771
- * @param search - Optional search filter to limit which documents trigger events
1772
- * @returns A function that unsubscribes from the events
1850
+ * @param documentTypes The document types to unregister
1851
+ * @returns true if all modules were unregistered, false if any were not found
1773
1852
  */
1774
- onDocumentDeleted(callback: (documentIds: string[]) => void, search?: SearchFilter): () => void;
1853
+ unregisterModules(...documentTypes: string[]): boolean;
1775
1854
  /**
1776
- * Subscribes to document state updates
1855
+ * Get a specific document model module by document type and optional version.
1856
+ * If version is not specified, returns the latest version.
1777
1857
  *
1778
- * @param callback - Function called when documents are updated
1779
- * @param search - Optional search filter to limit which documents trigger events
1780
- * @param view - Optional filter containing branch and scopes information
1781
- * @returns A function that unsubscribes from the events
1858
+ * @param documentType The document type identifier
1859
+ * @param version Optional version number to retrieve
1860
+ * @returns The document model module
1861
+ * @throws ModuleNotFoundError if the document type or version is not registered
1782
1862
  */
1783
- onDocumentStateUpdated(callback: (result: PagedResults<PHDocument>) => void, search?: SearchFilter, view?: ViewFilter): () => void;
1863
+ getModule(documentType: string, version?: number): DocumentModelModule<any>;
1784
1864
  /**
1785
- * Subscribes to parent-child relationship change events
1865
+ * Get all registered document model modules.
1786
1866
  *
1787
- * @param callback - Function called when parent-child relationships change
1788
- * @param search - Optional search filter to limit which documents trigger events
1789
- * @returns A function that unsubscribes from the events
1867
+ * @returns Array of all registered modules
1790
1868
  */
1791
- onRelationshipChanged(callback: (parentId: string, childId: string, changeType: RelationshipChangeType) => void, search?: SearchFilter): () => void;
1792
- }
1793
- //#endregion
1794
- //#region src/decision/types.d.ts
1795
- /** One operation stream. */
1796
- type StreamQuery = {
1797
- documentId: string;
1798
- branch: string;
1799
- scope: string;
1800
- };
1801
- /**
1802
- * What building a decision model reads a stream's state through.
1803
- *
1804
- * `IWriteCache` satisfies this and is what the write paths pass. The read path
1805
- * cannot: the write cache is a write-side projection invalidated by the process
1806
- * that runs the executor, so a reactor whose executors live in worker processes
1807
- * holds state in its parent that no commit ever invalidates. A read there would
1808
- * decide against a policy arbitrarily far behind the one the write paths
1809
- * enforce. Reads therefore pass a reader backed by the read side.
1810
- */
1811
- interface IStreamStateReader {
1812
- getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
1813
- }
1814
- /** The document and branch a decision model is built for. */
1815
- type DecisionTarget = {
1816
- documentId: string;
1817
- branch: string;
1818
- };
1819
- /**
1820
- * What a decision's conditions may read beyond the projections: the executing
1821
- * scope's own state and the attempted action's input. Populated only while
1822
- * authConditions is on; otherwise both stay undefined and conditional grants
1823
- * never apply.
1824
- */
1825
- type DecisionContext = {
1826
- scopeState: unknown;
1827
- actionInput?: unknown;
1828
- };
1829
- /** A statically-queried stream's operations, named after its projection. */
1830
- type StreamHistory = {
1831
- name: string;
1832
- operations: Operation[];
1833
- };
1834
- /**
1835
- * A named stream whose value in the model is that scope's state from the
1836
- * document rebuild the reactor already performs. A derived query may read
1837
- * only statically-queried projections, so composition is one layer deep.
1838
- */
1839
- type Projection<M> = {
1840
- query: StreamQuery | ((model: Partial<M>) => StreamQuery[]);
1841
- /**
1842
- * For a derived projection, the streams it may read anywhere in an
1843
- * evaluated range, derived from the statically-queried streams' operations
1844
- * (including the operations under evaluation). A positional walk cannot use
1845
- * `query`, because the folded state it depends on changes over the range;
1846
- * this over-approximates by design, since a stream referenced at any
1847
- * position stays readable when the earlier range is re-evaluated even if a
1848
- * later operation removes the reference. Ignored on static projections.
1849
- */
1850
- queryOverHistory?: (reads: StreamHistory[]) => StreamQuery[];
1851
- /**
1852
- * Action types in this stream that can change an evaluation. Reads of the stream
1853
- * are filtered to these, so anything left out is invisible to a decision.
1854
- */
1855
- decidingActions: string[]; /** Applies one of this stream's operations while deciding. */
1856
- apply: (document: PHDocument, operation: Operation) => PHDocument;
1857
- };
1858
- /**
1859
- * The outcome of evaluating one operation. A refusal carries the reason it is
1860
- * recorded with, because a model has more than one way to refuse.
1861
- */
1862
- type Evaluation = {
1863
- decision: "allow";
1864
- } | {
1865
- decision: "deny";
1866
- reason: string;
1867
- };
1868
- /** Projections plus a decision function over the built model. */
1869
- type DecisionModel<M> = {
1870
- projections: { [K in keyof M]: Projection<M> };
1871
- /**
1872
- * Present when decide reads the executing scope's state through the
1873
- * decision context. A positional walk then folds the evaluated stream with
1874
- * this, from its base state through every effective operation, so
1875
- * conditions read the state as it stood at each operation's position
1876
- * rather than at the head.
1877
- */
1878
- foldEvaluatedScope?: (document: PHDocument, operation: Operation) => PHDocument;
1869
+ getAllModules(): DocumentModelModule<any>[];
1879
1870
  /**
1880
- * Whether or not this model decides about operations in a given scope. That
1881
- * is, a scope it reads is not necessarily one it evaluates, and vise-versa.
1871
+ * Clear all registered modules and upgrade manifests.
1882
1872
  */
1883
- evaluatesScope(scope: string): boolean;
1884
- decide(model: M, subject: AuthSubject, request: AuthRequest, ctx: DecisionContext): Evaluation;
1885
- };
1886
- /** A built model plus the read-set condition recording what the build read. */
1887
- type BuiltDecisionModel<M> = {
1888
- model: M;
1889
- appendCondition: AppendCondition;
1890
- };
1891
- //#endregion
1892
- //#region src/client/types.d.ts
1893
- /**
1894
- * Describes the types of document changes that can occur.
1895
- */
1896
- declare enum DocumentChangeType {
1897
- Created = "created",
1898
- Deleted = "deleted",
1899
- Updated = "updated",
1900
- ParentAdded = "parent_added",
1901
- ParentRemoved = "parent_removed",
1902
- ChildAdded = "child_added",
1903
- ChildRemoved = "child_removed"
1904
- }
1905
- /**
1906
- * Represents a change event for documents.
1907
- */
1908
- type DocumentChangeEvent = {
1909
- type: DocumentChangeType;
1910
- documents: PHDocument[];
1911
- context?: {
1912
- parentId?: string;
1913
- childId?: string;
1914
- };
1915
- };
1916
- /**
1917
- * Options for creating an empty document.
1918
- */
1919
- type CreateDocumentOptions = {
1920
- /** Optional "id" or "slug" of parent document */parentIdentifier?: string; /** Optional version of the document model to use (defaults to latest) */
1921
- documentModelVersion?: number;
1922
- };
1923
- /**
1924
- * Options for upgrading a document.
1925
- */
1926
- type UpgradeDocumentOptions = {
1873
+ clear(): void;
1927
1874
  /**
1928
- * How many times to retry with a fresh read when the executor rejects the
1929
- * upgrade because the document changed after it was read. Defaults to
1930
- * {@link DEFAULT_UPGRADE_CONFLICT_RETRIES}.
1875
+ * Get all supported versions for a document type, sorted in ascending order.
1876
+ *
1877
+ * @param documentType The document type identifier
1878
+ * @returns Array of version numbers sorted ascending
1879
+ * @throws ModuleNotFoundError if no modules are registered for the document type
1931
1880
  */
1932
- maxConflictRetries?: number;
1933
- };
1934
- /**
1935
- * Drive-aware operations grouped under `client.drives`.
1936
- *
1937
- * These methods orchestrate the multi-action, multi-document choreography
1938
- * required to keep a drive's `state.global.nodes` array consistent with the
1939
- * relationship index and the underlying documents. Use the flat
1940
- * `IReactorClient` primitives (`get`, `execute`, `find`) for everything that
1941
- * is not drive-aware.
1942
- */
1943
- interface IDriveClient {
1881
+ getSupportedVersions(documentType: string): number[];
1944
1882
  /**
1945
- * Creates a new drive document and waits for completion.
1883
+ * Get the latest (highest) version number for a document type.
1884
+ *
1885
+ * @param documentType The document type identifier
1886
+ * @returns The highest version number registered for this document type
1887
+ * @throws ModuleNotFoundError if no modules are registered for the document type
1946
1888
  */
1947
- create(input: DriveInput, signal?: AbortSignal): Promise<DocumentDriveDocument>;
1889
+ getLatestVersion(documentType: string): number;
1948
1890
  /**
1949
- * Adds a document to a drive as a single batched operation.
1891
+ * Register upgrade manifests that define upgrade paths between versions.
1892
+ * Invalid or duplicate manifests are skipped without breaking registration of the remaining manifests.
1950
1893
  *
1951
- * Issues CREATE_DOCUMENT, UPGRADE_DOCUMENT, ADD_RELATIONSHIP on the new
1952
- * document and ADD_FILE on the drive in a single dependent batch.
1894
+ * @param manifests Upgrade manifests to register
1895
+ * @returns Array of results, one per manifest, indicating success or failure
1953
1896
  */
1954
- addFile<TDocument extends PHDocument = PHDocument>(driveIdentifier: string, document: PHDocument, parentFolder?: string, signal?: AbortSignal): Promise<TDocument>;
1897
+ registerUpgradeManifests(...manifests: UpgradeManifest<readonly number[]>[]): RegistrationResult<UpgradeManifest<readonly number[]>>[];
1955
1898
  /**
1956
- * Adds a folder node to a drive.
1957
- */
1958
- addFolder(driveIdentifier: string, name: string, parentFolder?: string, signal?: AbortSignal): Promise<FolderNode>;
1899
+ * Unregister upgrade manifests for the specified document types.
1900
+ * @param documentTypes The document types whose upgrade manifests should be unregistered
1901
+ * @returns true if all modules were unregistered, false if any were not found
1902
+ **/
1903
+ unregisterUpgradeManifests(...documentTypes: string[]): boolean;
1959
1904
  /**
1960
- * Removes a node from a drive. Folder nodes cascade: descendant file
1961
- * documents are deleted first, then the folder node entry itself.
1905
+ * Get the upgrade manifest for a document type.
1906
+ *
1907
+ * @param documentType The document type identifier
1908
+ * @returns The upgrade manifest
1909
+ * @throws ManifestNotFoundError if no manifest is registered for the document type
1962
1910
  */
1963
- removeNode(driveIdentifier: string, nodeId: string, signal?: AbortSignal): Promise<void>;
1911
+ getUpgradeManifest(documentType: string): UpgradeManifest<readonly number[]>;
1964
1912
  /**
1965
- * Renames a node. Updates both the underlying document header and the
1966
- * drive's node entry.
1913
+ * Compute the upgrade path from one version to another.
1914
+ * Returns the sequence of upgrade transitions needed.
1915
+ *
1916
+ * @param documentType The document type identifier
1917
+ * @param fromVersion The starting version
1918
+ * @param toVersion The target version
1919
+ * @returns Array of upgrade transitions in order
1920
+ * @throws DowngradeNotSupportedError if toVersion is less than fromVersion
1921
+ * @throws ManifestNotFoundError if no upgrade manifest is registered
1922
+ * @throws MissingUpgradeTransitionError if any transition in the path is missing
1967
1923
  */
1968
- renameNode(driveIdentifier: string, nodeId: string, name: string, signal?: AbortSignal): Promise<Node>;
1924
+ computeUpgradePath(documentType: string, fromVersion: number, toVersion: number): UpgradeTransition[];
1969
1925
  /**
1970
- * Updates the preferred editor recorded in the document header meta for
1971
- * a node. Pass `null` to clear it.
1926
+ * Get the upgrade reducer for a single-step version transition.
1927
+ *
1928
+ * @param documentType The document type identifier
1929
+ * @param fromVersion The starting version
1930
+ * @param toVersion The target version (must be fromVersion + 1)
1931
+ * @returns The upgrade reducer function
1932
+ * @throws InvalidUpgradeStepError if toVersion is not fromVersion + 1
1933
+ * @throws ManifestNotFoundError if no upgrade manifest is registered
1934
+ * @throws MissingUpgradeTransitionError if the transition is not found
1972
1935
  */
1973
- setPreferredEditorOnNode(nodeId: string, preferredEditor: string | null, signal?: AbortSignal): Promise<PHDocument>;
1936
+ getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
1937
+ }
1938
+ //#endregion
1939
+ //#region src/cache/buffer/ring-buffer.d.ts
1940
+ /**
1941
+ * RingBuffer is a generic circular buffer implementation that stores a fixed number
1942
+ * of items. When the buffer is full, new items overwrite the oldest items.
1943
+ *
1944
+ * This implementation maintains O(1) time complexity for push operations and provides
1945
+ * items in chronological order (oldest to newest) via getAll().
1946
+ *
1947
+ * @template T - The type of items stored in the buffer
1948
+ */
1949
+ declare class RingBuffer<T> {
1950
+ private buffer;
1951
+ private head;
1952
+ private size;
1953
+ private capacity;
1954
+ constructor(capacity: number);
1974
1955
  /**
1975
- * Moves a node to a different parent folder within the same drive.
1976
- * Pass `undefined` to move the node to the drive root.
1956
+ * Adds an item to the buffer. If the buffer is full, overwrites the oldest item.
1957
+ *
1958
+ * @param item - The item to add
1977
1959
  */
1978
- moveNode(driveIdentifier: string, srcNodeId: string, targetParentFolderId: string | undefined, signal?: AbortSignal): Promise<DocumentDriveDocument>;
1960
+ push(item: T): void;
1979
1961
  /**
1980
- * Copies a node (and its subtree, if it is a folder) within a drive.
1981
- * Each copied file gets a new id and a duplicated document.
1962
+ * Returns all items in the buffer in chronological order (oldest to newest).
1963
+ *
1964
+ * @returns Array of items in insertion order
1982
1965
  */
1983
- copyNode(driveIdentifier: string, srcNodeId: string, targetParentFolderId: string | undefined, signal?: AbortSignal): Promise<DocumentDriveDocument>;
1966
+ getAll(): T[];
1984
1967
  /**
1985
- * Returns a single node from the drive's `state.global.nodes` array.
1968
+ * Clears all items from the buffer.
1986
1969
  */
1987
- getNode(driveIdentifier: string, nodeId: string, signal?: AbortSignal): Promise<Node>;
1970
+ clear(): void;
1988
1971
  /**
1989
- * Returns nodes in the drive, optionally filtered by parent folder:
1990
- * - omit `parentFolder` (or pass `undefined`) to list every node in the drive.
1991
- * - pass `null` to list only root-level nodes.
1992
- * - pass a folder id to list only the direct children of that folder.
1993
- *
1994
- * Returns a paged result so callers can stream through drives with very
1995
- * large node counts without materialising the whole list in memory.
1972
+ * Gets the current number of items in the buffer.
1996
1973
  */
1997
- listNodes(driveIdentifier: string, parentFolder?: string | null, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Node>>;
1974
+ get length(): number;
1998
1975
  }
1999
- /**
2000
- * One operation an authorization preflight predicts a verdict for. The input is
2001
- * what a conditional grant reads, so a candidate standing for a filled-in form
2002
- * carries that form's input.
2003
- */
2004
- type ActionCandidate = {
2005
- scope: string;
2006
- type: string;
2007
- input?: unknown;
1976
+ //#endregion
1977
+ //#region src/cache/kysely-write-cache.d.ts
1978
+ type DocumentStream = {
1979
+ key: string;
1980
+ ringBuffer: RingBuffer<CachedSnapshot>;
2008
1981
  };
2009
1982
  /**
2010
- * The predicted verdicts for a set of candidates, in the order they were given,
2011
- * with the aggregates a UI branches on.
1983
+ * In-memory write cache with keyframe persistence for PHDocuments.
2012
1984
  *
2013
- * The aggregates are redundant -- a verdict is binary, so `allDenied` is
2014
- * `!anyAllowed` and `anyDenied` is `!allAllowed` -- and all four are returned
2015
- * so that a caller reads the one its question is phrased in rather than
2016
- * negating another. Over no candidates every aggregate is false: nothing is
2017
- * allowed and nothing is denied.
2018
- */
2019
- type ActionEvaluations = {
2020
- evaluations: Evaluation[];
2021
- allAllowed: boolean;
2022
- anyAllowed: boolean;
2023
- allDenied: boolean;
2024
- anyDenied: boolean;
2025
- };
2026
- /**
2027
- * The ReactorClient interface that wraps lower-level APIs to provide
2028
- * a simpler interface for document operations.
1985
+ * Caches document snapshots in ring buffers with LRU eviction. On cache miss,
1986
+ * rebuilds documents from nearest keyframe or full operation history.
2029
1987
  *
2030
- * Features:
2031
- * - Wraps Jobs with Promises for easier async handling
2032
- * - Manages signing of submitted Action objects
2033
- * - Provides quality-of-life functions for common tasks
2034
- * - Wraps subscription interface with ViewFilters
1988
+ * **Performance Characteristics:**
1989
+ * - Cache hit: O(1) lookup in ring buffer
1990
+ * - Cold miss: O(n) where n is total operation count, or O(k) where k is operations since keyframe
1991
+ * - Warm miss: O(m) where m is operations since cached revision
1992
+ * - Eviction: O(1) for LRU tracking and removal
1993
+ *
1994
+ * **Thread Safety:**
1995
+ * Not thread-safe. Designed for single-threaded job executor environment.
1996
+ * External synchronization required for concurrent access across multiple executors.
1997
+ *
1998
+ * **Example:**
1999
+ * ```typescript
2000
+ * const cache = new KyselyWriteCache(
2001
+ * keyframeStore,
2002
+ * operationStore,
2003
+ * registry,
2004
+ * { maxDocuments: 1000, ringBufferSize: 10, keyframeInterval: 10 }
2005
+ * );
2006
+ *
2007
+ * await cache.startup();
2008
+ *
2009
+ * // Retrieve or rebuild document
2010
+ * const doc = await cache.getState(docId, docType, scope, branch, revision);
2011
+ *
2012
+ * // Cache result after job execution
2013
+ * cache.putState(docId, docType, scope, branch, newRevision, updatedDoc);
2014
+ *
2015
+ * await cache.shutdown();
2016
+ * ```
2035
2017
  */
2036
- interface IReactorClient {
2018
+ declare class KyselyWriteCache implements IWriteCache {
2019
+ private streams;
2020
+ private lruTracker;
2021
+ private keyframeStore;
2022
+ private operationStore;
2023
+ private registry;
2024
+ private config;
2025
+ constructor(keyframeStore: IKeyframeStore, operationStore: IOperationStore, registry: IDocumentModelRegistry, config: WriteCacheConfig);
2026
+ withScopedStores(operationStore: IOperationStore, keyframeStore: IKeyframeStore): KyselyWriteCache;
2037
2027
  /**
2038
- * Drive-aware operations. See {@link IDriveClient}.
2028
+ * Initializes the write cache.
2029
+ * Currently a no-op as keyframe store lifecycle is managed externally.
2039
2030
  */
2040
- readonly drives: IDriveClient;
2031
+ startup(): Promise<void>;
2041
2032
  /**
2042
- * Retrieves a list of document model modules.
2043
- *
2044
- * @param namespace - Optional namespace like "powerhouse" or "sky", defaults to ""
2045
- * @param paging - Optional pagination options
2046
- * @param signal - Optional abort signal to cancel the request
2047
- * @returns List of document model modules
2033
+ * Shuts down the write cache.
2034
+ * Currently a no-op as keyframe store lifecycle is managed externally.
2048
2035
  */
2049
- getDocumentModelModules(namespace?: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentModelModule>>;
2036
+ shutdown(): Promise<void>;
2050
2037
  /**
2051
- * Retrieves a specific document model module by document type.
2038
+ * Retrieves document state at a specific revision from cache or rebuilds it.
2052
2039
  *
2053
- * @param documentType - The document type identifier
2054
- * @returns The document model module
2055
- */
2056
- getDocumentModelModule(documentType: string): Promise<DocumentModelModule<any>>;
2057
- /**
2058
- * Retrieves a specific document by identifier (either id or slug).
2040
+ * Note: this returns a _shallow_ copy of the document.
2059
2041
  *
2060
- * @param identifier - Required, this is the document id or slug
2061
- * @param view - Optional filter containing branch and scopes information
2062
- * @param signal - Optional abort signal to cancel the request
2063
- * @returns The up-to-date PHDocument with scopes and list of child document ids
2042
+ * Cache hit path: Returns cached snapshot if available (O(1))
2043
+ * Warm miss path: Rebuilds from cached base revision + incremental ops
2044
+ * Cold miss path: Rebuilds from keyframe or from scratch using all operations
2045
+ *
2046
+ * @param documentId - The document identifier
2047
+ * @param scope - The operation scope
2048
+ * @param branch - The operation branch
2049
+ * @param targetRevision - The target revision, or undefined for newest
2050
+ * @param signal - Optional abort signal to cancel the operation
2051
+ * @returns The document at the target revision
2052
+ * @throws {Error} "Operation aborted" if signal is aborted
2053
+ * @throws {ModuleNotFoundError} If document type not registered in registry
2054
+ * @throws {Error} "Failed to rebuild document" if operation store fails
2055
+ * @throws {Error} If reducer throws during operation application
2056
+ * @throws {Error} If document serialization fails
2064
2057
  */
2065
- get<TDocument extends PHDocument>(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<TDocument>;
2058
+ getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
2066
2059
  /**
2067
- * Resolves an identifier (either an id or a slug) to the canonical document
2068
- * id, using the same lookup as the read/operation data paths. Resolves
2069
- * against the "main" branch. Throws if the identifier cannot be resolved or
2070
- * is ambiguous.
2060
+ * Stores a document snapshot in the cache at a specific revision.
2071
2061
  *
2072
- * @param identifier - Required, this is the document id or slug
2073
- * @param signal - Optional abort signal to cancel the request
2074
- * @returns The canonical document id
2062
+ * The cached document is a shallow copy of the input with its operation history
2063
+ * truncated to the last operation per scope and its clipboard cleared. This keeps
2064
+ * memory use and copy costs constant regardless of operation count. Consumers of
2065
+ * getState() must not rely on the full operation history being present; the only
2066
+ * guaranteed invariant is that operations[scope].at(-1) reflects the latest
2067
+ * operation index for each scope.
2068
+ *
2069
+ * Updates LRU tracker and may evict least recently used stream if at capacity.
2070
+ * Asynchronously persists keyframes at configured intervals (fire-and-forget).
2071
+ *
2072
+ * @param documentId - The document identifier
2073
+ * @param scope - The operation scope
2074
+ * @param branch - The operation branch
2075
+ * @param revision - The revision number
2076
+ * @param document - The document to cache
2077
+ * @throws {Error} If document serialization fails
2075
2078
  */
2076
- resolveIdOrSlug(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<string>;
2077
- /** True when the id is taken; a soft-deleted document's id is still taken. */
2078
- isDocumentIdTaken(documentId: string, signal?: AbortSignal): Promise<boolean>;
2079
+ putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, position: SnapshotPosition): void;
2079
2080
  /**
2080
- * Retrieves operations for a document.
2081
- *
2082
- * @param documentIdentifier - Required, this is either a document "id" field or a "slug"
2083
- * @param view - Optional filter containing branch and scopes information
2084
- * @param filter - Optional filter for actionTypes, timestamps, and revision
2085
- * @param paging - Optional pagination options
2086
- * @param signal - Optional abort signal to cancel the request
2087
- * @returns Paginated list of operations
2081
+ * Stores the run's head and mints a keyframe for every interval the run
2082
+ * crossed on its way there. Only the head enters the ring buffer; the
2083
+ * earlier revisions are keyframe candidates and nothing more.
2088
2084
  */
2089
- getOperations(documentIdentifier: string, view?: ViewFilter, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
2085
+ putRun(documentId: string, scope: string, branch: string, run: readonly {
2086
+ revision: number;
2087
+ document: PHDocument;
2088
+ }[]): void;
2089
+ private store;
2090
+ /** Persists the snapshot if this revision is one the interval falls on. */
2091
+ private persistKeyframe;
2090
2092
  /**
2091
- * Retrieves outgoing relationships of a given type from a source document.
2093
+ * Invalidates cached document streams.
2092
2094
  *
2093
- * @param sourceIdentifier - Required, this is either a document "id" field or a "slug"
2094
- * @param relationshipType - The relationship type to filter by
2095
- * @param view - Optional filter containing branch and scopes information
2096
- * @param paging - Optional pagination options
2097
- * @param signal - Optional abort signal to cancel the request
2098
- * @returns The target documents and paging cursor
2095
+ * Supports three invalidation scopes:
2096
+ * - Document-level: invalidate(documentId) - removes all streams for document
2097
+ * - Scope-level: invalidate(documentId, scope) - removes all branches for scope
2098
+ * - Stream-level: invalidate(documentId, scope, branch) - removes specific stream
2099
+ *
2100
+ * @param documentId - The document identifier
2101
+ * @param scope - Optional scope to narrow invalidation
2102
+ * @param branch - Optional branch to narrow invalidation (requires scope)
2103
+ * @returns The number of streams evicted
2099
2104
  */
2100
- getOutgoingRelationships(sourceIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
2105
+ invalidate(documentId: string, scope?: string, branch?: string): number;
2101
2106
  /**
2102
- * Retrieves incoming relationships of a given type to a target document.
2103
- *
2104
- * @param targetIdentifier - Required, this is either a document "id" field or a "slug"
2105
- * @param relationshipType - The relationship type to filter by
2106
- * @param view - Optional filter containing branch and scopes information
2107
- * @param paging - Optional pagination options
2108
- * @param signal - Optional abort signal to cancel the request
2109
- * @returns The source documents and paging cursor
2107
+ * Clears the entire cache, removing all cached document streams.
2108
+ * Resets LRU tracking state. This operation always succeeds.
2110
2109
  */
2111
- getIncomingRelationships(targetIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
2110
+ clear(): void;
2112
2111
  /**
2113
- * Retrieves the outgoing relationship edges of a source document.
2114
- *
2115
- * Unlike {@link IReactorClient.getOutgoingRelationships}, which returns the
2116
- * documents at the far end, this returns the edges themselves, carrying the
2117
- * metadata and timestamps recorded against each relationship.
2112
+ * Retrieves a specific stream for a document. Exposed on the implementation
2113
+ * for testing, but not on the interface.
2118
2114
  *
2119
- * @param sourceIdentifier - Required, this is either a document "id" field or a "slug"
2120
- * @param relationshipType - Optional relationship type to filter by
2121
- * @param view - Optional filter containing branch and scopes information
2122
- * @param paging - Optional pagination options
2123
- * @param signal - Optional abort signal to cancel the request
2124
- * @returns The matching relationship edges and paging cursor
2115
+ * @internal
2125
2116
  */
2126
- getOutgoingRelationshipEdges(sourceIdentifier: string, relationshipType?: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentRelationship>>;
2117
+ getStream(documentId: string, scope: string, branch: string): DocumentStream | undefined;
2118
+ private findNearestKeyframe;
2127
2119
  /**
2128
- * Retrieves the incoming relationship edges of a target document.
2129
- *
2130
- * Unlike {@link IReactorClient.getIncomingRelationships}, which returns the
2131
- * documents at the far end, this returns the edges themselves, carrying the
2132
- * metadata and timestamps recorded against each relationship.
2120
+ * Rebuilds a scope from a keyframe or from the whole operation history.
2133
2121
  *
2134
- * @param targetIdentifier - Required, this is either a document "id" field or a "slug"
2135
- * @param relationshipType - Optional relationship type to filter by
2136
- * @param view - Optional filter containing branch and scopes information
2137
- * @param paging - Optional pagination options
2138
- * @param signal - Optional abort signal to cancel the request
2139
- * @returns The matching relationship edges and paging cursor
2122
+ * The document scope is always rebuilt first, because it carries the type,
2123
+ * the upgrades and the deletion marker. Its version-changing upgrades are not
2124
+ * applied there though: an upgrade reducer must see the state the requested
2125
+ * scope has reached at that upgrade's boundary, so each one is held back and
2126
+ * applied when the replay below crosses the boundary that
2127
+ * resolveModuleVersionForOp derives from it. Upgrades whose boundary lies past
2128
+ * the last replayed operation are applied at the end. Creation-time 0->N seed
2129
+ * upgrades carry the initial state, so they still apply immediately.
2140
2130
  */
2141
- getIncomingRelationshipEdges(targetIdentifier: string, relationshipType?: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentRelationship>>;
2131
+ private coldMissRebuild;
2142
2132
  /**
2143
- * Filters documents by criteria and returns a list of them
2144
- *
2145
- * @param search - Search filter options (type, parentId, identifiers)
2146
- * @param view - Optional filter containing branch and scopes information
2147
- * @param paging - Optional pagination options
2148
- * @param signal - Optional abort signal to cancel the request
2149
- * @returns List of documents matching criteria and pagination cursor
2133
+ * Applies and removes every held-back upgrade whose target version is at or
2134
+ * below `throughVersion`, in the order the document scope recorded them.
2150
2135
  */
2151
- find(search: SearchFilter, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
2136
+ private applyPendingUpgrades;
2152
2137
  /**
2153
- * Predicts whether the subject would be admitted to execute each of a set of
2154
- * candidate operations, without submitting any of them. A UI asks this to
2155
- * disable a control rather than offer an action that fails on submit.
2156
- *
2157
- * The answer is a prediction, not a promise. Three caveats hold:
2158
- *
2159
- * - Real admission compiles an append condition over everything it read and
2160
- * the store enforces it at write time. A preflight reads no future, so a
2161
- * policy change landing between this answer and the submit changes the
2162
- * verdict. The submit path stays the only authority.
2163
- * - The verdict is evaluated at the stream heads. It is therefore correct for
2164
- * a candidate that will be stamped at or after every timestamp the
2165
- * evaluation read, which is the normal case for a control the user is about
2166
- * to click. A backdated submission is out of contract: the reactor decides
2167
- * that one by position, against the policy as it stood there.
2168
- * - A candidate whose input decides the verdict needs that input supplied.
2169
- * With `authConditions` on, a conditional grant reads `action.input`, so
2170
- * omitting the input predicts the denial an empty input would earn rather
2171
- * than the verdict the filled-in form will get.
2172
- *
2173
- * Document-scope candidates are decided against the policy of the document
2174
- * their input names, not the one passed here: delete and upgrade name it in
2175
- * `input.documentId`, and the relationship actions in `input.sourceId`. This
2176
- * follows the executor's own gate, which decides against the document
2177
- * guarding the write. `CREATE_DOCUMENT` follows the gate's exemption: it runs
2178
- * before its document exists, so the executor never decides it against a
2179
- * policy and the preflight predicts allow.
2180
- *
2181
- * @param documentIdentifier - Document "id" or "slug" the candidates target
2182
- * @param branch - Branch to evaluate against
2183
- * @param candidates - Operations to predict a verdict for, each with the scope it would execute in
2184
- * @param subject - Optional subject to decide for, defaulting to the client's own signer. A plain subject rather than a ViewFilter: the evaluation reads no view, so a filter's branch or scopes would be silently ignored here
2185
- * @param signal - Optional abort signal to cancel the request
2186
- * @returns One evaluation per candidate, in the order given, with the aggregates over them
2187
- * @throws AuthEnforcementDisabledError if the reactor's authEnforcement flag is off, in which case it holds no decision model and the legacy host-table permission system cannot answer for one
2138
+ * Applies the remaining held-back upgrades after the requested scope's
2139
+ * replay has finished. A head read applies them all. A positional read
2140
+ * applies only those whose boundary for this scope lies at or before the
2141
+ * target position: applying a later one would label migrated state with a
2142
+ * pre-upgrade revision, and a keyframe stored from that poisons every
2143
+ * rebuild that resumes from it. Boundaries come from the upgrade's revision
2144
+ * snapshot; an upgrade without one records no position for this scope, and
2145
+ * the replay loop not having crossed it already places it past the target.
2188
2146
  */
2189
- evaluateActions(documentIdentifier: string, branch: string, candidates: ActionCandidate[], subject?: AuthSubject, signal?: AbortSignal): Promise<ActionEvaluations>;
2147
+ private applyTailPendingUpgrades;
2190
2148
  /**
2191
- * Creates a document and waits for completion
2192
- *
2193
- * @param document - Document with optional id, slug, parent, model type, and initial state
2194
- * @param parentIdentifier - Optional "id" or "slug" of parent document
2195
- * @param signal - Optional abort signal to cancel the request
2196
- * @returns The created document
2149
+ * Applies one held-back upgrade, then re-applies the deletes the document
2150
+ * scope recorded after it so the hold-back cannot invert their order.
2197
2151
  */
2198
- create<TDocument extends PHDocument = PHDocument>(document: PHDocument, parentIdentifier?: string, signal?: AbortSignal): Promise<TDocument>;
2152
+ private applyPendingUpgrade;
2199
2153
  /**
2200
- * Creates an empty document and waits for completion
2201
- *
2202
- * @param documentModelType - Type of document to create
2203
- * @param options - Optional creation options (parentIdentifier, documentModelVersion)
2204
- * @param signal - Optional abort signal to cancel the request
2154
+ * Copies the current document revisions onto the document. Overwrites the
2155
+ * requested scope revision with the target revision, if provided.
2205
2156
  */
2206
- createEmpty<TDocument extends PHDocument>(documentModelType: string, options?: CreateDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
2157
+ private stampRevisions;
2158
+ /** The stored operation at `index`, or undefined if it is no longer there. */
2159
+ private operationAt;
2207
2160
  /**
2208
- * Retrieves the document model module matching the version a document is
2209
- * stamped with. Use this instead of {@link getDocumentModelModule}
2210
- * whenever a specific document is in hand: the latest-wins lookup feeds
2211
- * not-yet-upgraded documents the wrong reducer, diverging from replay.
2161
+ * Resolves which module version to use for a given operation in phase 2.
2212
2162
  *
2213
- * @param document - The document whose stamped version selects the module
2214
- * @returns The document model module registered for that version
2215
- * @throws UnsupportedDocumentModelVersionError if no module is registered for the stamped version
2163
+ * Uses the validated-upgrade boundary rules from D7:
2164
+ * - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary
2165
+ * - Otherwise: timestamp fallback
2166
+ * - Falls back to final module version when neither is decidable
2216
2167
  */
2217
- getDocumentModelModuleForDocument(document: PHDocument): Promise<DocumentModelModule<any>>;
2168
+ private resolveModuleVersionForOp;
2169
+ private warmMissRebuild;
2170
+ private findNearestOlderSnapshot;
2171
+ private makeStreamKey;
2172
+ private getOrCreateStream;
2173
+ private isKeyframeRevision;
2174
+ }
2175
+ //#endregion
2176
+ //#region src/storage/kysely/store.d.ts
2177
+ declare class KyselyOperationStore implements IOperationStore {
2178
+ private db;
2179
+ private trx?;
2180
+ constructor(db: Kysely<Database$1>);
2181
+ private get queryExecutor();
2182
+ withTransaction(trx: Transaction<Database$1>): KyselyOperationStore;
2183
+ apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal, condition?: AppendCondition): Promise<Operation[]>;
2184
+ private resolveUniqueConstraint;
2185
+ private executeApply;
2218
2186
  /**
2219
- * Upgrades a document to a newer document model version by dispatching an
2220
- * UPGRADE_DOCUMENT action. When toVersion is omitted, upgrades to the
2221
- * latest registered module version for the document's type. Returns the
2222
- * document unchanged when it is already at the target version.
2223
- *
2224
- * The action carries a snapshot of the document's version and per-scope
2225
- * revisions, which the executor validates before persisting. When an edit
2226
- * lands between the read and the upgrade executing, the upgrade is
2227
- * rejected and retried with a fresh read up to
2228
- * {@link UpgradeDocumentOptions.maxConflictRetries} times before the
2229
- * conflict is surfaced.
2230
- *
2231
- * @param documentIdentifier - Target document id or slug
2232
- * @param toVersion - Optional target document model version; defaults to latest
2233
- * @param options - Optional upgrade options (maxConflictRetries)
2234
- * @param signal - Optional abort signal to cancel the request
2235
- * @returns The upgraded document
2236
- * @throws DowngradeNotSupportedError if toVersion is less than the document's current version
2187
+ * Locks the written stream and every read-set stream, in sorted key order
2188
+ * so that overlapping concurrent appends serialize rather than deadlock.
2189
+ * The locks are still taken one row at a time, so the query preserves that
2190
+ * order. It must stay separate from the guarded insert, which would
2191
+ * otherwise read a snapshot taken before the locks were held.
2237
2192
  */
2238
- upgradeDocument<TDocument extends PHDocument = PHDocument>(documentIdentifier: string, toVersion?: number, options?: UpgradeDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
2193
+ private acquireStreamLocks;
2239
2194
  /**
2240
- * Creates an empty document in a drive as a single batched operation.
2241
- * This is more efficient than createEmpty + addFile as it batches all
2242
- * actions into dependent jobs and waits for them to complete together.
2243
- *
2244
- * @deprecated Use {@link IDriveClient.addFile} via `client.drives.addFile`
2245
- * instead. This method will be removed in a future release.
2246
- * @param driveId - The drive document id or slug
2247
- * @param document - The document to create
2248
- * @param parentFolder - Optional folder id within the drive
2249
- * @param signal - Optional abort signal to cancel the request
2250
- * @returns The created document
2195
+ * Inserts the staged operations with the condition compiled in as a WHERE
2196
+ * NOT EXISTS guard, making the check and the append one statement. Returns
2197
+ * the rows inserted; zero means the guard failed and nothing was written.
2251
2198
  */
2252
- createDocumentInDrive<TDocument extends PHDocument>(driveId: string, document: PHDocument, parentFolder?: string, signal?: AbortSignal): Promise<TDocument>;
2199
+ private insertGuarded;
2200
+ private findIdempotentReplay;
2201
+ /** True when the staged write creates a document rather than appending to one. */
2202
+ private isCreate;
2253
2203
  /**
2254
- * Applies a list of actions to a document and waits for completion
2255
- *
2256
- * The document handed back is a read like any other, so it goes through the
2257
- * read gate. `subject` names who that read is for, the same way
2258
- * {@link ViewFilter.subject} does on `get` and `find`; a host that shares one
2259
- * client across many callers has no meaningful signer to fall back to, and
2260
- * without it the gate would strip the domain scopes of a policied document
2261
- * and resolve with a husk whose `state.global` is absent — reading as a
2262
- * rejected write when the write in fact succeeded.
2263
- *
2264
- * @param documentIdentifier - Target document id or slug
2265
- * @param branch - Branch to apply actions to
2266
- * @param actions - List of actions to apply
2267
- * @param signal - Optional abort signal to cancel the request
2268
- * @param subject - Optional read subject for the returned document; defaults
2269
- * to the client's signer
2270
- * @returns The updated document
2204
+ * The paging cursor here encodes the index to resume from (one past the
2205
+ * last row returned), not the last row's own index. This keeps "0" an
2206
+ * unambiguous start-of-stream sentinel even when a page ends at index 0
2207
+ * (e.g. `limit: 1` on a fresh stream), which would otherwise make
2208
+ * `nextCursor` equal the start cursor and loop a caller that walks pages
2209
+ * forever.
2271
2210
  */
2272
- execute<TDocument extends PHDocument>(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal, subject?: AuthSubject): Promise<TDocument>;
2211
+ getSince(documentId: string, scope: string, branch: string, revision: number, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
2212
+ getSinceId(id: number, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<OperationWithContext$1>>;
2273
2213
  /**
2274
- * Submits a list of actions to a document
2275
- *
2276
- * @param documentIdentifier - Target document id or slug
2277
- * @param branch - Branch to apply actions to
2278
- * @param actions - List of actions to apply
2279
- * @param signal - Optional abort signal to cancel the request
2280
- * @returns The job
2214
+ * The paging cursor here encodes the index to resume from (one past the
2215
+ * last row returned), not the last row's own index, for the same reason as
2216
+ * `getSince`: a page ending at index 0 must not produce a cursor that is
2217
+ * indistinguishable from the start-of-stream sentinel.
2281
2218
  */
2282
- executeAsync(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal): Promise<JobInfo>;
2219
+ getConflicting(documentId: string, scope: string, branch: string, minTimestamp: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
2220
+ getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
2221
+ getStreamLatestTimestamp(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
2222
+ findOperationIds(documentId: string, scope: string, branch: string, opIds: string[], signal?: AbortSignal): Promise<Set<string>>;
2223
+ getOperationsByIds(documentId: string, scope: string, branch: string, opIds: string[], signal?: AbortSignal): Promise<Operation[]>;
2224
+ private rowToOperation;
2225
+ private rowToOperationWithContext;
2226
+ }
2227
+ //#endregion
2228
+ //#region src/storage/kysely/keyframe-store.d.ts
2229
+ declare class KyselyKeyframeStore implements IKeyframeStore {
2230
+ private db;
2231
+ private trx?;
2232
+ constructor(db: Kysely<Database$1>);
2233
+ private get queryExecutor();
2234
+ withTransaction(trx: Transaction<Database$1>): KyselyKeyframeStore;
2235
+ putKeyframe(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, signal?: AbortSignal): Promise<void>;
2236
+ findNearestKeyframe(documentId: string, scope: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<{
2237
+ revision: number;
2238
+ document: PHDocument;
2239
+ } | undefined>;
2240
+ listKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<Array<{
2241
+ scope: string;
2242
+ branch: string;
2243
+ revision: number;
2244
+ document: PHDocument;
2245
+ }>>;
2246
+ deleteKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<number>;
2247
+ }
2248
+ //#endregion
2249
+ //#region src/executor/execution-scope.d.ts
2250
+ interface ExecutionStores {
2251
+ operationStore: IOperationStore;
2252
+ operationIndex: IOperationIndex;
2253
+ writeCache: IWriteCache;
2254
+ documentMetaCache: IDocumentMetaCache;
2255
+ collectionMembershipCache: ICollectionMembershipCache;
2256
+ }
2257
+ interface IExecutionScope {
2258
+ run<T>(fn: (stores: ExecutionStores) => Promise<T>, signal?: AbortSignal): Promise<T>;
2259
+ }
2260
+ //#endregion
2261
+ //#region src/executor/types.d.ts
2262
+ /**
2263
+ * Represents the result of a job execution
2264
+ */
2265
+ type JobResult = {
2266
+ /** The job that was executed */job: Job; /** Whether the job executed successfully */
2267
+ success: boolean; /** Error if the job failed */
2268
+ error?: Error; /** The operations generated from the actions (if successful) */
2269
+ operations?: Operation[];
2283
2270
  /**
2284
- * Applies multiple mutation jobs in dependency order and waits for all to
2285
- * complete. Actions on each job are signed by the client signer before
2286
- * dispatch. Throws on the first failed job; the others may still execute
2287
- * because dispatch is fire-and-await-all.
2288
- *
2289
- * @param request - Batch mutation request with per-job actions and dependsOn keys
2290
- * @param signal - Optional abort signal to cancel the request
2291
- * @returns The completed batch result (job ids keyed by plan key)
2271
+ * Operations with context (includes ephemeral resultingState).
2272
+ * Used for emitting to IDocumentView via event bus.
2292
2273
  */
2293
- executeBatch(request: BatchExecutionRequest, signal?: AbortSignal): Promise<BatchExecutionResult>;
2274
+ operationsWithContext?: OperationWithContext$1[]; /** Timestamp when the job execution completed */
2275
+ completedAt?: string; /** Duration of job execution in milliseconds */
2276
+ duration?: number; /** Any additional metadata from the execution */
2277
+ metadata?: Record<string, any>;
2278
+ };
2279
+ /**
2280
+ * Enforcement the reactor performs, each off by default.
2281
+ *
2282
+ * An evaluation made while replaying is part of the document's history, so two
2283
+ * reactors that share documents and disagree on these diverge. A flag is turned
2284
+ * on for a set of reactors that sync with each other, not for one node.
2285
+ */
2286
+ type ReactorFeatureFlags = {
2294
2287
  /**
2295
- * Renames a document and waits for completion
2296
- *
2297
- * @param documentIdentifier - Target document id or slug
2298
- * @param name - The new name of the document
2299
- * @param branch - Optional branch to rename the document, defaults to "main"
2300
- * @param signal - Optional abort signal to cancel the request
2301
- * @returns The updated document.
2302
- */
2303
- rename(documentIdentifier: string, name: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
2304
- /**
2305
- * Updates the preferred editor in the document header meta and waits for completion.
2306
- *
2307
- * @param documentIdentifier - Target document id or slug
2308
- * @param preferredEditor - The new preferred editor, or `null` to clear it
2309
- * @param branch - Optional branch, defaults to "main"
2310
- * @param signal - Optional abort signal to cancel the request
2311
- * @returns The updated document.
2312
- */
2313
- setPreferredEditor(documentIdentifier: string, preferredEditor: string | null, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
2314
- /**
2315
- * Adds a relationship between two documents and waits for completion.
2316
- *
2317
- * Adding a relationship that already exists is a no-op, metadata included.
2318
- * Use {@link IReactorClient.updateRelationship} to change an existing edge.
2319
- *
2320
- * @param sourceIdentifier - Source document id or slug
2321
- * @param targetIdentifier - Target document id or slug
2322
- * @param relationshipType - Relationship type identifier
2323
- * @param metadata - Optional metadata to attach to the relationship
2324
- * @param branch - Optional branch to add the relationship to, defaults to "main"
2325
- * @param signal - Optional abort signal to cancel the request
2326
- * @returns The updated source document
2327
- */
2328
- addRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, metadata?: Record<string, unknown>, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
2329
- /**
2330
- * Replaces the metadata of an existing relationship and waits for completion.
2331
- * The relationship's createdAt is preserved.
2332
- *
2333
- * @param sourceIdentifier - Source document id or slug
2334
- * @param targetIdentifier - Target document id or slug
2335
- * @param relationshipType - Relationship type identifier
2336
- * @param metadata - The metadata to store; null clears it
2337
- * @param branch - Optional branch holding the relationship, defaults to "main"
2338
- * @param signal - Optional abort signal to cancel the request
2339
- * @returns The updated source document
2340
- */
2341
- updateRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, metadata: Record<string, unknown> | null, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
2342
- /**
2343
- * Removes a relationship between two documents and waits for completion.
2344
- *
2345
- * @param sourceIdentifier - Source document id or slug
2346
- * @param targetIdentifier - Target document id or slug
2347
- * @param relationshipType - Relationship type identifier
2348
- * @param branch - Optional branch to remove the relationship from, defaults to "main"
2349
- * @param signal - Optional abort signal to cancel the request
2350
- * @returns The updated source document
2351
- */
2352
- removeRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
2353
- /**
2354
- * Moves a relationship from one source document to another and waits for completion.
2355
- *
2356
- * @param sourceParentIdentifier - Source parent document id or slug
2357
- * @param targetParentIdentifier - Target parent document id or slug
2358
- * @param targetIdentifier - The target document id or slug
2359
- * @param relationshipType - Relationship type identifier
2360
- * @param branch - Optional branch to apply the move to, defaults to "main"
2361
- * @param signal - Optional abort signal to cancel the request
2362
- * @returns The updated source and target documents
2288
+ * Decide whether an operation may be admitted by building a decision model
2289
+ * over the document stream, rather than reading the deleted flag from the
2290
+ * document meta cache. Deletion then takes effect from the deleting
2291
+ * operation's position rather than for the whole document.
2363
2292
  */
2364
- moveRelationship(sourceParentIdentifier: string, targetParentIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<{
2365
- source: PHDocument;
2366
- target: PHDocument;
2367
- }>;
2293
+ documentDecisions: boolean;
2368
2294
  /**
2369
- * Deletes a document and waits for completion
2370
- *
2371
- * @param identifier - Document identifier (id or slug)
2372
- * @param propagate - Optional mode for handling children, CASCADE deletes child documents
2373
- * @param signal - Optional abort signal to cancel the request
2374
- * @returns a promise, resolving on deletion confirmation
2295
+ * Evaluate the auth policy by reading the auth scope as a second projection.
2296
+ * Requires documentDecisions.
2375
2297
  */
2376
- deleteDocument(identifier: string, propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
2298
+ authEnforcement: boolean;
2377
2299
  /**
2378
- * Deletes documents and waits for completion
2379
- *
2380
- * @param identifiers - Document identifiers (ids or slugs)
2381
- * @param propagate - Optional mode for handling children, CASCADE deletes child documents
2382
- * @param signal - Optional abort signal to cancel the request
2383
- * @returns a promise, resolving on deletion confirmation
2300
+ * Match { group } principals by folding the referenced PHGroup documents as
2301
+ * derived projections. Requires authEnforcement.
2384
2302
  */
2385
- deleteDocuments(identifiers: string[], propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
2303
+ authGroups: boolean;
2386
2304
  /**
2387
- * Loads multiple batches of pre-existing operations across documents with dependency management.
2388
- * Waits for all jobs to complete.
2389
- *
2390
- * @param request - Batch load request containing jobs with dependencies
2391
- * @param signal - Optional abort signal to cancel the request
2392
- * @returns Map of job keys to completed job information
2305
+ * Evaluate `where` clauses and { match } principals against the executing
2306
+ * scope's state, the subject, and the action input. Requires authGroups.
2393
2307
  */
2394
- loadBatch(request: BatchLoadRequest, signal?: AbortSignal): Promise<BatchLoadResult>;
2308
+ authConditions: boolean;
2309
+ };
2310
+ /**
2311
+ * Configuration options for the job executor
2312
+ */
2313
+ type JobExecutorConfig = {
2314
+ /** Feature flags; anything unset is off. */featureFlags?: Partial<ReactorFeatureFlags>; /** Maximum number of conflicting operations to skip when reshuffling. */
2315
+ maxSkipThreshold?: number; /** Maximum number of concurrent jobs to execute */
2316
+ maxConcurrency?: number; /** Maximum time in milliseconds a job can run before being considered timed out */
2317
+ jobTimeoutMs?: number;
2318
+ /** How long a job whose document is missing waits for it before failing.
2319
+ * Unbounded deferral never resolves the caller awaiting the job. */
2320
+ deferredJobTtlMs?: number; /** Base delay in milliseconds for exponential backoff retries */
2321
+ retryBaseDelayMs?: number; /** Maximum delay in milliseconds for exponential backoff retries */
2322
+ retryMaxDelayMs?: number;
2323
+ /** Maximum elapsed milliseconds before yielding to the main thread between actions.
2324
+ * Keeps the UI responsive when processing large batches. */
2325
+ yieldDeadlineMs?: number;
2395
2326
  /**
2396
- * Retrieves the status of a job
2327
+ * Persist a job's writes in one store transaction rather than one each.
2397
2328
  *
2398
- * @param jobId - The job id
2399
- * @param signal - Optional abort signal to cancel the request
2400
- * @returns The job status
2401
- */
2402
- getJobStatus(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
2403
- /**
2404
- * Waits for a job to complete
2329
+ * On by default. A job's operations are reduced sequentially either way; this
2330
+ * only changes how many apply calls carry them, which is one advisory lock
2331
+ * and one guarded insert per batch instead of per operation. Only runs that
2332
+ * qualify are batched, and the executor falls back per write for the rest, so
2333
+ * this never changes which operations are produced -- only how many
2334
+ * transactions they arrive in.
2405
2335
  *
2406
- * @param jobId - The job id or job object
2407
- * @param signal - Optional abort signal to cancel the request
2408
- * @returns The result of the job
2336
+ * Atomicity is not one of the things it changes. A job either fully applies
2337
+ * or leaves nothing durable behind regardless of this setting, because the
2338
+ * whole job runs inside the execution scope's transaction and a failure
2339
+ * rolls it back.
2340
+ * That guarantee belongs to KyselyExecutionScope, which backs both Postgres
2341
+ * and PGlite; DefaultExecutionScope opens no transaction and is used only by
2342
+ * unit-test harnesses, which therefore see writes survive a failed job.
2409
2343
  */
2410
- waitForJob(jobId: string | JobInfo, signal?: AbortSignal): Promise<JobInfo>;
2344
+ batchApplies?: boolean; /** Defaults to `enforce`; `log` counts refusals and admits the write. */
2345
+ signatureVerification?: SignatureVerificationMode;
2346
+ };
2347
+ /**
2348
+ * Event types for the job executor
2349
+ */
2350
+ declare const JobExecutorEventTypes: {
2351
+ readonly JOB_STARTED: 20000;
2352
+ readonly JOB_COMPLETED: 20001;
2353
+ readonly JOB_FAILED: 20002;
2354
+ readonly EXECUTOR_STARTED: 20003;
2355
+ readonly EXECUTOR_STOPPED: 20004;
2356
+ };
2357
+ /**
2358
+ * Event data for job execution events
2359
+ */
2360
+ type JobStartedEvent = {
2361
+ job: Job;
2362
+ startedAt: string;
2411
2363
  /**
2412
- * Subscribes to changes for documents matching specified filters
2413
- *
2414
- * @param search - Search filter options (type, parentId, identifiers)
2415
- * @param callback - Function called when documents change with the change event details
2416
- * @param view - Optional filter containing branch and scopes information
2417
- * @returns A function that unsubscribes from the changes
2364
+ * Identifier of the executor that took the job. For the worker pool this is
2365
+ * the thread-worker id (e.g. "reactor-worker-3"); for the in-process simple
2366
+ * manager it is "in-process-<index>". Optional for backwards compatibility
2367
+ * with consumers built before the field was added.
2418
2368
  */
2419
- subscribe(search: SearchFilter, callback: (event: DocumentChangeEvent) => void, view?: ViewFilter): () => void;
2420
- }
2421
- //#endregion
2422
- //#region src/cache/collection-membership-cache.d.ts
2423
- interface ICollectionMembershipCache {
2424
- getCollectionsForDocuments(documentIds: string[]): Promise<Record<string, string[]>>;
2425
- invalidate(documentId: string): void;
2426
- }
2369
+ workerId?: string;
2370
+ };
2371
+ type JobCompletedEvent = {
2372
+ job: Job;
2373
+ result: JobResult; /** See {@link JobStartedEvent.workerId}. */
2374
+ workerId?: string;
2375
+ };
2376
+ type JobFailedEvent = {
2377
+ job: Job;
2378
+ error: string;
2379
+ willRetry: boolean;
2380
+ retryCount: number; /** See {@link JobStartedEvent.workerId}. */
2381
+ workerId?: string;
2382
+ };
2383
+ type ExecutorStartedEvent = {
2384
+ config: JobExecutorConfig;
2385
+ startedAt: string;
2386
+ };
2387
+ type ExecutorStoppedEvent = {
2388
+ stoppedAt: string;
2389
+ graceful: boolean;
2390
+ };
2391
+ /**
2392
+ * Status information for the job executor manager
2393
+ */
2394
+ type ExecutorManagerStatus = {
2395
+ /** Whether the manager is currently running */isRunning: boolean; /** Number of executor instances managed */
2396
+ numExecutors: number; /** Number of jobs currently being processed */
2397
+ activeJobs: number; /** Total number of jobs processed since start */
2398
+ totalJobsProcessed: number;
2399
+ };
2427
2400
  //#endregion
2428
- //#region src/cache/document-meta-cache-types.d.ts
2401
+ //#region src/executor/worker/protocol.d.ts
2429
2402
  /**
2430
- * Cached document metadata from the "document" scope.
2403
+ * A JSON-clonable value safe to send across the worker IPC boundary.
2431
2404
  *
2432
- * This lightweight structure holds essential document information needed by
2433
- * the job executor without fetching full scope state. It provides an explicit
2434
- * cross-scope contract for accessing document scope metadata.
2405
+ * The shape mirrors the structured-clone subset used by the parent's
2406
+ * sanitizer: primitives, arrays, plain objects, plus the explicit
2407
+ * {@link ErrorInfo} shape for marshalled Errors.
2408
+ *
2409
+ * @see Wire Protocol Reference wiki page
2410
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2435
2411
  */
2436
- type CachedDocumentMeta = {
2437
- /**
2438
- * The full PHDocumentState from document.state.document.
2439
- * Contains version, hash, isDeleted, deletedAtUtcIso, etc.
2440
- */
2441
- state: PHDocumentState;
2442
- /**
2443
- * The document type (from header), cached for convenience.
2444
- */
2445
- documentType: string;
2446
- /**
2447
- * The revision of the document scope when this metadata was captured.
2448
- * Used for cache invalidation and consistency checks.
2449
- */
2450
- documentScopeRevision: number;
2412
+ type SanitizedArg = null | boolean | number | string | ErrorInfo | SanitizedArg[] | {
2413
+ [key: string]: SanitizedArg;
2451
2414
  };
2452
2415
  /**
2453
- * Interface for the document metadata cache.
2416
+ * Structured representation of an Error for IPC transport.
2454
2417
  *
2455
- * This cache provides an explicit cross-scope contract for accessing document
2456
- * scope metadata. It solves the problem where job execution in one scope (e.g.,
2457
- * "global") needs access to document scope state (version, isDeleted, etc.)
2458
- * which may be stale in scope-specific caches or keyframes.
2418
+ * Class instances cannot be structured-cloned across worker boundaries,
2419
+ * so Errors are flattened into this shape on the worker side and
2420
+ * reconstructed on the parent side.
2459
2421
  *
2460
- * The cache supports:
2461
- * - Latest metadata retrieval with LRU caching
2462
- * - Historical metadata reconstruction for reshuffling scenarios
2463
- * - Eager updates after document scope operations
2422
+ * @see Wire Protocol Reference wiki page
2423
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2464
2424
  */
2465
- interface IDocumentMetaCache {
2466
- /**
2467
- * Retrieves the LATEST document metadata from cache or rebuilds from operations.
2468
- *
2469
- * On cache miss, fetches all document scope operations and reconstructs the
2470
- * current PHDocumentState by applying UPGRADE_DOCUMENT and DELETE_DOCUMENT
2471
- * operations.
2472
- *
2473
- * @param documentId - The document identifier
2474
- * @param branch - Branch name
2475
- * @param signal - Optional abort signal to cancel the operation
2476
- * @returns The cached or rebuilt document metadata
2477
- * @throws {Error} "Operation aborted" if signal is aborted
2478
- * @throws {Error} If document not found (no CREATE_DOCUMENT operation)
2479
- */
2480
- getDocumentMeta(documentId: string, branch: string, signal?: AbortSignal): Promise<CachedDocumentMeta>;
2481
- /**
2482
- * Rebuilds document metadata at a SPECIFIC revision (always rebuilds, no caching).
2483
- *
2484
- * Used during reshuffling when operations need to be inserted at a previous
2485
- * revision and we need the document scope state as of that point in time.
2486
- *
2487
- * @param documentId - The document identifier
2488
- * @param branch - Branch name
2489
- * @param targetRevision - The document scope revision to reconstruct up to
2490
- * @param signal - Optional abort signal to cancel the operation
2491
- * @returns Document metadata as of the target revision
2492
- * @throws {Error} "Operation aborted" if signal is aborted
2493
- * @throws {Error} If document not found
2494
- */
2495
- rebuildAtRevision(documentId: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<CachedDocumentMeta>;
2496
- /**
2497
- * Eagerly updates cached metadata after document scope operations.
2498
- *
2499
- * Called by the job executor after CREATE_DOCUMENT, UPGRADE_DOCUMENT, or
2500
- * DELETE_DOCUMENT operations to keep the cache current.
2501
- *
2502
- * @param documentId - The document identifier
2503
- * @param branch - Branch name
2504
- * @param meta - The new metadata to cache
2505
- */
2506
- putDocumentMeta(documentId: string, branch: string, meta: CachedDocumentMeta): void;
2507
- /**
2508
- * Invalidates cached document metadata.
2509
- *
2510
- * Call before reshuffling operations that modify the document scope, or
2511
- * when document state may have changed externally.
2512
- *
2513
- * @param documentId - The document identifier
2514
- * @param branch - Optional branch to narrow invalidation (if omitted, all branches)
2515
- * @returns Number of entries invalidated
2516
- */
2517
- invalidate(documentId: string, branch?: string): number;
2518
- /**
2519
- * Clears all cached document metadata.
2520
- */
2521
- clear(): void;
2425
+ type ErrorInfo = {
2426
+ name: string;
2427
+ message: string;
2428
+ stack?: string;
2429
+ cause?: ErrorInfo;
2430
+ };
2431
+ /**
2432
+ * Reference to a module that the worker should `import()` at runtime,
2433
+ * along with the named export to pluck out as the factory.
2434
+ *
2435
+ * Exactly one of `packageName` or `filePath` is provided.
2436
+ *
2437
+ * @see Wire Protocol Reference wiki page
2438
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2439
+ */
2440
+ type ModuleRef = {
2441
+ /** Bare-specifier package name (resolved by the worker's module loader). */packageName: string; /** Named export within the module to invoke as the factory. */
2442
+ exportName: string;
2443
+ } | {
2444
+ /** Absolute or worker-resolvable file path to import. */filePath: string; /** Named export within the module to invoke as the factory. */
2445
+ exportName: string;
2446
+ };
2447
+ /**
2448
+ * Factory specification shared by the signer, trust policy and document
2449
+ * model spec channels. The worker imports `module.exportName` and invokes
2450
+ * it with `initArgs` to obtain the actual instance.
2451
+ *
2452
+ * `initArgs` must be JSON-clonable.
2453
+ *
2454
+ * @see Wire Protocol Reference wiki page
2455
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2456
+ */
2457
+ type FactorySpec = {
2458
+ module: ModuleRef;
2459
+ initArgs?: SanitizedArg;
2460
+ };
2461
+ /**
2462
+ * Factory spec for a document model module the worker should instantiate.
2463
+ *
2464
+ * Structurally identical to {@link FactorySpec}; the alias exists so call
2465
+ * sites read intent-fully.
2466
+ *
2467
+ * @see Wire Protocol Reference wiki page
2468
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2469
+ */
2470
+ type DocumentModelSpec = FactorySpec;
2471
+ /**
2472
+ * One entry in the document model manifest the worker materializes on
2473
+ * startup (or extends lazily via `load-model`).
2474
+ *
2475
+ * @see Wire Protocol Reference wiki page
2476
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2477
+ */
2478
+ type ModelManifestEntry = {
2479
+ /** Document type identifier (e.g. "ph/account"). */documentType: string; /** Document model version this entry registers. */
2480
+ version: string; /** Factory spec the worker imports and invokes to obtain the model. */
2481
+ spec: DocumentModelSpec;
2482
+ };
2483
+ /**
2484
+ * JSON-clonable Postgres connection info passed to the worker so it can
2485
+ * open its own pool. Storage-specific wiring may extend this shape in
2486
+ * later phases.
2487
+ *
2488
+ * @see Wire Protocol Reference wiki page
2489
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2490
+ */
2491
+ type DbConfig = {
2492
+ host: string;
2493
+ port: number;
2494
+ database: string;
2495
+ user: string;
2496
+ password: string;
2497
+ ssl?: boolean;
2498
+ applicationName?: string;
2499
+ poolSize?: number;
2522
2500
  /**
2523
- * Performs startup initialization.
2501
+ * Maximum time (ms) a caller will wait to acquire a connection from the
2502
+ * pool before pg.Pool throws. When omitted, pg defaults to 0 (unlimited
2503
+ * wait), which hides acquire-starvation as silent latency.
2524
2504
  */
2525
- startup(): Promise<void>;
2505
+ connectionTimeoutMillis?: number;
2526
2506
  /**
2527
- * Performs graceful shutdown.
2507
+ * How long (ms) an idle connection stays open before pg closes it. When
2508
+ * omitted, pg defaults to 10000.
2528
2509
  */
2529
- shutdown(): Promise<void>;
2530
- }
2531
- //#endregion
2532
- //#region src/storage/kysely/types.d.ts
2533
- interface OperationTable {
2534
- id: Generated<number>;
2535
- jobId: string;
2536
- opId: string;
2537
- prevOpId: string;
2538
- writeTimestampUtcMs: Generated<Date>;
2539
- documentId: string;
2540
- documentType: string;
2541
- scope: string;
2542
- branch: string;
2543
- timestampUtcMs: Date;
2544
- index: number;
2545
- action: unknown;
2546
- skip: number;
2547
- error?: string | null;
2548
- deniedReason?: string | null;
2549
- hash: string;
2550
- }
2551
- interface KeyframeTable {
2552
- id: Generated<number>;
2553
- documentId: string;
2554
- documentType: string;
2555
- scope: string;
2556
- branch: string;
2557
- revision: number;
2558
- document: unknown;
2559
- createdAt: Generated<Date>;
2560
- }
2561
- interface DocumentCollectionTable {
2562
- documentId: string;
2563
- collectionId: string;
2564
- joinedOrdinal: bigint;
2565
- leftOrdinal: bigint | null;
2566
- }
2567
- interface OperationIndexOperationTable {
2568
- ordinal: Generated<number>;
2569
- opId: string;
2570
- documentId: string;
2571
- documentType: string;
2572
- scope: string;
2573
- branch: string;
2574
- timestampUtcMs: string;
2575
- writeTimestampUtcMs: Generated<Date>;
2576
- index: number;
2577
- skip: number;
2578
- hash: string;
2579
- action: unknown;
2580
- deniedReason?: string | null;
2581
- sourceRemote: Generated<string>;
2582
- }
2583
- interface SyncRemoteTable {
2584
- name: string;
2585
- collection_id: string;
2586
- channel_type: string;
2587
- channel_id: string;
2588
- remote_name: string;
2589
- channel_parameters: unknown;
2590
- filter_document_ids: unknown;
2591
- filter_scopes: unknown;
2592
- filter_branch: string;
2593
- push_state: string;
2594
- push_last_success_utc_ms: string | null;
2595
- push_last_failure_utc_ms: string | null;
2596
- push_failure_count: number;
2597
- pull_state: string;
2598
- pull_last_success_utc_ms: string | null;
2599
- pull_last_failure_utc_ms: string | null;
2600
- pull_failure_count: number;
2601
- bound_address: string | null;
2602
- created_at: Generated<Date>;
2603
- updated_at: Generated<Date>;
2604
- }
2605
- interface SyncCursorTable {
2606
- remote_name: string;
2607
- cursor_type: string;
2608
- cursor_ordinal: bigint;
2609
- last_synced_at_utc_ms: string | null;
2610
- updated_at: Generated<Date>;
2611
- }
2510
+ idleTimeoutMillis?: number;
2511
+ };
2612
2512
  /**
2613
- * Kysely table definition for the `sync_dead_letters` table.
2513
+ * Configuration for the executor worker pool.
2514
+ *
2515
+ * Mirrors the `workerPool` sub-config on {@link JobExecutorConfig};
2516
+ * a later card wires this into the executor config.
2517
+ *
2518
+ * @see Wire Protocol Reference wiki page
2519
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2614
2520
  */
2615
- interface SyncDeadLetterTable {
2616
- ordinal: Generated<number>;
2617
- id: string;
2618
- job_id: string;
2619
- job_dependencies: unknown;
2620
- remote_name: string;
2621
- document_id: string;
2622
- scopes: unknown;
2623
- branch: string;
2624
- operations: unknown;
2625
- error_source: string;
2626
- error_message: string;
2627
- error_type: Generated<string>;
2628
- created_at: Generated<Date>;
2629
- }
2521
+ type WorkerPoolConfig = {
2522
+ /** Whether the worker pool is active; when false the executor runs in-process. */enabled: boolean; /** Number of worker instances to spawn. */
2523
+ numWorkers: number; /** Worker isolation mode. */
2524
+ workerType: "thread" | "process"; /** Optional heartbeat interval in milliseconds. */
2525
+ heartbeatMs?: number; /** Optional per-worker Postgres pool size override. */
2526
+ workerPgPoolSize?: number;
2527
+ };
2630
2528
  /**
2631
- * One (document, group) reference ever discovered from an auth operation's
2632
- * input. Rows are never updated or deleted (see migration 017).
2529
+ * Payload the worker reports back when a job's write phase is complete.
2530
+ *
2531
+ * Parent fills `collectionMemberships` at emission time, so it is
2532
+ * intentionally absent from the worker -> parent message.
2533
+ *
2534
+ * @see Wire Protocol Reference wiki page
2535
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2633
2536
  */
2634
- interface GroupReferenceTable {
2635
- documentId: string;
2636
- groupId: string;
2637
- }
2638
- interface Database$1 {
2639
- Operation: OperationTable;
2640
- Keyframe: KeyframeTable;
2641
- document_collections: DocumentCollectionTable;
2642
- operation_index_operations: OperationIndexOperationTable;
2643
- group_references: GroupReferenceTable;
2644
- sync_remotes: SyncRemoteTable;
2645
- sync_cursors: SyncCursorTable;
2646
- sync_dead_letters: SyncDeadLetterTable;
2647
- }
2648
- interface DocumentTable {
2649
- id: string;
2650
- createdAt: Generated<Date>;
2651
- updatedAt: Generated<Date>;
2652
- }
2653
- interface DocumentRelationshipTable {
2654
- id: Generated<string>;
2655
- sourceId: string;
2656
- targetId: string;
2657
- relationshipType: string;
2658
- metadata: unknown;
2659
- createdAt: Generated<Date>;
2660
- updatedAt: Generated<Date>;
2661
- }
2662
- interface IndexerStateTable {
2663
- id: Generated<number>;
2664
- lastOperationId: number;
2665
- lastOperationTimestamp: Generated<Date>;
2666
- }
2667
- interface DocumentIndexerDatabase {
2668
- Document: DocumentTable;
2669
- DocumentRelationship: DocumentRelationshipTable;
2670
- IndexerState: IndexerStateTable;
2671
- }
2672
- //#endregion
2673
- //#region src/executor/worker/protocol.d.ts
2537
+ type JobWriteReadyPayload = {
2538
+ operations: OperationWithContext$1[];
2539
+ jobMeta: JobMeta;
2540
+ };
2674
2541
  /**
2675
- * A JSON-clonable value safe to send across the worker IPC boundary.
2542
+ * Initializes a freshly spawned worker with the configuration and
2543
+ * factories it needs to start executing jobs.
2676
2544
  *
2677
- * The shape mirrors the structured-clone subset used by the parent's
2678
- * sanitizer: primitives, arrays, plain objects, plus the explicit
2679
- * {@link ErrorInfo} shape for marshalled Errors.
2545
+ * @see Wire Protocol Reference wiki page
2546
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2547
+ */
2548
+ type InitMessage = {
2549
+ type: "init";
2550
+ correlationId: string;
2551
+ workerId: string;
2552
+ poolConfig: WorkerPoolConfig;
2553
+ db: DbConfig;
2554
+ models: ModelManifestEntry[]; /** Omitted = the worker builds its executor with the built-in defaults. */
2555
+ executorConfig?: JobExecutorConfig; /** Builds the `ISigner` for synthesized operations; omitted = unsigned. */
2556
+ signer?: FactorySpec; /** Builds the `SignatureTrustPolicy`; omitted = the default. */
2557
+ trustPolicy?: FactorySpec;
2558
+ };
2559
+ /**
2560
+ * Dispatches a job to the worker for execution.
2680
2561
  *
2681
2562
  * @see Wire Protocol Reference wiki page
2682
2563
  * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2683
2564
  */
2684
- type SanitizedArg = null | boolean | number | string | ErrorInfo | SanitizedArg[] | {
2685
- [key: string]: SanitizedArg;
2565
+ type ExecuteMessage = {
2566
+ type: "execute";
2567
+ correlationId: string;
2568
+ job: Job;
2686
2569
  };
2687
2570
  /**
2688
- * Structured representation of an Error for IPC transport.
2571
+ * Requests cancellation of an in-flight job.
2689
2572
  *
2690
- * Class instances cannot be structured-cloned across worker boundaries,
2691
- * so Errors are flattened into this shape on the worker side and
2692
- * reconstructed on the parent side.
2573
+ * @see Wire Protocol Reference wiki page
2574
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2575
+ */
2576
+ type AbortMessage = {
2577
+ type: "abort";
2578
+ correlationId: string; /** correlationId of the `execute` message being aborted. */
2579
+ targetCorrelationId: string;
2580
+ reason?: string;
2581
+ };
2582
+ /**
2583
+ * Asks the worker to drain in-flight work and exit.
2693
2584
  *
2694
2585
  * @see Wire Protocol Reference wiki page
2695
2586
  * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2696
2587
  */
2697
- type ErrorInfo = {
2698
- name: string;
2588
+ type ShutdownMessage = {
2589
+ type: "shutdown";
2590
+ correlationId: string; /** Optional grace period before the parent force-terminates the worker. */
2591
+ graceMs?: number;
2592
+ };
2593
+ /**
2594
+ * Lazily registers an additional document model on a running worker.
2595
+ *
2596
+ * @see Wire Protocol Reference wiki page
2597
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2598
+ */
2599
+ type LoadModelMessage = {
2600
+ type: "load-model";
2601
+ correlationId: string;
2602
+ model: ModelManifestEntry;
2603
+ };
2604
+ /**
2605
+ * Union of all messages the parent may send to a worker.
2606
+ *
2607
+ * @see Wire Protocol Reference wiki page
2608
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2609
+ */
2610
+ type ParentMessage = InitMessage | ExecuteMessage | AbortMessage | ShutdownMessage | LoadModelMessage;
2611
+ /**
2612
+ * Announces that the worker has finished `init` and is ready to accept
2613
+ * `execute` messages.
2614
+ *
2615
+ * @see Wire Protocol Reference wiki page
2616
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2617
+ */
2618
+ type ReadyMessage = {
2619
+ type: "ready"; /** correlationId of the originating `init` message. */
2620
+ correlationId: string;
2621
+ workerId: string;
2622
+ };
2623
+ /**
2624
+ * Final result for an `execute` job.
2625
+ *
2626
+ * On success, `writeReady` carries the operations and job meta the
2627
+ * parent needs to emit `JOB_WRITE_READY`. On failure, `error` is set
2628
+ * and `result.success` is false.
2629
+ *
2630
+ * @see Wire Protocol Reference wiki page
2631
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2632
+ */
2633
+ type ResultMessage = {
2634
+ type: "result"; /** correlationId of the originating `execute` message. */
2635
+ correlationId: string;
2636
+ result: JobResult;
2637
+ writeReady?: JobWriteReadyPayload; /** Re-emitted on the parent bus, which is where observers subscribe. */
2638
+ signatureRefusals?: SignatureRefusedEvent[];
2639
+ error?: ErrorInfo;
2640
+ };
2641
+ /**
2642
+ * Acknowledges that a `load-model` request succeeded.
2643
+ *
2644
+ * @see Wire Protocol Reference wiki page
2645
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2646
+ */
2647
+ type ModelLoadedMessage = {
2648
+ type: "model-loaded"; /** correlationId of the originating `load-model` message. */
2649
+ correlationId: string;
2650
+ documentType: string;
2651
+ version: string;
2652
+ };
2653
+ /**
2654
+ * Reports that a `load-model` request failed.
2655
+ *
2656
+ * @see Wire Protocol Reference wiki page
2657
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2658
+ */
2659
+ type ModelLoadFailedMessage = {
2660
+ type: "model-load-failed"; /** correlationId of the originating `load-model` message. */
2661
+ correlationId: string;
2662
+ documentType: string;
2663
+ version: string;
2664
+ error: ErrorInfo;
2665
+ };
2666
+ /**
2667
+ * Forwarded log line from the worker. `args` is constrained to
2668
+ * {@link SanitizedArg} so callers cannot accidentally ship non-clonable
2669
+ * values across the boundary.
2670
+ *
2671
+ * The sanitizer in `./sanitize.ts` enforces the {@link SanitizedArg}
2672
+ * invariant on the producer side before each message is posted.
2673
+ *
2674
+ * @see Wire Protocol Reference wiki page
2675
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2676
+ */
2677
+ type LogMessage = {
2678
+ type: "log";
2679
+ level: "debug" | "info" | "warn" | "error";
2699
2680
  message: string;
2700
- stack?: string;
2701
- cause?: ErrorInfo;
2681
+ args: SanitizedArg[]; /** Epoch milliseconds at which the worker generated the log line. */
2682
+ timestamp: number;
2683
+ };
2684
+ /**
2685
+ * Periodic liveness signal. Included now to unblock Phase-3 scaffolding;
2686
+ * the wiki marks heartbeats as a Phase-5 future extension.
2687
+ *
2688
+ * @see Wire Protocol Reference wiki page
2689
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2690
+ */
2691
+ type HeartbeatMessage = {
2692
+ type: "heartbeat";
2693
+ workerId: string; /** Epoch milliseconds the worker generated the heartbeat. */
2694
+ timestamp: number; /** Optional snapshot of in-flight job correlation ids. */
2695
+ inFlightCorrelationIds?: string[];
2696
+ };
2697
+ /**
2698
+ * Periodic counters / gauges the worker reports for observability.
2699
+ *
2700
+ * @see Wire Protocol Reference wiki page
2701
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2702
+ */
2703
+ type MetricsMessage = {
2704
+ type: "metrics";
2705
+ workerId: string; /** Epoch milliseconds the worker generated the metrics snapshot. */
2706
+ timestamp: number;
2707
+ counters: {
2708
+ [name: string]: number;
2709
+ };
2710
+ gauges: {
2711
+ [name: string]: number;
2712
+ };
2713
+ };
2714
+ /**
2715
+ * Snapshot of one worker pool's acquire-wait samples and pool-stat counters,
2716
+ * forwarded periodically so the host can re-record into the shared
2717
+ * pg.Pool histogram and observable gauges. The worker owns the real
2718
+ * pg.Pool; the host's {@link PoolInstrumentation} is a forwarder driven
2719
+ * by these messages.
2720
+ */
2721
+ type PoolAcquireSamplesMessage = {
2722
+ type: "pool-acquire-samples";
2723
+ workerId: string; /** Stable identifier matching the host-side instrumentation name (e.g. "worker-0"). */
2724
+ poolName: string; /** Epoch milliseconds the worker generated the batch. */
2725
+ timestamp: number; /** Acquire-wait durations (ms) accumulated since the previous batch. */
2726
+ durations: number[]; /** Most recent pg.Pool counter snapshot at batch send time. */
2727
+ size: number;
2728
+ idle: number;
2729
+ waiting: number;
2730
+ };
2731
+ /**
2732
+ * Union of all messages a worker may send to the parent.
2733
+ *
2734
+ * @see Wire Protocol Reference wiki page
2735
+ * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2736
+ */
2737
+ type WorkerMessage = ReadyMessage | ResultMessage | ModelLoadedMessage | ModelLoadFailedMessage | LogMessage | HeartbeatMessage | MetricsMessage | PoolAcquireSamplesMessage;
2738
+ //#endregion
2739
+ //#region src/signer/types.d.ts
2740
+ /** The signer a client signs with and the executor signs synthesized operations with. */
2741
+ type SignerConfig = {
2742
+ /**
2743
+ * The signer used to sign actions before submission.
2744
+ */
2745
+ signer: ISigner;
2746
+ /**
2747
+ * What a pooled executor worker imports to build the same signer, which
2748
+ * cannot cross the thread boundary itself. Omitted = pooled workers store
2749
+ * synthesized operations unsigned.
2750
+ */
2751
+ workerSigner?: FactorySpec; /** Decides which keys may sign as which users; see {@link SignatureTrustPolicy}. */
2752
+ trustPolicy?: SignatureTrustPolicy;
2753
+ /**
2754
+ * What a pooled executor worker imports to build the same trust policy.
2755
+ * Omitted = pooled workers apply the default.
2756
+ */
2757
+ workerTrustPolicy?: FactorySpec;
2702
2758
  };
2703
2759
  /**
2704
- * Reference to a module that the worker should `import()` at runtime,
2705
- * along with the named export to pluck out as the factory.
2760
+ * The host's answer to whether `key` may sign as `signer.user`. The reactor has
2761
+ * already proven that `key` made the signature over this action in this
2762
+ * document.
2706
2763
  *
2707
- * Exactly one of `packageName` or `filePath` is provided.
2764
+ * Asked once per signed write at admission, never on a re-append, and never for
2765
+ * an unsigned action. `false` refuses the write as `SIGNER_UNAUTHORIZED`. A
2766
+ * throw is a job error: the job is retried and nothing is dropped, so a
2767
+ * transient failure must throw rather than answer `false`.
2708
2768
  *
2709
- * @see Wire Protocol Reference wiki page
2710
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2711
- */
2712
- type ModuleRef = {
2713
- /** Bare-specifier package name (resolved by the worker's module loader). */packageName: string; /** Named export within the module to invoke as the factory. */
2714
- exportName: string;
2769
+ * The answer may not depend on when it is asked: replicas admit the same write
2770
+ * at different times and must reach the same verdict. Cache an acceptance and
2771
+ * never expire it.
2772
+ *
2773
+ * Key a cache on (`signer.user`, `key`) only. The reactor's own key signing as
2774
+ * its current user is accepted before the policy is asked, read live on every
2775
+ * ask, and never cached. Invalidate nothing when the local identity changes:
2776
+ * other users' verdicts do not depend on it. Without a policy, a signed write
2777
+ * is refused under `authEnforcement` and accepted otherwise.
2778
+ */
2779
+ type SignatureTrustPolicy = {
2780
+ authorizeSigner(signer: ActionSigner, key: string, documentId: string): Promise<boolean>;
2781
+ };
2782
+ /** `log` counts refusals and admits anyway; `enforce` refuses. */
2783
+ type SignatureVerificationMode = "log" | "enforce";
2784
+ declare const SIGNATURE_REFUSAL_CODES: readonly ["UNSIGNED_REQUIRED", "UNSIGNED_IDENTITY", "KEY_MISMATCH", "MALFORMED_TUPLE", "TIMESTAMP_MISMATCH", "HASH_MISMATCH", "BAD_SIGNATURE", "SCHEME_BELOW_POLICY", "ID_MISMATCH", "DUPLICATE_ACTION", "SIGNER_UNAUTHORIZED"];
2785
+ type SignatureRefusalCode = (typeof SIGNATURE_REFUSAL_CODES)[number];
2786
+ /** Read from the prefix or length of tuple[2]. */
2787
+ type SignatureScheme = "unsigned" | "v2" | "legacy-renown" | "legacy-shared" | "legacy-unknown";
2788
+ /** Where this reactor first stores the write. */
2789
+ type AdmissionPath = "mutation" | "load";
2790
+ type SignatureVerdict = {
2791
+ ok: true;
2792
+ scheme: SignatureScheme;
2715
2793
  } | {
2716
- /** Absolute or worker-resolvable file path to import. */filePath: string; /** Named export within the module to invoke as the factory. */
2717
- exportName: string;
2794
+ ok: false;
2795
+ scheme: SignatureScheme;
2796
+ code: SignatureRefusalCode;
2797
+ reason: string;
2718
2798
  };
2799
+ //#endregion
2800
+ //#region src/events/types.d.ts
2719
2801
  /**
2720
- * Factory specification shared by the signature verifier and document
2721
- * model spec channels. The worker imports `module.exportName` and invokes
2722
- * it with `initArgs` to obtain the actual instance.
2802
+ * Describes a function to unsubscribe from an event.
2803
+ */
2804
+ type Unsubscribe = () => void;
2805
+ /**
2806
+ * A subscriber is a function that is called when an event is emitted.
2723
2807
  *
2724
- * `initArgs` must be JSON-clonable.
2808
+ * It is passed the event type and the data.
2809
+ * It can return a promise or a value.
2810
+ * If it returns a promise, the event bus will wait for the promise to resolve before calling the next subscriber.
2811
+ * If it throws an error, the event bus will reject with an aggregate error of all errors.
2725
2812
  *
2726
- * @see Wire Protocol Reference wiki page
2727
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2813
+ * @param type - The type of event to emit.
2814
+ * @param data - The data to pass to the subscriber.
2728
2815
  */
2729
- type FactorySpec = {
2730
- module: ModuleRef;
2731
- initArgs?: SanitizedArg;
2816
+ type Subscriber = (type: number, data: any) => void | Promise<void>;
2817
+ /**
2818
+ * Custom error class that aggregates multiple errors from event subscribers.
2819
+ */
2820
+ declare class EventBusAggregateError extends Error {
2821
+ readonly errors: any[];
2822
+ constructor(errors: unknown[]);
2823
+ }
2824
+ /**
2825
+ * Event types for reactor lifecycle events.
2826
+ */
2827
+ declare const ReactorEventTypes: {
2828
+ readonly JOB_PENDING: 10001;
2829
+ readonly JOB_RUNNING: 10002;
2830
+ readonly JOB_WRITE_READY: 10003;
2831
+ readonly JOB_READ_READY: 10004;
2832
+ readonly JOB_FAILED: 10005;
2833
+ readonly READMODEL_BATCH_COMPLETED: 10006;
2834
+ readonly READMODEL_INDEXED: 10007;
2835
+ readonly MODEL_LOADED: 10008;
2836
+ readonly SIGNATURE_REFUSED: 10009;
2732
2837
  };
2733
2838
  /**
2734
- * Factory spec for the signature verifier the worker should instantiate.
2735
- *
2736
- * Structurally identical to {@link FactorySpec}; the alias exists so call
2737
- * sites read intent-fully.
2738
- *
2739
- * @see Wire Protocol Reference wiki page
2740
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2839
+ * Stage within ReadModelCoordinator.runChain. Used as a dimension on
2840
+ * stage-attribution events and histograms.
2841
+ */
2842
+ type ReadModelStage = "pre_ready" | "emit" | "post_ready";
2843
+ /**
2844
+ * Stage in which an individual read model ran. The emit stage does not
2845
+ * involve a read model so it is excluded from this discriminant.
2741
2846
  */
2742
- type SignatureVerifierSpec = FactorySpec;
2847
+ type ReadModelIndexingStage = "pre_ready" | "post_ready";
2743
2848
  /**
2744
- * Factory spec for a document model module the worker should instantiate.
2745
- *
2746
- * Structurally identical to {@link FactorySpec}; the alias exists so call
2747
- * sites read intent-fully.
2748
- *
2749
- * @see Wire Protocol Reference wiki page
2750
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2849
+ * Emitted after the resolver loads a model on demand, so peers load it too.
2751
2850
  */
2752
- type DocumentModelSpec = FactorySpec;
2851
+ type ModelLoadedEvent = {
2852
+ documentType: string;
2853
+ };
2753
2854
  /**
2754
- * One entry in the document model manifest the worker materializes on
2755
- * startup (or extends lazily via `load-model`).
2756
- *
2757
- * @see Wire Protocol Reference wiki page
2758
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2855
+ * Event emitted when a job is registered and waiting to be executed.
2759
2856
  */
2760
- type ModelManifestEntry = {
2761
- /** Document type identifier (e.g. "ph/account"). */documentType: string; /** Document model version this entry registers. */
2762
- version: string; /** Factory spec the worker imports and invokes to obtain the model. */
2763
- spec: DocumentModelSpec;
2857
+ type JobPendingEvent = {
2858
+ jobId: string;
2859
+ jobMeta: JobMeta;
2764
2860
  };
2765
2861
  /**
2766
- * JSON-clonable Postgres connection info passed to the worker so it can
2767
- * open its own pool. Storage-specific wiring may extend this shape in
2768
- * later phases.
2769
- *
2770
- * @see Wire Protocol Reference wiki page
2771
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2862
+ * Event emitted when a job starts executing.
2772
2863
  */
2773
- type DbConfig = {
2774
- host: string;
2775
- port: number;
2776
- database: string;
2777
- user: string;
2778
- password: string;
2779
- ssl?: boolean;
2780
- applicationName?: string;
2781
- poolSize?: number;
2864
+ type JobRunningEvent = {
2865
+ jobId: string;
2866
+ jobMeta: JobMeta;
2867
+ };
2868
+ /**
2869
+ * Event emitted when operations are written to IOperationStore.
2870
+ * Contains the operations directly to avoid round-trip queries.
2871
+ */
2872
+ type JobWriteReadyEvent = {
2873
+ jobId: string;
2874
+ operations: OperationWithContext$1[];
2875
+ jobMeta: JobMeta;
2782
2876
  /**
2783
- * Maximum time (ms) a caller will wait to acquire a connection from the
2784
- * pool before pg.Pool throws. When omitted, pg defaults to 0 (unlimited
2785
- * wait), which hides acquire-starvation as silent latency.
2877
+ * The ids of the actions the caller submitted with this job. `operations`
2878
+ * can also carry operations the job merely moved into a new position, so a
2879
+ * consumer reporting back to the caller needs this to tell the two apart.
2880
+ * Absent on jobs that carry no submitted actions.
2786
2881
  */
2787
- connectionTimeoutMillis?: number;
2882
+ submittedActionIds?: string[];
2788
2883
  /**
2789
- * How long (ms) an idle connection stays open before pg closes it. When
2790
- * omitted, pg defaults to 10000.
2884
+ * Maps documentId to the collection IDs it belongs to.
2885
+ * Used by SyncManager to route operations only to remotes
2886
+ * whose collection contains the document.
2791
2887
  */
2792
- idleTimeoutMillis?: number;
2888
+ collectionMemberships?: Record<string, string[]>;
2793
2889
  };
2794
2890
  /**
2795
- * Configuration for the executor worker pool.
2796
- *
2797
- * Mirrors the `workerPool` sub-config on {@link JobExecutorConfig};
2798
- * a later card wires this into the executor config.
2891
+ * Event emitted after all read models have finished processing operations.
2892
+ * This event fires after JOB_WRITE_READY and guarantees that:
2893
+ * - All read models (DocumentView, DocumentIndexer, etc.) have indexed the operations
2894
+ * - All consistency trackers have been updated with the new operation indices
2895
+ * - Queries without consistency tokens will now see the updated data
2799
2896
  *
2800
- * @see Wire Protocol Reference wiki page
2801
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2897
+ * This event is useful for:
2898
+ * - Test synchronization (knowing when read models are ready)
2899
+ * - Observability (measuring read model latency)
2900
+ * - Event-driven workflows (triggering downstream processes)
2802
2901
  */
2803
- type WorkerPoolConfig = {
2804
- /** Whether the worker pool is active; when false the executor runs in-process. */enabled: boolean; /** Number of worker instances to spawn. */
2805
- numWorkers: number; /** Worker isolation mode. */
2806
- workerType: "thread" | "process"; /** Optional heartbeat interval in milliseconds. */
2807
- heartbeatMs?: number; /** Optional per-worker Postgres pool size override. */
2808
- workerPgPoolSize?: number;
2902
+ type JobReadReadyEvent = {
2903
+ jobId: string;
2904
+ operations: OperationWithContext$1[];
2809
2905
  };
2810
2906
  /**
2811
- * Payload the worker reports back when a job's write phase is complete.
2812
- *
2813
- * Parent fills `collectionMemberships` at emission time, so it is
2814
- * intentionally absent from the worker -> parent message.
2815
- *
2816
- * @see Wire Protocol Reference wiki page
2817
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2907
+ * Event emitted when a job fails with an unrecoverable error.
2908
+ * This event allows the JobAwaiter and other subscribers to react to job failures
2909
+ * without polling.
2818
2910
  */
2819
- type JobWriteReadyPayload = {
2820
- operations: OperationWithContext$1[];
2821
- jobMeta: JobMeta;
2911
+ type JobFailedEvent$1 = {
2912
+ jobId: string;
2913
+ error: Error;
2914
+ job?: Job;
2822
2915
  };
2823
2916
  /**
2824
- * Initializes a freshly spawned worker with the configuration and
2825
- * factories it needs to start executing jobs.
2826
- *
2827
- * @see Wire Protocol Reference wiki page
2828
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2917
+ * Event emitted once per batch processed by ReadModelCoordinator.runChain,
2918
+ * after all three projection stages complete. Carries per-stage wall times,
2919
+ * the chain wait time, and the batch size so projection cost can be
2920
+ * attributed by an observer.
2829
2921
  */
2830
- type InitMessage = {
2831
- type: "init";
2832
- correlationId: string;
2833
- workerId: string;
2834
- poolConfig: WorkerPoolConfig;
2835
- db: DbConfig; /** Omitted = the worker performs no executor-side signature verification. */
2836
- signatureVerifier?: SignatureVerifierSpec;
2837
- models: ModelManifestEntry[]; /** Omitted = the worker builds its executor with the built-in defaults. */
2838
- executorConfig?: JobExecutorConfig;
2922
+ type ReadModelBatchCompletedEvent = {
2923
+ jobId: string;
2924
+ batchSize: number;
2925
+ chainWaitDurationMs: number;
2926
+ preReadyDurationMs: number;
2927
+ emitDurationMs: number;
2928
+ postReadyDurationMs: number;
2929
+ };
2930
+ /**
2931
+ * Event emitted once per individual read model per batch and stage, after
2932
+ * that read model's indexOperations call resolves (or rejects). Lets
2933
+ * observers attribute projection cost to a specific read model.
2934
+ */
2935
+ type ReadModelIndexedEvent = {
2936
+ jobId: string;
2937
+ readModelName: string;
2938
+ stage: ReadModelIndexingStage;
2939
+ durationMs: number;
2940
+ operationCount: number;
2941
+ success: boolean;
2942
+ };
2943
+ /** A write failed admission; `enforced` is false in log mode, which admits it. */
2944
+ type SignatureRefusedEvent = {
2945
+ jobId: string;
2946
+ documentId: string;
2947
+ scope: string;
2948
+ branch: string;
2949
+ actionId: string;
2950
+ code: SignatureRefusalCode;
2951
+ scheme: SignatureScheme;
2952
+ path: AdmissionPath;
2953
+ enforced: boolean;
2954
+ reason: string;
2839
2955
  };
2956
+ //#endregion
2957
+ //#region src/events/interfaces.d.ts
2958
+ /**
2959
+ * Describes an object that manages event subscriptions and emissions.
2960
+ */
2961
+ interface IEventBus {
2962
+ /**
2963
+ * Register a new subscriber.
2964
+ * Order is preserved by pushing to the end of the per-type array.
2965
+ *
2966
+ * @param type - The type of event to subscribe to.
2967
+ * @param subscriber - The subscriber function to call when the event is emitted.
2968
+ *
2969
+ * @returns A function to unsubscribe from the event.
2970
+ */
2971
+ subscribe<K>(type: number, subscriber: (type: number, event: K) => void | Promise<void>): Unsubscribe;
2972
+ /**
2973
+ * Emits an event and waits until **all** subscribers finish.
2974
+ * - Every subscriber present at emit-start is called, in registration order.
2975
+ * - Calls are invoked and settled sequentially.
2976
+ * - If subscribers throw/reject, `emit` rejects with an aggregate error of all errors.
2977
+ *
2978
+ * @param type - The type of event to emit.
2979
+ * @param data - The data to pass to the subscribers.
2980
+ */
2981
+ emit(type: number, data: any): Promise<void>;
2982
+ }
2983
+ //#endregion
2984
+ //#region src/shared/awaiter.d.ts
2985
+ interface IJobAwaiter {
2986
+ /**
2987
+ * Waits for a job to complete: turns a job into a promise.
2988
+ *
2989
+ * @param jobId - The job id or job object
2990
+ * @param signal - Optional abort signal to cancel the request
2991
+ * @returns The result of the job
2992
+ */
2993
+ waitForJob(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
2994
+ /**
2995
+ * Shuts down the job awaiter. This will synchronously reject all pending jobs.
2996
+ */
2997
+ shutdown(): void;
2998
+ }
2840
2999
  /**
2841
- * Dispatches a job to the worker for execution.
2842
- *
2843
- * @see Wire Protocol Reference wiki page
2844
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3000
+ * Event-driven implementation of IJobAwaiter.
3001
+ * Subscribes to operation events to detect job completion without polling.
2845
3002
  */
2846
- type ExecuteMessage = {
2847
- type: "execute";
2848
- correlationId: string;
2849
- job: Job;
2850
- };
3003
+ declare class JobAwaiter implements IJobAwaiter {
3004
+ private eventBus;
3005
+ private getJobStatus;
3006
+ private pendingJobs;
3007
+ private unsubscribers;
3008
+ constructor(eventBus: IEventBus, getJobStatus: (jobId: string, signal?: AbortSignal) => Promise<JobInfo>);
3009
+ private subscribeToEvents;
3010
+ shutdown(): void;
3011
+ waitForJob(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
3012
+ private handleWriteReady;
3013
+ private handleReadReady;
3014
+ private handleJobFailed;
3015
+ private checkAndResolveWaiters;
3016
+ }
3017
+ //#endregion
3018
+ //#region src/subs/types.d.ts
2851
3019
  /**
2852
- * Requests cancellation of an in-flight job.
2853
- *
2854
- * @see Wire Protocol Reference wiki page
2855
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3020
+ * Error handler for subscription callback errors
2856
3021
  */
2857
- type AbortMessage = {
2858
- type: "abort";
2859
- correlationId: string; /** correlationId of the `execute` message being aborted. */
2860
- targetCorrelationId: string;
2861
- reason?: string;
2862
- };
3022
+ interface ISubscriptionErrorHandler {
3023
+ /**
3024
+ * Called when a subscription callback throws an error
3025
+ * @param error - The error that was thrown
3026
+ * @param context - Context about which subscription failed
3027
+ */
3028
+ handleError(error: unknown, context: SubscriptionErrorContext): void;
3029
+ }
2863
3030
  /**
2864
- * Asks the worker to drain in-flight work and exit.
2865
- *
2866
- * @see Wire Protocol Reference wiki page
2867
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3031
+ * Context information about a subscription error
2868
3032
  */
2869
- type ShutdownMessage = {
2870
- type: "shutdown";
2871
- correlationId: string; /** Optional grace period before the parent force-terminates the worker. */
2872
- graceMs?: number;
2873
- };
3033
+ interface SubscriptionErrorContext {
3034
+ /** The type of event that was being processed */
3035
+ eventType: "created" | "deleted" | "updated" | "relationshipChanged";
3036
+ /** The subscription ID that failed */
3037
+ subscriptionId: string;
3038
+ /** Optional additional data about the event */
3039
+ eventData?: unknown;
3040
+ }
2874
3041
  /**
2875
- * Lazily registers an additional document model on a running worker.
2876
- *
2877
- * @see Wire Protocol Reference wiki page
2878
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3042
+ * Interface for subscribing to document events in the reactor.
2879
3043
  */
2880
- type LoadModelMessage = {
2881
- type: "load-model";
2882
- correlationId: string;
2883
- model: ModelManifestEntry;
3044
+ interface IReactorSubscriptionManager {
3045
+ /**
3046
+ * Subscribes to document creation events
3047
+ *
3048
+ * @param callback - Function called when documents are created
3049
+ * @param search - Optional search filter to limit which documents trigger events
3050
+ * @param view - Optional filter containing branch and scopes information
3051
+ * @returns A function that unsubscribes from the events
3052
+ */
3053
+ onDocumentCreated(callback: (result: PagedResults<string>) => void, search?: SearchFilter): () => void;
3054
+ /**
3055
+ * Subscribes to document deletion events
3056
+ *
3057
+ * @param callback - Function called when documents are deleted
3058
+ * @param search - Optional search filter to limit which documents trigger events
3059
+ * @returns A function that unsubscribes from the events
3060
+ */
3061
+ onDocumentDeleted(callback: (documentIds: string[]) => void, search?: SearchFilter): () => void;
3062
+ /**
3063
+ * Subscribes to document state updates
3064
+ *
3065
+ * @param callback - Function called when documents are updated
3066
+ * @param search - Optional search filter to limit which documents trigger events
3067
+ * @param view - Optional filter containing branch and scopes information
3068
+ * @returns A function that unsubscribes from the events
3069
+ */
3070
+ onDocumentStateUpdated(callback: (result: PagedResults<PHDocument>) => void, search?: SearchFilter, view?: ViewFilter): () => void;
3071
+ /**
3072
+ * Subscribes to parent-child relationship change events
3073
+ *
3074
+ * @param callback - Function called when parent-child relationships change
3075
+ * @param search - Optional search filter to limit which documents trigger events
3076
+ * @returns A function that unsubscribes from the events
3077
+ */
3078
+ onRelationshipChanged(callback: (parentId: string, childId: string, changeType: RelationshipChangeType) => void, search?: SearchFilter): () => void;
3079
+ }
3080
+ //#endregion
3081
+ //#region src/decision/types.d.ts
3082
+ /** One operation stream. */
3083
+ type StreamQuery = {
3084
+ documentId: string;
3085
+ branch: string;
3086
+ scope: string;
2884
3087
  };
2885
3088
  /**
2886
- * Union of all messages the parent may send to a worker.
2887
- *
2888
- * @see Wire Protocol Reference wiki page
2889
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2890
- */
2891
- type ParentMessage = InitMessage | ExecuteMessage | AbortMessage | ShutdownMessage | LoadModelMessage;
2892
- /**
2893
- * Announces that the worker has finished `init` and is ready to accept
2894
- * `execute` messages.
3089
+ * What building a decision model reads a stream's state through.
2895
3090
  *
2896
- * @see Wire Protocol Reference wiki page
2897
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3091
+ * `IWriteCache` satisfies this and is what the write paths pass. The read path
3092
+ * cannot: the write cache is a write-side projection invalidated by the process
3093
+ * that runs the executor, so a reactor whose executors live in worker processes
3094
+ * holds state in its parent that no commit ever invalidates. A read there would
3095
+ * decide against a policy arbitrarily far behind the one the write paths
3096
+ * enforce. Reads therefore pass a reader backed by the read side.
2898
3097
  */
2899
- type ReadyMessage = {
2900
- type: "ready"; /** correlationId of the originating `init` message. */
2901
- correlationId: string;
2902
- workerId: string;
3098
+ interface IStreamStateReader {
3099
+ getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
3100
+ }
3101
+ /** The document and branch a decision model is built for. */
3102
+ type DecisionTarget = {
3103
+ documentId: string;
3104
+ branch: string;
2903
3105
  };
2904
3106
  /**
2905
- * Final result for an `execute` job.
2906
- *
2907
- * On success, `writeReady` carries the operations and job meta the
2908
- * parent needs to emit `JOB_WRITE_READY`. On failure, `error` is set
2909
- * and `result.success` is false.
2910
- *
2911
- * @see Wire Protocol Reference wiki page
2912
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3107
+ * What a decision's conditions may read beyond the projections: the executing
3108
+ * scope's own state and the attempted action's input. Populated only while
3109
+ * authConditions is on; otherwise both stay undefined and conditional grants
3110
+ * never apply.
2913
3111
  */
2914
- type ResultMessage = {
2915
- type: "result"; /** correlationId of the originating `execute` message. */
2916
- correlationId: string;
2917
- result: JobResult;
2918
- writeReady?: JobWriteReadyPayload;
2919
- error?: ErrorInfo;
3112
+ type DecisionContext = {
3113
+ scopeState: unknown;
3114
+ actionInput?: unknown;
2920
3115
  };
2921
- /**
2922
- * Acknowledges that a `load-model` request succeeded.
2923
- *
2924
- * @see Wire Protocol Reference wiki page
2925
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2926
- */
2927
- type ModelLoadedMessage = {
2928
- type: "model-loaded"; /** correlationId of the originating `load-model` message. */
2929
- correlationId: string;
2930
- documentType: string;
2931
- version: string;
3116
+ /** A statically-queried stream's operations, named after its projection. */
3117
+ type StreamHistory = {
3118
+ name: string;
3119
+ operations: Operation[];
2932
3120
  };
2933
3121
  /**
2934
- * Reports that a `load-model` request failed.
2935
- *
2936
- * @see Wire Protocol Reference wiki page
2937
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3122
+ * A named stream whose value in the model is that scope's state from the
3123
+ * document rebuild the reactor already performs. A derived query may read
3124
+ * only statically-queried projections, so composition is one layer deep.
2938
3125
  */
2939
- type ModelLoadFailedMessage = {
2940
- type: "model-load-failed"; /** correlationId of the originating `load-model` message. */
2941
- correlationId: string;
2942
- documentType: string;
2943
- version: string;
2944
- error: ErrorInfo;
3126
+ type Projection<M> = {
3127
+ query: StreamQuery | ((model: Partial<M>) => StreamQuery[]);
3128
+ /**
3129
+ * For a derived projection, the streams it may read anywhere in an
3130
+ * evaluated range, derived from the statically-queried streams' operations
3131
+ * (including the operations under evaluation). A positional walk cannot use
3132
+ * `query`, because the folded state it depends on changes over the range;
3133
+ * this over-approximates by design, since a stream referenced at any
3134
+ * position stays readable when the earlier range is re-evaluated even if a
3135
+ * later operation removes the reference. Ignored on static projections.
3136
+ */
3137
+ queryOverHistory?: (reads: StreamHistory[]) => StreamQuery[];
3138
+ /**
3139
+ * Action types in this stream that can change an evaluation. Reads of the stream
3140
+ * are filtered to these, so anything left out is invisible to a decision.
3141
+ */
3142
+ decidingActions: string[]; /** Applies one of this stream's operations while deciding. */
3143
+ apply: (document: PHDocument, operation: Operation) => PHDocument;
2945
3144
  };
2946
3145
  /**
2947
- * Forwarded log line from the worker. `args` is constrained to
2948
- * {@link SanitizedArg} so callers cannot accidentally ship non-clonable
2949
- * values across the boundary.
2950
- *
2951
- * The sanitizer in `./sanitize.ts` enforces the {@link SanitizedArg}
2952
- * invariant on the producer side before each message is posted.
2953
- *
2954
- * @see Wire Protocol Reference wiki page
2955
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3146
+ * The outcome of evaluating one operation. A refusal carries the reason it is
3147
+ * recorded with, because a model has more than one way to refuse.
2956
3148
  */
2957
- type LogMessage = {
2958
- type: "log";
2959
- level: "debug" | "info" | "warn" | "error";
2960
- message: string;
2961
- args: SanitizedArg[]; /** Epoch milliseconds at which the worker generated the log line. */
2962
- timestamp: number;
3149
+ type Evaluation = {
3150
+ decision: "allow";
3151
+ } | {
3152
+ decision: "deny";
3153
+ reason: string;
3154
+ };
3155
+ /** Projections plus a decision function over the built model. */
3156
+ type DecisionModel<M> = {
3157
+ projections: { [K in keyof M]: Projection<M> };
3158
+ /**
3159
+ * Present when decide reads the executing scope's state through the
3160
+ * decision context. A positional walk then folds the evaluated stream with
3161
+ * this, from its base state through every effective operation, so
3162
+ * conditions read the state as it stood at each operation's position
3163
+ * rather than at the head.
3164
+ */
3165
+ foldEvaluatedScope?: (document: PHDocument, operation: Operation) => PHDocument;
3166
+ /**
3167
+ * Whether or not this model decides about operations in a given scope. That
3168
+ * is, a scope it reads is not necessarily one it evaluates, and vise-versa.
3169
+ */
3170
+ evaluatesScope(scope: string): boolean;
3171
+ decide(model: M, subject: AuthSubject, request: AuthRequest, ctx: DecisionContext): Evaluation;
2963
3172
  };
2964
- /**
2965
- * Periodic liveness signal. Included now to unblock Phase-3 scaffolding;
2966
- * the wiki marks heartbeats as a Phase-5 future extension.
2967
- *
2968
- * @see Wire Protocol Reference wiki page
2969
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
2970
- */
2971
- type HeartbeatMessage = {
2972
- type: "heartbeat";
2973
- workerId: string; /** Epoch milliseconds the worker generated the heartbeat. */
2974
- timestamp: number; /** Optional snapshot of in-flight job correlation ids. */
2975
- inFlightCorrelationIds?: string[];
3173
+ /** A built model plus the read-set condition recording what the build read. */
3174
+ type BuiltDecisionModel<M> = {
3175
+ model: M;
3176
+ appendCondition: AppendCondition;
2976
3177
  };
3178
+ //#endregion
3179
+ //#region src/client/types.d.ts
2977
3180
  /**
2978
- * Periodic counters / gauges the worker reports for observability.
2979
- *
2980
- * @see Wire Protocol Reference wiki page
2981
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3181
+ * Describes the types of document changes that can occur.
2982
3182
  */
2983
- type MetricsMessage = {
2984
- type: "metrics";
2985
- workerId: string; /** Epoch milliseconds the worker generated the metrics snapshot. */
2986
- timestamp: number;
2987
- counters: {
2988
- [name: string]: number;
2989
- };
2990
- gauges: {
2991
- [name: string]: number;
2992
- };
2993
- };
3183
+ declare enum DocumentChangeType {
3184
+ Created = "created",
3185
+ Deleted = "deleted",
3186
+ Updated = "updated",
3187
+ ParentAdded = "parent_added",
3188
+ ParentRemoved = "parent_removed",
3189
+ ChildAdded = "child_added",
3190
+ ChildRemoved = "child_removed"
3191
+ }
2994
3192
  /**
2995
- * Snapshot of one worker pool's acquire-wait samples and pool-stat counters,
2996
- * forwarded periodically so the host can re-record into the shared
2997
- * pg.Pool histogram and observable gauges. The worker owns the real
2998
- * pg.Pool; the host's {@link PoolInstrumentation} is a forwarder driven
2999
- * by these messages.
3193
+ * Represents a change event for documents.
3000
3194
  */
3001
- type PoolAcquireSamplesMessage = {
3002
- type: "pool-acquire-samples";
3003
- workerId: string; /** Stable identifier matching the host-side instrumentation name (e.g. "worker-0"). */
3004
- poolName: string; /** Epoch milliseconds the worker generated the batch. */
3005
- timestamp: number; /** Acquire-wait durations (ms) accumulated since the previous batch. */
3006
- durations: number[]; /** Most recent pg.Pool counter snapshot at batch send time. */
3007
- size: number;
3008
- idle: number;
3009
- waiting: number;
3195
+ type DocumentChangeEvent = {
3196
+ type: DocumentChangeType;
3197
+ documents: PHDocument[];
3198
+ context?: {
3199
+ parentId?: string;
3200
+ childId?: string;
3201
+ };
3010
3202
  };
3011
3203
  /**
3012
- * Union of all messages a worker may send to the parent.
3013
- *
3014
- * @see Wire Protocol Reference wiki page
3015
- * (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
3204
+ * Options for creating an empty document.
3016
3205
  */
3017
- type WorkerMessage = ReadyMessage | ResultMessage | ModelLoadedMessage | ModelLoadFailedMessage | LogMessage | HeartbeatMessage | MetricsMessage | PoolAcquireSamplesMessage;
3018
- //#endregion
3019
- //#region src/core/model-sources.d.ts
3020
- /** An importable file holding one or more document-model exports. */
3021
- type FileModelSource = {
3022
- filePath: string;
3023
- exportName?: string;
3024
- };
3025
- /** An importable package specifier holding one or more document-model exports. */
3026
- type PackageModelSource = {
3027
- packageName: string;
3028
- subpath?: string;
3029
- exportName?: string;
3206
+ type CreateDocumentOptions = {
3207
+ /** Optional "id" or "slug" of parent document */parentIdentifier?: string; /** Optional version of the document model to use (defaults to latest) */
3208
+ documentModelVersion?: number; /** Merged over the model's defaults; `signature: 2` makes it v2-required. */
3209
+ protocolVersions?: {
3210
+ [protocol: string]: number;
3211
+ }; /** Overrides the client's creation default for this document. */
3212
+ signaturePolicy?: SignaturePolicy;
3030
3213
  };
3031
3214
  /**
3032
- * A source of document models: a live module, an importable file, or an
3033
- * importable package. File and package sources can cross a worker-thread
3034
- * boundary (workers re-import them); a live module cannot.
3215
+ * Options for upgrading a document.
3035
3216
  */
3036
- type DocumentModelSource = DocumentModelModule<any> | FileModelSource | PackageModelSource;
3037
- //#endregion
3038
- //#region src/registry/interfaces.d.ts
3039
- type RegistrationResult<T> = {
3040
- status: "success";
3041
- item: T;
3042
- } | {
3043
- status: "error";
3044
- item: T;
3045
- error: Error;
3217
+ type UpgradeDocumentOptions = {
3218
+ /**
3219
+ * How many times to retry with a fresh read when the executor rejects the
3220
+ * upgrade because the document changed after it was read. Defaults to
3221
+ * {@link DEFAULT_UPGRADE_CONFLICT_RETRIES}.
3222
+ */
3223
+ maxConflictRetries?: number;
3046
3224
  };
3047
3225
  /**
3048
- * Loader that asynchronously resolves a document type to a
3049
- * {@link DocumentModelSource}. Used by the queue to gate CREATE_DOCUMENT
3050
- * jobs until the required model is available in the registry.
3226
+ * Drive-aware operations grouped under `client.drives`.
3051
3227
  *
3052
- * Return an importable source ({ filePath } or { packageName }) whenever
3053
- * possible: the resolver registers the resolved models on the host registry
3054
- * and broadcasts importable sources to executor workers. A live
3055
- * DocumentModelModule is also valid but host-only — it cannot cross a
3056
- * worker-thread boundary, so worker pools will not receive it.
3057
- */
3058
- interface IDocumentModelLoader {
3059
- load(documentType: string): Promise<DocumentModelSource>;
3060
- }
3061
- /**
3062
- * Registry for managing document model modules.
3063
- * Provides centralized access to document models' reducers, utils, and specifications.
3064
- * Supports version-aware module storage and upgrade manifest management.
3228
+ * These methods orchestrate the multi-action, multi-document choreography
3229
+ * required to keep a drive's `state.global.nodes` array consistent with the
3230
+ * relationship index and the underlying documents. Use the flat
3231
+ * `IReactorClient` primitives (`get`, `execute`, `find`) for everything that
3232
+ * is not drive-aware.
3065
3233
  */
3066
- interface IDocumentModelRegistry {
3067
- /**
3068
- * Register multiple modules at once.
3069
- * Modules without a version field default to version 1.
3070
- * Invalid or duplicate modules are skipped without breaking registration of the remaining modules.
3071
- *
3072
- * @param modules Document model modules to register
3073
- * @returns Array of results, one per module, indicating success or failure
3074
- */
3075
- registerModules(...modules: DocumentModelModule<any>[]): RegistrationResult<DocumentModelModule<any>>[];
3234
+ interface IDriveClient {
3076
3235
  /**
3077
- * Unregister all versions of the specified document types.
3078
- *
3079
- * @param documentTypes The document types to unregister
3080
- * @returns true if all modules were unregistered, false if any were not found
3236
+ * Creates a new drive document and waits for completion.
3081
3237
  */
3082
- unregisterModules(...documentTypes: string[]): boolean;
3238
+ create(input: DriveInput, signal?: AbortSignal): Promise<DocumentDriveDocument>;
3083
3239
  /**
3084
- * Get a specific document model module by document type and optional version.
3085
- * If version is not specified, returns the latest version.
3240
+ * Adds a document to a drive as a single batched operation.
3086
3241
  *
3087
- * @param documentType The document type identifier
3088
- * @param version Optional version number to retrieve
3089
- * @returns The document model module
3090
- * @throws ModuleNotFoundError if the document type or version is not registered
3242
+ * Issues CREATE_DOCUMENT, UPGRADE_DOCUMENT, ADD_RELATIONSHIP on the new
3243
+ * document and ADD_FILE on the drive in a single dependent batch.
3091
3244
  */
3092
- getModule(documentType: string, version?: number): DocumentModelModule<any>;
3245
+ addFile<TDocument extends PHDocument = PHDocument>(driveIdentifier: string, document: PHDocument, parentFolder?: string, signal?: AbortSignal): Promise<TDocument>;
3093
3246
  /**
3094
- * Get all registered document model modules.
3095
- *
3096
- * @returns Array of all registered modules
3247
+ * Adds a folder node to a drive.
3097
3248
  */
3098
- getAllModules(): DocumentModelModule<any>[];
3249
+ addFolder(driveIdentifier: string, name: string, parentFolder?: string, signal?: AbortSignal): Promise<FolderNode>;
3099
3250
  /**
3100
- * Clear all registered modules and upgrade manifests.
3251
+ * Removes a node from a drive. Folder nodes cascade: descendant file
3252
+ * documents are deleted first, then the folder node entry itself.
3101
3253
  */
3102
- clear(): void;
3254
+ removeNode(driveIdentifier: string, nodeId: string, signal?: AbortSignal): Promise<void>;
3103
3255
  /**
3104
- * Get all supported versions for a document type, sorted in ascending order.
3105
- *
3106
- * @param documentType The document type identifier
3107
- * @returns Array of version numbers sorted ascending
3108
- * @throws ModuleNotFoundError if no modules are registered for the document type
3256
+ * Renames a node. Updates both the underlying document header and the
3257
+ * drive's node entry.
3109
3258
  */
3110
- getSupportedVersions(documentType: string): number[];
3259
+ renameNode(driveIdentifier: string, nodeId: string, name: string, signal?: AbortSignal): Promise<Node>;
3111
3260
  /**
3112
- * Get the latest (highest) version number for a document type.
3113
- *
3114
- * @param documentType The document type identifier
3115
- * @returns The highest version number registered for this document type
3116
- * @throws ModuleNotFoundError if no modules are registered for the document type
3261
+ * Updates the preferred editor recorded in the document header meta for
3262
+ * a node. Pass `null` to clear it.
3117
3263
  */
3118
- getLatestVersion(documentType: string): number;
3264
+ setPreferredEditorOnNode(nodeId: string, preferredEditor: string | null, signal?: AbortSignal): Promise<PHDocument>;
3119
3265
  /**
3120
- * Register upgrade manifests that define upgrade paths between versions.
3121
- * Invalid or duplicate manifests are skipped without breaking registration of the remaining manifests.
3122
- *
3123
- * @param manifests Upgrade manifests to register
3124
- * @returns Array of results, one per manifest, indicating success or failure
3266
+ * Moves a node to a different parent folder within the same drive.
3267
+ * Pass `undefined` to move the node to the drive root.
3125
3268
  */
3126
- registerUpgradeManifests(...manifests: UpgradeManifest<readonly number[]>[]): RegistrationResult<UpgradeManifest<readonly number[]>>[];
3127
- /**
3128
- * Unregister upgrade manifests for the specified document types.
3129
- * @param documentTypes The document types whose upgrade manifests should be unregistered
3130
- * @returns true if all modules were unregistered, false if any were not found
3131
- **/
3132
- unregisterUpgradeManifests(...documentTypes: string[]): boolean;
3269
+ moveNode(driveIdentifier: string, srcNodeId: string, targetParentFolderId: string | undefined, signal?: AbortSignal): Promise<DocumentDriveDocument>;
3133
3270
  /**
3134
- * Get the upgrade manifest for a document type.
3135
- *
3136
- * @param documentType The document type identifier
3137
- * @returns The upgrade manifest
3138
- * @throws ManifestNotFoundError if no manifest is registered for the document type
3271
+ * Copies a node (and its subtree, if it is a folder) within a drive.
3272
+ * Each copied file gets a new id and a duplicated document.
3139
3273
  */
3140
- getUpgradeManifest(documentType: string): UpgradeManifest<readonly number[]>;
3274
+ copyNode(driveIdentifier: string, srcNodeId: string, targetParentFolderId: string | undefined, signal?: AbortSignal): Promise<DocumentDriveDocument>;
3141
3275
  /**
3142
- * Compute the upgrade path from one version to another.
3143
- * Returns the sequence of upgrade transitions needed.
3144
- *
3145
- * @param documentType The document type identifier
3146
- * @param fromVersion The starting version
3147
- * @param toVersion The target version
3148
- * @returns Array of upgrade transitions in order
3149
- * @throws DowngradeNotSupportedError if toVersion is less than fromVersion
3150
- * @throws ManifestNotFoundError if no upgrade manifest is registered
3151
- * @throws MissingUpgradeTransitionError if any transition in the path is missing
3276
+ * Returns a single node from the drive's `state.global.nodes` array.
3152
3277
  */
3153
- computeUpgradePath(documentType: string, fromVersion: number, toVersion: number): UpgradeTransition[];
3278
+ getNode(driveIdentifier: string, nodeId: string, signal?: AbortSignal): Promise<Node>;
3154
3279
  /**
3155
- * Get the upgrade reducer for a single-step version transition.
3280
+ * Returns nodes in the drive, optionally filtered by parent folder:
3281
+ * - omit `parentFolder` (or pass `undefined`) to list every node in the drive.
3282
+ * - pass `null` to list only root-level nodes.
3283
+ * - pass a folder id to list only the direct children of that folder.
3156
3284
  *
3157
- * @param documentType The document type identifier
3158
- * @param fromVersion The starting version
3159
- * @param toVersion The target version (must be fromVersion + 1)
3160
- * @returns The upgrade reducer function
3161
- * @throws InvalidUpgradeStepError if toVersion is not fromVersion + 1
3162
- * @throws ManifestNotFoundError if no upgrade manifest is registered
3163
- * @throws MissingUpgradeTransitionError if the transition is not found
3285
+ * Returns a paged result so callers can stream through drives with very
3286
+ * large node counts without materialising the whole list in memory.
3164
3287
  */
3165
- getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
3288
+ listNodes(driveIdentifier: string, parentFolder?: string | null, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Node>>;
3166
3289
  }
3167
- //#endregion
3168
- //#region src/cache/buffer/ring-buffer.d.ts
3169
3290
  /**
3170
- * RingBuffer is a generic circular buffer implementation that stores a fixed number
3171
- * of items. When the buffer is full, new items overwrite the oldest items.
3291
+ * One operation an authorization preflight predicts a verdict for. The input is
3292
+ * what a conditional grant reads, so a candidate standing for a filled-in form
3293
+ * carries that form's input.
3294
+ */
3295
+ type ActionCandidate = {
3296
+ scope: string;
3297
+ type: string;
3298
+ input?: unknown;
3299
+ };
3300
+ /**
3301
+ * The predicted verdicts for a set of candidates, in the order they were given,
3302
+ * with the aggregates a UI branches on.
3172
3303
  *
3173
- * This implementation maintains O(1) time complexity for push operations and provides
3174
- * items in chronological order (oldest to newest) via getAll().
3304
+ * The aggregates are redundant -- a verdict is binary, so `allDenied` is
3305
+ * `!anyAllowed` and `anyDenied` is `!allAllowed` -- and all four are returned
3306
+ * so that a caller reads the one its question is phrased in rather than
3307
+ * negating another. Over no candidates every aggregate is false: nothing is
3308
+ * allowed and nothing is denied.
3309
+ */
3310
+ type ActionEvaluations = {
3311
+ evaluations: Evaluation[];
3312
+ allAllowed: boolean;
3313
+ anyAllowed: boolean;
3314
+ allDenied: boolean;
3315
+ anyDenied: boolean;
3316
+ };
3317
+ /**
3318
+ * The ReactorClient interface that wraps lower-level APIs to provide
3319
+ * a simpler interface for document operations.
3175
3320
  *
3176
- * @template T - The type of items stored in the buffer
3321
+ * Features:
3322
+ * - Wraps Jobs with Promises for easier async handling
3323
+ * - Manages signing of submitted Action objects
3324
+ * - Provides quality-of-life functions for common tasks
3325
+ * - Wraps subscription interface with ViewFilters
3177
3326
  */
3178
- declare class RingBuffer<T> {
3179
- private buffer;
3180
- private head;
3181
- private size;
3182
- private capacity;
3183
- constructor(capacity: number);
3327
+ interface IReactorClient {
3184
3328
  /**
3185
- * Adds an item to the buffer. If the buffer is full, overwrites the oldest item.
3329
+ * Drive-aware operations. See {@link IDriveClient}.
3330
+ */
3331
+ readonly drives: IDriveClient;
3332
+ /**
3333
+ * Retrieves a list of document model modules.
3186
3334
  *
3187
- * @param item - The item to add
3335
+ * @param namespace - Optional namespace like "powerhouse" or "sky", defaults to ""
3336
+ * @param paging - Optional pagination options
3337
+ * @param signal - Optional abort signal to cancel the request
3338
+ * @returns List of document model modules
3188
3339
  */
3189
- push(item: T): void;
3340
+ getDocumentModelModules(namespace?: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentModelModule>>;
3190
3341
  /**
3191
- * Returns all items in the buffer in chronological order (oldest to newest).
3342
+ * Retrieves a specific document model module by document type.
3192
3343
  *
3193
- * @returns Array of items in insertion order
3344
+ * @param documentType - The document type identifier
3345
+ * @returns The document model module
3194
3346
  */
3195
- getAll(): T[];
3347
+ getDocumentModelModule(documentType: string): Promise<DocumentModelModule<any>>;
3196
3348
  /**
3197
- * Clears all items from the buffer.
3349
+ * Retrieves a specific document by identifier (either id or slug).
3350
+ *
3351
+ * @param identifier - Required, this is the document id or slug
3352
+ * @param view - Optional filter containing branch and scopes information
3353
+ * @param signal - Optional abort signal to cancel the request
3354
+ * @returns The up-to-date PHDocument with scopes and list of child document ids
3198
3355
  */
3199
- clear(): void;
3356
+ get<TDocument extends PHDocument>(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<TDocument>;
3200
3357
  /**
3201
- * Gets the current number of items in the buffer.
3358
+ * Resolves an identifier (either an id or a slug) to the canonical document
3359
+ * id, using the same lookup as the read/operation data paths. Resolves
3360
+ * against the "main" branch. Throws if the identifier cannot be resolved or
3361
+ * is ambiguous.
3362
+ *
3363
+ * @param identifier - Required, this is the document id or slug
3364
+ * @param signal - Optional abort signal to cancel the request
3365
+ * @returns The canonical document id
3202
3366
  */
3203
- get length(): number;
3204
- }
3205
- //#endregion
3206
- //#region src/cache/kysely-write-cache.d.ts
3207
- type DocumentStream = {
3208
- key: string;
3209
- ringBuffer: RingBuffer<CachedSnapshot>;
3210
- };
3211
- /**
3212
- * In-memory write cache with keyframe persistence for PHDocuments.
3213
- *
3214
- * Caches document snapshots in ring buffers with LRU eviction. On cache miss,
3215
- * rebuilds documents from nearest keyframe or full operation history.
3216
- *
3217
- * **Performance Characteristics:**
3218
- * - Cache hit: O(1) lookup in ring buffer
3219
- * - Cold miss: O(n) where n is total operation count, or O(k) where k is operations since keyframe
3220
- * - Warm miss: O(m) where m is operations since cached revision
3221
- * - Eviction: O(1) for LRU tracking and removal
3222
- *
3223
- * **Thread Safety:**
3224
- * Not thread-safe. Designed for single-threaded job executor environment.
3225
- * External synchronization required for concurrent access across multiple executors.
3226
- *
3227
- * **Example:**
3228
- * ```typescript
3229
- * const cache = new KyselyWriteCache(
3230
- * keyframeStore,
3231
- * operationStore,
3232
- * registry,
3233
- * { maxDocuments: 1000, ringBufferSize: 10, keyframeInterval: 10 }
3234
- * );
3235
- *
3236
- * await cache.startup();
3237
- *
3238
- * // Retrieve or rebuild document
3239
- * const doc = await cache.getState(docId, docType, scope, branch, revision);
3240
- *
3241
- * // Cache result after job execution
3242
- * cache.putState(docId, docType, scope, branch, newRevision, updatedDoc);
3243
- *
3244
- * await cache.shutdown();
3245
- * ```
3246
- */
3247
- declare class KyselyWriteCache implements IWriteCache {
3248
- private streams;
3249
- private lruTracker;
3250
- private keyframeStore;
3251
- private operationStore;
3252
- private registry;
3253
- private config;
3254
- constructor(keyframeStore: IKeyframeStore, operationStore: IOperationStore, registry: IDocumentModelRegistry, config: WriteCacheConfig);
3255
- withScopedStores(operationStore: IOperationStore, keyframeStore: IKeyframeStore): KyselyWriteCache;
3367
+ resolveIdOrSlug(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<string>;
3368
+ /** True when the id is taken; a soft-deleted document's id is still taken. */
3369
+ isDocumentIdTaken(documentId: string, signal?: AbortSignal): Promise<boolean>;
3256
3370
  /**
3257
- * Initializes the write cache.
3258
- * Currently a no-op as keyframe store lifecycle is managed externally.
3371
+ * Retrieves operations for a document.
3372
+ *
3373
+ * @param documentIdentifier - Required, this is either a document "id" field or a "slug"
3374
+ * @param view - Optional filter containing branch and scopes information
3375
+ * @param filter - Optional filter for actionTypes, timestamps, and revision
3376
+ * @param paging - Optional pagination options
3377
+ * @param signal - Optional abort signal to cancel the request
3378
+ * @returns Paginated list of operations
3259
3379
  */
3260
- startup(): Promise<void>;
3380
+ getOperations(documentIdentifier: string, view?: ViewFilter, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
3261
3381
  /**
3262
- * Shuts down the write cache.
3263
- * Currently a no-op as keyframe store lifecycle is managed externally.
3382
+ * Retrieves outgoing relationships of a given type from a source document.
3383
+ *
3384
+ * @param sourceIdentifier - Required, this is either a document "id" field or a "slug"
3385
+ * @param relationshipType - The relationship type to filter by
3386
+ * @param view - Optional filter containing branch and scopes information
3387
+ * @param paging - Optional pagination options
3388
+ * @param signal - Optional abort signal to cancel the request
3389
+ * @returns The target documents and paging cursor
3264
3390
  */
3265
- shutdown(): Promise<void>;
3391
+ getOutgoingRelationships(sourceIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
3266
3392
  /**
3267
- * Retrieves document state at a specific revision from cache or rebuilds it.
3393
+ * Retrieves incoming relationships of a given type to a target document.
3268
3394
  *
3269
- * Note: this returns a _shallow_ copy of the document.
3395
+ * @param targetIdentifier - Required, this is either a document "id" field or a "slug"
3396
+ * @param relationshipType - The relationship type to filter by
3397
+ * @param view - Optional filter containing branch and scopes information
3398
+ * @param paging - Optional pagination options
3399
+ * @param signal - Optional abort signal to cancel the request
3400
+ * @returns The source documents and paging cursor
3401
+ */
3402
+ getIncomingRelationships(targetIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
3403
+ /**
3404
+ * Retrieves the outgoing relationship edges of a source document.
3270
3405
  *
3271
- * Cache hit path: Returns cached snapshot if available (O(1))
3272
- * Warm miss path: Rebuilds from cached base revision + incremental ops
3273
- * Cold miss path: Rebuilds from keyframe or from scratch using all operations
3406
+ * Unlike {@link IReactorClient.getOutgoingRelationships}, which returns the
3407
+ * documents at the far end, this returns the edges themselves, carrying the
3408
+ * metadata and timestamps recorded against each relationship.
3274
3409
  *
3275
- * @param documentId - The document identifier
3276
- * @param scope - The operation scope
3277
- * @param branch - The operation branch
3278
- * @param targetRevision - The target revision, or undefined for newest
3279
- * @param signal - Optional abort signal to cancel the operation
3280
- * @returns The document at the target revision
3281
- * @throws {Error} "Operation aborted" if signal is aborted
3282
- * @throws {ModuleNotFoundError} If document type not registered in registry
3283
- * @throws {Error} "Failed to rebuild document" if operation store fails
3284
- * @throws {Error} If reducer throws during operation application
3285
- * @throws {Error} If document serialization fails
3410
+ * @param sourceIdentifier - Required, this is either a document "id" field or a "slug"
3411
+ * @param relationshipType - Optional relationship type to filter by
3412
+ * @param view - Optional filter containing branch and scopes information
3413
+ * @param paging - Optional pagination options
3414
+ * @param signal - Optional abort signal to cancel the request
3415
+ * @returns The matching relationship edges and paging cursor
3286
3416
  */
3287
- getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
3417
+ getOutgoingRelationshipEdges(sourceIdentifier: string, relationshipType?: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentRelationship>>;
3288
3418
  /**
3289
- * Stores a document snapshot in the cache at a specific revision.
3290
- *
3291
- * The cached document is a shallow copy of the input with its operation history
3292
- * truncated to the last operation per scope and its clipboard cleared. This keeps
3293
- * memory use and copy costs constant regardless of operation count. Consumers of
3294
- * getState() must not rely on the full operation history being present; the only
3295
- * guaranteed invariant is that operations[scope].at(-1) reflects the latest
3296
- * operation index for each scope.
3419
+ * Retrieves the incoming relationship edges of a target document.
3297
3420
  *
3298
- * Updates LRU tracker and may evict least recently used stream if at capacity.
3299
- * Asynchronously persists keyframes at configured intervals (fire-and-forget).
3421
+ * Unlike {@link IReactorClient.getIncomingRelationships}, which returns the
3422
+ * documents at the far end, this returns the edges themselves, carrying the
3423
+ * metadata and timestamps recorded against each relationship.
3300
3424
  *
3301
- * @param documentId - The document identifier
3302
- * @param scope - The operation scope
3303
- * @param branch - The operation branch
3304
- * @param revision - The revision number
3305
- * @param document - The document to cache
3306
- * @throws {Error} If document serialization fails
3425
+ * @param targetIdentifier - Required, this is either a document "id" field or a "slug"
3426
+ * @param relationshipType - Optional relationship type to filter by
3427
+ * @param view - Optional filter containing branch and scopes information
3428
+ * @param paging - Optional pagination options
3429
+ * @param signal - Optional abort signal to cancel the request
3430
+ * @returns The matching relationship edges and paging cursor
3307
3431
  */
3308
- putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, position: SnapshotPosition): void;
3432
+ getIncomingRelationshipEdges(targetIdentifier: string, relationshipType?: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentRelationship>>;
3309
3433
  /**
3310
- * Stores the run's head and mints a keyframe for every interval the run
3311
- * crossed on its way there. Only the head enters the ring buffer; the
3312
- * earlier revisions are keyframe candidates and nothing more.
3434
+ * Filters documents by criteria and returns a list of them
3435
+ *
3436
+ * @param search - Search filter options (type, parentId, identifiers)
3437
+ * @param view - Optional filter containing branch and scopes information
3438
+ * @param paging - Optional pagination options
3439
+ * @param signal - Optional abort signal to cancel the request
3440
+ * @returns List of documents matching criteria and pagination cursor
3313
3441
  */
3314
- putRun(documentId: string, scope: string, branch: string, run: readonly {
3315
- revision: number;
3316
- document: PHDocument;
3317
- }[]): void;
3318
- private store;
3319
- /** Persists the snapshot if this revision is one the interval falls on. */
3320
- private persistKeyframe;
3442
+ find(search: SearchFilter, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
3321
3443
  /**
3322
- * Invalidates cached document streams.
3444
+ * Predicts whether the subject would be admitted to execute each of a set of
3445
+ * candidate operations, without submitting any of them. A UI asks this to
3446
+ * disable a control rather than offer an action that fails on submit.
3447
+ *
3448
+ * The answer is a prediction, not a promise. Three caveats hold:
3449
+ *
3450
+ * - Real admission compiles an append condition over everything it read and
3451
+ * the store enforces it at write time. A preflight reads no future, so a
3452
+ * policy change landing between this answer and the submit changes the
3453
+ * verdict. The submit path stays the only authority.
3454
+ * - The verdict is evaluated at the stream heads. It is therefore correct for
3455
+ * a candidate that will be stamped at or after every timestamp the
3456
+ * evaluation read, which is the normal case for a control the user is about
3457
+ * to click. A backdated submission is out of contract: the reactor decides
3458
+ * that one by position, against the policy as it stood there.
3459
+ * - A candidate whose input decides the verdict needs that input supplied.
3460
+ * With `authConditions` on, a conditional grant reads `action.input`, so
3461
+ * omitting the input predicts the denial an empty input would earn rather
3462
+ * than the verdict the filled-in form will get.
3323
3463
  *
3324
- * Supports three invalidation scopes:
3325
- * - Document-level: invalidate(documentId) - removes all streams for document
3326
- * - Scope-level: invalidate(documentId, scope) - removes all branches for scope
3327
- * - Stream-level: invalidate(documentId, scope, branch) - removes specific stream
3464
+ * Document-scope candidates are decided against the policy of the document
3465
+ * their input names, not the one passed here: delete and upgrade name it in
3466
+ * `input.documentId`, and the relationship actions in `input.sourceId`. This
3467
+ * follows the executor's own gate, which decides against the document
3468
+ * guarding the write. `CREATE_DOCUMENT` follows the gate's exemption: it runs
3469
+ * before its document exists, so the executor never decides it against a
3470
+ * policy and the preflight predicts allow.
3328
3471
  *
3329
- * @param documentId - The document identifier
3330
- * @param scope - Optional scope to narrow invalidation
3331
- * @param branch - Optional branch to narrow invalidation (requires scope)
3332
- * @returns The number of streams evicted
3472
+ * @param documentIdentifier - Document "id" or "slug" the candidates target
3473
+ * @param branch - Branch to evaluate against
3474
+ * @param candidates - Operations to predict a verdict for, each with the scope it would execute in
3475
+ * @param subject - Optional subject to decide for, defaulting to the client's own signer. A plain subject rather than a ViewFilter: the evaluation reads no view, so a filter's branch or scopes would be silently ignored here
3476
+ * @param signal - Optional abort signal to cancel the request
3477
+ * @returns One evaluation per candidate, in the order given, with the aggregates over them
3478
+ * @throws AuthEnforcementDisabledError if the reactor's authEnforcement flag is off, in which case it holds no decision model and the legacy host-table permission system cannot answer for one
3333
3479
  */
3334
- invalidate(documentId: string, scope?: string, branch?: string): number;
3480
+ evaluateActions(documentIdentifier: string, branch: string, candidates: ActionCandidate[], subject?: AuthSubject, signal?: AbortSignal): Promise<ActionEvaluations>;
3335
3481
  /**
3336
- * Clears the entire cache, removing all cached document streams.
3337
- * Resets LRU tracking state. This operation always succeeds.
3482
+ * The signature policy this client gives the documents it creates when the
3483
+ * caller does not choose one. It never changes an existing document.
3338
3484
  */
3339
- clear(): void;
3485
+ getCreateSignaturePolicy(): Promise<SignaturePolicy>;
3340
3486
  /**
3341
- * Retrieves a specific stream for a document. Exposed on the implementation
3342
- * for testing, but not on the interface.
3487
+ * Creates a document and waits for completion. The document keeps the
3488
+ * signature policy and id its header carries.
3343
3489
  *
3344
- * @internal
3490
+ * @param document - Document with optional id, slug, parent, model type, and initial state
3491
+ * @param parentIdentifier - Optional "id" or "slug" of parent document
3492
+ * @param signal - Optional abort signal to cancel the request
3493
+ * @returns The created document
3345
3494
  */
3346
- getStream(documentId: string, scope: string, branch: string): DocumentStream | undefined;
3347
- private findNearestKeyframe;
3495
+ create<TDocument extends PHDocument = PHDocument>(document: PHDocument, parentIdentifier?: string, signal?: AbortSignal): Promise<TDocument>;
3348
3496
  /**
3349
- * Rebuilds a scope from a keyframe or from the whole operation history.
3497
+ * Creates an empty document and waits for completion
3350
3498
  *
3351
- * The document scope is always rebuilt first, because it carries the type,
3352
- * the upgrades and the deletion marker. Its version-changing upgrades are not
3353
- * applied there though: an upgrade reducer must see the state the requested
3354
- * scope has reached at that upgrade's boundary, so each one is held back and
3355
- * applied when the replay below crosses the boundary that
3356
- * resolveModuleVersionForOp derives from it. Upgrades whose boundary lies past
3357
- * the last replayed operation are applied at the end. Creation-time 0->N seed
3358
- * upgrades carry the initial state, so they still apply immediately.
3359
- */
3360
- private coldMissRebuild;
3361
- /**
3362
- * Applies and removes every held-back upgrade whose target version is at or
3363
- * below `throughVersion`, in the order the document scope recorded them.
3499
+ * @param documentModelType - Type of document to create
3500
+ * @param options - Optional creation options (parentIdentifier, documentModelVersion)
3501
+ * @param signal - Optional abort signal to cancel the request
3364
3502
  */
3365
- private applyPendingUpgrades;
3503
+ createEmpty<TDocument extends PHDocument>(documentModelType: string, options?: CreateDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
3366
3504
  /**
3367
- * Applies the remaining held-back upgrades after the requested scope's
3368
- * replay has finished. A head read applies them all. A positional read
3369
- * applies only those whose boundary for this scope lies at or before the
3370
- * target position: applying a later one would label migrated state with a
3371
- * pre-upgrade revision, and a keyframe stored from that poisons every
3372
- * rebuild that resumes from it. Boundaries come from the upgrade's revision
3373
- * snapshot; an upgrade without one records no position for this scope, and
3374
- * the replay loop not having crossed it already places it past the target.
3505
+ * Retrieves the document model module matching the version a document is
3506
+ * stamped with. Use this instead of {@link getDocumentModelModule}
3507
+ * whenever a specific document is in hand: the latest-wins lookup feeds
3508
+ * not-yet-upgraded documents the wrong reducer, diverging from replay.
3509
+ *
3510
+ * @param document - The document whose stamped version selects the module
3511
+ * @returns The document model module registered for that version
3512
+ * @throws UnsupportedDocumentModelVersionError if no module is registered for the stamped version
3375
3513
  */
3376
- private applyTailPendingUpgrades;
3514
+ getDocumentModelModuleForDocument(document: PHDocument): Promise<DocumentModelModule<any>>;
3377
3515
  /**
3378
- * Applies one held-back upgrade, then re-applies the deletes the document
3379
- * scope recorded after it so the hold-back cannot invert their order.
3516
+ * Upgrades a document to a newer document model version by dispatching an
3517
+ * UPGRADE_DOCUMENT action. When toVersion is omitted, upgrades to the
3518
+ * latest registered module version for the document's type. Returns the
3519
+ * document unchanged when it is already at the target version.
3520
+ *
3521
+ * The action carries a snapshot of the document's version and per-scope
3522
+ * revisions, which the executor validates before persisting. When an edit
3523
+ * lands between the read and the upgrade executing, the upgrade is
3524
+ * rejected and retried with a fresh read up to
3525
+ * {@link UpgradeDocumentOptions.maxConflictRetries} times before the
3526
+ * conflict is surfaced.
3527
+ *
3528
+ * @param documentIdentifier - Target document id or slug
3529
+ * @param toVersion - Optional target document model version; defaults to latest
3530
+ * @param options - Optional upgrade options (maxConflictRetries)
3531
+ * @param signal - Optional abort signal to cancel the request
3532
+ * @returns The upgraded document
3533
+ * @throws DowngradeNotSupportedError if toVersion is less than the document's current version
3380
3534
  */
3381
- private applyPendingUpgrade;
3535
+ upgradeDocument<TDocument extends PHDocument = PHDocument>(documentIdentifier: string, toVersion?: number, options?: UpgradeDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
3382
3536
  /**
3383
- * Copies the current document revisions onto the document. Overwrites the
3384
- * requested scope revision with the target revision, if provided.
3537
+ * Creates an empty document in a drive as a single batched operation.
3538
+ * This is more efficient than createEmpty + addFile as it batches all
3539
+ * actions into dependent jobs and waits for them to complete together.
3540
+ *
3541
+ * @deprecated Use {@link IDriveClient.addFile} via `client.drives.addFile`
3542
+ * instead. This method will be removed in a future release.
3543
+ * @param driveId - The drive document id or slug
3544
+ * @param document - The document to create
3545
+ * @param parentFolder - Optional folder id within the drive
3546
+ * @param signal - Optional abort signal to cancel the request
3547
+ * @returns The created document
3385
3548
  */
3386
- private stampRevisions;
3387
- /** The stored operation at `index`, or undefined if it is no longer there. */
3388
- private operationAt;
3549
+ createDocumentInDrive<TDocument extends PHDocument>(driveId: string, document: PHDocument, parentFolder?: string, signal?: AbortSignal): Promise<TDocument>;
3389
3550
  /**
3390
- * Resolves which module version to use for a given operation in phase 2.
3551
+ * Applies a list of actions to a document and waits for completion
3391
3552
  *
3392
- * Uses the validated-upgrade boundary rules from D7:
3393
- * - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary
3394
- * - Otherwise: timestamp fallback
3395
- * - Falls back to final module version when neither is decidable
3553
+ * The document handed back is a read like any other, so it goes through the
3554
+ * read gate. `subject` names who that read is for, the same way
3555
+ * {@link ViewFilter.subject} does on `get` and `find`; a host that shares one
3556
+ * client across many callers has no meaningful signer to fall back to, and
3557
+ * without it the gate would strip the domain scopes of a policied document
3558
+ * and resolve with a husk whose `state.global` is absent — reading as a
3559
+ * rejected write when the write in fact succeeded.
3560
+ *
3561
+ * @param documentIdentifier - Target document id or slug
3562
+ * @param branch - Branch to apply actions to
3563
+ * @param actions - List of actions to apply
3564
+ * @param signal - Optional abort signal to cancel the request
3565
+ * @param subject - Optional read subject for the returned document; defaults
3566
+ * to the client's signer
3567
+ * @returns The updated document
3396
3568
  */
3397
- private resolveModuleVersionForOp;
3398
- private warmMissRebuild;
3399
- private findNearestOlderSnapshot;
3400
- private makeStreamKey;
3401
- private getOrCreateStream;
3402
- private isKeyframeRevision;
3403
- }
3404
- //#endregion
3405
- //#region src/storage/kysely/store.d.ts
3406
- declare class KyselyOperationStore implements IOperationStore {
3407
- private db;
3408
- private trx?;
3409
- constructor(db: Kysely<Database$1>);
3410
- private get queryExecutor();
3411
- withTransaction(trx: Transaction<Database$1>): KyselyOperationStore;
3412
- apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal, condition?: AppendCondition): Promise<Operation[]>;
3413
- private resolveUniqueConstraint;
3414
- private executeApply;
3569
+ execute<TDocument extends PHDocument>(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal, subject?: AuthSubject): Promise<TDocument>;
3415
3570
  /**
3416
- * Locks the written stream and every read-set stream, in sorted key order
3417
- * so that overlapping concurrent appends serialize rather than deadlock.
3418
- * The locks are still taken one row at a time, so the query preserves that
3419
- * order. It must stay separate from the guarded insert, which would
3420
- * otherwise read a snapshot taken before the locks were held.
3571
+ * Submits a list of actions to a document
3572
+ *
3573
+ * @param documentIdentifier - Target document id or slug
3574
+ * @param branch - Branch to apply actions to
3575
+ * @param actions - List of actions to apply
3576
+ * @param signal - Optional abort signal to cancel the request
3577
+ * @returns The job
3421
3578
  */
3422
- private acquireStreamLocks;
3579
+ executeAsync(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal): Promise<JobInfo>;
3423
3580
  /**
3424
- * Inserts the staged operations with the condition compiled in as a WHERE
3425
- * NOT EXISTS guard, making the check and the append one statement. Returns
3426
- * the rows inserted; zero means the guard failed and nothing was written.
3581
+ * Applies multiple mutation jobs in dependency order and waits for all to
3582
+ * complete. Actions on each job are signed by the client signer before
3583
+ * dispatch. Throws on the first failed job; the others may still execute
3584
+ * because dispatch is fire-and-await-all.
3585
+ *
3586
+ * @param request - Batch mutation request with per-job actions and dependsOn keys
3587
+ * @param signal - Optional abort signal to cancel the request
3588
+ * @returns The completed batch result (job ids keyed by plan key)
3427
3589
  */
3428
- private insertGuarded;
3429
- private findIdempotentReplay;
3430
- /** True when the staged write creates a document rather than appending to one. */
3431
- private isCreate;
3590
+ executeBatch(request: BatchExecutionRequest, signal?: AbortSignal): Promise<BatchExecutionResult>;
3432
3591
  /**
3433
- * The paging cursor here encodes the index to resume from (one past the
3434
- * last row returned), not the last row's own index. This keeps "0" an
3435
- * unambiguous start-of-stream sentinel even when a page ends at index 0
3436
- * (e.g. `limit: 1` on a fresh stream), which would otherwise make
3437
- * `nextCursor` equal the start cursor and loop a caller that walks pages
3438
- * forever.
3592
+ * Renames a document and waits for completion
3593
+ *
3594
+ * @param documentIdentifier - Target document id or slug
3595
+ * @param name - The new name of the document
3596
+ * @param branch - Optional branch to rename the document, defaults to "main"
3597
+ * @param signal - Optional abort signal to cancel the request
3598
+ * @returns The updated document.
3439
3599
  */
3440
- getSince(documentId: string, scope: string, branch: string, revision: number, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
3441
- getSinceId(id: number, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<OperationWithContext$1>>;
3600
+ rename(documentIdentifier: string, name: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
3442
3601
  /**
3443
- * The paging cursor here encodes the index to resume from (one past the
3444
- * last row returned), not the last row's own index, for the same reason as
3445
- * `getSince`: a page ending at index 0 must not produce a cursor that is
3446
- * indistinguishable from the start-of-stream sentinel.
3447
- */
3448
- getConflicting(documentId: string, scope: string, branch: string, minTimestamp: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
3449
- getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
3450
- getStreamLatestTimestamp(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
3451
- private rowToOperation;
3452
- private rowToOperationWithContext;
3453
- }
3454
- //#endregion
3455
- //#region src/storage/kysely/keyframe-store.d.ts
3456
- declare class KyselyKeyframeStore implements IKeyframeStore {
3457
- private db;
3458
- private trx?;
3459
- constructor(db: Kysely<Database$1>);
3460
- private get queryExecutor();
3461
- withTransaction(trx: Transaction<Database$1>): KyselyKeyframeStore;
3462
- putKeyframe(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, signal?: AbortSignal): Promise<void>;
3463
- findNearestKeyframe(documentId: string, scope: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<{
3464
- revision: number;
3465
- document: PHDocument;
3466
- } | undefined>;
3467
- listKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<Array<{
3468
- scope: string;
3469
- branch: string;
3470
- revision: number;
3471
- document: PHDocument;
3472
- }>>;
3473
- deleteKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<number>;
3474
- }
3475
- //#endregion
3476
- //#region src/executor/execution-scope.d.ts
3477
- interface ExecutionStores {
3478
- operationStore: IOperationStore;
3479
- operationIndex: IOperationIndex;
3480
- writeCache: IWriteCache;
3481
- documentMetaCache: IDocumentMetaCache;
3482
- collectionMembershipCache: ICollectionMembershipCache;
3483
- }
3484
- interface IExecutionScope {
3485
- run<T>(fn: (stores: ExecutionStores) => Promise<T>, signal?: AbortSignal): Promise<T>;
3486
- }
3487
- //#endregion
3488
- //#region src/executor/types.d.ts
3489
- /**
3490
- * Represents the result of a job execution
3491
- */
3492
- type JobResult = {
3493
- /** The job that was executed */job: Job; /** Whether the job executed successfully */
3494
- success: boolean; /** Error if the job failed */
3495
- error?: Error; /** The operations generated from the actions (if successful) */
3496
- operations?: Operation[];
3602
+ * Updates the preferred editor in the document header meta and waits for completion.
3603
+ *
3604
+ * @param documentIdentifier - Target document id or slug
3605
+ * @param preferredEditor - The new preferred editor, or `null` to clear it
3606
+ * @param branch - Optional branch, defaults to "main"
3607
+ * @param signal - Optional abort signal to cancel the request
3608
+ * @returns The updated document.
3609
+ */
3610
+ setPreferredEditor(documentIdentifier: string, preferredEditor: string | null, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
3497
3611
  /**
3498
- * Operations with context (includes ephemeral resultingState).
3499
- * Used for emitting to IDocumentView via event bus.
3612
+ * Adds a relationship between two documents and waits for completion.
3613
+ *
3614
+ * Adding a relationship that already exists is a no-op, metadata included.
3615
+ * Use {@link IReactorClient.updateRelationship} to change an existing edge.
3616
+ *
3617
+ * @param sourceIdentifier - Source document id or slug
3618
+ * @param targetIdentifier - Target document id or slug
3619
+ * @param relationshipType - Relationship type identifier
3620
+ * @param metadata - Optional metadata to attach to the relationship
3621
+ * @param branch - Optional branch to add the relationship to, defaults to "main"
3622
+ * @param signal - Optional abort signal to cancel the request
3623
+ * @returns The updated source document
3500
3624
  */
3501
- operationsWithContext?: OperationWithContext$1[]; /** Timestamp when the job execution completed */
3502
- completedAt?: string; /** Duration of job execution in milliseconds */
3503
- duration?: number; /** Any additional metadata from the execution */
3504
- metadata?: Record<string, any>;
3505
- };
3506
- /**
3507
- * Enforcement the reactor performs, each off by default.
3508
- *
3509
- * An evaluation made while replaying is part of the document's history, so two
3510
- * reactors that share documents and disagree on these diverge. A flag is turned
3511
- * on for a set of reactors that sync with each other, not for one node.
3512
- */
3513
- type ReactorFeatureFlags = {
3625
+ addRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, metadata?: Record<string, unknown>, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
3514
3626
  /**
3515
- * Decide whether an operation may be admitted by building a decision model
3516
- * over the document stream, rather than reading the deleted flag from the
3517
- * document meta cache. Deletion then takes effect from the deleting
3518
- * operation's position rather than for the whole document.
3627
+ * Replaces the metadata of an existing relationship and waits for completion.
3628
+ * The relationship's createdAt is preserved.
3629
+ *
3630
+ * @param sourceIdentifier - Source document id or slug
3631
+ * @param targetIdentifier - Target document id or slug
3632
+ * @param relationshipType - Relationship type identifier
3633
+ * @param metadata - The metadata to store; null clears it
3634
+ * @param branch - Optional branch holding the relationship, defaults to "main"
3635
+ * @param signal - Optional abort signal to cancel the request
3636
+ * @returns The updated source document
3519
3637
  */
3520
- documentDecisions: boolean;
3638
+ updateRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, metadata: Record<string, unknown> | null, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
3521
3639
  /**
3522
- * Evaluate the auth policy by reading the auth scope as a second projection.
3523
- * Requires documentDecisions.
3640
+ * Removes a relationship between two documents and waits for completion.
3641
+ *
3642
+ * @param sourceIdentifier - Source document id or slug
3643
+ * @param targetIdentifier - Target document id or slug
3644
+ * @param relationshipType - Relationship type identifier
3645
+ * @param branch - Optional branch to remove the relationship from, defaults to "main"
3646
+ * @param signal - Optional abort signal to cancel the request
3647
+ * @returns The updated source document
3524
3648
  */
3525
- authEnforcement: boolean;
3649
+ removeRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
3526
3650
  /**
3527
- * Match { group } principals by folding the referenced PHGroup documents as
3528
- * derived projections. Requires authEnforcement.
3651
+ * Moves a relationship from one source document to another and waits for completion.
3652
+ *
3653
+ * @param sourceParentIdentifier - Source parent document id or slug
3654
+ * @param targetParentIdentifier - Target parent document id or slug
3655
+ * @param targetIdentifier - The target document id or slug
3656
+ * @param relationshipType - Relationship type identifier
3657
+ * @param branch - Optional branch to apply the move to, defaults to "main"
3658
+ * @param signal - Optional abort signal to cancel the request
3659
+ * @returns The updated source and target documents
3529
3660
  */
3530
- authGroups: boolean;
3661
+ moveRelationship(sourceParentIdentifier: string, targetParentIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<{
3662
+ source: PHDocument;
3663
+ target: PHDocument;
3664
+ }>;
3531
3665
  /**
3532
- * Evaluate `where` clauses and { match } principals against the executing
3533
- * scope's state, the subject, and the action input. Requires authGroups.
3666
+ * Deletes a document and waits for completion
3667
+ *
3668
+ * @param identifier - Document identifier (id or slug)
3669
+ * @param propagate - Optional mode for handling children, CASCADE deletes child documents
3670
+ * @param signal - Optional abort signal to cancel the request
3671
+ * @returns a promise, resolving on deletion confirmation
3534
3672
  */
3535
- authConditions: boolean;
3536
- };
3537
- /**
3538
- * Configuration options for the job executor
3539
- */
3540
- type JobExecutorConfig = {
3541
- /** Feature flags; anything unset is off. */featureFlags?: Partial<ReactorFeatureFlags>; /** Maximum number of conflicting operations to skip when reshuffling. */
3542
- maxSkipThreshold?: number; /** Maximum number of concurrent jobs to execute */
3543
- maxConcurrency?: number; /** Maximum time in milliseconds a job can run before being considered timed out */
3544
- jobTimeoutMs?: number;
3545
- /** How long a job whose document is missing waits for it before failing.
3546
- * Unbounded deferral never resolves the caller awaiting the job. */
3547
- deferredJobTtlMs?: number; /** Base delay in milliseconds for exponential backoff retries */
3548
- retryBaseDelayMs?: number; /** Maximum delay in milliseconds for exponential backoff retries */
3549
- retryMaxDelayMs?: number;
3550
- /** Maximum elapsed milliseconds before yielding to the main thread between actions.
3551
- * Keeps the UI responsive when processing large batches. */
3552
- yieldDeadlineMs?: number;
3673
+ deleteDocument(identifier: string, propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
3553
3674
  /**
3554
- * Persist a job's writes in one store transaction rather than one each.
3675
+ * Deletes documents and waits for completion
3555
3676
  *
3556
- * On by default. A job's operations are reduced sequentially either way; this
3557
- * only changes how many apply calls carry them, which is one advisory lock
3558
- * and one guarded insert per batch instead of per operation. Only runs that
3559
- * qualify are batched, and the executor falls back per write for the rest, so
3560
- * this never changes which operations are produced -- only how many
3561
- * transactions they arrive in.
3677
+ * @param identifiers - Document identifiers (ids or slugs)
3678
+ * @param propagate - Optional mode for handling children, CASCADE deletes child documents
3679
+ * @param signal - Optional abort signal to cancel the request
3680
+ * @returns a promise, resolving on deletion confirmation
3681
+ */
3682
+ deleteDocuments(identifiers: string[], propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
3683
+ /**
3684
+ * Loads multiple batches of pre-existing operations across documents with dependency management.
3685
+ * Waits for all jobs to complete.
3562
3686
  *
3563
- * Atomicity is not one of the things it changes. A job either fully applies
3564
- * or leaves nothing durable behind regardless of this setting, because the
3565
- * whole job runs inside the execution scope's transaction and a failure
3566
- * rolls it back.
3567
- * That guarantee belongs to KyselyExecutionScope, which backs both Postgres
3568
- * and PGlite; DefaultExecutionScope opens no transaction and is used only by
3569
- * unit-test harnesses, which therefore see writes survive a failed job.
3687
+ * @param request - Batch load request containing jobs with dependencies
3688
+ * @param signal - Optional abort signal to cancel the request
3689
+ * @returns Map of job keys to completed job information
3570
3690
  */
3571
- batchApplies?: boolean;
3572
- };
3573
- /**
3574
- * Event types for the job executor
3575
- */
3576
- declare const JobExecutorEventTypes: {
3577
- readonly JOB_STARTED: 20000;
3578
- readonly JOB_COMPLETED: 20001;
3579
- readonly JOB_FAILED: 20002;
3580
- readonly EXECUTOR_STARTED: 20003;
3581
- readonly EXECUTOR_STOPPED: 20004;
3582
- };
3583
- /**
3584
- * Event data for job execution events
3585
- */
3586
- type JobStartedEvent = {
3587
- job: Job;
3588
- startedAt: string;
3691
+ loadBatch(request: BatchLoadRequest, signal?: AbortSignal): Promise<BatchLoadResult>;
3589
3692
  /**
3590
- * Identifier of the executor that took the job. For the worker pool this is
3591
- * the thread-worker id (e.g. "reactor-worker-3"); for the in-process simple
3592
- * manager it is "in-process-<index>". Optional for backwards compatibility
3593
- * with consumers built before the field was added.
3693
+ * Retrieves the status of a job
3694
+ *
3695
+ * @param jobId - The job id
3696
+ * @param signal - Optional abort signal to cancel the request
3697
+ * @returns The job status
3594
3698
  */
3595
- workerId?: string;
3596
- };
3597
- type JobCompletedEvent = {
3598
- job: Job;
3599
- result: JobResult; /** See {@link JobStartedEvent.workerId}. */
3600
- workerId?: string;
3601
- };
3602
- type JobFailedEvent = {
3603
- job: Job;
3604
- error: string;
3605
- willRetry: boolean;
3606
- retryCount: number; /** See {@link JobStartedEvent.workerId}. */
3607
- workerId?: string;
3608
- };
3609
- type ExecutorStartedEvent = {
3610
- config: JobExecutorConfig;
3611
- startedAt: string;
3612
- };
3613
- type ExecutorStoppedEvent = {
3614
- stoppedAt: string;
3615
- graceful: boolean;
3616
- };
3617
- /**
3618
- * Status information for the job executor manager
3619
- */
3620
- type ExecutorManagerStatus = {
3621
- /** Whether the manager is currently running */isRunning: boolean; /** Number of executor instances managed */
3622
- numExecutors: number; /** Number of jobs currently being processed */
3623
- activeJobs: number; /** Total number of jobs processed since start */
3624
- totalJobsProcessed: number;
3625
- };
3699
+ getJobStatus(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
3700
+ /**
3701
+ * Waits for a job to complete
3702
+ *
3703
+ * @param jobId - The job id or job object
3704
+ * @param signal - Optional abort signal to cancel the request
3705
+ * @returns The result of the job
3706
+ */
3707
+ waitForJob(jobId: string | JobInfo, signal?: AbortSignal): Promise<JobInfo>;
3708
+ /**
3709
+ * Subscribes to changes for documents matching specified filters
3710
+ *
3711
+ * @param search - Search filter options (type, parentId, identifiers)
3712
+ * @param callback - Function called when documents change with the change event details
3713
+ * @param view - Optional filter containing branch and scopes information
3714
+ * @returns A function that unsubscribes from the changes
3715
+ */
3716
+ subscribe(search: SearchFilter, callback: (event: DocumentChangeEvent) => void, view?: ViewFilter): () => void;
3717
+ }
3626
3718
  //#endregion
3627
3719
  //#region src/decision/document-decision-model.d.ts
3628
3720
  /** What the document decision model reads: the target's document scope. */
@@ -3890,8 +3982,9 @@ declare class ReactorClient implements IReactorClient {
3890
3982
  private documentView;
3891
3983
  private readGate;
3892
3984
  private actionEvaluation;
3985
+ private readonly createSignaturePolicy;
3893
3986
  readonly drives: IDriveClient;
3894
- constructor(logger: ILogger, reactor: IReactor, signer: ISigner, subscriptionManager: IReactorSubscriptionManager, jobAwaiter: IJobAwaiter, documentIndexer: IDocumentIndexer, documentView: IDocumentView, readGate?: IReadGate, actionEvaluation?: ActionEvaluationConfig);
3987
+ constructor(logger: ILogger, reactor: IReactor, signer: ISigner, subscriptionManager: IReactorSubscriptionManager, jobAwaiter: IJobAwaiter, documentIndexer: IDocumentIndexer, documentView: IDocumentView, readGate?: IReadGate, actionEvaluation?: ActionEvaluationConfig, createSignaturePolicy?: SignaturePolicy);
3895
3988
  private readSubject;
3896
3989
  /**
3897
3990
  * Which scopes of one document the subject may read. Resolved once per
@@ -4017,6 +4110,7 @@ declare class ReactorClient implements IReactorClient {
4017
4110
  * is why the answer is a prediction.
4018
4111
  */
4019
4112
  private buildEvaluationTarget;
4113
+ getCreateSignaturePolicy(): Promise<SignaturePolicy>;
4020
4114
  /**
4021
4115
  * Creates a document and waits for completion
4022
4116
  */
@@ -4056,6 +4150,12 @@ declare class ReactorClient implements IReactorClient {
4056
4150
  * Submits a list of actions to a document
4057
4151
  */
4058
4152
  executeAsync(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal): Promise<JobInfo>;
4153
+ /**
4154
+ * The id a write on `identifier` is stored under, which its signatures bind.
4155
+ * A create names its own id, and an id no slug maps to is taken as given, so
4156
+ * a document still in flight resolves to itself.
4157
+ */
4158
+ private resolveWriteTarget;
4059
4159
  executeBatch(request: BatchExecutionRequest, signal?: AbortSignal): Promise<BatchExecutionResult>;
4060
4160
  /**
4061
4161
  * Renames a document and waits for completion
@@ -4128,6 +4228,7 @@ type WorkerInFlightSnapshot = {
4128
4228
  type WorkerExecutionOutcome = {
4129
4229
  result: JobResult;
4130
4230
  writeReady?: JobWriteReadyPayload;
4231
+ signatureRefusals?: SignatureRefusedEvent[];
4131
4232
  };
4132
4233
  /**
4133
4234
  * Parent-side handle for a single executor worker.
@@ -5996,22 +6097,6 @@ declare class HybridProjectionCoordinator implements ILiveReadModelCoordinator {
5996
6097
  private queueKeyFor;
5997
6098
  }
5998
6099
  //#endregion
5999
- //#region src/signer/types.d.ts
6000
- /**
6001
- * Configuration for signing and verification.
6002
- */
6003
- type SignerConfig = {
6004
- /**
6005
- * The signer used to sign actions before submission.
6006
- */
6007
- signer: ISigner;
6008
- /**
6009
- * Optional handler for verifying signatures on incoming operations.
6010
- * If not provided, signature verification will be skipped.
6011
- */
6012
- verifier?: SignatureVerificationHandler;
6013
- };
6014
- //#endregion
6015
6100
  //#region src/storage/migrations/types.d.ts
6016
6101
  type MigrationStrategy = "auto" | "manual" | "none";
6017
6102
  interface MigrationResult {
@@ -6095,12 +6180,6 @@ interface ReadModelCoordinatorFactoryDeps {
6095
6180
  type ReadModelCoordinatorFactory = (deps: ReadModelCoordinatorFactoryDeps) => IReadModelCoordinator | Promise<IReadModelCoordinator>;
6096
6181
  type WorkerPoolBase = {
6097
6182
  /** Number of worker threads to spawn; also the sticky-routing modulus. */numWorkers: number;
6098
- /**
6099
- * Factory spec the default transport's workers import to instantiate
6100
- * their signature verifier. Omitted = no executor-side verification,
6101
- * parity with the in-process executor's default.
6102
- */
6103
- verifier?: SignatureVerifierSpec;
6104
6183
  };
6105
6184
  /**
6106
6185
  * Executor worker-pool configuration. Either `db` (default thread
@@ -6165,8 +6244,11 @@ declare class ReactorBuilder {
6165
6244
  private eventBus?;
6166
6245
  private readModelCoordinator?;
6167
6246
  private readModelCoordinatorFactory?;
6168
- private signatureVerifier?;
6169
6247
  private kyselyInstance?;
6248
+ private signer?;
6249
+ private workerSigner?;
6250
+ private trustPolicy?;
6251
+ private workerTrustPolicy?;
6170
6252
  private signalHandlersEnabled;
6171
6253
  private queueInstance?;
6172
6254
  private channelScheme?;
@@ -6214,7 +6296,22 @@ declare class ReactorBuilder {
6214
6296
  withMigrationStrategy(strategy: MigrationStrategy): this;
6215
6297
  withSync(syncBuilder: SyncBuilder): this;
6216
6298
  withEventBus(eventBus: IEventBus): this;
6217
- withSignatureVerifier(verifier: SignatureVerificationHandler): this;
6299
+ /**
6300
+ * Signs the operations the executor synthesizes: the NOOP an UNDO becomes and
6301
+ * the action a REDO rebuilds. Without one they are stored unsigned. Pooled
6302
+ * workers import `workerSigner` to build the same signer.
6303
+ */
6304
+ withSigner(signer: ISigner, workerSigner?: FactorySpec): this;
6305
+ /** Whether {@link withSigner} was called. */
6306
+ hasSigner(): boolean;
6307
+ /**
6308
+ * Decides at admission whether a key may sign as the user it claims; see
6309
+ * {@link SignatureTrustPolicy} for the contract and the default. Pooled
6310
+ * workers import `workerTrustPolicy` to build the same policy.
6311
+ */
6312
+ withTrustPolicy(trustPolicy: SignatureTrustPolicy, workerTrustPolicy?: FactorySpec): this;
6313
+ /** Whether {@link withTrustPolicy} was called. */
6314
+ hasTrustPolicy(): boolean;
6218
6315
  withKysely(kysely: Kysely<Database>): this;
6219
6316
  /**
6220
6317
  * Register an externally-constructed pg.Pool's {@link PoolInstrumentation}
@@ -6244,8 +6341,7 @@ declare class ReactorBuilder {
6244
6341
  * this enables the pool — there is no `enabled` flag. Provide `db`
6245
6342
  * (each worker opens its own Postgres pool; the parent database is built
6246
6343
  * from it too unless {@link withKysely} is set) or a custom `factory`
6247
- * transport. `verifier` is imported by the default transport's workers;
6248
- * omitted = no executor-side signature verification.
6344
+ * transport.
6249
6345
  */
6250
6346
  withWorkerPool(options: WorkerPoolOptions): this;
6251
6347
  /**
@@ -6331,7 +6427,10 @@ declare class ReactorClientBuilder {
6331
6427
  private documentIndexer?;
6332
6428
  private documentView?;
6333
6429
  private signer?;
6334
- private signatureVerifier?;
6430
+ private workerSigner?;
6431
+ private trustPolicy?;
6432
+ private workerTrustPolicy?;
6433
+ private createSignaturePolicy;
6335
6434
  private subscriptionManager?;
6336
6435
  private jobAwaiter?;
6337
6436
  private documentModelLoader?;
@@ -6351,11 +6450,17 @@ declare class ReactorClientBuilder {
6351
6450
  */
6352
6451
  withReactor(reactor: IReactor, eventBus: IEventBus, documentIndexer: IDocumentIndexer, documentView: IDocumentView): this;
6353
6452
  /**
6354
- * Sets the signer configuration for signing and verifying actions.
6355
- *
6356
- * @param config - Either an ISigner for signing only, or a SignerConfig for both signing and verification
6453
+ * Signs submitted actions, and the operations a reactor built from
6454
+ * `withReactorBuilder` synthesizes unless that builder has its own signer.
6455
+ * A `trustPolicy` reaches that builder unless it has its own.
6357
6456
  */
6358
6457
  withSigner(config: ISigner | SignerConfig): this;
6458
+ /**
6459
+ * What the client creates new documents as when a call does not say:
6460
+ * `v2-required` (the default) or `legacy`, for a fleet with peers that
6461
+ * predate v2-required documents. Existing documents keep their policy.
6462
+ */
6463
+ withCreateSignaturePolicy(policy: SignaturePolicy): this;
6359
6464
  withSubscriptionManager(subscriptionManager: IReactorSubscriptionManager): this;
6360
6465
  withJobAwaiter(jobAwaiter: IJobAwaiter): this;
6361
6466
  withDocumentModelLoader(loader: IDocumentModelLoader): this;
@@ -6465,6 +6570,14 @@ declare function parseDriveUrl(url: string): ParsedDriveUrl;
6465
6570
  declare function driveIdFromUrl(url: string): string;
6466
6571
  //#endregion
6467
6572
  //#region src/shared/errors.d.ts
6573
+ /** The message carries the code: only name and message cross the queue. */
6574
+ declare class InvalidSignatureError extends Error {
6575
+ readonly documentId: string;
6576
+ readonly code: SignatureRefusalCode;
6577
+ readonly reason: string;
6578
+ constructor(documentId: string, code: SignatureRefusalCode, reason: string);
6579
+ static isError(error: unknown): error is InvalidSignatureError;
6580
+ }
6468
6581
  /**
6469
6582
  * An authorization preflight was asked for while the reactor's decision model
6470
6583
  * is off, so there is no model to answer from.
@@ -6523,6 +6636,20 @@ type ParsedPaging = {
6523
6636
  */
6524
6637
  declare function parsePagingOptions(paging: PagingOptions | undefined, defaultLimit: number): ParsedPaging;
6525
6638
  //#endregion
6639
+ //#region src/signer/verify-action-signature.d.ts
6640
+ type VerificationTarget = {
6641
+ /** The stream the operation is stored in. */documentId: string;
6642
+ branch: string; /** Of the document `documentId` names; legacy when omitted. */
6643
+ policy?: SignaturePolicy;
6644
+ };
6645
+ /**
6646
+ * Integrity only: identity binding and the live-id check sit with the caller.
6647
+ * `operation` is the incoming operation at load admission.
6648
+ */
6649
+ declare function verifyActionSignature(action: Action, target: VerificationTarget, path: AdmissionPath, operation?: {
6650
+ timestampUtcMs: string;
6651
+ }): Promise<SignatureVerdict>;
6652
+ //#endregion
6526
6653
  //#region src/subs/default-error-handler.d.ts
6527
6654
  /**
6528
6655
  * Default error handler that re-throws subscription errors.
@@ -6761,10 +6888,15 @@ declare class SimpleJobExecutor implements IJobExecutor {
6761
6888
  private config;
6762
6889
  private featureFlags;
6763
6890
  private decisionModel;
6764
- private signatureVerifierModule;
6891
+ private signatureAdmission;
6765
6892
  private documentActionHandler;
6766
6893
  private executionScope;
6767
- constructor(logger: ILogger, registry: IDocumentModelRegistry, operationStore: IOperationStore, eventBus: IEventBus, writeCache: IWriteCache, operationIndex: IOperationIndex, documentMetaCache: IDocumentMetaCache, collectionMembershipCache: ICollectionMembershipCache, driveContainerTypes: ReadonlySet<string>, config: JobExecutorConfig, signatureVerifier?: SignatureVerificationHandler, executionScope?: IExecutionScope);
6894
+ private signer;
6895
+ /**
6896
+ * `signer` signs the operations the reducer synthesizes; unsigned if omitted.
6897
+ * `trustPolicy` decides which keys may sign as which users at admission.
6898
+ */
6899
+ constructor(logger: ILogger, registry: IDocumentModelRegistry, operationStore: IOperationStore, eventBus: IEventBus, writeCache: IWriteCache, operationIndex: IOperationIndex, documentMetaCache: IDocumentMetaCache, collectionMembershipCache: ICollectionMembershipCache, driveContainerTypes: ReadonlySet<string>, config: JobExecutorConfig, executionScope?: IExecutionScope, signer?: ISigner, trustPolicy?: SignatureTrustPolicy);
6768
6900
  /**
6769
6901
  * Execute a single job by applying all its actions through the appropriate reducers.
6770
6902
  * Actions are processed sequentially in order.
@@ -6794,6 +6926,18 @@ declare class SimpleJobExecutor implements IJobExecutor {
6794
6926
  * has not committed yet has nothing to announce.
6795
6927
  */
6796
6928
  private executeInScope;
6929
+ /**
6930
+ * A successful mutation's result and the write-ready event it owes, carrying
6931
+ * what earlier attempts committed ahead of what this one wrote.
6932
+ */
6933
+ private committedOutcome;
6934
+ /**
6935
+ * The stored operations of writes an earlier attempt committed, as a fresh
6936
+ * write would report them. State is rebuilt from the write cache, and left
6937
+ * out when it cannot be.
6938
+ */
6939
+ private reloadCommitted;
6940
+ private rebuiltState;
6797
6941
  /**
6798
6942
  * Drops the cached state of every stream a job wrote, after its transaction
6799
6943
  * did not commit.
@@ -6842,7 +6986,7 @@ declare class SimpleJobExecutor implements IJobExecutor {
6842
6986
  * apply and its own reasons for it.
6843
6987
  * - A positional or replayed run carries skips and re-appended operations,
6844
6988
  * whose indices are not a simple ascending run from the head.
6845
- * - UNDO, REDO, PRUNE and NOOP-with-skip each invalidate the write cache to
6989
+ * - UNDO, REDO and NOOP-with-skip each invalidate the write cache to
6846
6990
  * force a full-history rebuild, so they cannot be reduced against state
6847
6991
  * threaded from the write before them.
6848
6992
  * - The auth scope decides later writes against the policy earlier ones
@@ -6943,6 +7087,8 @@ declare class SimpleJobExecutor implements IJobExecutor {
6943
7087
  */
6944
7088
  private executeReevaluationJob;
6945
7089
  private executeLoadJob;
7090
+ /** The conflicting window a load opens, and which of its operations are new. */
7091
+ private selectLoadWrites;
6946
7092
  private accumulateResultOrReturnError;
6947
7093
  }
6948
7094
  //#endregion
@@ -7727,26 +7873,26 @@ declare class DocumentIntegrityService implements IDocumentIntegrityService {
7727
7873
  }
7728
7874
  //#endregion
7729
7875
  //#region src/processors/processor-manager.d.ts
7876
+ type PendingSlot = {
7877
+ factoryId: string;
7878
+ driveId: string;
7879
+ reservedAt: number;
7880
+ lowestRoutedOrdinal: number | undefined;
7881
+ settled: Promise<void> | undefined;
7882
+ };
7883
+ type FactoryRun = () => Promise<void>;
7730
7884
  type ProcessorManagerOptions = {
7731
7885
  legacyProcessorIds?: boolean;
7732
7886
  };
7733
- /**
7734
- * Manages processor lifecycle based on operations.
7735
- * Extends BaseReadModel to receive operations from ReadModelCoordinator.
7736
- *
7737
- * Responsibilities:
7738
- * 1. Detect drive creation from CREATE_DOCUMENT operations
7739
- * 2. Create processors for each drive using registered factories
7740
- * 3. Route operations to matching processors based on filters
7741
- * 4. Clean up processors when drives are deleted or factories are unregistered
7742
- * 5. Track per-processor cursors for failure recovery and backfill
7743
- */
7744
7887
  declare class ProcessorManager extends BaseReadModel implements IProcessorManager$1 {
7745
7888
  private factoryRegistry;
7746
7889
  private processorsByDrive;
7747
- private factoryToProcessors;
7890
+ private pendingSlots;
7748
7891
  private knownDrives;
7892
+ private highestRoutedOrdinal;
7749
7893
  private cursorCache;
7894
+ private cursorWrites;
7895
+ private draining;
7750
7896
  private logger;
7751
7897
  private driveContainerTypes;
7752
7898
  private legacyProcessorIds;
@@ -7757,23 +7903,36 @@ declare class ProcessorManager extends BaseReadModel implements IProcessorManage
7757
7903
  unregisterFactory(identifier: string): Promise<void>;
7758
7904
  get(processorId: string): TrackedProcessor$1 | undefined;
7759
7905
  getAll(): TrackedProcessor$1[];
7906
+ /** Synchronous: reserves a slot per registered factory for each new drive. */
7907
+ protected detectNewDrives(items: OperationWithContext$1[]): {
7908
+ runs: FactoryRun[];
7909
+ reserved: Set<PendingSlot>;
7910
+ };
7911
+ /** Synchronous: drops a deleted drive's processors from the tables. */
7912
+ protected detectDeletedDrives(items: OperationWithContext$1[]): Promise<void>[];
7913
+ /** Synchronous: puts each processor's share of the batch on its queue. */
7914
+ protected enqueueRouted(items: OperationWithContext$1[], reserved: ReadonlySet<PendingSlot>): Promise<void>[];
7915
+ /** Synchronous: binds records, or discards them if the slot was cancelled. */
7916
+ protected bind(slot: PendingSlot, records: ProcessorRecord$1[] | undefined, creationOrdinal: number, creationItems: OperationWithContext$1[] | undefined): {
7917
+ persisted: Promise<void>;
7918
+ delivered: Promise<void>;
7919
+ };
7920
+ /** Synchronous: removes a factory's slots, processors and cursor rows. */
7921
+ protected removeFactory(identifier: string): Promise<void>[];
7922
+ private reserveSlot;
7923
+ private runFactory;
7924
+ private track;
7925
+ private discard;
7926
+ private highWater;
7927
+ private allBound;
7760
7928
  private allTrackedProcessors;
7761
- private detectAndRegisterNewDrives;
7762
7929
  private isDriveCreation;
7763
- private detectAndCleanupDeletedDrives;
7764
7930
  private discoverExistingDrives;
7765
- private isDeletedDocumentADrive;
7766
- private createProcessorsForDrive;
7767
- private backfillProcessor;
7768
- private retryProcessor;
7769
- private cleanupDriveProcessors;
7770
- private safeDisconnect;
7771
- private routeOperationsToProcessors;
7772
7931
  private loadAllCursors;
7773
- private safeSaveProcessorCursor;
7774
- private saveProcessorCursor;
7775
- private deleteProcessorCursors;
7932
+ private lane;
7933
+ private writeCursor;
7934
+ private deleteCursors;
7776
7935
  }
7777
7936
  //#endregion
7778
- export { ALWAYS_READABLE_SCOPES, APPEND_CONDITION_FAILED_PREFIX, type AbortMessage, type ActionCandidate, type ActionEvaluationConfig, type ActionEvaluations, type AdmissionDecision, type AppendCondition, AppendConditionFailedError, type AppendConditionStream, type AtomicTxn, type AttachmentHash, type AttachmentRef, type AuthDecisionModel, AuthEnforcementDisabledError, BareReadGate, BaseReadModel, type BaseReadModelConfig, 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_COMMIT_CHUNK_SIZE, DEFAULT_DRIVE_CONTAINER_TYPES, DEFAULT_READ_MODEL_YIELD_DEADLINE_MS, DOCUMENT_INDEXER_READ_MODEL, DOCUMENT_VIEW_READ_MODEL, DRIVE_AUTH_ERROR_MESSAGES, type Database, type DbConfig, type DeadLetterAddedEvent, type DecisionContext, type DecisionModel, type DecisionTarget, DefaultSubscriptionErrorHandler, type DegradedComponent, DeletedDocumentRead, DocumentAlreadyExistsError, type DocumentChangeEvent, DocumentChangeType, type DocumentDecisionModel, DocumentExistence, type DocumentGraphEdge, type DocumentIndexerDatabase, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, type DocumentModelSource, type DocumentModelSpec, type DocumentRelationship, type DocumentRevisions, type DocumentStreamKey, type DocumentViewDatabase, DriveClient, DriveCollectionId, DriveRequestError, 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, HybridProjectionCoordinator, type HybridProjectionCoordinatorOptions, type HybridProjectionOptions, 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 IProcessorHostModuleBase, type IProcessorManager, type IProjectionTransport, type IQueue, type IReactor, type IReactorClient, type IReactorProcessorHostModuleBase, 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 JobResultSummary, 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 ProjectionShardHooks, type ProjectionShardManagerConfig, type ProjectionWorkerFactory, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, RECOVERABLE_GRAPHQL_ERROR_CODES, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, type ReactorClientModule, ReactorEventTypes, type ReactorFeatureFlags, type ReactorFeatures, type ReactorHostModuleBaseOptions, type JobFailedEvent$1 as ReactorJobFailedEvent, type ReactorModule, type ReactorReadModels, ReactorSubscriptionManager, type ReadGateOptions, type ReadModelBatchCompletedEvent, ReadModelCoordinator, type ReadModelCoordinatorFactory, type ReadModelCoordinatorFactoryDeps, type ReadModelFactory, type ReadModelFactoryDeps, type ReadModelIndexedEvent, type ReadModelIndexingConfig, type ReadModelIndexingStage, type ReadModelRegistrationStage, type ReadModelStage, type ReadyMessage, type RebuildResult, type RegisteredDecisionModel, RelationalDbProcessor, RelationshipChangeType, RelationshipNotFoundError, type Remote, type RemoteCursor, type RemoteFilter, type RemoteMeta, type RemoteOptions, type RemoteRecord, type RemoteStatus, type ResultMessage, RetryAccounting, RevisionMismatchError, type SanitizedArg, type SearchFilter, SeededStateReader, type ShutdownMessage, type ShutdownStatus, type SignatureVerificationHandler, type SignatureVerifierSpec, type SignerConfig, SimpleJobExecutorManager, type SnapshotValidationIssue, type Database$1 as StorageDatabase, type StreamOrderIssue, type StreamQuery, type SubmittedActionResult, type SubscriptionErrorContext, SyncBuilder, type SyncEnvelope, type SyncEnvelopeType, SyncEventTypes, type SyncFailedEvent, type SyncModule, SyncOperation, SyncOperationAggregateError, type SyncOperationErrorType, SyncOperationStatus, type SyncPendingEvent, SyncScopeGate, 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, createHybridProjectionCoordinatorFactory, createMutableShutdownStatus, createReactorHostModuleBase, createRelationalDb, decideAtHead, defaultReadModelIndexingConfig, deleteDocumentAction, documentActions, documentDecisionModel, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, firstOutOfOrderPair, getMigrationStatus, instrumentPgPool, isDriveAuthError, isRecoverableGraphQLError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, quarantinesDocument, readDecisionModel, removeRelationshipAction, runMigrations, sanitizeArg, selectDecisionModel, supportsLiveReadModelRegistration, syncOperationErrorType, trimMailboxFromAckOrdinal, unchunkedReadModelIndexingConfig, updateRelationshipAction, upgradeDocumentAction, workerEntryPath };
7937
+ export { ALWAYS_READABLE_SCOPES, APPEND_CONDITION_FAILED_PREFIX, type AbortMessage, type ActionCandidate, type ActionEvaluationConfig, type ActionEvaluations, type AdmissionDecision, type AdmissionPath, type AppendCondition, AppendConditionFailedError, type AppendConditionStream, type AtomicTxn, type AttachmentHash, type AttachmentRef, type AuthDecisionModel, AuthEnforcementDisabledError, BareReadGate, BaseReadModel, type BaseReadModelConfig, 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_COMMIT_CHUNK_SIZE, DEFAULT_DRIVE_CONTAINER_TYPES, DEFAULT_READ_MODEL_YIELD_DEADLINE_MS, DOCUMENT_INDEXER_READ_MODEL, DOCUMENT_VIEW_READ_MODEL, DRIVE_AUTH_ERROR_MESSAGES, type Database, type DbConfig, type DeadLetterAddedEvent, type DecisionContext, type DecisionModel, type DecisionTarget, DefaultSubscriptionErrorHandler, type DegradedComponent, DeletedDocumentRead, DocumentAlreadyExistsError, type DocumentChangeEvent, DocumentChangeType, type DocumentDecisionModel, DocumentExistence, type DocumentGraphEdge, type DocumentIndexerDatabase, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, type DocumentModelSource, type DocumentModelSpec, type DocumentRelationship, type DocumentRevisions, type DocumentStreamKey, type DocumentViewDatabase, DriveClient, DriveCollectionId, DriveRequestError, 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, HybridProjectionCoordinator, type HybridProjectionCoordinatorOptions, type HybridProjectionOptions, 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 IProcessorHostModuleBase, type IProcessorManager, type IProjectionTransport, type IQueue, type IReactor, type IReactorClient, type IReactorProcessorHostModuleBase, 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, InvalidSignatureError, type Job, type JobAvailableEvent, JobAwaiter, type JobCompletedEvent, type JobExecutorConfig, JobExecutorEventTypes, type JobExecutorFactory, type JobFailedEvent, type JobInfo, type JobPendingEvent, type JobReadReadyEvent, type JobResult, type JobResultSummary, 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 ProjectionShardHooks, type ProjectionShardManagerConfig, type ProjectionWorkerFactory, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, RECOVERABLE_GRAPHQL_ERROR_CODES, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, type ReactorClientModule, ReactorEventTypes, type ReactorFeatureFlags, type ReactorFeatures, type ReactorHostModuleBaseOptions, type JobFailedEvent$1 as ReactorJobFailedEvent, type ReactorModule, type ReactorReadModels, ReactorSubscriptionManager, type ReadGateOptions, type ReadModelBatchCompletedEvent, ReadModelCoordinator, type ReadModelCoordinatorFactory, type ReadModelCoordinatorFactoryDeps, type ReadModelFactory, type ReadModelFactoryDeps, type ReadModelIndexedEvent, type ReadModelIndexingConfig, type ReadModelIndexingStage, type ReadModelRegistrationStage, type ReadModelStage, type ReadyMessage, type RebuildResult, type RegisteredDecisionModel, RelationalDbProcessor, RelationshipChangeType, RelationshipNotFoundError, type Remote, type RemoteCursor, type RemoteFilter, type RemoteMeta, type RemoteOptions, type RemoteRecord, type RemoteStatus, type ResultMessage, RetryAccounting, RevisionMismatchError, SIGNATURE_REFUSAL_CODES, type SanitizedArg, type SearchFilter, SeededStateReader, type ShutdownMessage, type ShutdownStatus, type SignatureRefusalCode, type SignatureRefusedEvent, type SignatureScheme, type SignatureTrustPolicy, type SignatureVerificationHandler, type SignatureVerificationMode, type SignerConfig, SimpleJobExecutorManager, type SnapshotValidationIssue, type Database$1 as StorageDatabase, type StreamOrderIssue, type StreamQuery, type SubmittedActionResult, type SubscriptionErrorContext, SyncBuilder, type SyncEnvelope, type SyncEnvelopeType, SyncEventTypes, type SyncFailedEvent, type SyncModule, SyncOperation, SyncOperationAggregateError, type SyncOperationErrorType, SyncOperationStatus, type SyncPendingEvent, SyncScopeGate, SyncStatus, type SyncStatusChangeCallback, SyncStatusTracker, type SyncSucceededEvent, type TrackedProcessor, type Unsubscribe, type ValidationResult, type VerificationTarget, type ViewFilter, type ErrorInfo as WorkerErrorInfo, type WorkerMessage, type WorkerPoolConfig, type WorkerPoolOptions, type WriteCacheConfig, addRelationshipAction, authDecisionModel, batchOperationsByDocument, buildDecisionModel, classifyJobFailure, consolidateSyncOperations, createDocumentAction, createForwardingLogger, createHybridProjectionCoordinatorFactory, createMutableShutdownStatus, createReactorHostModuleBase, createRelationalDb, decideAtHead, defaultReadModelIndexingConfig, deleteDocumentAction, documentActions, documentDecisionModel, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, firstOutOfOrderPair, getMigrationStatus, instrumentPgPool, isDriveAuthError, isRecoverableGraphQLError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, quarantinesDocument, readDecisionModel, removeRelationshipAction, runMigrations, sanitizeArg, selectDecisionModel, supportsLiveReadModelRegistration, syncOperationErrorType, trimMailboxFromAckOrdinal, unchunkedReadModelIndexingConfig, updateRelationshipAction, upgradeDocumentAction, verifyActionSignature, workerEntryPath };
7779
7938
  //# sourceMappingURL=index.d.ts.map