@powerhousedao/reactor 6.2.2-dev.5 → 6.2.2-dev.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{build-worker-executor--nhFRF47.js → build-worker-executor-NT9b3rNm.js} +2 -2
- package/dist/{build-worker-executor--nhFRF47.js.map → build-worker-executor-NT9b3rNm.js.map} +1 -1
- package/dist/{document-indexer-FGJmRAdX.js → document-indexer-DlpJB8AK.js} +37 -22
- package/dist/document-indexer-DlpJB8AK.js.map +1 -0
- package/dist/{drive-container-types-DpJp2AmE.js → drive-container-types-RZa1wukO.js} +2182 -314
- package/dist/drive-container-types-RZa1wukO.js.map +1 -0
- package/dist/entry.js +3 -2
- package/dist/entry.js.map +1 -1
- package/dist/index.d.ts +2302 -1313
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +959 -100
- package/dist/index.js.map +1 -1
- package/dist/projection-entry.js +4 -4
- package/dist/projection-entry.js.map +1 -1
- package/dist/{worker-handle-B1w03nRA.js → worker-handle-CrERzl8s.js} +3 -2
- package/dist/worker-handle-CrERzl8s.js.map +1 -0
- package/dist/{worker-DBJOv8Gp.js → worker-sw2vjrd3.js} +2 -2
- package/dist/{worker-DBJOv8Gp.js.map → worker-sw2vjrd3.js.map} +1 -1
- package/package.json +5 -4
- package/dist/document-indexer-FGJmRAdX.js.map +0 -1
- package/dist/drive-container-types-DpJp2AmE.js.map +0 -1
- package/dist/worker-handle-B1w03nRA.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Action, CreateDocumentActionInput, DocumentModelModule, ISigner, Operation, OperationContext, OperationWithContext, OperationWithContext as OperationWithContext$1, PHDocument, PHDocumentState, SignatureVerificationHandler, UpgradeDocumentActionInput, UpgradeManifest, UpgradeReducer, UpgradeTransition, actions as documentActions } from "@powerhousedao/shared/document-model";
|
|
1
|
+
import { Action, AuthRequest, AuthSubject, CreateDocumentActionInput, DocumentModelModule, ISigner, Operation, OperationContext, OperationWithContext, OperationWithContext as OperationWithContext$1, PHAuthState, PHDocument, PHDocumentState, SignatureVerificationHandler, UpgradeDocumentActionInput, UpgradeManifest, UpgradeReducer, UpgradeTransition, actions as documentActions } from "@powerhousedao/shared/document-model";
|
|
2
2
|
import { DocumentDriveDocument, DriveInput, FolderNode, Node } from "@powerhousedao/shared/document-drive";
|
|
3
3
|
import { ILogger } from "document-model";
|
|
4
4
|
import * as kysely from "kysely";
|
|
@@ -57,7 +57,14 @@ declare function updateRelationshipAction(sourceId: string, targetId: string, re
|
|
|
57
57
|
declare function removeRelationshipAction(sourceId: string, targetId: string, relationshipType?: string): Action;
|
|
58
58
|
//#endregion
|
|
59
59
|
//#region src/queue/types.d.ts
|
|
60
|
-
|
|
60
|
+
/**
|
|
61
|
+
* What a job carries: a mutation applies actions, a load imports synced
|
|
62
|
+
* operations, and a reevaluation re-judges a document's stored operations
|
|
63
|
+
* because a read-set stream elsewhere (a group document) changed. A
|
|
64
|
+
* reevaluation job carries no actions or operations; its work is derived
|
|
65
|
+
* from what is already stored.
|
|
66
|
+
*/
|
|
67
|
+
type JobKind = "mutation" | "load" | "reevaluation";
|
|
61
68
|
/**
|
|
62
69
|
* State of a job in the queue
|
|
63
70
|
*/
|
|
@@ -69,6 +76,17 @@ declare enum JobQueueState {
|
|
|
69
76
|
RUNNING = 3,
|
|
70
77
|
RESOLVED = 4
|
|
71
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* How a retry is accounted against the job's retry limit.
|
|
81
|
+
* - `CountAgainstLimit` (default): a fault; the job eventually exhausts its
|
|
82
|
+
* retries and fails terminally.
|
|
83
|
+
* - `ExemptFromLimit`: not a fault, so the attempt is not charged to the job.
|
|
84
|
+
* Used for concurrency conflicts, where the retry does new work.
|
|
85
|
+
*/
|
|
86
|
+
declare enum RetryAccounting {
|
|
87
|
+
CountAgainstLimit = "count-against-limit",
|
|
88
|
+
ExemptFromLimit = "exempt-from-limit"
|
|
89
|
+
}
|
|
72
90
|
/**
|
|
73
91
|
* Interface for a job execution handle
|
|
74
92
|
*/
|
|
@@ -127,9 +145,14 @@ type JobAvailableEvent = {
|
|
|
127
145
|
//#endregion
|
|
128
146
|
//#region src/shared/types.d.ts
|
|
129
147
|
/**
|
|
130
|
-
* Information about an error including message and stack trace.
|
|
148
|
+
* Information about an error including its name, message and stack trace.
|
|
149
|
+
*
|
|
150
|
+
* The name is what survives the crossing out of the executor: a consumer that
|
|
151
|
+
* has to tell a terminal failure from a retryable one, or classify a dead
|
|
152
|
+
* letter, only ever sees this record rather than the thrown error.
|
|
131
153
|
*/
|
|
132
154
|
type ErrorInfo$1 = {
|
|
155
|
+
name: string;
|
|
133
156
|
message: string;
|
|
134
157
|
stack: string;
|
|
135
158
|
};
|
|
@@ -230,6 +253,11 @@ type ViewFilter = {
|
|
|
230
253
|
branch?: string;
|
|
231
254
|
scopes?: string[];
|
|
232
255
|
revision?: number;
|
|
256
|
+
/**
|
|
257
|
+
* Read subject for the IReactorClient read gate; defaults to the client's
|
|
258
|
+
* signer. Set per request when serving many principals. Ignored by IReactor.
|
|
259
|
+
*/
|
|
260
|
+
subject?: AuthSubject;
|
|
233
261
|
};
|
|
234
262
|
/**
|
|
235
263
|
* Describes filter options for searching documents.
|
|
@@ -328,6 +356,16 @@ interface IReadModelCoordinator {
|
|
|
328
356
|
*/
|
|
329
357
|
getChainDepth(): number;
|
|
330
358
|
}
|
|
359
|
+
type ReadModelRegistrationStage = "pre_ready" | "post_ready";
|
|
360
|
+
/**
|
|
361
|
+
* Optional capability exposed by coordinators that support adding read models
|
|
362
|
+
* after construction. Custom and remote coordinators are not required to
|
|
363
|
+
* implement it.
|
|
364
|
+
*/
|
|
365
|
+
interface ILiveReadModelCoordinator extends IReadModelCoordinator {
|
|
366
|
+
addReadModel(readModel: IReadModel, stage: ReadModelRegistrationStage): void;
|
|
367
|
+
}
|
|
368
|
+
declare function supportsLiveReadModelRegistration(coordinator: IReadModelCoordinator): coordinator is ILiveReadModelCoordinator;
|
|
331
369
|
//#endregion
|
|
332
370
|
//#region src/sync/types.d.ts
|
|
333
371
|
declare enum ChannelScheme {
|
|
@@ -398,7 +436,13 @@ declare enum ChannelErrorSource {
|
|
|
398
436
|
Inbox = "inbox",
|
|
399
437
|
Outbox = "outbox"
|
|
400
438
|
}
|
|
401
|
-
type SyncOperationErrorType = "SIGNATURE_INVALID" | "HASH_MISMATCH" | "LIBRARY_ERROR" | "MISSING_OPERATIONS" | "EXCESSIVE_SHUFFLE" | "GRACEFUL_ABORT"
|
|
439
|
+
type SyncOperationErrorType = "SIGNATURE_INVALID" | "HASH_MISMATCH" | "LIBRARY_ERROR" | "MISSING_OPERATIONS" | "EXCESSIVE_SHUFFLE" | "GRACEFUL_ABORT"
|
|
440
|
+
/**
|
|
441
|
+
* An arriving auth operation did not exceed the local auth head. Exempt from
|
|
442
|
+
* quarantine, because reconciling the two policies needs the traffic a
|
|
443
|
+
* quarantine would stop.
|
|
444
|
+
*/
|
|
445
|
+
| "AUTH_TIMESTAMP_NOT_MONOTONIC" /** An arriving operation carried a timestamp that is not an ISO-8601 instant. */ | "INVALID_TIMESTAMP" /** No classification applies, including rows written before the field. */ | "UNCLASSIFIED";
|
|
402
446
|
type ChannelHealth = {
|
|
403
447
|
state: "idle" | "running" | "error";
|
|
404
448
|
lastSuccessUtcMs?: number;
|
|
@@ -491,6 +535,7 @@ type DeadLetterAddedEvent = {
|
|
|
491
535
|
remoteName: string;
|
|
492
536
|
documentId: string;
|
|
493
537
|
errorSource: ChannelErrorSource;
|
|
538
|
+
errorType: SyncOperationErrorType;
|
|
494
539
|
};
|
|
495
540
|
/**
|
|
496
541
|
* Status of a sync operation result.
|
|
@@ -537,6 +582,36 @@ declare class OptimisticLockError extends Error {
|
|
|
537
582
|
declare class RevisionMismatchError extends Error {
|
|
538
583
|
constructor(expected: number, actual: number);
|
|
539
584
|
}
|
|
585
|
+
/**
|
|
586
|
+
* One read-set stream and the highest operation index observed on it, or -1
|
|
587
|
+
* if it was observed empty.
|
|
588
|
+
*/
|
|
589
|
+
type AppendConditionStream = {
|
|
590
|
+
documentId: string;
|
|
591
|
+
scope: string;
|
|
592
|
+
branch: string;
|
|
593
|
+
revision: number;
|
|
594
|
+
};
|
|
595
|
+
/**
|
|
596
|
+
* A read-set enforced by {@link IOperationStore.apply}: the append fails if
|
|
597
|
+
* any stream has operations past its recorded revision.
|
|
598
|
+
*/
|
|
599
|
+
type AppendCondition = {
|
|
600
|
+
streams: AppendConditionStream[];
|
|
601
|
+
};
|
|
602
|
+
/** Error history keeps messages, not classes, so failures match by prefix. */
|
|
603
|
+
declare const APPEND_CONDITION_FAILED_PREFIX = "Append condition failed: ";
|
|
604
|
+
/**
|
|
605
|
+
* A read-set stream grew before the append committed. A concurrency
|
|
606
|
+
* conflict, not a fault: the caller retries against the new stream heads.
|
|
607
|
+
*/
|
|
608
|
+
declare class AppendConditionFailedError extends Error {
|
|
609
|
+
readonly condition: AppendCondition;
|
|
610
|
+
constructor(condition: AppendCondition);
|
|
611
|
+
static isError(error: unknown): error is AppendConditionFailedError;
|
|
612
|
+
/** True when a recorded error message is an append-condition failure. */
|
|
613
|
+
static isFailureMessage(message: string): boolean;
|
|
614
|
+
}
|
|
540
615
|
/**
|
|
541
616
|
* A write transaction passed to {@link IOperationStore.apply}. Accumulates
|
|
542
617
|
* operations that are committed atomically when the callback returns.
|
|
@@ -550,7 +625,7 @@ interface AtomicTxn {
|
|
|
550
625
|
* revision field and lastModified timestamp.
|
|
551
626
|
*/
|
|
552
627
|
type DocumentRevisions = {
|
|
553
|
-
/** Map of scope to operation index for that scope */revision: Record<string, number>; /**
|
|
628
|
+
/** Map of scope to operation index for that scope */revision: Record<string, number>; /** The largest operation timestamp in the document, across every scope. */
|
|
554
629
|
latestTimestamp: string;
|
|
555
630
|
};
|
|
556
631
|
/**
|
|
@@ -571,6 +646,12 @@ interface IOperationStore {
|
|
|
571
646
|
* returned instead of throwing. If no matching stored row is found, the
|
|
572
647
|
* original error is propagated unchanged.
|
|
573
648
|
*
|
|
649
|
+
* With an {@link AppendCondition}, the append additionally fails with
|
|
650
|
+
* {@link AppendConditionFailedError} — writing nothing — if any read-set
|
|
651
|
+
* stream has operations past its recorded revision. The written and
|
|
652
|
+
* read-set streams are advisory-locked in sorted key order, so concurrent
|
|
653
|
+
* conditional appends on overlapping streams serialize.
|
|
654
|
+
*
|
|
574
655
|
* @param documentId - The document id
|
|
575
656
|
* @param documentType - The document type identifier
|
|
576
657
|
* @param scope - The operation scope (e.g. "global", "local")
|
|
@@ -578,9 +659,10 @@ interface IOperationStore {
|
|
|
578
659
|
* @param revision - Expected current revision (optimistic lock)
|
|
579
660
|
* @param fn - Callback that stages operations via {@link AtomicTxn}
|
|
580
661
|
* @param signal - Optional abort signal to cancel the request
|
|
662
|
+
* @param condition - Optional read-set to enforce at write time
|
|
581
663
|
* @returns The stored operations; empty array when no operations were staged
|
|
582
664
|
*/
|
|
583
|
-
apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal): Promise<Operation[]>;
|
|
665
|
+
apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal, condition?: AppendCondition): Promise<Operation[]>;
|
|
584
666
|
/**
|
|
585
667
|
* Returns operations for a document/scope/branch whose index is greater
|
|
586
668
|
* than the given revision.
|
|
@@ -627,6 +709,16 @@ interface IOperationStore {
|
|
|
627
709
|
* @returns Object containing revision map and latest timestamp
|
|
628
710
|
*/
|
|
629
711
|
getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
|
|
712
|
+
/**
|
|
713
|
+
* The largest operation timestamp in one stream, or undefined when it is empty.
|
|
714
|
+
* Distinct from {@link DocumentRevisions.latestTimestamp}, which maxes over
|
|
715
|
+
* every scope.
|
|
716
|
+
*
|
|
717
|
+
* Must be a real maximum, not the last-indexed operation's timestamp: a
|
|
718
|
+
* re-evaluation pass re-appends at a fresh index while keeping the original
|
|
719
|
+
* timestamp, so a later timestamp can sit behind the last row.
|
|
720
|
+
*/
|
|
721
|
+
getStreamLatestTimestamp(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
|
|
630
722
|
}
|
|
631
723
|
/**
|
|
632
724
|
* Stores periodic document snapshots (keyframes) so that document state
|
|
@@ -1045,7 +1137,8 @@ type DeadLetterRecord = {
|
|
|
1045
1137
|
branch: string;
|
|
1046
1138
|
operations: OperationWithContext$1[];
|
|
1047
1139
|
errorSource: ChannelErrorSource;
|
|
1048
|
-
errorMessage: string;
|
|
1140
|
+
errorMessage: string; /** Why it failed, in the closed set sync classifies failures into. */
|
|
1141
|
+
errorType: SyncOperationErrorType;
|
|
1049
1142
|
};
|
|
1050
1143
|
/**
|
|
1051
1144
|
* Persists dead-lettered sync operations so they survive reactor restarts.
|
|
@@ -1103,6 +1196,15 @@ interface IOperationIndexTxn {
|
|
|
1103
1196
|
createCollection(collectionId: string): void;
|
|
1104
1197
|
addToCollection(collectionId: string, documentId: string): void;
|
|
1105
1198
|
removeFromCollection(collectionId: string, documentId: string): void;
|
|
1199
|
+
/**
|
|
1200
|
+
* Records the group documents an auth operation's input names, tied to the
|
|
1201
|
+
* last written operation like addToCollection. At commit each reference is
|
|
1202
|
+
* remembered permanently and the group joins every collection the
|
|
1203
|
+
* referencing document belongs to, keeping the earliest join and reopening
|
|
1204
|
+
* a closed membership, so sync serves the group's history to every remote
|
|
1205
|
+
* that can observe the referencing grant.
|
|
1206
|
+
*/
|
|
1207
|
+
recordGroupReferences(documentId: string, groupIds: string[]): void;
|
|
1106
1208
|
write(operations: OperationIndexEntry[]): void;
|
|
1107
1209
|
}
|
|
1108
1210
|
/**
|
|
@@ -1124,6 +1226,13 @@ interface IOperationIndex {
|
|
|
1124
1226
|
* Returns a map of documentId to array of collection IDs.
|
|
1125
1227
|
*/
|
|
1126
1228
|
getCollectionsForDocuments(documentIds: string[]): Promise<Record<string, string[]>>;
|
|
1229
|
+
/**
|
|
1230
|
+
* The documents whose auth history has ever referenced the group, from the
|
|
1231
|
+
* group-reference relation. This is the set a group-stream change owes a
|
|
1232
|
+
* re-evaluation pass to; it is complete because a group's auth scope cannot
|
|
1233
|
+
* reference other groups.
|
|
1234
|
+
*/
|
|
1235
|
+
getGroupReferencers(groupId: string, signal?: AbortSignal): Promise<string[]>;
|
|
1127
1236
|
}
|
|
1128
1237
|
/**
|
|
1129
1238
|
* Identifies the collection a remote synchronizes. Collections are drive-level
|
|
@@ -1152,6 +1261,51 @@ declare class DriveCollectionId {
|
|
|
1152
1261
|
equals(other: DriveCollectionId): boolean;
|
|
1153
1262
|
}
|
|
1154
1263
|
//#endregion
|
|
1264
|
+
//#region src/cache/write-cache-types.d.ts
|
|
1265
|
+
/**
|
|
1266
|
+
* Configuration options for the write cache
|
|
1267
|
+
*/
|
|
1268
|
+
type WriteCacheConfig = {
|
|
1269
|
+
/** Maximum number of document streams to cache (LRU eviction). Default: 1000 */maxDocuments: number; /** Number of snapshots to keep in each document's ring buffer. Default: 10 */
|
|
1270
|
+
ringBufferSize: number; /** Persist a keyframe snapshot every N revisions. Default: 10 */
|
|
1271
|
+
keyframeInterval: number;
|
|
1272
|
+
};
|
|
1273
|
+
/**
|
|
1274
|
+
* Unique identifier for a document stream
|
|
1275
|
+
*/
|
|
1276
|
+
type DocumentStreamKey = {
|
|
1277
|
+
/** Document identifier */documentId: string; /** Operation scope */
|
|
1278
|
+
scope: string; /** Branch name */
|
|
1279
|
+
branch: string;
|
|
1280
|
+
};
|
|
1281
|
+
/**
|
|
1282
|
+
* Where a snapshot sits in its stream.
|
|
1283
|
+
*
|
|
1284
|
+
* - `Head`: the newest revision of the stream when it was stored. Only these
|
|
1285
|
+
* can answer a read that asks for the head.
|
|
1286
|
+
* - `Historical`: state at an earlier revision. Usable as a starting point to
|
|
1287
|
+
* replay forward from, and as an answer to a read for that same revision.
|
|
1288
|
+
*/
|
|
1289
|
+
declare enum SnapshotPosition {
|
|
1290
|
+
Head = "head",
|
|
1291
|
+
Historical = "historical"
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* A cached document snapshot at a specific revision
|
|
1295
|
+
*/
|
|
1296
|
+
type CachedSnapshot = {
|
|
1297
|
+
/** The revision number of this snapshot */revision: number; /** The document state at this revision */
|
|
1298
|
+
document: PHDocument; /** Where this snapshot sat in the stream when it was stored */
|
|
1299
|
+
position: SnapshotPosition;
|
|
1300
|
+
};
|
|
1301
|
+
/**
|
|
1302
|
+
* Serialized keyframe snapshot for K/V store persistence
|
|
1303
|
+
*/
|
|
1304
|
+
type KeyframeSnapshot = {
|
|
1305
|
+
/** The revision number of this keyframe */revision: number; /** Serialized document state */
|
|
1306
|
+
document: string;
|
|
1307
|
+
};
|
|
1308
|
+
//#endregion
|
|
1155
1309
|
//#region src/cache/write/interfaces.d.ts
|
|
1156
1310
|
/**
|
|
1157
1311
|
* IWriteCache is a write-side projection that optimizes document state retrieval
|
|
@@ -1166,7 +1320,8 @@ interface IWriteCache {
|
|
|
1166
1320
|
* @param documentId - The document identifier
|
|
1167
1321
|
* @param scope - Operation scope
|
|
1168
1322
|
* @param branch - Branch name
|
|
1169
|
-
* @param targetRevision -
|
|
1323
|
+
* @param targetRevision - Index of the last operation to apply, defaulting
|
|
1324
|
+
* to latest. An operation index, never `header.revision[scope]`.
|
|
1170
1325
|
* @param signal - Optional abort signal to cancel the operation
|
|
1171
1326
|
* @returns The complete document at the specified revision
|
|
1172
1327
|
*
|
|
@@ -1192,15 +1347,19 @@ interface IWriteCache {
|
|
|
1192
1347
|
* @param documentId - The document identifier
|
|
1193
1348
|
* @param scope - Operation scope
|
|
1194
1349
|
* @param branch - Branch name
|
|
1195
|
-
* @param revision -
|
|
1350
|
+
* @param revision - Index of the last operation this document reflects, so
|
|
1351
|
+
* `header.revision[scope]` is one greater. -1 for an empty scope.
|
|
1196
1352
|
* @param document - The document to cache
|
|
1353
|
+
* @param position - Whether `revision` is the stream's head. Nothing checks
|
|
1354
|
+
* it: claiming `Head` for an earlier revision makes a getState() with no
|
|
1355
|
+
* target return stale state.
|
|
1197
1356
|
*
|
|
1198
1357
|
* @example
|
|
1199
1358
|
* ```typescript
|
|
1200
|
-
* cache.putState(docId, 'global', 'main', 42, document);
|
|
1359
|
+
* cache.putState(docId, 'global', 'main', 42, document, SnapshotPosition.Head);
|
|
1201
1360
|
* ```
|
|
1202
1361
|
*/
|
|
1203
|
-
putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument): void;
|
|
1362
|
+
putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, position: SnapshotPosition): void;
|
|
1204
1363
|
/**
|
|
1205
1364
|
* Invalidates (removes) cached entries for a document stream.
|
|
1206
1365
|
*
|
|
@@ -1500,6 +1659,104 @@ interface IReactorSubscriptionManager {
|
|
|
1500
1659
|
onRelationshipChanged(callback: (parentId: string, childId: string, changeType: RelationshipChangeType) => void, search?: SearchFilter): () => void;
|
|
1501
1660
|
}
|
|
1502
1661
|
//#endregion
|
|
1662
|
+
//#region src/decision/types.d.ts
|
|
1663
|
+
/** One operation stream. */
|
|
1664
|
+
type StreamQuery = {
|
|
1665
|
+
documentId: string;
|
|
1666
|
+
branch: string;
|
|
1667
|
+
scope: string;
|
|
1668
|
+
};
|
|
1669
|
+
/**
|
|
1670
|
+
* What building a decision model reads a stream's state through.
|
|
1671
|
+
*
|
|
1672
|
+
* `IWriteCache` satisfies this and is what the write paths pass. The read path
|
|
1673
|
+
* cannot: the write cache is a write-side projection invalidated by the process
|
|
1674
|
+
* that runs the executor, so a reactor whose executors live in worker processes
|
|
1675
|
+
* holds state in its parent that no commit ever invalidates. A read there would
|
|
1676
|
+
* decide against a policy arbitrarily far behind the one the write paths
|
|
1677
|
+
* enforce. Reads therefore pass a reader backed by the read side.
|
|
1678
|
+
*/
|
|
1679
|
+
interface IStreamStateReader {
|
|
1680
|
+
getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
|
|
1681
|
+
}
|
|
1682
|
+
/** The document and branch a decision model is built for. */
|
|
1683
|
+
type DecisionTarget = {
|
|
1684
|
+
documentId: string;
|
|
1685
|
+
branch: string;
|
|
1686
|
+
};
|
|
1687
|
+
/**
|
|
1688
|
+
* What a decision's conditions may read beyond the projections: the executing
|
|
1689
|
+
* scope's own state and the attempted action's input. Populated only while
|
|
1690
|
+
* authConditions is on; otherwise both stay undefined and conditional grants
|
|
1691
|
+
* never apply.
|
|
1692
|
+
*/
|
|
1693
|
+
type DecisionContext = {
|
|
1694
|
+
scopeState: unknown;
|
|
1695
|
+
actionInput?: unknown;
|
|
1696
|
+
};
|
|
1697
|
+
/** A statically-queried stream's operations, named after its projection. */
|
|
1698
|
+
type StreamHistory = {
|
|
1699
|
+
name: string;
|
|
1700
|
+
operations: Operation[];
|
|
1701
|
+
};
|
|
1702
|
+
/**
|
|
1703
|
+
* A named stream whose value in the model is that scope's state from the
|
|
1704
|
+
* document rebuild the reactor already performs. A derived query may read
|
|
1705
|
+
* only statically-queried projections, so composition is one layer deep.
|
|
1706
|
+
*/
|
|
1707
|
+
type Projection<M> = {
|
|
1708
|
+
query: StreamQuery | ((model: Partial<M>) => StreamQuery[]);
|
|
1709
|
+
/**
|
|
1710
|
+
* For a derived projection, the streams it may read anywhere in an
|
|
1711
|
+
* evaluated range, derived from the statically-queried streams' operations
|
|
1712
|
+
* (including the operations under evaluation). A positional walk cannot use
|
|
1713
|
+
* `query`, because the folded state it depends on changes over the range;
|
|
1714
|
+
* this over-approximates by design, since a stream referenced at any
|
|
1715
|
+
* position stays readable when the earlier range is re-evaluated even if a
|
|
1716
|
+
* later operation removes the reference. Ignored on static projections.
|
|
1717
|
+
*/
|
|
1718
|
+
queryOverHistory?: (reads: StreamHistory[]) => StreamQuery[];
|
|
1719
|
+
/**
|
|
1720
|
+
* Action types in this stream that can change an evaluation. Reads of the stream
|
|
1721
|
+
* are filtered to these, so anything left out is invisible to a decision.
|
|
1722
|
+
*/
|
|
1723
|
+
decidingActions: string[]; /** Applies one of this stream's operations while deciding. */
|
|
1724
|
+
apply: (document: PHDocument, operation: Operation) => PHDocument;
|
|
1725
|
+
};
|
|
1726
|
+
/**
|
|
1727
|
+
* The outcome of evaluating one operation. A refusal carries the reason it is
|
|
1728
|
+
* recorded with, because a model has more than one way to refuse.
|
|
1729
|
+
*/
|
|
1730
|
+
type Evaluation = {
|
|
1731
|
+
decision: "allow";
|
|
1732
|
+
} | {
|
|
1733
|
+
decision: "deny";
|
|
1734
|
+
reason: string;
|
|
1735
|
+
};
|
|
1736
|
+
/** Projections plus a decision function over the built model. */
|
|
1737
|
+
type DecisionModel<M> = {
|
|
1738
|
+
projections: { [K in keyof M]: Projection<M> };
|
|
1739
|
+
/**
|
|
1740
|
+
* Present when decide reads the executing scope's state through the
|
|
1741
|
+
* decision context. A positional walk then folds the evaluated stream with
|
|
1742
|
+
* this, from its base state through every effective operation, so
|
|
1743
|
+
* conditions read the state as it stood at each operation's position
|
|
1744
|
+
* rather than at the head.
|
|
1745
|
+
*/
|
|
1746
|
+
foldEvaluatedScope?: (document: PHDocument, operation: Operation) => PHDocument;
|
|
1747
|
+
/**
|
|
1748
|
+
* Whether or not this model decides about operations in a given scope. That
|
|
1749
|
+
* is, a scope it reads is not necessarily one it evaluates, and vise-versa.
|
|
1750
|
+
*/
|
|
1751
|
+
evaluatesScope(scope: string): boolean;
|
|
1752
|
+
decide(model: M, subject: AuthSubject, request: AuthRequest, ctx: DecisionContext): Evaluation;
|
|
1753
|
+
};
|
|
1754
|
+
/** A built model plus the read-set condition recording what the build read. */
|
|
1755
|
+
type BuiltDecisionModel<M> = {
|
|
1756
|
+
model: M;
|
|
1757
|
+
appendCondition: AppendCondition;
|
|
1758
|
+
};
|
|
1759
|
+
//#endregion
|
|
1503
1760
|
//#region src/client/types.d.ts
|
|
1504
1761
|
/**
|
|
1505
1762
|
* Describes the types of document changes that can occur.
|
|
@@ -1531,6 +1788,17 @@ type CreateDocumentOptions = {
|
|
|
1531
1788
|
/** Optional "id" or "slug" of parent document */parentIdentifier?: string; /** Optional version of the document model to use (defaults to latest) */
|
|
1532
1789
|
documentModelVersion?: number;
|
|
1533
1790
|
};
|
|
1791
|
+
/**
|
|
1792
|
+
* Options for upgrading a document.
|
|
1793
|
+
*/
|
|
1794
|
+
type UpgradeDocumentOptions = {
|
|
1795
|
+
/**
|
|
1796
|
+
* How many times to retry with a fresh read when the executor rejects the
|
|
1797
|
+
* upgrade because the document changed after it was read. Defaults to
|
|
1798
|
+
* {@link DEFAULT_UPGRADE_CONFLICT_RETRIES}.
|
|
1799
|
+
*/
|
|
1800
|
+
maxConflictRetries?: number;
|
|
1801
|
+
};
|
|
1534
1802
|
/**
|
|
1535
1803
|
* Drive-aware operations grouped under `client.drives`.
|
|
1536
1804
|
*
|
|
@@ -1596,6 +1864,33 @@ interface IDriveClient {
|
|
|
1596
1864
|
*/
|
|
1597
1865
|
listNodes(driveIdentifier: string, parentFolder?: string | null, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Node>>;
|
|
1598
1866
|
}
|
|
1867
|
+
/**
|
|
1868
|
+
* One operation an authorization preflight predicts a verdict for. The input is
|
|
1869
|
+
* what a conditional grant reads, so a candidate standing for a filled-in form
|
|
1870
|
+
* carries that form's input.
|
|
1871
|
+
*/
|
|
1872
|
+
type ActionCandidate = {
|
|
1873
|
+
scope: string;
|
|
1874
|
+
type: string;
|
|
1875
|
+
input?: unknown;
|
|
1876
|
+
};
|
|
1877
|
+
/**
|
|
1878
|
+
* The predicted verdicts for a set of candidates, in the order they were given,
|
|
1879
|
+
* with the aggregates a UI branches on.
|
|
1880
|
+
*
|
|
1881
|
+
* The aggregates are redundant -- a verdict is binary, so `allDenied` is
|
|
1882
|
+
* `!anyAllowed` and `anyDenied` is `!allAllowed` -- and all four are returned
|
|
1883
|
+
* so that a caller reads the one its question is phrased in rather than
|
|
1884
|
+
* negating another. Over no candidates every aggregate is false: nothing is
|
|
1885
|
+
* allowed and nothing is denied.
|
|
1886
|
+
*/
|
|
1887
|
+
type ActionEvaluations = {
|
|
1888
|
+
evaluations: Evaluation[];
|
|
1889
|
+
allAllowed: boolean;
|
|
1890
|
+
anyAllowed: boolean;
|
|
1891
|
+
allDenied: boolean;
|
|
1892
|
+
anyDenied: boolean;
|
|
1893
|
+
};
|
|
1599
1894
|
/**
|
|
1600
1895
|
* The ReactorClient interface that wraps lower-level APIs to provide
|
|
1601
1896
|
* a simpler interface for document operations.
|
|
@@ -1646,7 +1941,7 @@ interface IReactorClient {
|
|
|
1646
1941
|
* @param signal - Optional abort signal to cancel the request
|
|
1647
1942
|
* @returns The canonical document id
|
|
1648
1943
|
*/
|
|
1649
|
-
resolveIdOrSlug(identifier: string, signal?: AbortSignal): Promise<string>;
|
|
1944
|
+
resolveIdOrSlug(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<string>;
|
|
1650
1945
|
/**
|
|
1651
1946
|
* Retrieves operations for a document.
|
|
1652
1947
|
*
|
|
@@ -1690,6 +1985,44 @@ interface IReactorClient {
|
|
|
1690
1985
|
* @returns List of documents matching criteria and pagination cursor
|
|
1691
1986
|
*/
|
|
1692
1987
|
find(search: SearchFilter, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
|
|
1988
|
+
/**
|
|
1989
|
+
* Predicts whether the subject would be admitted to execute each of a set of
|
|
1990
|
+
* candidate operations, without submitting any of them. A UI asks this to
|
|
1991
|
+
* disable a control rather than offer an action that fails on submit.
|
|
1992
|
+
*
|
|
1993
|
+
* The answer is a prediction, not a promise. Three caveats hold:
|
|
1994
|
+
*
|
|
1995
|
+
* - Real admission compiles an append condition over everything it read and
|
|
1996
|
+
* the store enforces it at write time. A preflight reads no future, so a
|
|
1997
|
+
* policy change landing between this answer and the submit changes the
|
|
1998
|
+
* verdict. The submit path stays the only authority.
|
|
1999
|
+
* - The verdict is evaluated at the stream heads. It is therefore correct for
|
|
2000
|
+
* a candidate that will be stamped at or after every timestamp the
|
|
2001
|
+
* evaluation read, which is the normal case for a control the user is about
|
|
2002
|
+
* to click. A backdated submission is out of contract: the reactor decides
|
|
2003
|
+
* that one by position, against the policy as it stood there.
|
|
2004
|
+
* - A candidate whose input decides the verdict needs that input supplied.
|
|
2005
|
+
* With `authConditions` on, a conditional grant reads `action.input`, so
|
|
2006
|
+
* omitting the input predicts the denial an empty input would earn rather
|
|
2007
|
+
* than the verdict the filled-in form will get.
|
|
2008
|
+
*
|
|
2009
|
+
* Document-scope candidates are decided against the policy of the document
|
|
2010
|
+
* their input names, not the one passed here: delete and upgrade name it in
|
|
2011
|
+
* `input.documentId`, and the relationship actions in `input.sourceId`. This
|
|
2012
|
+
* follows the executor's own gate, which decides against the document
|
|
2013
|
+
* guarding the write. `CREATE_DOCUMENT` follows the gate's exemption: it runs
|
|
2014
|
+
* before its document exists, so the executor never decides it against a
|
|
2015
|
+
* policy and the preflight predicts allow.
|
|
2016
|
+
*
|
|
2017
|
+
* @param documentIdentifier - Document "id" or "slug" the candidates target
|
|
2018
|
+
* @param branch - Branch to evaluate against
|
|
2019
|
+
* @param candidates - Operations to predict a verdict for, each with the scope it would execute in
|
|
2020
|
+
* @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
|
|
2021
|
+
* @param signal - Optional abort signal to cancel the request
|
|
2022
|
+
* @returns One evaluation per candidate, in the order given, with the aggregates over them
|
|
2023
|
+
* @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
|
|
2024
|
+
*/
|
|
2025
|
+
evaluateActions(documentIdentifier: string, branch: string, candidates: ActionCandidate[], subject?: AuthSubject, signal?: AbortSignal): Promise<ActionEvaluations>;
|
|
1693
2026
|
/**
|
|
1694
2027
|
* Creates a document and waits for completion
|
|
1695
2028
|
*
|
|
@@ -1707,6 +2040,38 @@ interface IReactorClient {
|
|
|
1707
2040
|
* @param signal - Optional abort signal to cancel the request
|
|
1708
2041
|
*/
|
|
1709
2042
|
createEmpty<TDocument extends PHDocument>(documentModelType: string, options?: CreateDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
|
|
2043
|
+
/**
|
|
2044
|
+
* Retrieves the document model module matching the version a document is
|
|
2045
|
+
* stamped with. Use this instead of {@link getDocumentModelModule}
|
|
2046
|
+
* whenever a specific document is in hand: the latest-wins lookup feeds
|
|
2047
|
+
* not-yet-upgraded documents the wrong reducer, diverging from replay.
|
|
2048
|
+
*
|
|
2049
|
+
* @param document - The document whose stamped version selects the module
|
|
2050
|
+
* @returns The document model module registered for that version
|
|
2051
|
+
* @throws UnsupportedDocumentModelVersionError if no module is registered for the stamped version
|
|
2052
|
+
*/
|
|
2053
|
+
getDocumentModelModuleForDocument(document: PHDocument): Promise<DocumentModelModule<any>>;
|
|
2054
|
+
/**
|
|
2055
|
+
* Upgrades a document to a newer document model version by dispatching an
|
|
2056
|
+
* UPGRADE_DOCUMENT action. When toVersion is omitted, upgrades to the
|
|
2057
|
+
* latest registered module version for the document's type. Returns the
|
|
2058
|
+
* document unchanged when it is already at the target version.
|
|
2059
|
+
*
|
|
2060
|
+
* The action carries a snapshot of the document's version and per-scope
|
|
2061
|
+
* revisions, which the executor validates before persisting. When an edit
|
|
2062
|
+
* lands between the read and the upgrade executing, the upgrade is
|
|
2063
|
+
* rejected and retried with a fresh read up to
|
|
2064
|
+
* {@link UpgradeDocumentOptions.maxConflictRetries} times before the
|
|
2065
|
+
* conflict is surfaced.
|
|
2066
|
+
*
|
|
2067
|
+
* @param documentIdentifier - Target document id or slug
|
|
2068
|
+
* @param toVersion - Optional target document model version; defaults to latest
|
|
2069
|
+
* @param options - Optional upgrade options (maxConflictRetries)
|
|
2070
|
+
* @param signal - Optional abort signal to cancel the request
|
|
2071
|
+
* @returns The upgraded document
|
|
2072
|
+
* @throws DowngradeNotSupportedError if toVersion is less than the document's current version
|
|
2073
|
+
*/
|
|
2074
|
+
upgradeDocument<TDocument extends PHDocument = PHDocument>(documentIdentifier: string, toVersion?: number, options?: UpgradeDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
|
|
1710
2075
|
/**
|
|
1711
2076
|
* Creates an empty document in a drive as a single batched operation.
|
|
1712
2077
|
* This is more efficient than createEmpty + addFile as it batches all
|
|
@@ -1863,136 +2228,1042 @@ interface IReactorClient {
|
|
|
1863
2228
|
subscribe(search: SearchFilter, callback: (event: DocumentChangeEvent) => void, view?: ViewFilter): () => void;
|
|
1864
2229
|
}
|
|
1865
2230
|
//#endregion
|
|
1866
|
-
//#region src/
|
|
2231
|
+
//#region src/cache/collection-membership-cache.d.ts
|
|
2232
|
+
interface ICollectionMembershipCache {
|
|
2233
|
+
getCollectionsForDocuments(documentIds: string[]): Promise<Record<string, string[]>>;
|
|
2234
|
+
invalidate(documentId: string): void;
|
|
2235
|
+
}
|
|
2236
|
+
//#endregion
|
|
2237
|
+
//#region src/cache/document-meta-cache-types.d.ts
|
|
1867
2238
|
/**
|
|
1868
|
-
*
|
|
1869
|
-
* a simpler interface for document operations.
|
|
2239
|
+
* Cached document metadata from the "document" scope.
|
|
1870
2240
|
*
|
|
1871
|
-
*
|
|
1872
|
-
*
|
|
1873
|
-
* -
|
|
1874
|
-
* - Provides quality-of-life functions for common tasks
|
|
1875
|
-
* - Wraps subscription interface with ViewFilters
|
|
2241
|
+
* This lightweight structure holds essential document information needed by
|
|
2242
|
+
* the job executor without fetching full scope state. It provides an explicit
|
|
2243
|
+
* cross-scope contract for accessing document scope metadata.
|
|
1876
2244
|
*/
|
|
1877
|
-
|
|
1878
|
-
private logger;
|
|
1879
|
-
private reactor;
|
|
1880
|
-
private signer;
|
|
1881
|
-
private subscriptionManager;
|
|
1882
|
-
private jobAwaiter;
|
|
1883
|
-
private documentIndexer;
|
|
1884
|
-
private documentView;
|
|
1885
|
-
readonly drives: IDriveClient;
|
|
1886
|
-
constructor(logger: ILogger, reactor: IReactor, signer: ISigner, subscriptionManager: IReactorSubscriptionManager, jobAwaiter: IJobAwaiter, documentIndexer: IDocumentIndexer, documentView: IDocumentView);
|
|
2245
|
+
type CachedDocumentMeta = {
|
|
1887
2246
|
/**
|
|
1888
|
-
*
|
|
2247
|
+
* The full PHDocumentState from document.state.document.
|
|
2248
|
+
* Contains version, hash, isDeleted, deletedAtUtcIso, etc.
|
|
1889
2249
|
*/
|
|
1890
|
-
|
|
2250
|
+
state: PHDocumentState;
|
|
1891
2251
|
/**
|
|
1892
|
-
*
|
|
1893
|
-
*
|
|
1894
|
-
* @param documentType - The document type identifier
|
|
1895
|
-
* @returns The document model module
|
|
2252
|
+
* The document type (from header), cached for convenience.
|
|
1896
2253
|
*/
|
|
1897
|
-
|
|
2254
|
+
documentType: string;
|
|
1898
2255
|
/**
|
|
1899
|
-
*
|
|
2256
|
+
* The revision of the document scope when this metadata was captured.
|
|
2257
|
+
* Used for cache invalidation and consistency checks.
|
|
1900
2258
|
*/
|
|
1901
|
-
|
|
2259
|
+
documentScopeRevision: number;
|
|
2260
|
+
};
|
|
2261
|
+
/**
|
|
2262
|
+
* Interface for the document metadata cache.
|
|
2263
|
+
*
|
|
2264
|
+
* This cache provides an explicit cross-scope contract for accessing document
|
|
2265
|
+
* scope metadata. It solves the problem where job execution in one scope (e.g.,
|
|
2266
|
+
* "global") needs access to document scope state (version, isDeleted, etc.)
|
|
2267
|
+
* which may be stale in scope-specific caches or keyframes.
|
|
2268
|
+
*
|
|
2269
|
+
* The cache supports:
|
|
2270
|
+
* - Latest metadata retrieval with LRU caching
|
|
2271
|
+
* - Historical metadata reconstruction for reshuffling scenarios
|
|
2272
|
+
* - Eager updates after document scope operations
|
|
2273
|
+
*/
|
|
2274
|
+
interface IDocumentMetaCache {
|
|
1902
2275
|
/**
|
|
1903
|
-
*
|
|
1904
|
-
*
|
|
1905
|
-
*
|
|
2276
|
+
* Retrieves the LATEST document metadata from cache or rebuilds from operations.
|
|
2277
|
+
*
|
|
2278
|
+
* On cache miss, fetches all document scope operations and reconstructs the
|
|
2279
|
+
* current PHDocumentState by applying UPGRADE_DOCUMENT and DELETE_DOCUMENT
|
|
2280
|
+
* operations.
|
|
2281
|
+
*
|
|
2282
|
+
* @param documentId - The document identifier
|
|
2283
|
+
* @param branch - Branch name
|
|
2284
|
+
* @param signal - Optional abort signal to cancel the operation
|
|
2285
|
+
* @returns The cached or rebuilt document metadata
|
|
2286
|
+
* @throws {Error} "Operation aborted" if signal is aborted
|
|
2287
|
+
* @throws {Error} If document not found (no CREATE_DOCUMENT operation)
|
|
1906
2288
|
*/
|
|
1907
|
-
|
|
2289
|
+
getDocumentMeta(documentId: string, branch: string, signal?: AbortSignal): Promise<CachedDocumentMeta>;
|
|
1908
2290
|
/**
|
|
1909
|
-
*
|
|
2291
|
+
* Rebuilds document metadata at a SPECIFIC revision (always rebuilds, no caching).
|
|
2292
|
+
*
|
|
2293
|
+
* Used during reshuffling when operations need to be inserted at a previous
|
|
2294
|
+
* revision and we need the document scope state as of that point in time.
|
|
2295
|
+
*
|
|
2296
|
+
* @param documentId - The document identifier
|
|
2297
|
+
* @param branch - Branch name
|
|
2298
|
+
* @param targetRevision - The document scope revision to reconstruct up to
|
|
2299
|
+
* @param signal - Optional abort signal to cancel the operation
|
|
2300
|
+
* @returns Document metadata as of the target revision
|
|
2301
|
+
* @throws {Error} "Operation aborted" if signal is aborted
|
|
2302
|
+
* @throws {Error} If document not found
|
|
1910
2303
|
*/
|
|
1911
|
-
|
|
1912
|
-
private getOperationsWithCompositeCursor;
|
|
2304
|
+
rebuildAtRevision(documentId: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<CachedDocumentMeta>;
|
|
1913
2305
|
/**
|
|
1914
|
-
*
|
|
2306
|
+
* Eagerly updates cached metadata after document scope operations.
|
|
2307
|
+
*
|
|
2308
|
+
* Called by the job executor after CREATE_DOCUMENT, UPGRADE_DOCUMENT, or
|
|
2309
|
+
* DELETE_DOCUMENT operations to keep the cache current.
|
|
2310
|
+
*
|
|
2311
|
+
* @param documentId - The document identifier
|
|
2312
|
+
* @param branch - Branch name
|
|
2313
|
+
* @param meta - The new metadata to cache
|
|
1915
2314
|
*/
|
|
1916
|
-
|
|
2315
|
+
putDocumentMeta(documentId: string, branch: string, meta: CachedDocumentMeta): void;
|
|
1917
2316
|
/**
|
|
1918
|
-
*
|
|
2317
|
+
* Invalidates cached document metadata.
|
|
2318
|
+
*
|
|
2319
|
+
* Call before reshuffling operations that modify the document scope, or
|
|
2320
|
+
* when document state may have changed externally.
|
|
2321
|
+
*
|
|
2322
|
+
* @param documentId - The document identifier
|
|
2323
|
+
* @param branch - Optional branch to narrow invalidation (if omitted, all branches)
|
|
2324
|
+
* @returns Number of entries invalidated
|
|
1919
2325
|
*/
|
|
1920
|
-
|
|
2326
|
+
invalidate(documentId: string, branch?: string): number;
|
|
1921
2327
|
/**
|
|
1922
|
-
*
|
|
2328
|
+
* Clears all cached document metadata.
|
|
1923
2329
|
*/
|
|
1924
|
-
|
|
2330
|
+
clear(): void;
|
|
1925
2331
|
/**
|
|
1926
|
-
*
|
|
2332
|
+
* Performs startup initialization.
|
|
1927
2333
|
*/
|
|
1928
|
-
|
|
2334
|
+
startup(): Promise<void>;
|
|
1929
2335
|
/**
|
|
1930
|
-
*
|
|
2336
|
+
* Performs graceful shutdown.
|
|
1931
2337
|
*/
|
|
1932
|
-
|
|
2338
|
+
shutdown(): Promise<void>;
|
|
2339
|
+
}
|
|
2340
|
+
//#endregion
|
|
2341
|
+
//#region src/storage/kysely/types.d.ts
|
|
2342
|
+
interface OperationTable {
|
|
2343
|
+
id: Generated<number>;
|
|
2344
|
+
jobId: string;
|
|
2345
|
+
opId: string;
|
|
2346
|
+
prevOpId: string;
|
|
2347
|
+
writeTimestampUtcMs: Generated<Date>;
|
|
2348
|
+
documentId: string;
|
|
2349
|
+
documentType: string;
|
|
2350
|
+
scope: string;
|
|
2351
|
+
branch: string;
|
|
2352
|
+
timestampUtcMs: Date;
|
|
2353
|
+
index: number;
|
|
2354
|
+
action: unknown;
|
|
2355
|
+
skip: number;
|
|
2356
|
+
error?: string | null;
|
|
2357
|
+
deniedReason?: string | null;
|
|
2358
|
+
hash: string;
|
|
2359
|
+
}
|
|
2360
|
+
interface KeyframeTable {
|
|
2361
|
+
id: Generated<number>;
|
|
2362
|
+
documentId: string;
|
|
2363
|
+
documentType: string;
|
|
2364
|
+
scope: string;
|
|
2365
|
+
branch: string;
|
|
2366
|
+
revision: number;
|
|
2367
|
+
document: unknown;
|
|
2368
|
+
createdAt: Generated<Date>;
|
|
2369
|
+
}
|
|
2370
|
+
interface DocumentCollectionTable {
|
|
2371
|
+
documentId: string;
|
|
2372
|
+
collectionId: string;
|
|
2373
|
+
joinedOrdinal: bigint;
|
|
2374
|
+
leftOrdinal: bigint | null;
|
|
2375
|
+
}
|
|
2376
|
+
interface OperationIndexOperationTable {
|
|
2377
|
+
ordinal: Generated<number>;
|
|
2378
|
+
opId: string;
|
|
2379
|
+
documentId: string;
|
|
2380
|
+
documentType: string;
|
|
2381
|
+
scope: string;
|
|
2382
|
+
branch: string;
|
|
2383
|
+
timestampUtcMs: string;
|
|
2384
|
+
writeTimestampUtcMs: Generated<Date>;
|
|
2385
|
+
index: number;
|
|
2386
|
+
skip: number;
|
|
2387
|
+
hash: string;
|
|
2388
|
+
action: unknown;
|
|
2389
|
+
deniedReason?: string | null;
|
|
2390
|
+
sourceRemote: Generated<string>;
|
|
2391
|
+
}
|
|
2392
|
+
interface SyncRemoteTable {
|
|
2393
|
+
name: string;
|
|
2394
|
+
collection_id: string;
|
|
2395
|
+
channel_type: string;
|
|
2396
|
+
channel_id: string;
|
|
2397
|
+
remote_name: string;
|
|
2398
|
+
channel_parameters: unknown;
|
|
2399
|
+
filter_document_ids: unknown;
|
|
2400
|
+
filter_scopes: unknown;
|
|
2401
|
+
filter_branch: string;
|
|
2402
|
+
push_state: string;
|
|
2403
|
+
push_last_success_utc_ms: string | null;
|
|
2404
|
+
push_last_failure_utc_ms: string | null;
|
|
2405
|
+
push_failure_count: number;
|
|
2406
|
+
pull_state: string;
|
|
2407
|
+
pull_last_success_utc_ms: string | null;
|
|
2408
|
+
pull_last_failure_utc_ms: string | null;
|
|
2409
|
+
pull_failure_count: number;
|
|
2410
|
+
created_at: Generated<Date>;
|
|
2411
|
+
updated_at: Generated<Date>;
|
|
2412
|
+
}
|
|
2413
|
+
interface SyncCursorTable {
|
|
2414
|
+
remote_name: string;
|
|
2415
|
+
cursor_type: string;
|
|
2416
|
+
cursor_ordinal: bigint;
|
|
2417
|
+
last_synced_at_utc_ms: string | null;
|
|
2418
|
+
updated_at: Generated<Date>;
|
|
2419
|
+
}
|
|
2420
|
+
/**
|
|
2421
|
+
* Kysely table definition for the `sync_dead_letters` table.
|
|
2422
|
+
*/
|
|
2423
|
+
interface SyncDeadLetterTable {
|
|
2424
|
+
ordinal: Generated<number>;
|
|
2425
|
+
id: string;
|
|
2426
|
+
job_id: string;
|
|
2427
|
+
job_dependencies: unknown;
|
|
2428
|
+
remote_name: string;
|
|
2429
|
+
document_id: string;
|
|
2430
|
+
scopes: unknown;
|
|
2431
|
+
branch: string;
|
|
2432
|
+
operations: unknown;
|
|
2433
|
+
error_source: string;
|
|
2434
|
+
error_message: string;
|
|
2435
|
+
error_type: Generated<string>;
|
|
2436
|
+
created_at: Generated<Date>;
|
|
2437
|
+
}
|
|
2438
|
+
/**
|
|
2439
|
+
* One (document, group) reference ever discovered from an auth operation's
|
|
2440
|
+
* input. Rows are never updated or deleted (see migration 017).
|
|
2441
|
+
*/
|
|
2442
|
+
interface GroupReferenceTable {
|
|
2443
|
+
documentId: string;
|
|
2444
|
+
groupId: string;
|
|
2445
|
+
}
|
|
2446
|
+
interface Database$1 {
|
|
2447
|
+
Operation: OperationTable;
|
|
2448
|
+
Keyframe: KeyframeTable;
|
|
2449
|
+
document_collections: DocumentCollectionTable;
|
|
2450
|
+
operation_index_operations: OperationIndexOperationTable;
|
|
2451
|
+
group_references: GroupReferenceTable;
|
|
2452
|
+
sync_remotes: SyncRemoteTable;
|
|
2453
|
+
sync_cursors: SyncCursorTable;
|
|
2454
|
+
sync_dead_letters: SyncDeadLetterTable;
|
|
2455
|
+
}
|
|
2456
|
+
interface DocumentTable {
|
|
2457
|
+
id: string;
|
|
2458
|
+
createdAt: Generated<Date>;
|
|
2459
|
+
updatedAt: Generated<Date>;
|
|
2460
|
+
}
|
|
2461
|
+
interface DocumentRelationshipTable {
|
|
2462
|
+
id: Generated<string>;
|
|
2463
|
+
sourceId: string;
|
|
2464
|
+
targetId: string;
|
|
2465
|
+
relationshipType: string;
|
|
2466
|
+
metadata: unknown;
|
|
2467
|
+
createdAt: Generated<Date>;
|
|
2468
|
+
updatedAt: Generated<Date>;
|
|
2469
|
+
}
|
|
2470
|
+
interface IndexerStateTable {
|
|
2471
|
+
id: Generated<number>;
|
|
2472
|
+
lastOperationId: number;
|
|
2473
|
+
lastOperationTimestamp: Generated<Date>;
|
|
2474
|
+
}
|
|
2475
|
+
interface DocumentIndexerDatabase {
|
|
2476
|
+
Document: DocumentTable;
|
|
2477
|
+
DocumentRelationship: DocumentRelationshipTable;
|
|
2478
|
+
IndexerState: IndexerStateTable;
|
|
2479
|
+
}
|
|
2480
|
+
//#endregion
|
|
2481
|
+
//#region src/executor/worker/protocol.d.ts
|
|
2482
|
+
/**
|
|
2483
|
+
* A JSON-clonable value safe to send across the worker IPC boundary.
|
|
2484
|
+
*
|
|
2485
|
+
* The shape mirrors the structured-clone subset used by the parent's
|
|
2486
|
+
* sanitizer: primitives, arrays, plain objects, plus the explicit
|
|
2487
|
+
* {@link ErrorInfo} shape for marshalled Errors.
|
|
2488
|
+
*
|
|
2489
|
+
* @see Wire Protocol Reference wiki page
|
|
2490
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2491
|
+
*/
|
|
2492
|
+
type SanitizedArg = null | boolean | number | string | ErrorInfo | SanitizedArg[] | {
|
|
2493
|
+
[key: string]: SanitizedArg;
|
|
2494
|
+
};
|
|
2495
|
+
/**
|
|
2496
|
+
* Structured representation of an Error for IPC transport.
|
|
2497
|
+
*
|
|
2498
|
+
* Class instances cannot be structured-cloned across worker boundaries,
|
|
2499
|
+
* so Errors are flattened into this shape on the worker side and
|
|
2500
|
+
* reconstructed on the parent side.
|
|
2501
|
+
*
|
|
2502
|
+
* @see Wire Protocol Reference wiki page
|
|
2503
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2504
|
+
*/
|
|
2505
|
+
type ErrorInfo = {
|
|
2506
|
+
name: string;
|
|
2507
|
+
message: string;
|
|
2508
|
+
stack?: string;
|
|
2509
|
+
cause?: ErrorInfo;
|
|
2510
|
+
};
|
|
2511
|
+
/**
|
|
2512
|
+
* Reference to a module that the worker should `import()` at runtime,
|
|
2513
|
+
* along with the named export to pluck out as the factory.
|
|
2514
|
+
*
|
|
2515
|
+
* Exactly one of `packageName` or `filePath` is provided.
|
|
2516
|
+
*
|
|
2517
|
+
* @see Wire Protocol Reference wiki page
|
|
2518
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2519
|
+
*/
|
|
2520
|
+
type ModuleRef = {
|
|
2521
|
+
/** Bare-specifier package name (resolved by the worker's module loader). */packageName: string; /** Named export within the module to invoke as the factory. */
|
|
2522
|
+
exportName: string;
|
|
2523
|
+
} | {
|
|
2524
|
+
/** Absolute or worker-resolvable file path to import. */filePath: string; /** Named export within the module to invoke as the factory. */
|
|
2525
|
+
exportName: string;
|
|
2526
|
+
};
|
|
2527
|
+
/**
|
|
2528
|
+
* Factory specification shared by the signature verifier and document
|
|
2529
|
+
* model spec channels. The worker imports `module.exportName` and invokes
|
|
2530
|
+
* it with `initArgs` to obtain the actual instance.
|
|
2531
|
+
*
|
|
2532
|
+
* `initArgs` must be JSON-clonable.
|
|
2533
|
+
*
|
|
2534
|
+
* @see Wire Protocol Reference wiki page
|
|
2535
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2536
|
+
*/
|
|
2537
|
+
type FactorySpec = {
|
|
2538
|
+
module: ModuleRef;
|
|
2539
|
+
initArgs?: SanitizedArg;
|
|
2540
|
+
};
|
|
2541
|
+
/**
|
|
2542
|
+
* Factory spec for the signature verifier the worker should instantiate.
|
|
2543
|
+
*
|
|
2544
|
+
* Structurally identical to {@link FactorySpec}; the alias exists so call
|
|
2545
|
+
* sites read intent-fully.
|
|
2546
|
+
*
|
|
2547
|
+
* @see Wire Protocol Reference wiki page
|
|
2548
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2549
|
+
*/
|
|
2550
|
+
type SignatureVerifierSpec = FactorySpec;
|
|
2551
|
+
/**
|
|
2552
|
+
* Factory spec for a document model module the worker should instantiate.
|
|
2553
|
+
*
|
|
2554
|
+
* Structurally identical to {@link FactorySpec}; the alias exists so call
|
|
2555
|
+
* sites read intent-fully.
|
|
2556
|
+
*
|
|
2557
|
+
* @see Wire Protocol Reference wiki page
|
|
2558
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2559
|
+
*/
|
|
2560
|
+
type DocumentModelSpec = FactorySpec;
|
|
2561
|
+
/**
|
|
2562
|
+
* One entry in the document model manifest the worker materializes on
|
|
2563
|
+
* startup (or extends lazily via `load-model`).
|
|
2564
|
+
*
|
|
2565
|
+
* @see Wire Protocol Reference wiki page
|
|
2566
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2567
|
+
*/
|
|
2568
|
+
type ModelManifestEntry = {
|
|
2569
|
+
/** Document type identifier (e.g. "ph/account"). */documentType: string; /** Document model version this entry registers. */
|
|
2570
|
+
version: string; /** Factory spec the worker imports and invokes to obtain the model. */
|
|
2571
|
+
spec: DocumentModelSpec;
|
|
2572
|
+
};
|
|
2573
|
+
/**
|
|
2574
|
+
* JSON-clonable Postgres connection info passed to the worker so it can
|
|
2575
|
+
* open its own pool. Storage-specific wiring may extend this shape in
|
|
2576
|
+
* later phases.
|
|
2577
|
+
*
|
|
2578
|
+
* @see Wire Protocol Reference wiki page
|
|
2579
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2580
|
+
*/
|
|
2581
|
+
type DbConfig = {
|
|
2582
|
+
host: string;
|
|
2583
|
+
port: number;
|
|
2584
|
+
database: string;
|
|
2585
|
+
user: string;
|
|
2586
|
+
password: string;
|
|
2587
|
+
ssl?: boolean;
|
|
2588
|
+
applicationName?: string;
|
|
2589
|
+
poolSize?: number;
|
|
2590
|
+
/**
|
|
2591
|
+
* Maximum time (ms) a caller will wait to acquire a connection from the
|
|
2592
|
+
* pool before pg.Pool throws. When omitted, pg defaults to 0 (unlimited
|
|
2593
|
+
* wait), which hides acquire-starvation as silent latency.
|
|
2594
|
+
*/
|
|
2595
|
+
connectionTimeoutMillis?: number;
|
|
2596
|
+
/**
|
|
2597
|
+
* How long (ms) an idle connection stays open before pg closes it. When
|
|
2598
|
+
* omitted, pg defaults to 10000.
|
|
2599
|
+
*/
|
|
2600
|
+
idleTimeoutMillis?: number;
|
|
2601
|
+
};
|
|
2602
|
+
/**
|
|
2603
|
+
* Configuration for the executor worker pool.
|
|
2604
|
+
*
|
|
2605
|
+
* Mirrors the `workerPool` sub-config on {@link JobExecutorConfig};
|
|
2606
|
+
* a later card wires this into the executor config.
|
|
2607
|
+
*
|
|
2608
|
+
* @see Wire Protocol Reference wiki page
|
|
2609
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2610
|
+
*/
|
|
2611
|
+
type WorkerPoolConfig = {
|
|
2612
|
+
/** Whether the worker pool is active; when false the executor runs in-process. */enabled: boolean; /** Number of worker instances to spawn. */
|
|
2613
|
+
numWorkers: number; /** Worker isolation mode. */
|
|
2614
|
+
workerType: "thread" | "process"; /** Optional heartbeat interval in milliseconds. */
|
|
2615
|
+
heartbeatMs?: number; /** Optional per-worker Postgres pool size override. */
|
|
2616
|
+
workerPgPoolSize?: number;
|
|
2617
|
+
};
|
|
2618
|
+
/**
|
|
2619
|
+
* Payload the worker reports back when a job's write phase is complete.
|
|
2620
|
+
*
|
|
2621
|
+
* Parent fills `collectionMemberships` at emission time, so it is
|
|
2622
|
+
* intentionally absent from the worker -> parent message.
|
|
2623
|
+
*
|
|
2624
|
+
* @see Wire Protocol Reference wiki page
|
|
2625
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2626
|
+
*/
|
|
2627
|
+
type JobWriteReadyPayload = {
|
|
2628
|
+
operations: OperationWithContext$1[];
|
|
2629
|
+
jobMeta: JobMeta;
|
|
2630
|
+
};
|
|
2631
|
+
/**
|
|
2632
|
+
* Initializes a freshly spawned worker with the configuration and
|
|
2633
|
+
* factories it needs to start executing jobs.
|
|
2634
|
+
*
|
|
2635
|
+
* @see Wire Protocol Reference wiki page
|
|
2636
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2637
|
+
*/
|
|
2638
|
+
type InitMessage = {
|
|
2639
|
+
type: "init";
|
|
2640
|
+
correlationId: string;
|
|
2641
|
+
workerId: string;
|
|
2642
|
+
poolConfig: WorkerPoolConfig;
|
|
2643
|
+
db: DbConfig; /** Omitted = the worker performs no executor-side signature verification. */
|
|
2644
|
+
signatureVerifier?: SignatureVerifierSpec;
|
|
2645
|
+
models: ModelManifestEntry[]; /** Omitted = the worker builds its executor with the built-in defaults. */
|
|
2646
|
+
executorConfig?: JobExecutorConfig;
|
|
2647
|
+
};
|
|
2648
|
+
/**
|
|
2649
|
+
* Dispatches a job to the worker for execution.
|
|
2650
|
+
*
|
|
2651
|
+
* @see Wire Protocol Reference wiki page
|
|
2652
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2653
|
+
*/
|
|
2654
|
+
type ExecuteMessage = {
|
|
2655
|
+
type: "execute";
|
|
2656
|
+
correlationId: string;
|
|
2657
|
+
job: Job;
|
|
2658
|
+
};
|
|
2659
|
+
/**
|
|
2660
|
+
* Requests cancellation of an in-flight job.
|
|
2661
|
+
*
|
|
2662
|
+
* @see Wire Protocol Reference wiki page
|
|
2663
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2664
|
+
*/
|
|
2665
|
+
type AbortMessage = {
|
|
2666
|
+
type: "abort";
|
|
2667
|
+
correlationId: string; /** correlationId of the `execute` message being aborted. */
|
|
2668
|
+
targetCorrelationId: string;
|
|
2669
|
+
reason?: string;
|
|
2670
|
+
};
|
|
2671
|
+
/**
|
|
2672
|
+
* Asks the worker to drain in-flight work and exit.
|
|
2673
|
+
*
|
|
2674
|
+
* @see Wire Protocol Reference wiki page
|
|
2675
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2676
|
+
*/
|
|
2677
|
+
type ShutdownMessage = {
|
|
2678
|
+
type: "shutdown";
|
|
2679
|
+
correlationId: string; /** Optional grace period before the parent force-terminates the worker. */
|
|
2680
|
+
graceMs?: number;
|
|
2681
|
+
};
|
|
2682
|
+
/**
|
|
2683
|
+
* Lazily registers an additional document model on a running worker.
|
|
2684
|
+
*
|
|
2685
|
+
* @see Wire Protocol Reference wiki page
|
|
2686
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2687
|
+
*/
|
|
2688
|
+
type LoadModelMessage = {
|
|
2689
|
+
type: "load-model";
|
|
2690
|
+
correlationId: string;
|
|
2691
|
+
model: ModelManifestEntry;
|
|
2692
|
+
};
|
|
2693
|
+
/**
|
|
2694
|
+
* Union of all messages the parent may send to a worker.
|
|
2695
|
+
*
|
|
2696
|
+
* @see Wire Protocol Reference wiki page
|
|
2697
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2698
|
+
*/
|
|
2699
|
+
type ParentMessage = InitMessage | ExecuteMessage | AbortMessage | ShutdownMessage | LoadModelMessage;
|
|
2700
|
+
/**
|
|
2701
|
+
* Announces that the worker has finished `init` and is ready to accept
|
|
2702
|
+
* `execute` messages.
|
|
2703
|
+
*
|
|
2704
|
+
* @see Wire Protocol Reference wiki page
|
|
2705
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2706
|
+
*/
|
|
2707
|
+
type ReadyMessage = {
|
|
2708
|
+
type: "ready"; /** correlationId of the originating `init` message. */
|
|
2709
|
+
correlationId: string;
|
|
2710
|
+
workerId: string;
|
|
2711
|
+
};
|
|
2712
|
+
/**
|
|
2713
|
+
* Final result for an `execute` job.
|
|
2714
|
+
*
|
|
2715
|
+
* On success, `writeReady` carries the operations and job meta the
|
|
2716
|
+
* parent needs to emit `JOB_WRITE_READY`. On failure, `error` is set
|
|
2717
|
+
* and `result.success` is false.
|
|
2718
|
+
*
|
|
2719
|
+
* @see Wire Protocol Reference wiki page
|
|
2720
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2721
|
+
*/
|
|
2722
|
+
type ResultMessage = {
|
|
2723
|
+
type: "result"; /** correlationId of the originating `execute` message. */
|
|
2724
|
+
correlationId: string;
|
|
2725
|
+
result: JobResult;
|
|
2726
|
+
writeReady?: JobWriteReadyPayload;
|
|
2727
|
+
error?: ErrorInfo;
|
|
2728
|
+
};
|
|
2729
|
+
/**
|
|
2730
|
+
* Acknowledges that a `load-model` request succeeded.
|
|
2731
|
+
*
|
|
2732
|
+
* @see Wire Protocol Reference wiki page
|
|
2733
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2734
|
+
*/
|
|
2735
|
+
type ModelLoadedMessage = {
|
|
2736
|
+
type: "model-loaded"; /** correlationId of the originating `load-model` message. */
|
|
2737
|
+
correlationId: string;
|
|
2738
|
+
documentType: string;
|
|
2739
|
+
version: string;
|
|
2740
|
+
};
|
|
2741
|
+
/**
|
|
2742
|
+
* Reports that a `load-model` request failed.
|
|
2743
|
+
*
|
|
2744
|
+
* @see Wire Protocol Reference wiki page
|
|
2745
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2746
|
+
*/
|
|
2747
|
+
type ModelLoadFailedMessage = {
|
|
2748
|
+
type: "model-load-failed"; /** correlationId of the originating `load-model` message. */
|
|
2749
|
+
correlationId: string;
|
|
2750
|
+
documentType: string;
|
|
2751
|
+
version: string;
|
|
2752
|
+
error: ErrorInfo;
|
|
2753
|
+
};
|
|
2754
|
+
/**
|
|
2755
|
+
* Forwarded log line from the worker. `args` is constrained to
|
|
2756
|
+
* {@link SanitizedArg} so callers cannot accidentally ship non-clonable
|
|
2757
|
+
* values across the boundary.
|
|
2758
|
+
*
|
|
2759
|
+
* The sanitizer in `./sanitize.ts` enforces the {@link SanitizedArg}
|
|
2760
|
+
* invariant on the producer side before each message is posted.
|
|
2761
|
+
*
|
|
2762
|
+
* @see Wire Protocol Reference wiki page
|
|
2763
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2764
|
+
*/
|
|
2765
|
+
type LogMessage = {
|
|
2766
|
+
type: "log";
|
|
2767
|
+
level: "debug" | "info" | "warn" | "error";
|
|
2768
|
+
message: string;
|
|
2769
|
+
args: SanitizedArg[]; /** Epoch milliseconds at which the worker generated the log line. */
|
|
2770
|
+
timestamp: number;
|
|
2771
|
+
};
|
|
2772
|
+
/**
|
|
2773
|
+
* Periodic liveness signal. Included now to unblock Phase-3 scaffolding;
|
|
2774
|
+
* the wiki marks heartbeats as a Phase-5 future extension.
|
|
2775
|
+
*
|
|
2776
|
+
* @see Wire Protocol Reference wiki page
|
|
2777
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2778
|
+
*/
|
|
2779
|
+
type HeartbeatMessage = {
|
|
2780
|
+
type: "heartbeat";
|
|
2781
|
+
workerId: string; /** Epoch milliseconds the worker generated the heartbeat. */
|
|
2782
|
+
timestamp: number; /** Optional snapshot of in-flight job correlation ids. */
|
|
2783
|
+
inFlightCorrelationIds?: string[];
|
|
2784
|
+
};
|
|
2785
|
+
/**
|
|
2786
|
+
* Periodic counters / gauges the worker reports for observability.
|
|
2787
|
+
*
|
|
2788
|
+
* @see Wire Protocol Reference wiki page
|
|
2789
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2790
|
+
*/
|
|
2791
|
+
type MetricsMessage = {
|
|
2792
|
+
type: "metrics";
|
|
2793
|
+
workerId: string; /** Epoch milliseconds the worker generated the metrics snapshot. */
|
|
2794
|
+
timestamp: number;
|
|
2795
|
+
counters: {
|
|
2796
|
+
[name: string]: number;
|
|
2797
|
+
};
|
|
2798
|
+
gauges: {
|
|
2799
|
+
[name: string]: number;
|
|
2800
|
+
};
|
|
2801
|
+
};
|
|
2802
|
+
/**
|
|
2803
|
+
* Snapshot of one worker pool's acquire-wait samples and pool-stat counters,
|
|
2804
|
+
* forwarded periodically so the host can re-record into the shared
|
|
2805
|
+
* pg.Pool histogram and observable gauges. The worker owns the real
|
|
2806
|
+
* pg.Pool; the host's {@link PoolInstrumentation} is a forwarder driven
|
|
2807
|
+
* by these messages.
|
|
2808
|
+
*/
|
|
2809
|
+
type PoolAcquireSamplesMessage = {
|
|
2810
|
+
type: "pool-acquire-samples";
|
|
2811
|
+
workerId: string; /** Stable identifier matching the host-side instrumentation name (e.g. "worker-0"). */
|
|
2812
|
+
poolName: string; /** Epoch milliseconds the worker generated the batch. */
|
|
2813
|
+
timestamp: number; /** Acquire-wait durations (ms) accumulated since the previous batch. */
|
|
2814
|
+
durations: number[]; /** Most recent pg.Pool counter snapshot at batch send time. */
|
|
2815
|
+
size: number;
|
|
2816
|
+
idle: number;
|
|
2817
|
+
waiting: number;
|
|
2818
|
+
};
|
|
2819
|
+
/**
|
|
2820
|
+
* Union of all messages a worker may send to the parent.
|
|
2821
|
+
*
|
|
2822
|
+
* @see Wire Protocol Reference wiki page
|
|
2823
|
+
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2824
|
+
*/
|
|
2825
|
+
type WorkerMessage = ReadyMessage | ResultMessage | ModelLoadedMessage | ModelLoadFailedMessage | LogMessage | HeartbeatMessage | MetricsMessage | PoolAcquireSamplesMessage;
|
|
2826
|
+
//#endregion
|
|
2827
|
+
//#region src/core/model-sources.d.ts
|
|
2828
|
+
/** An importable file holding one or more document-model exports. */
|
|
2829
|
+
type FileModelSource = {
|
|
2830
|
+
filePath: string;
|
|
2831
|
+
exportName?: string;
|
|
2832
|
+
};
|
|
2833
|
+
/** An importable package specifier holding one or more document-model exports. */
|
|
2834
|
+
type PackageModelSource = {
|
|
2835
|
+
packageName: string;
|
|
2836
|
+
subpath?: string;
|
|
2837
|
+
exportName?: string;
|
|
2838
|
+
};
|
|
2839
|
+
/**
|
|
2840
|
+
* A source of document models: a live module, an importable file, or an
|
|
2841
|
+
* importable package. File and package sources can cross a worker-thread
|
|
2842
|
+
* boundary (workers re-import them); a live module cannot.
|
|
2843
|
+
*/
|
|
2844
|
+
type DocumentModelSource = DocumentModelModule<any> | FileModelSource | PackageModelSource;
|
|
2845
|
+
//#endregion
|
|
2846
|
+
//#region src/registry/interfaces.d.ts
|
|
2847
|
+
type RegistrationResult<T> = {
|
|
2848
|
+
status: "success";
|
|
2849
|
+
item: T;
|
|
2850
|
+
} | {
|
|
2851
|
+
status: "error";
|
|
2852
|
+
item: T;
|
|
2853
|
+
error: Error;
|
|
2854
|
+
};
|
|
2855
|
+
/**
|
|
2856
|
+
* Loader that asynchronously resolves a document type to a
|
|
2857
|
+
* {@link DocumentModelSource}. Used by the queue to gate CREATE_DOCUMENT
|
|
2858
|
+
* jobs until the required model is available in the registry.
|
|
2859
|
+
*
|
|
2860
|
+
* Return an importable source ({ filePath } or { packageName }) whenever
|
|
2861
|
+
* possible: the resolver registers the resolved models on the host registry
|
|
2862
|
+
* and broadcasts importable sources to executor workers. A live
|
|
2863
|
+
* DocumentModelModule is also valid but host-only — it cannot cross a
|
|
2864
|
+
* worker-thread boundary, so worker pools will not receive it.
|
|
2865
|
+
*/
|
|
2866
|
+
interface IDocumentModelLoader {
|
|
2867
|
+
load(documentType: string): Promise<DocumentModelSource>;
|
|
2868
|
+
}
|
|
2869
|
+
/**
|
|
2870
|
+
* Registry for managing document model modules.
|
|
2871
|
+
* Provides centralized access to document models' reducers, utils, and specifications.
|
|
2872
|
+
* Supports version-aware module storage and upgrade manifest management.
|
|
2873
|
+
*/
|
|
2874
|
+
interface IDocumentModelRegistry {
|
|
2875
|
+
/**
|
|
2876
|
+
* Register multiple modules at once.
|
|
2877
|
+
* Modules without a version field default to version 1.
|
|
2878
|
+
* Invalid or duplicate modules are skipped without breaking registration of the remaining modules.
|
|
2879
|
+
*
|
|
2880
|
+
* @param modules Document model modules to register
|
|
2881
|
+
* @returns Array of results, one per module, indicating success or failure
|
|
2882
|
+
*/
|
|
2883
|
+
registerModules(...modules: DocumentModelModule<any>[]): RegistrationResult<DocumentModelModule<any>>[];
|
|
2884
|
+
/**
|
|
2885
|
+
* Unregister all versions of the specified document types.
|
|
2886
|
+
*
|
|
2887
|
+
* @param documentTypes The document types to unregister
|
|
2888
|
+
* @returns true if all modules were unregistered, false if any were not found
|
|
2889
|
+
*/
|
|
2890
|
+
unregisterModules(...documentTypes: string[]): boolean;
|
|
2891
|
+
/**
|
|
2892
|
+
* Get a specific document model module by document type and optional version.
|
|
2893
|
+
* If version is not specified, returns the latest version.
|
|
2894
|
+
*
|
|
2895
|
+
* @param documentType The document type identifier
|
|
2896
|
+
* @param version Optional version number to retrieve
|
|
2897
|
+
* @returns The document model module
|
|
2898
|
+
* @throws ModuleNotFoundError if the document type or version is not registered
|
|
2899
|
+
*/
|
|
2900
|
+
getModule(documentType: string, version?: number): DocumentModelModule<any>;
|
|
2901
|
+
/**
|
|
2902
|
+
* Get all registered document model modules.
|
|
2903
|
+
*
|
|
2904
|
+
* @returns Array of all registered modules
|
|
2905
|
+
*/
|
|
2906
|
+
getAllModules(): DocumentModelModule<any>[];
|
|
2907
|
+
/**
|
|
2908
|
+
* Clear all registered modules and upgrade manifests.
|
|
2909
|
+
*/
|
|
2910
|
+
clear(): void;
|
|
2911
|
+
/**
|
|
2912
|
+
* Get all supported versions for a document type, sorted in ascending order.
|
|
2913
|
+
*
|
|
2914
|
+
* @param documentType The document type identifier
|
|
2915
|
+
* @returns Array of version numbers sorted ascending
|
|
2916
|
+
* @throws ModuleNotFoundError if no modules are registered for the document type
|
|
2917
|
+
*/
|
|
2918
|
+
getSupportedVersions(documentType: string): number[];
|
|
1933
2919
|
/**
|
|
1934
|
-
*
|
|
1935
|
-
* Delegates to {@link IDriveClient.addFile}.
|
|
2920
|
+
* Get the latest (highest) version number for a document type.
|
|
1936
2921
|
*
|
|
1937
|
-
* @
|
|
1938
|
-
*
|
|
2922
|
+
* @param documentType The document type identifier
|
|
2923
|
+
* @returns The highest version number registered for this document type
|
|
2924
|
+
* @throws ModuleNotFoundError if no modules are registered for the document type
|
|
1939
2925
|
*/
|
|
1940
|
-
|
|
2926
|
+
getLatestVersion(documentType: string): number;
|
|
1941
2927
|
/**
|
|
1942
|
-
*
|
|
2928
|
+
* Register upgrade manifests that define upgrade paths between versions.
|
|
2929
|
+
* Invalid or duplicate manifests are skipped without breaking registration of the remaining manifests.
|
|
2930
|
+
*
|
|
2931
|
+
* @param manifests Upgrade manifests to register
|
|
2932
|
+
* @returns Array of results, one per manifest, indicating success or failure
|
|
1943
2933
|
*/
|
|
1944
|
-
|
|
2934
|
+
registerUpgradeManifests(...manifests: UpgradeManifest<readonly number[]>[]): RegistrationResult<UpgradeManifest<readonly number[]>>[];
|
|
1945
2935
|
/**
|
|
1946
|
-
*
|
|
2936
|
+
* Unregister upgrade manifests for the specified document types.
|
|
2937
|
+
* @param documentTypes The document types whose upgrade manifests should be unregistered
|
|
2938
|
+
* @returns true if all modules were unregistered, false if any were not found
|
|
2939
|
+
**/
|
|
2940
|
+
unregisterUpgradeManifests(...documentTypes: string[]): boolean;
|
|
2941
|
+
/**
|
|
2942
|
+
* Get the upgrade manifest for a document type.
|
|
2943
|
+
*
|
|
2944
|
+
* @param documentType The document type identifier
|
|
2945
|
+
* @returns The upgrade manifest
|
|
2946
|
+
* @throws ManifestNotFoundError if no manifest is registered for the document type
|
|
1947
2947
|
*/
|
|
1948
|
-
|
|
1949
|
-
executeBatch(request: BatchExecutionRequest, signal?: AbortSignal): Promise<BatchExecutionResult>;
|
|
2948
|
+
getUpgradeManifest(documentType: string): UpgradeManifest<readonly number[]>;
|
|
1950
2949
|
/**
|
|
1951
|
-
*
|
|
2950
|
+
* Compute the upgrade path from one version to another.
|
|
2951
|
+
* Returns the sequence of upgrade transitions needed.
|
|
2952
|
+
*
|
|
2953
|
+
* @param documentType The document type identifier
|
|
2954
|
+
* @param fromVersion The starting version
|
|
2955
|
+
* @param toVersion The target version
|
|
2956
|
+
* @returns Array of upgrade transitions in order
|
|
2957
|
+
* @throws DowngradeNotSupportedError if toVersion is less than fromVersion
|
|
2958
|
+
* @throws ManifestNotFoundError if no upgrade manifest is registered
|
|
2959
|
+
* @throws MissingUpgradeTransitionError if any transition in the path is missing
|
|
1952
2960
|
*/
|
|
1953
|
-
|
|
2961
|
+
computeUpgradePath(documentType: string, fromVersion: number, toVersion: number): UpgradeTransition[];
|
|
1954
2962
|
/**
|
|
1955
|
-
*
|
|
1956
|
-
*
|
|
2963
|
+
* Get the upgrade reducer for a single-step version transition.
|
|
2964
|
+
*
|
|
2965
|
+
* @param documentType The document type identifier
|
|
2966
|
+
* @param fromVersion The starting version
|
|
2967
|
+
* @param toVersion The target version (must be fromVersion + 1)
|
|
2968
|
+
* @returns The upgrade reducer function
|
|
2969
|
+
* @throws InvalidUpgradeStepError if toVersion is not fromVersion + 1
|
|
2970
|
+
* @throws ManifestNotFoundError if no upgrade manifest is registered
|
|
2971
|
+
* @throws MissingUpgradeTransitionError if the transition is not found
|
|
1957
2972
|
*/
|
|
1958
|
-
|
|
2973
|
+
getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
|
|
2974
|
+
}
|
|
2975
|
+
//#endregion
|
|
2976
|
+
//#region src/cache/buffer/ring-buffer.d.ts
|
|
2977
|
+
/**
|
|
2978
|
+
* RingBuffer is a generic circular buffer implementation that stores a fixed number
|
|
2979
|
+
* of items. When the buffer is full, new items overwrite the oldest items.
|
|
2980
|
+
*
|
|
2981
|
+
* This implementation maintains O(1) time complexity for push operations and provides
|
|
2982
|
+
* items in chronological order (oldest to newest) via getAll().
|
|
2983
|
+
*
|
|
2984
|
+
* @template T - The type of items stored in the buffer
|
|
2985
|
+
*/
|
|
2986
|
+
declare class RingBuffer<T> {
|
|
2987
|
+
private buffer;
|
|
2988
|
+
private head;
|
|
2989
|
+
private size;
|
|
2990
|
+
private capacity;
|
|
2991
|
+
constructor(capacity: number);
|
|
1959
2992
|
/**
|
|
1960
|
-
* Adds
|
|
2993
|
+
* Adds an item to the buffer. If the buffer is full, overwrites the oldest item.
|
|
2994
|
+
*
|
|
2995
|
+
* @param item - The item to add
|
|
1961
2996
|
*/
|
|
1962
|
-
|
|
2997
|
+
push(item: T): void;
|
|
1963
2998
|
/**
|
|
1964
|
-
*
|
|
2999
|
+
* Returns all items in the buffer in chronological order (oldest to newest).
|
|
3000
|
+
*
|
|
3001
|
+
* @returns Array of items in insertion order
|
|
1965
3002
|
*/
|
|
1966
|
-
|
|
3003
|
+
getAll(): T[];
|
|
1967
3004
|
/**
|
|
1968
|
-
*
|
|
3005
|
+
* Clears all items from the buffer.
|
|
1969
3006
|
*/
|
|
1970
|
-
|
|
1971
|
-
source: PHDocument;
|
|
1972
|
-
target: PHDocument;
|
|
1973
|
-
}>;
|
|
1974
|
-
loadBatch(request: BatchLoadRequest, signal?: AbortSignal): Promise<BatchLoadResult>;
|
|
3007
|
+
clear(): void;
|
|
1975
3008
|
/**
|
|
1976
|
-
*
|
|
3009
|
+
* Gets the current number of items in the buffer.
|
|
1977
3010
|
*/
|
|
1978
|
-
|
|
3011
|
+
get length(): number;
|
|
3012
|
+
}
|
|
3013
|
+
//#endregion
|
|
3014
|
+
//#region src/cache/kysely-write-cache.d.ts
|
|
3015
|
+
type DocumentStream = {
|
|
3016
|
+
key: string;
|
|
3017
|
+
ringBuffer: RingBuffer<CachedSnapshot>;
|
|
3018
|
+
};
|
|
3019
|
+
/**
|
|
3020
|
+
* In-memory write cache with keyframe persistence for PHDocuments.
|
|
3021
|
+
*
|
|
3022
|
+
* Caches document snapshots in ring buffers with LRU eviction. On cache miss,
|
|
3023
|
+
* rebuilds documents from nearest keyframe or full operation history.
|
|
3024
|
+
*
|
|
3025
|
+
* **Performance Characteristics:**
|
|
3026
|
+
* - Cache hit: O(1) lookup in ring buffer
|
|
3027
|
+
* - Cold miss: O(n) where n is total operation count, or O(k) where k is operations since keyframe
|
|
3028
|
+
* - Warm miss: O(m) where m is operations since cached revision
|
|
3029
|
+
* - Eviction: O(1) for LRU tracking and removal
|
|
3030
|
+
*
|
|
3031
|
+
* **Thread Safety:**
|
|
3032
|
+
* Not thread-safe. Designed for single-threaded job executor environment.
|
|
3033
|
+
* External synchronization required for concurrent access across multiple executors.
|
|
3034
|
+
*
|
|
3035
|
+
* **Example:**
|
|
3036
|
+
* ```typescript
|
|
3037
|
+
* const cache = new KyselyWriteCache(
|
|
3038
|
+
* keyframeStore,
|
|
3039
|
+
* operationStore,
|
|
3040
|
+
* registry,
|
|
3041
|
+
* { maxDocuments: 1000, ringBufferSize: 10, keyframeInterval: 10 }
|
|
3042
|
+
* );
|
|
3043
|
+
*
|
|
3044
|
+
* await cache.startup();
|
|
3045
|
+
*
|
|
3046
|
+
* // Retrieve or rebuild document
|
|
3047
|
+
* const doc = await cache.getState(docId, docType, scope, branch, revision);
|
|
3048
|
+
*
|
|
3049
|
+
* // Cache result after job execution
|
|
3050
|
+
* cache.putState(docId, docType, scope, branch, newRevision, updatedDoc);
|
|
3051
|
+
*
|
|
3052
|
+
* await cache.shutdown();
|
|
3053
|
+
* ```
|
|
3054
|
+
*/
|
|
3055
|
+
declare class KyselyWriteCache implements IWriteCache {
|
|
3056
|
+
private streams;
|
|
3057
|
+
private lruTracker;
|
|
3058
|
+
private keyframeStore;
|
|
3059
|
+
private operationStore;
|
|
3060
|
+
private registry;
|
|
3061
|
+
private config;
|
|
3062
|
+
constructor(keyframeStore: IKeyframeStore, operationStore: IOperationStore, registry: IDocumentModelRegistry, config: WriteCacheConfig);
|
|
3063
|
+
withScopedStores(operationStore: IOperationStore, keyframeStore: IKeyframeStore): KyselyWriteCache;
|
|
1979
3064
|
/**
|
|
1980
|
-
*
|
|
3065
|
+
* Initializes the write cache.
|
|
3066
|
+
* Currently a no-op as keyframe store lifecycle is managed externally.
|
|
1981
3067
|
*/
|
|
1982
|
-
|
|
3068
|
+
startup(): Promise<void>;
|
|
1983
3069
|
/**
|
|
1984
|
-
*
|
|
3070
|
+
* Shuts down the write cache.
|
|
3071
|
+
* Currently a no-op as keyframe store lifecycle is managed externally.
|
|
1985
3072
|
*/
|
|
1986
|
-
|
|
3073
|
+
shutdown(): Promise<void>;
|
|
3074
|
+
/**
|
|
3075
|
+
* Retrieves document state at a specific revision from cache or rebuilds it.
|
|
3076
|
+
*
|
|
3077
|
+
* Note: this returns a _shallow_ copy of the document.
|
|
3078
|
+
*
|
|
3079
|
+
* Cache hit path: Returns cached snapshot if available (O(1))
|
|
3080
|
+
* Warm miss path: Rebuilds from cached base revision + incremental ops
|
|
3081
|
+
* Cold miss path: Rebuilds from keyframe or from scratch using all operations
|
|
3082
|
+
*
|
|
3083
|
+
* @param documentId - The document identifier
|
|
3084
|
+
* @param scope - The operation scope
|
|
3085
|
+
* @param branch - The operation branch
|
|
3086
|
+
* @param targetRevision - The target revision, or undefined for newest
|
|
3087
|
+
* @param signal - Optional abort signal to cancel the operation
|
|
3088
|
+
* @returns The document at the target revision
|
|
3089
|
+
* @throws {Error} "Operation aborted" if signal is aborted
|
|
3090
|
+
* @throws {ModuleNotFoundError} If document type not registered in registry
|
|
3091
|
+
* @throws {Error} "Failed to rebuild document" if operation store fails
|
|
3092
|
+
* @throws {Error} If reducer throws during operation application
|
|
3093
|
+
* @throws {Error} If document serialization fails
|
|
3094
|
+
*/
|
|
3095
|
+
getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
|
|
3096
|
+
/**
|
|
3097
|
+
* Stores a document snapshot in the cache at a specific revision.
|
|
3098
|
+
*
|
|
3099
|
+
* The cached document is a shallow copy of the input with its operation history
|
|
3100
|
+
* truncated to the last operation per scope and its clipboard cleared. This keeps
|
|
3101
|
+
* memory use and copy costs constant regardless of operation count. Consumers of
|
|
3102
|
+
* getState() must not rely on the full operation history being present; the only
|
|
3103
|
+
* guaranteed invariant is that operations[scope].at(-1) reflects the latest
|
|
3104
|
+
* operation index for each scope.
|
|
3105
|
+
*
|
|
3106
|
+
* Updates LRU tracker and may evict least recently used stream if at capacity.
|
|
3107
|
+
* Asynchronously persists keyframes at configured intervals (fire-and-forget).
|
|
3108
|
+
*
|
|
3109
|
+
* @param documentId - The document identifier
|
|
3110
|
+
* @param scope - The operation scope
|
|
3111
|
+
* @param branch - The operation branch
|
|
3112
|
+
* @param revision - The revision number
|
|
3113
|
+
* @param document - The document to cache
|
|
3114
|
+
* @throws {Error} If document serialization fails
|
|
3115
|
+
*/
|
|
3116
|
+
putState(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, position: SnapshotPosition): void;
|
|
3117
|
+
private store;
|
|
3118
|
+
/**
|
|
3119
|
+
* Invalidates cached document streams.
|
|
3120
|
+
*
|
|
3121
|
+
* Supports three invalidation scopes:
|
|
3122
|
+
* - Document-level: invalidate(documentId) - removes all streams for document
|
|
3123
|
+
* - Scope-level: invalidate(documentId, scope) - removes all branches for scope
|
|
3124
|
+
* - Stream-level: invalidate(documentId, scope, branch) - removes specific stream
|
|
3125
|
+
*
|
|
3126
|
+
* @param documentId - The document identifier
|
|
3127
|
+
* @param scope - Optional scope to narrow invalidation
|
|
3128
|
+
* @param branch - Optional branch to narrow invalidation (requires scope)
|
|
3129
|
+
* @returns The number of streams evicted
|
|
3130
|
+
*/
|
|
3131
|
+
invalidate(documentId: string, scope?: string, branch?: string): number;
|
|
3132
|
+
/**
|
|
3133
|
+
* Clears the entire cache, removing all cached document streams.
|
|
3134
|
+
* Resets LRU tracking state. This operation always succeeds.
|
|
3135
|
+
*/
|
|
3136
|
+
clear(): void;
|
|
3137
|
+
/**
|
|
3138
|
+
* Retrieves a specific stream for a document. Exposed on the implementation
|
|
3139
|
+
* for testing, but not on the interface.
|
|
3140
|
+
*
|
|
3141
|
+
* @internal
|
|
3142
|
+
*/
|
|
3143
|
+
getStream(documentId: string, scope: string, branch: string): DocumentStream | undefined;
|
|
3144
|
+
private findNearestKeyframe;
|
|
3145
|
+
/**
|
|
3146
|
+
* Rebuilds a scope from a keyframe or from the whole operation history.
|
|
3147
|
+
*
|
|
3148
|
+
* The document scope is always rebuilt first, because it carries the type,
|
|
3149
|
+
* the upgrades and the deletion marker. Its version-changing upgrades are not
|
|
3150
|
+
* applied there though: an upgrade reducer must see the state the requested
|
|
3151
|
+
* scope has reached at that upgrade's boundary, so each one is held back and
|
|
3152
|
+
* applied when the replay below crosses the boundary that
|
|
3153
|
+
* resolveModuleVersionForOp derives from it. Upgrades whose boundary lies past
|
|
3154
|
+
* the last replayed operation are applied at the end. Creation-time 0->N seed
|
|
3155
|
+
* upgrades carry the initial state, so they still apply immediately.
|
|
3156
|
+
*/
|
|
3157
|
+
private coldMissRebuild;
|
|
3158
|
+
/**
|
|
3159
|
+
* Applies and removes every held-back upgrade whose target version is at or
|
|
3160
|
+
* below `throughVersion`, in the order the document scope recorded them.
|
|
3161
|
+
*/
|
|
3162
|
+
private applyPendingUpgrades;
|
|
3163
|
+
/**
|
|
3164
|
+
* Applies the remaining held-back upgrades after the requested scope's
|
|
3165
|
+
* replay has finished. A head read applies them all. A positional read
|
|
3166
|
+
* applies only those whose boundary for this scope lies at or before the
|
|
3167
|
+
* target position: applying a later one would label migrated state with a
|
|
3168
|
+
* pre-upgrade revision, and a keyframe stored from that poisons every
|
|
3169
|
+
* rebuild that resumes from it. Boundaries come from the upgrade's revision
|
|
3170
|
+
* snapshot; an upgrade without one records no position for this scope, and
|
|
3171
|
+
* the replay loop not having crossed it already places it past the target.
|
|
3172
|
+
*/
|
|
3173
|
+
private applyTailPendingUpgrades;
|
|
3174
|
+
/**
|
|
3175
|
+
* Applies one held-back upgrade, then re-applies the deletes the document
|
|
3176
|
+
* scope recorded after it so the hold-back cannot invert their order.
|
|
3177
|
+
*/
|
|
3178
|
+
private applyPendingUpgrade;
|
|
3179
|
+
/**
|
|
3180
|
+
* Copies the current document revisions onto the document. Overwrites the
|
|
3181
|
+
* requested scope revision with the target revision, if provided.
|
|
3182
|
+
*/
|
|
3183
|
+
private stampRevisions;
|
|
3184
|
+
/** The stored operation at `index`, or undefined if it is no longer there. */
|
|
3185
|
+
private operationAt;
|
|
3186
|
+
/**
|
|
3187
|
+
* Resolves which module version to use for a given operation in phase 2.
|
|
3188
|
+
*
|
|
3189
|
+
* Uses the validated-upgrade boundary rules from D7:
|
|
3190
|
+
* - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary
|
|
3191
|
+
* - Otherwise: timestamp fallback
|
|
3192
|
+
* - Falls back to final module version when neither is decidable
|
|
3193
|
+
*/
|
|
3194
|
+
private resolveModuleVersionForOp;
|
|
3195
|
+
private warmMissRebuild;
|
|
3196
|
+
private findNearestOlderSnapshot;
|
|
3197
|
+
private makeStreamKey;
|
|
3198
|
+
private getOrCreateStream;
|
|
3199
|
+
private isKeyframeRevision;
|
|
3200
|
+
}
|
|
3201
|
+
//#endregion
|
|
3202
|
+
//#region src/storage/kysely/store.d.ts
|
|
3203
|
+
declare class KyselyOperationStore implements IOperationStore {
|
|
3204
|
+
private db;
|
|
3205
|
+
private trx?;
|
|
3206
|
+
constructor(db: Kysely<Database$1>);
|
|
3207
|
+
private get queryExecutor();
|
|
3208
|
+
withTransaction(trx: Transaction<Database$1>): KyselyOperationStore;
|
|
3209
|
+
apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal, condition?: AppendCondition): Promise<Operation[]>;
|
|
3210
|
+
private resolveUniqueConstraint;
|
|
3211
|
+
private executeApply;
|
|
1987
3212
|
/**
|
|
1988
|
-
*
|
|
3213
|
+
* Locks the written stream and every read-set stream, in sorted key order
|
|
3214
|
+
* so that overlapping concurrent appends serialize rather than deadlock.
|
|
3215
|
+
* The locks are still taken one row at a time, so the query preserves that
|
|
3216
|
+
* order. It must stay separate from the guarded insert, which would
|
|
3217
|
+
* otherwise read a snapshot taken before the locks were held.
|
|
1989
3218
|
*/
|
|
1990
|
-
|
|
3219
|
+
private acquireStreamLocks;
|
|
1991
3220
|
/**
|
|
1992
|
-
*
|
|
3221
|
+
* Inserts the staged operations with the condition compiled in as a WHERE
|
|
3222
|
+
* NOT EXISTS guard, making the check and the append one statement. Returns
|
|
3223
|
+
* the rows inserted; zero means the guard failed and nothing was written.
|
|
1993
3224
|
*/
|
|
1994
|
-
|
|
1995
|
-
private
|
|
3225
|
+
private insertGuarded;
|
|
3226
|
+
private findIdempotentReplay;
|
|
3227
|
+
getSince(documentId: string, scope: string, branch: string, revision: number, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
|
|
3228
|
+
getSinceId(id: number, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<OperationWithContext$1>>;
|
|
3229
|
+
getConflicting(documentId: string, scope: string, branch: string, minTimestamp: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
|
|
3230
|
+
getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
|
|
3231
|
+
getStreamLatestTimestamp(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
|
|
3232
|
+
private rowToOperation;
|
|
3233
|
+
private rowToOperationWithContext;
|
|
3234
|
+
}
|
|
3235
|
+
//#endregion
|
|
3236
|
+
//#region src/storage/kysely/keyframe-store.d.ts
|
|
3237
|
+
declare class KyselyKeyframeStore implements IKeyframeStore {
|
|
3238
|
+
private db;
|
|
3239
|
+
private trx?;
|
|
3240
|
+
constructor(db: Kysely<Database$1>);
|
|
3241
|
+
private get queryExecutor();
|
|
3242
|
+
withTransaction(trx: Transaction<Database$1>): KyselyKeyframeStore;
|
|
3243
|
+
putKeyframe(documentId: string, scope: string, branch: string, revision: number, document: PHDocument, signal?: AbortSignal): Promise<void>;
|
|
3244
|
+
findNearestKeyframe(documentId: string, scope: string, branch: string, targetRevision: number, signal?: AbortSignal): Promise<{
|
|
3245
|
+
revision: number;
|
|
3246
|
+
document: PHDocument;
|
|
3247
|
+
} | undefined>;
|
|
3248
|
+
listKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<Array<{
|
|
3249
|
+
scope: string;
|
|
3250
|
+
branch: string;
|
|
3251
|
+
revision: number;
|
|
3252
|
+
document: PHDocument;
|
|
3253
|
+
}>>;
|
|
3254
|
+
deleteKeyframes(documentId: string, scope?: string, branch?: string, signal?: AbortSignal): Promise<number>;
|
|
3255
|
+
}
|
|
3256
|
+
//#endregion
|
|
3257
|
+
//#region src/executor/execution-scope.d.ts
|
|
3258
|
+
interface ExecutionStores {
|
|
3259
|
+
operationStore: IOperationStore;
|
|
3260
|
+
operationIndex: IOperationIndex;
|
|
3261
|
+
writeCache: IWriteCache;
|
|
3262
|
+
documentMetaCache: IDocumentMetaCache;
|
|
3263
|
+
collectionMembershipCache: ICollectionMembershipCache;
|
|
3264
|
+
}
|
|
3265
|
+
interface IExecutionScope {
|
|
3266
|
+
run<T>(fn: (stores: ExecutionStores) => Promise<T>, signal?: AbortSignal): Promise<T>;
|
|
1996
3267
|
}
|
|
1997
3268
|
//#endregion
|
|
1998
3269
|
//#region src/executor/types.d.ts
|
|
@@ -2013,11 +3284,43 @@ type JobResult = {
|
|
|
2013
3284
|
duration?: number; /** Any additional metadata from the execution */
|
|
2014
3285
|
metadata?: Record<string, any>;
|
|
2015
3286
|
};
|
|
3287
|
+
/**
|
|
3288
|
+
* Enforcement the reactor performs, each off by default.
|
|
3289
|
+
*
|
|
3290
|
+
* An evaluation made while replaying is part of the document's history, so two
|
|
3291
|
+
* reactors that share documents and disagree on these diverge. A flag is turned
|
|
3292
|
+
* on for a set of reactors that sync with each other, not for one node.
|
|
3293
|
+
*/
|
|
3294
|
+
type ReactorFeatureFlags = {
|
|
3295
|
+
/**
|
|
3296
|
+
* Decide whether an operation may be admitted by building a decision model
|
|
3297
|
+
* over the document stream, rather than reading the deleted flag from the
|
|
3298
|
+
* document meta cache. Deletion then takes effect from the deleting
|
|
3299
|
+
* operation's position rather than for the whole document.
|
|
3300
|
+
*/
|
|
3301
|
+
documentDecisions: boolean;
|
|
3302
|
+
/**
|
|
3303
|
+
* Evaluate the auth policy by reading the auth scope as a second projection.
|
|
3304
|
+
* Requires documentDecisions.
|
|
3305
|
+
*/
|
|
3306
|
+
authEnforcement: boolean;
|
|
3307
|
+
/**
|
|
3308
|
+
* Match { group } principals by folding the referenced PHGroup documents as
|
|
3309
|
+
* derived projections. Requires authEnforcement.
|
|
3310
|
+
*/
|
|
3311
|
+
authGroups: boolean;
|
|
3312
|
+
/**
|
|
3313
|
+
* Evaluate `where` clauses and { match } principals against the executing
|
|
3314
|
+
* scope's state, the subject, and the action input. Requires authGroups.
|
|
3315
|
+
*/
|
|
3316
|
+
authConditions: boolean;
|
|
3317
|
+
};
|
|
2016
3318
|
/**
|
|
2017
3319
|
* Configuration options for the job executor
|
|
2018
3320
|
*/
|
|
2019
3321
|
type JobExecutorConfig = {
|
|
2020
|
-
/**
|
|
3322
|
+
/** Feature flags; anything unset is off. */featureFlags?: Partial<ReactorFeatureFlags>; /** Maximum number of conflicting operations to skip when reshuffling. */
|
|
3323
|
+
maxSkipThreshold?: number; /** Maximum number of concurrent jobs to execute */
|
|
2021
3324
|
maxConcurrency?: number; /** Maximum time in milliseconds a job can run before being considered timed out */
|
|
2022
3325
|
jobTimeoutMs?: number; /** Base delay in milliseconds for exponential backoff retries */
|
|
2023
3326
|
retryBaseDelayMs?: number; /** Maximum delay in milliseconds for exponential backoff retries */
|
|
@@ -2074,356 +3377,430 @@ type ExecutorStoppedEvent = {
|
|
|
2074
3377
|
* Status information for the job executor manager
|
|
2075
3378
|
*/
|
|
2076
3379
|
type ExecutorManagerStatus = {
|
|
2077
|
-
/** Whether the manager is currently running */isRunning: boolean; /** Number of executor instances managed */
|
|
2078
|
-
numExecutors: number; /** Number of jobs currently being processed */
|
|
2079
|
-
activeJobs: number; /** Total number of jobs processed since start */
|
|
2080
|
-
totalJobsProcessed: number;
|
|
2081
|
-
};
|
|
2082
|
-
//#endregion
|
|
2083
|
-
//#region src/
|
|
2084
|
-
/**
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
* The shape mirrors the structured-clone subset used by the parent's
|
|
2088
|
-
* sanitizer: primitives, arrays, plain objects, plus the explicit
|
|
2089
|
-
* {@link ErrorInfo} shape for marshalled Errors.
|
|
2090
|
-
*
|
|
2091
|
-
* @see Wire Protocol Reference wiki page
|
|
2092
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2093
|
-
*/
|
|
2094
|
-
type SanitizedArg = null | boolean | number | string | ErrorInfo | SanitizedArg[] | {
|
|
2095
|
-
[key: string]: SanitizedArg;
|
|
2096
|
-
};
|
|
2097
|
-
/**
|
|
2098
|
-
* Structured representation of an Error for IPC transport.
|
|
2099
|
-
*
|
|
2100
|
-
* Class instances cannot be structured-cloned across worker boundaries,
|
|
2101
|
-
* so Errors are flattened into this shape on the worker side and
|
|
2102
|
-
* reconstructed on the parent side.
|
|
2103
|
-
*
|
|
2104
|
-
* @see Wire Protocol Reference wiki page
|
|
2105
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2106
|
-
*/
|
|
2107
|
-
type ErrorInfo = {
|
|
2108
|
-
name: string;
|
|
2109
|
-
message: string;
|
|
2110
|
-
stack?: string;
|
|
2111
|
-
cause?: ErrorInfo;
|
|
2112
|
-
};
|
|
2113
|
-
/**
|
|
2114
|
-
* Reference to a module that the worker should `import()` at runtime,
|
|
2115
|
-
* along with the named export to pluck out as the factory.
|
|
2116
|
-
*
|
|
2117
|
-
* Exactly one of `packageName` or `filePath` is provided.
|
|
2118
|
-
*
|
|
2119
|
-
* @see Wire Protocol Reference wiki page
|
|
2120
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2121
|
-
*/
|
|
2122
|
-
type ModuleRef = {
|
|
2123
|
-
/** Bare-specifier package name (resolved by the worker's module loader). */packageName: string; /** Named export within the module to invoke as the factory. */
|
|
2124
|
-
exportName: string;
|
|
2125
|
-
} | {
|
|
2126
|
-
/** Absolute or worker-resolvable file path to import. */filePath: string; /** Named export within the module to invoke as the factory. */
|
|
2127
|
-
exportName: string;
|
|
2128
|
-
};
|
|
2129
|
-
/**
|
|
2130
|
-
* Factory specification shared by the signature verifier and document
|
|
2131
|
-
* model spec channels. The worker imports `module.exportName` and invokes
|
|
2132
|
-
* it with `initArgs` to obtain the actual instance.
|
|
2133
|
-
*
|
|
2134
|
-
* `initArgs` must be JSON-clonable.
|
|
2135
|
-
*
|
|
2136
|
-
* @see Wire Protocol Reference wiki page
|
|
2137
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2138
|
-
*/
|
|
2139
|
-
type FactorySpec = {
|
|
2140
|
-
module: ModuleRef;
|
|
2141
|
-
initArgs?: SanitizedArg;
|
|
2142
|
-
};
|
|
2143
|
-
/**
|
|
2144
|
-
* Factory spec for the signature verifier the worker should instantiate.
|
|
2145
|
-
*
|
|
2146
|
-
* Structurally identical to {@link FactorySpec}; the alias exists so call
|
|
2147
|
-
* sites read intent-fully.
|
|
2148
|
-
*
|
|
2149
|
-
* @see Wire Protocol Reference wiki page
|
|
2150
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2151
|
-
*/
|
|
2152
|
-
type SignatureVerifierSpec = FactorySpec;
|
|
2153
|
-
/**
|
|
2154
|
-
* Factory spec for a document model module the worker should instantiate.
|
|
2155
|
-
*
|
|
2156
|
-
* Structurally identical to {@link FactorySpec}; the alias exists so call
|
|
2157
|
-
* sites read intent-fully.
|
|
2158
|
-
*
|
|
2159
|
-
* @see Wire Protocol Reference wiki page
|
|
2160
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2161
|
-
*/
|
|
2162
|
-
type DocumentModelSpec = FactorySpec;
|
|
2163
|
-
/**
|
|
2164
|
-
* One entry in the document model manifest the worker materializes on
|
|
2165
|
-
* startup (or extends lazily via `load-model`).
|
|
2166
|
-
*
|
|
2167
|
-
* @see Wire Protocol Reference wiki page
|
|
2168
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2169
|
-
*/
|
|
2170
|
-
type ModelManifestEntry = {
|
|
2171
|
-
/** Document type identifier (e.g. "ph/account"). */documentType: string; /** Document model version this entry registers. */
|
|
2172
|
-
version: string; /** Factory spec the worker imports and invokes to obtain the model. */
|
|
2173
|
-
spec: DocumentModelSpec;
|
|
2174
|
-
};
|
|
2175
|
-
/**
|
|
2176
|
-
* JSON-clonable Postgres connection info passed to the worker so it can
|
|
2177
|
-
* open its own pool. Storage-specific wiring may extend this shape in
|
|
2178
|
-
* later phases.
|
|
2179
|
-
*
|
|
2180
|
-
* @see Wire Protocol Reference wiki page
|
|
2181
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2182
|
-
*/
|
|
2183
|
-
type DbConfig = {
|
|
2184
|
-
host: string;
|
|
2185
|
-
port: number;
|
|
2186
|
-
database: string;
|
|
2187
|
-
user: string;
|
|
2188
|
-
password: string;
|
|
2189
|
-
ssl?: boolean;
|
|
2190
|
-
applicationName?: string;
|
|
2191
|
-
poolSize?: number;
|
|
2192
|
-
/**
|
|
2193
|
-
* Maximum time (ms) a caller will wait to acquire a connection from the
|
|
2194
|
-
* pool before pg.Pool throws. When omitted, pg defaults to 0 (unlimited
|
|
2195
|
-
* wait), which hides acquire-starvation as silent latency.
|
|
2196
|
-
*/
|
|
2197
|
-
connectionTimeoutMillis?: number;
|
|
2198
|
-
/**
|
|
2199
|
-
* How long (ms) an idle connection stays open before pg closes it. When
|
|
2200
|
-
* omitted, pg defaults to 10000.
|
|
2201
|
-
*/
|
|
2202
|
-
idleTimeoutMillis?: number;
|
|
2203
|
-
};
|
|
2204
|
-
/**
|
|
2205
|
-
* Configuration for the executor worker pool.
|
|
2206
|
-
*
|
|
2207
|
-
* Mirrors the `workerPool` sub-config on {@link JobExecutorConfig};
|
|
2208
|
-
* a later card wires this into the executor config.
|
|
2209
|
-
*
|
|
2210
|
-
* @see Wire Protocol Reference wiki page
|
|
2211
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2212
|
-
*/
|
|
2213
|
-
type WorkerPoolConfig = {
|
|
2214
|
-
/** Whether the worker pool is active; when false the executor runs in-process. */enabled: boolean; /** Number of worker instances to spawn. */
|
|
2215
|
-
numWorkers: number; /** Worker isolation mode. */
|
|
2216
|
-
workerType: "thread" | "process"; /** Optional heartbeat interval in milliseconds. */
|
|
2217
|
-
heartbeatMs?: number; /** Optional per-worker Postgres pool size override. */
|
|
2218
|
-
workerPgPoolSize?: number;
|
|
2219
|
-
};
|
|
2220
|
-
/**
|
|
2221
|
-
* Payload the worker reports back when a job's write phase is complete.
|
|
2222
|
-
*
|
|
2223
|
-
* Parent fills `collectionMemberships` at emission time, so it is
|
|
2224
|
-
* intentionally absent from the worker -> parent message.
|
|
2225
|
-
*
|
|
2226
|
-
* @see Wire Protocol Reference wiki page
|
|
2227
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2228
|
-
*/
|
|
2229
|
-
type JobWriteReadyPayload = {
|
|
2230
|
-
operations: OperationWithContext$1[];
|
|
2231
|
-
jobMeta: JobMeta;
|
|
2232
|
-
};
|
|
2233
|
-
/**
|
|
2234
|
-
* Initializes a freshly spawned worker with the configuration and
|
|
2235
|
-
* factories it needs to start executing jobs.
|
|
2236
|
-
*
|
|
2237
|
-
* @see Wire Protocol Reference wiki page
|
|
2238
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2239
|
-
*/
|
|
2240
|
-
type InitMessage = {
|
|
2241
|
-
type: "init";
|
|
2242
|
-
correlationId: string;
|
|
2243
|
-
workerId: string;
|
|
2244
|
-
poolConfig: WorkerPoolConfig;
|
|
2245
|
-
db: DbConfig; /** Omitted = the worker performs no executor-side signature verification. */
|
|
2246
|
-
signatureVerifier?: SignatureVerifierSpec;
|
|
2247
|
-
models: ModelManifestEntry[];
|
|
2248
|
-
};
|
|
2249
|
-
/**
|
|
2250
|
-
* Dispatches a job to the worker for execution.
|
|
2251
|
-
*
|
|
2252
|
-
* @see Wire Protocol Reference wiki page
|
|
2253
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2254
|
-
*/
|
|
2255
|
-
type ExecuteMessage = {
|
|
2256
|
-
type: "execute";
|
|
2257
|
-
correlationId: string;
|
|
2258
|
-
job: Job;
|
|
3380
|
+
/** Whether the manager is currently running */isRunning: boolean; /** Number of executor instances managed */
|
|
3381
|
+
numExecutors: number; /** Number of jobs currently being processed */
|
|
3382
|
+
activeJobs: number; /** Total number of jobs processed since start */
|
|
3383
|
+
totalJobsProcessed: number;
|
|
3384
|
+
};
|
|
3385
|
+
//#endregion
|
|
3386
|
+
//#region src/decision/document-decision-model.d.ts
|
|
3387
|
+
/** What the document decision model reads: the target's document scope. */
|
|
3388
|
+
type DocumentDecisionModel = {
|
|
3389
|
+
document: PHDocumentState;
|
|
2259
3390
|
};
|
|
2260
3391
|
/**
|
|
2261
|
-
*
|
|
2262
|
-
*
|
|
2263
|
-
* @see Wire Protocol Reference wiki page
|
|
2264
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
3392
|
+
* The simplest decision model: one projection over the document scope, which
|
|
3393
|
+
* rejects on a deleted document.
|
|
2265
3394
|
*/
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
targetCorrelationId: string;
|
|
2270
|
-
reason?: string;
|
|
2271
|
-
};
|
|
3395
|
+
declare function documentDecisionModel(target: DecisionTarget): DecisionModel<DocumentDecisionModel>;
|
|
3396
|
+
//#endregion
|
|
3397
|
+
//#region src/decision/registered-model.d.ts
|
|
2272
3398
|
/**
|
|
2273
|
-
*
|
|
2274
|
-
*
|
|
2275
|
-
*
|
|
2276
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
3399
|
+
* A model this reactor can register. Every one carries the document projection,
|
|
3400
|
+
* because admission reads the version and the deletion timestamp off it; a model
|
|
3401
|
+
* with more projections than that is still assignable here.
|
|
2277
3402
|
*/
|
|
2278
|
-
type
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
3403
|
+
type RegisteredDecisionModel = (target: DecisionTarget) => DecisionModel<DocumentDecisionModel>;
|
|
3404
|
+
/** What admission needs out of a model built at the stream heads. */
|
|
3405
|
+
type AdmissionDecision = {
|
|
3406
|
+
evaluation: Evaluation;
|
|
3407
|
+
appendCondition: AppendCondition;
|
|
3408
|
+
documentVersion: number;
|
|
3409
|
+
deletedAtUtcIso: string | null;
|
|
2282
3410
|
};
|
|
2283
3411
|
/**
|
|
2284
|
-
*
|
|
2285
|
-
*
|
|
2286
|
-
*
|
|
2287
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
3412
|
+
* What decideAtHead resolves a condition context from: the action's input,
|
|
3413
|
+
* with the executing scope's state read at the head. Supplied only while
|
|
3414
|
+
* authConditions is on.
|
|
2288
3415
|
*/
|
|
2289
|
-
type
|
|
2290
|
-
|
|
2291
|
-
correlationId: string;
|
|
2292
|
-
model: ModelManifestEntry;
|
|
3416
|
+
type AdmissionConditions = {
|
|
3417
|
+
actionInput?: unknown;
|
|
2293
3418
|
};
|
|
2294
3419
|
/**
|
|
2295
|
-
*
|
|
3420
|
+
* Builds the model at the stream heads and decides one request against it. The
|
|
3421
|
+
* append condition it returns is the read-set the store enforces at write time.
|
|
2296
3422
|
*
|
|
2297
|
-
*
|
|
2298
|
-
*
|
|
3423
|
+
* With `conditions` supplied, the executing scope's state is read at the head
|
|
3424
|
+
* for `doc.<scope>.*` paths. That read carries no append-condition entry of
|
|
3425
|
+
* its own: the written stream's expected-revision check already refuses a
|
|
3426
|
+
* write whose scope grew between the read and the append.
|
|
2299
3427
|
*/
|
|
2300
|
-
|
|
3428
|
+
declare function decideAtHead(model: RegisteredDecisionModel, cache: IWriteCache, target: DecisionTarget, subject: AuthSubject, request: AuthRequest, signal?: AbortSignal, conditions?: AdmissionConditions): Promise<AdmissionDecision>;
|
|
2301
3429
|
/**
|
|
2302
|
-
*
|
|
2303
|
-
* `
|
|
2304
|
-
*
|
|
2305
|
-
*
|
|
2306
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
3430
|
+
* The model this reactor enforces. With `authEnforcement` off the auth scope is
|
|
3431
|
+
* absent from every append condition and no load walks it; with `authGroups`
|
|
3432
|
+
* on, the group documents the grant list names join the read-set and the
|
|
3433
|
+
* registry supplies the reducer that folds them.
|
|
2307
3434
|
*/
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
workerId: string;
|
|
2312
|
-
};
|
|
3435
|
+
declare function selectDecisionModel(flags: ReactorFeatureFlags, registry: IDocumentModelRegistry): RegisteredDecisionModel;
|
|
3436
|
+
//#endregion
|
|
3437
|
+
//#region src/decision/read-gate.d.ts
|
|
2313
3438
|
/**
|
|
2314
|
-
*
|
|
2315
|
-
*
|
|
2316
|
-
*
|
|
2317
|
-
*
|
|
2318
|
-
*
|
|
2319
|
-
*
|
|
2320
|
-
* @see Wire Protocol Reference wiki page
|
|
2321
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
3439
|
+
* Scopes every holder of a document may read, whatever the grants say. Denying
|
|
3440
|
+
* the policy itself would let a replica sync a document without it, read the
|
|
3441
|
+
* auth scope as uninitialized, and allow every operation it holds, so replicas
|
|
3442
|
+
* would diverge permanently. The document scope carries the metadata the same
|
|
3443
|
+
* argument covers. Grants gate domain-scope reads only.
|
|
2322
3444
|
*/
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
3445
|
+
declare const ALWAYS_READABLE_SCOPES: ReadonlySet<string>;
|
|
3446
|
+
/** Whether a subject may read each scope of one document. */
|
|
3447
|
+
interface IReadGate {
|
|
3448
|
+
/**
|
|
3449
|
+
* Resolves, for one document, which of its scopes the subject may read.
|
|
3450
|
+
*
|
|
3451
|
+
* The predicate is resolved up front rather than asked per scope so that the
|
|
3452
|
+
* filtering itself stays synchronous, and so that a model backing the answer
|
|
3453
|
+
* is built once per document instead of once per scope.
|
|
3454
|
+
*/
|
|
3455
|
+
scopePredicate(document: PHDocument, subject: AuthSubject, branch: string, signal?: AbortSignal): Promise<(scope: string) => boolean>;
|
|
3456
|
+
}
|
|
2330
3457
|
/**
|
|
2331
|
-
*
|
|
2332
|
-
*
|
|
2333
|
-
*
|
|
2334
|
-
*
|
|
3458
|
+
* The model reads enforce. Below `authEnforcement` there is no model to
|
|
3459
|
+
* enforce: the document-only model ignores the auth scope entirely, so reading
|
|
3460
|
+
* through it would serve every domain scope of a policied document to anyone.
|
|
3461
|
+
* Undefined therefore means "evaluate the policy alone", which is what the read
|
|
3462
|
+
* surface did before the model existed.
|
|
2335
3463
|
*/
|
|
2336
|
-
|
|
2337
|
-
type: "model-loaded"; /** correlationId of the originating `load-model` message. */
|
|
2338
|
-
correlationId: string;
|
|
2339
|
-
documentType: string;
|
|
2340
|
-
version: string;
|
|
2341
|
-
};
|
|
3464
|
+
declare function readDecisionModel(flags: ReactorFeatureFlags, registry: IDocumentModelRegistry): RegisteredDecisionModel | undefined;
|
|
2342
3465
|
/**
|
|
2343
|
-
*
|
|
2344
|
-
*
|
|
2345
|
-
*
|
|
2346
|
-
*
|
|
3466
|
+
* Evaluates the policy on its own, with no groups map and no condition context.
|
|
3467
|
+
* A `{ group }` or conditional grant therefore never applies: an allow that
|
|
3468
|
+
* does not apply withholds access, so this cannot widen a policy, but a policy
|
|
3469
|
+
* relying on a conditional deny is weaker here than it is written.
|
|
2347
3470
|
*/
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
documentType: string;
|
|
2352
|
-
version: string;
|
|
2353
|
-
error: ErrorInfo;
|
|
2354
|
-
};
|
|
3471
|
+
declare class BareReadGate implements IReadGate {
|
|
3472
|
+
scopePredicate(document: PHDocument, subject: AuthSubject): Promise<(scope: string) => boolean>;
|
|
3473
|
+
}
|
|
2355
3474
|
/**
|
|
2356
|
-
*
|
|
2357
|
-
*
|
|
2358
|
-
* values across the boundary.
|
|
3475
|
+
* Answers a stream read from the document already fetched, and anything else
|
|
3476
|
+
* through the read side.
|
|
2359
3477
|
*
|
|
2360
|
-
* The
|
|
2361
|
-
*
|
|
2362
|
-
*
|
|
2363
|
-
*
|
|
2364
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
3478
|
+
* The seed is why routing reads through a decision model costs no extra I/O for
|
|
3479
|
+
* the document being read: its `document` and `auth` scopes are the two static
|
|
3480
|
+
* projections, and the caller has both in hand. Only a group stream the grant
|
|
3481
|
+
* list names is fetched.
|
|
2365
3482
|
*/
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
3483
|
+
declare class SeededStateReader implements IStreamStateReader {
|
|
3484
|
+
private readonly documentView;
|
|
3485
|
+
private readonly seed;
|
|
3486
|
+
private readonly branch;
|
|
3487
|
+
constructor(documentView: IDocumentView, seed: PHDocument, branch: string);
|
|
3488
|
+
/**
|
|
3489
|
+
* A stream this replica does not hold has to reach buildDecisionModel as the
|
|
3490
|
+
* absence it recognises, or the whole read fails instead of leaving the group
|
|
3491
|
+
* out of the model, where its principal does not match and the policy fails
|
|
3492
|
+
* closed. The read side reports absence as a plain Error, so the absence is
|
|
3493
|
+
* confirmed rather than inferred from the message: a transient failure must
|
|
3494
|
+
* surface, not silently deny.
|
|
3495
|
+
*/
|
|
3496
|
+
getState(documentId: string, scope: string, branch: string, targetRevision?: number, signal?: AbortSignal): Promise<PHDocument>;
|
|
3497
|
+
private assertAbsent;
|
|
3498
|
+
}
|
|
2373
3499
|
/**
|
|
2374
|
-
*
|
|
2375
|
-
*
|
|
3500
|
+
* Evaluates a read against the registered decision model, built at the stream
|
|
3501
|
+
* heads. This is what makes `{ group }` principals and conditional grants apply
|
|
3502
|
+
* to a read: the model supplies the groups map and the scope's own state, the
|
|
3503
|
+
* same two things admission supplies.
|
|
2376
3504
|
*
|
|
2377
|
-
*
|
|
2378
|
-
* (Powerhouse board wiki id: 64c03e51-1aa4-4fa9-93d8-daa45642484d)
|
|
2379
|
-
*/
|
|
2380
|
-
type HeartbeatMessage = {
|
|
2381
|
-
type: "heartbeat";
|
|
2382
|
-
workerId: string; /** Epoch milliseconds the worker generated the heartbeat. */
|
|
2383
|
-
timestamp: number; /** Optional snapshot of in-flight job correlation ids. */
|
|
2384
|
-
inFlightCorrelationIds?: string[];
|
|
2385
|
-
};
|
|
2386
|
-
/**
|
|
2387
|
-
* Periodic counters / gauges the worker reports for observability.
|
|
3505
|
+
* A read has no action, so a condition on `action.input.*` never holds for one.
|
|
2388
3506
|
*
|
|
2389
|
-
*
|
|
2390
|
-
*
|
|
3507
|
+
* State is read through the read side rather than the write cache. The write
|
|
3508
|
+
* cache is invalidated by whichever process runs the executor, so a reactor
|
|
3509
|
+
* running its executors in worker processes would answer reads in the parent
|
|
3510
|
+
* from state no commit ever invalidates.
|
|
2391
3511
|
*/
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
3512
|
+
declare class ModelReadGate implements IReadGate {
|
|
3513
|
+
private readonly model;
|
|
3514
|
+
private readonly documentView;
|
|
3515
|
+
/**
|
|
3516
|
+
* Whether a group a policy names is served to that policy's audience. Only
|
|
3517
|
+
* meaningful with `authGroups`, which is what makes a `{ group }` grant
|
|
3518
|
+
* match at all; below it the grant fails closed, so serving the roster
|
|
3519
|
+
* would publish a member list no read grant can use.
|
|
3520
|
+
*/
|
|
3521
|
+
private readonly servesGroups;
|
|
3522
|
+
private readonly operationIndex?;
|
|
3523
|
+
private readonly logger?;
|
|
3524
|
+
constructor(model: RegisteredDecisionModel, documentView: IDocumentView,
|
|
3525
|
+
/**
|
|
3526
|
+
* Whether a group a policy names is served to that policy's audience. Only
|
|
3527
|
+
* meaningful with `authGroups`, which is what makes a `{ group }` grant
|
|
3528
|
+
* match at all; below it the grant fails closed, so serving the roster
|
|
3529
|
+
* would publish a member list no read grant can use.
|
|
3530
|
+
*/
|
|
3531
|
+
|
|
3532
|
+
servesGroups: boolean, operationIndex?: IOperationIndex | undefined, logger?: ILogger | undefined);
|
|
3533
|
+
/**
|
|
3534
|
+
* A served group yields its member list and nothing else. What the audience
|
|
3535
|
+
* is owed is the state it must fold to evaluate auth with the group; a
|
|
3536
|
+
* group's other scopes are its own business and stay behind its own grants.
|
|
3537
|
+
*/
|
|
3538
|
+
scopePredicate(document: PHDocument, subject: AuthSubject, branch: string, signal?: AbortSignal): Promise<(scope: string) => boolean>;
|
|
3539
|
+
/**
|
|
3540
|
+
* Whether the subject is served this group because a policy names it.
|
|
3541
|
+
*
|
|
3542
|
+
* A replica must fold a group's membership to evaluate auth with it, so a
|
|
3543
|
+
* group a grant names is served to the audience of the document that names
|
|
3544
|
+
* it, whatever the group's own read grants say. Naming a group in a policy
|
|
3545
|
+
* publishes its roster to that policy's audience; a group whose membership
|
|
3546
|
+
* must stay confidential does not belong in a grant.
|
|
3547
|
+
*
|
|
3548
|
+
* The referencing document's own domain scopes are the test. Its `auth` and
|
|
3549
|
+
* `document` scopes are readable by every holder, so testing those would
|
|
3550
|
+
* serve every referenced group to everybody.
|
|
3551
|
+
*
|
|
3552
|
+
* One level only. A referencer that is itself a group is skipped, and a
|
|
3553
|
+
* referencer's own readability is decided from its policy alone, so a
|
|
3554
|
+
* reference cycle terminates. Cycles are reachable: the reference relation
|
|
3555
|
+
* is recorded from an operation's input, including one later stored denied,
|
|
3556
|
+
* so a refused grant naming a group from inside another group leaves a row
|
|
3557
|
+
* behind that validation never saw.
|
|
3558
|
+
*
|
|
3559
|
+
* The referencers are probed a few at a time and the walk stops at the first
|
|
3560
|
+
* that serves, because a subject outside the audience is the case that runs to
|
|
3561
|
+
* the bound, and it is the common one. A probe that failed decides only when
|
|
3562
|
+
* nothing served: serving rests on a real allow, so this cannot widen, and it
|
|
3563
|
+
* stops one unreachable referencer from turning an allow already in hand into
|
|
3564
|
+
* a denial. A read records no operation, so replicas differing over a
|
|
3565
|
+
* transient failure has no consensus consequence.
|
|
3566
|
+
*
|
|
3567
|
+
* The probes are awaited together rather than raced, so none is ever left
|
|
3568
|
+
* running with nobody awaiting it, which is where unhandled rejections come
|
|
3569
|
+
* from.
|
|
3570
|
+
*/
|
|
3571
|
+
private servesGroupTo;
|
|
3572
|
+
/**
|
|
3573
|
+
* Whether one referencing document serves the subject any domain scope. A
|
|
3574
|
+
* referencer this replica does not hold serves nothing, which fails closed
|
|
3575
|
+
* the same way a group it does not hold does.
|
|
3576
|
+
*/
|
|
3577
|
+
private servesThrough;
|
|
3578
|
+
private servesGroup;
|
|
3579
|
+
/**
|
|
3580
|
+
* What this document's own policy says, with no group serving applied.
|
|
3581
|
+
*
|
|
3582
|
+
* An unpoliced document is readable in full, which is the common case and the
|
|
3583
|
+
* one worth answering without building anything. The test is the one
|
|
3584
|
+
* `evaluate` makes: a legacy `{}` auth scope and version 0 both mean
|
|
3585
|
+
* uninitialized, and "no grants" does not, because a policy with a version and
|
|
3586
|
+
* an empty grant list denies everything.
|
|
3587
|
+
*/
|
|
3588
|
+
private ownPolicyPredicate;
|
|
3589
|
+
}
|
|
3590
|
+
//#endregion
|
|
3591
|
+
//#region src/client/reactor-client.d.ts
|
|
2403
3592
|
/**
|
|
2404
|
-
*
|
|
2405
|
-
*
|
|
2406
|
-
*
|
|
2407
|
-
*
|
|
2408
|
-
*
|
|
3593
|
+
* What {@link IReactorClient.evaluateActions} decides against: the decision
|
|
3594
|
+
* model this reactor enforces, and the flags that selected it.
|
|
3595
|
+
*
|
|
3596
|
+
* Both, because neither alone is enough. The flags say which of the model's
|
|
3597
|
+
* inputs a decision may read, and the model itself cannot be derived from them
|
|
3598
|
+
* here: selecting one needs the document model registry, which a client does not
|
|
3599
|
+
* hold. Absent, this client answers no preflight at all -- which is the whole of
|
|
3600
|
+
* the non-coexistence guarantee, since a client built without a reactor holding
|
|
3601
|
+
* a decision model has nothing to answer from.
|
|
2409
3602
|
*/
|
|
2410
|
-
type
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
poolName: string; /** Epoch milliseconds the worker generated the batch. */
|
|
2414
|
-
timestamp: number; /** Acquire-wait durations (ms) accumulated since the previous batch. */
|
|
2415
|
-
durations: number[]; /** Most recent pg.Pool counter snapshot at batch send time. */
|
|
2416
|
-
size: number;
|
|
2417
|
-
idle: number;
|
|
2418
|
-
waiting: number;
|
|
3603
|
+
type ActionEvaluationConfig = {
|
|
3604
|
+
model: RegisteredDecisionModel;
|
|
3605
|
+
flags: ReactorFeatureFlags;
|
|
2419
3606
|
};
|
|
2420
3607
|
/**
|
|
2421
|
-
*
|
|
3608
|
+
* ReactorClient implementation that wraps lower-level APIs to provide
|
|
3609
|
+
* a simpler interface for document operations.
|
|
2422
3610
|
*
|
|
2423
|
-
*
|
|
2424
|
-
*
|
|
3611
|
+
* Features:
|
|
3612
|
+
* - Wraps Jobs with Promises for easier async handling
|
|
3613
|
+
* - Manages signing of submitted Action objects
|
|
3614
|
+
* - Provides quality-of-life functions for common tasks
|
|
3615
|
+
* - Wraps subscription interface with ViewFilters
|
|
2425
3616
|
*/
|
|
2426
|
-
|
|
3617
|
+
declare class ReactorClient implements IReactorClient {
|
|
3618
|
+
private logger;
|
|
3619
|
+
private reactor;
|
|
3620
|
+
private signer;
|
|
3621
|
+
private subscriptionManager;
|
|
3622
|
+
private jobAwaiter;
|
|
3623
|
+
private documentIndexer;
|
|
3624
|
+
private documentView;
|
|
3625
|
+
private readGate;
|
|
3626
|
+
private actionEvaluation;
|
|
3627
|
+
readonly drives: IDriveClient;
|
|
3628
|
+
constructor(logger: ILogger, reactor: IReactor, signer: ISigner, subscriptionManager: IReactorSubscriptionManager, jobAwaiter: IJobAwaiter, documentIndexer: IDocumentIndexer, documentView: IDocumentView, readGate?: IReadGate, actionEvaluation?: ActionEvaluationConfig);
|
|
3629
|
+
private readSubject;
|
|
3630
|
+
/**
|
|
3631
|
+
* Which scopes of one document the subject may read. Resolved once per
|
|
3632
|
+
* document, so the gate builds its model once however many scopes are then
|
|
3633
|
+
* tested, and the filtering itself stays synchronous.
|
|
3634
|
+
*/
|
|
3635
|
+
private readableScopes;
|
|
3636
|
+
/**
|
|
3637
|
+
* One document, filtered to the scopes the subject may read. Every method
|
|
3638
|
+
* that hands a document back goes through here, including the ones that
|
|
3639
|
+
* follow a write: a document returned from a mutation is a read like any
|
|
3640
|
+
* other, and returning it whole served scopes the same subject would be
|
|
3641
|
+
* refused by `get`. Its author still sees what it wrote, because an allow on
|
|
3642
|
+
* execute confers read of that scope.
|
|
3643
|
+
*/
|
|
3644
|
+
private gateDocument;
|
|
3645
|
+
/**
|
|
3646
|
+
* Retrieves a list of document model modules.
|
|
3647
|
+
*/
|
|
3648
|
+
getDocumentModelModules(namespace?: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<DocumentModelModule>>;
|
|
3649
|
+
/**
|
|
3650
|
+
* Retrieves a specific document model module by document type.
|
|
3651
|
+
*
|
|
3652
|
+
* @param documentType - The document type identifier
|
|
3653
|
+
* @returns The document model module
|
|
3654
|
+
*/
|
|
3655
|
+
getDocumentModelModule(documentType: string): Promise<DocumentModelModule<any>>;
|
|
3656
|
+
/**
|
|
3657
|
+
* Retrieves the document model module matching the version the document is
|
|
3658
|
+
* stamped with, so not-yet-upgraded documents get the reducer their
|
|
3659
|
+
* history was written with rather than the latest.
|
|
3660
|
+
*/
|
|
3661
|
+
getDocumentModelModuleForDocument(document: PHDocument): Promise<DocumentModelModule<any>>;
|
|
3662
|
+
/**
|
|
3663
|
+
* Retrieves a specific PHDocument
|
|
3664
|
+
*/
|
|
3665
|
+
get<TDocument extends PHDocument>(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<TDocument>;
|
|
3666
|
+
/**
|
|
3667
|
+
* Resolves an identifier (id or slug) to the canonical document id, using the
|
|
3668
|
+
* same lookup as the data path. Resolves against the "main" branch. Throws if
|
|
3669
|
+
* the identifier cannot be resolved or is ambiguous.
|
|
3670
|
+
*/
|
|
3671
|
+
resolveIdOrSlug(identifier: string, view?: ViewFilter, signal?: AbortSignal): Promise<string>;
|
|
3672
|
+
/**
|
|
3673
|
+
* Retrieves operations for a document
|
|
3674
|
+
*/
|
|
3675
|
+
getOperations(documentIdentifier: string, view?: ViewFilter, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
|
|
3676
|
+
private getOperationsWithCompositeCursor;
|
|
3677
|
+
/**
|
|
3678
|
+
* Retrieves outgoing relationships of a given type from a source document.
|
|
3679
|
+
*/
|
|
3680
|
+
getOutgoingRelationships(sourceIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
|
|
3681
|
+
/**
|
|
3682
|
+
* Retrieves incoming relationships of a given type to a target document.
|
|
3683
|
+
*/
|
|
3684
|
+
getIncomingRelationships(targetIdentifier: string, relationshipType: string, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
|
|
3685
|
+
/**
|
|
3686
|
+
* Filters documents by criteria and returns a list of them
|
|
3687
|
+
*/
|
|
3688
|
+
find(search: SearchFilter, view?: ViewFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<PHDocument>>;
|
|
3689
|
+
/**
|
|
3690
|
+
* Predicts the admission verdict for each candidate. See
|
|
3691
|
+
* {@link IReactorClient.evaluateActions} for the contract and its caveats.
|
|
3692
|
+
*
|
|
3693
|
+
* Read-only throughout, and never through the write cache: that cache is
|
|
3694
|
+
* invalidated by whichever process runs the executor, so a reactor running
|
|
3695
|
+
* its executors in worker processes would answer here from state no commit
|
|
3696
|
+
* ever invalidates.
|
|
3697
|
+
*/
|
|
3698
|
+
evaluateActions(documentIdentifier: string, branch: string, candidates: ActionCandidate[], subject?: AuthSubject, signal?: AbortSignal): Promise<ActionEvaluations>;
|
|
3699
|
+
/**
|
|
3700
|
+
* The decision model for one target document, built at its stream heads.
|
|
3701
|
+
*
|
|
3702
|
+
* The document is fetched unfiltered, because the policy is what decides:
|
|
3703
|
+
* reading it through the read gate would withhold the very scopes the
|
|
3704
|
+
* decision is about. A deleted document is served at its deletion boundary,
|
|
3705
|
+
* which is what lets the model refuse an execute against it -- authEnforcement
|
|
3706
|
+
* requires documentDecisions, so that read is available whenever this runs.
|
|
3707
|
+
*
|
|
3708
|
+
* Reading past the gate discloses nothing a submit does not. The `auth` and
|
|
3709
|
+
* `document` scopes are readable by every holder, so a verdict resting on the
|
|
3710
|
+
* policy alone is one the caller could compute unaided; and a verdict resting
|
|
3711
|
+
* on a conditional grant reads the executing scope's state exactly as
|
|
3712
|
+
* admission reads it, so the answer here is what submitting and being refused
|
|
3713
|
+
* would have revealed anyway.
|
|
3714
|
+
*
|
|
3715
|
+
* The append condition the build records is dropped. It guards a write, and
|
|
3716
|
+
* this makes none; reproducing it is also what the preflight cannot do, which
|
|
3717
|
+
* is why the answer is a prediction.
|
|
3718
|
+
*/
|
|
3719
|
+
private buildEvaluationTarget;
|
|
3720
|
+
/**
|
|
3721
|
+
* Creates a document and waits for completion
|
|
3722
|
+
*/
|
|
3723
|
+
create<TDocument extends PHDocument = PHDocument>(document: PHDocument, parentIdentifier?: string, signal?: AbortSignal): Promise<TDocument>;
|
|
3724
|
+
/**
|
|
3725
|
+
* Creates an empty document and waits for completion
|
|
3726
|
+
*/
|
|
3727
|
+
createEmpty<TDocument extends PHDocument>(documentModelType: string, options?: CreateDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
|
|
3728
|
+
/**
|
|
3729
|
+
* Upgrades a document to a newer document model version by dispatching an
|
|
3730
|
+
* UPGRADE_DOCUMENT action. When toVersion is omitted, upgrades to the
|
|
3731
|
+
* latest registered module version for the document's type. Returns the
|
|
3732
|
+
* document unchanged when it is already at the target version.
|
|
3733
|
+
*
|
|
3734
|
+
* The executor validates the action's version and revision snapshot against
|
|
3735
|
+
* the state the migration actually runs on. When a concurrent edit
|
|
3736
|
+
* invalidates the snapshot, the upgrade is rebuilt from a fresh read and
|
|
3737
|
+
* retried up to maxConflictRetries times before the conflict is surfaced.
|
|
3738
|
+
*/
|
|
3739
|
+
upgradeDocument<TDocument extends PHDocument = PHDocument>(documentIdentifier: string, toVersion?: number, options?: UpgradeDocumentOptions, signal?: AbortSignal): Promise<TDocument>;
|
|
3740
|
+
/**
|
|
3741
|
+
* Creates an empty document in a drive as a single batched operation.
|
|
3742
|
+
* Delegates to {@link IDriveClient.addFile}.
|
|
3743
|
+
*
|
|
3744
|
+
* @deprecated Use `client.drives.addFile` instead. This method will be
|
|
3745
|
+
* removed in a future release.
|
|
3746
|
+
*/
|
|
3747
|
+
createDocumentInDrive<TDocument extends PHDocument>(driveId: string, document: PHDocument, parentFolder?: string, signal?: AbortSignal): Promise<TDocument>;
|
|
3748
|
+
/**
|
|
3749
|
+
* Applies a list of actions to a document and waits for completion
|
|
3750
|
+
*/
|
|
3751
|
+
execute<TDocument extends PHDocument>(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal): Promise<TDocument>;
|
|
3752
|
+
/**
|
|
3753
|
+
* Submits a list of actions to a document
|
|
3754
|
+
*/
|
|
3755
|
+
executeAsync(documentIdentifier: string, branch: string, actions: Action[], signal?: AbortSignal): Promise<JobInfo>;
|
|
3756
|
+
executeBatch(request: BatchExecutionRequest, signal?: AbortSignal): Promise<BatchExecutionResult>;
|
|
3757
|
+
/**
|
|
3758
|
+
* Renames a document and waits for completion
|
|
3759
|
+
*/
|
|
3760
|
+
rename(documentIdentifier: string, name: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
|
|
3761
|
+
/**
|
|
3762
|
+
* Updates the preferred editor recorded in the document header meta.
|
|
3763
|
+
* Pass `null` to clear it.
|
|
3764
|
+
*/
|
|
3765
|
+
setPreferredEditor(documentIdentifier: string, preferredEditor: string | null, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
|
|
3766
|
+
/**
|
|
3767
|
+
* Adds multiple documents as children to another and waits for completion
|
|
3768
|
+
*/
|
|
3769
|
+
addRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
|
|
3770
|
+
/**
|
|
3771
|
+
* Removes a relationship between two documents and waits for completion.
|
|
3772
|
+
*/
|
|
3773
|
+
removeRelationship(sourceIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<PHDocument>;
|
|
3774
|
+
/**
|
|
3775
|
+
* Moves a relationship from one source document to another and waits for completion.
|
|
3776
|
+
*/
|
|
3777
|
+
moveRelationship(sourceParentIdentifier: string, targetParentIdentifier: string, targetIdentifier: string, relationshipType: string, branch?: string, signal?: AbortSignal): Promise<{
|
|
3778
|
+
source: PHDocument;
|
|
3779
|
+
target: PHDocument;
|
|
3780
|
+
}>;
|
|
3781
|
+
loadBatch(request: BatchLoadRequest, signal?: AbortSignal): Promise<BatchLoadResult>;
|
|
3782
|
+
/**
|
|
3783
|
+
* Deletes a document and waits for completion
|
|
3784
|
+
*/
|
|
3785
|
+
deleteDocument(identifier: string, propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
|
|
3786
|
+
/**
|
|
3787
|
+
* Deletes documents and waits for completion
|
|
3788
|
+
*/
|
|
3789
|
+
deleteDocuments(identifiers: string[], propagate?: PropagationMode, signal?: AbortSignal): Promise<void>;
|
|
3790
|
+
/**
|
|
3791
|
+
* Retrieves the status of a job
|
|
3792
|
+
*/
|
|
3793
|
+
getJobStatus(jobId: string, signal?: AbortSignal): Promise<JobInfo>;
|
|
3794
|
+
/**
|
|
3795
|
+
* Waits for a job to complete
|
|
3796
|
+
*/
|
|
3797
|
+
waitForJob(jobId: string | JobInfo, signal?: AbortSignal): Promise<JobInfo>;
|
|
3798
|
+
/**
|
|
3799
|
+
* Subscribes to changes for documents matching specified filters
|
|
3800
|
+
*/
|
|
3801
|
+
subscribe(search: SearchFilter, callback: (event: DocumentChangeEvent) => void, view?: ViewFilter): () => void;
|
|
3802
|
+
private removeAllIncomingRelationships;
|
|
3803
|
+
}
|
|
2427
3804
|
//#endregion
|
|
2428
3805
|
//#region src/executor/interfaces.d.ts
|
|
2429
3806
|
/**
|
|
@@ -2679,9 +4056,11 @@ interface IQueue {
|
|
|
2679
4056
|
* Retry a failed job.
|
|
2680
4057
|
* @param jobId - The ID of the job to retry
|
|
2681
4058
|
* @param error - Optional error information from the failure
|
|
4059
|
+
* @param accounting - Whether the attempt counts against the job's retry
|
|
4060
|
+
* limit; defaults to {@link RetryAccounting.CountAgainstLimit}
|
|
2682
4061
|
* @returns Promise that resolves when the job is requeued for retry
|
|
2683
4062
|
*/
|
|
2684
|
-
retryJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
|
|
4063
|
+
retryJob(jobId: string, error?: ErrorInfo$1, accounting?: RetryAccounting): Promise<void>;
|
|
2685
4064
|
/**
|
|
2686
4065
|
* Returns true if and only if all jobs have been resolved.
|
|
2687
4066
|
*/
|
|
@@ -2690,213 +4069,88 @@ interface IQueue {
|
|
|
2690
4069
|
* Blocks the queue from accepting new jobs.
|
|
2691
4070
|
* @param onDrained - Optional callback to call when the queue is drained
|
|
2692
4071
|
*/
|
|
2693
|
-
block(onDrained?: () => void): void;
|
|
2694
|
-
/**
|
|
2695
|
-
* Unblocks the queue from accepting new jobs.
|
|
2696
|
-
*/
|
|
2697
|
-
unblock(): void;
|
|
2698
|
-
}
|
|
2699
|
-
//#endregion
|
|
2700
|
-
//#region src/read-models/types.d.ts
|
|
2701
|
-
interface ViewStateTable {
|
|
2702
|
-
readModelId: string;
|
|
2703
|
-
lastOrdinal: number;
|
|
2704
|
-
lastOperationTimestamp: Generated<Date>;
|
|
2705
|
-
}
|
|
2706
|
-
interface DocumentSnapshotTable {
|
|
2707
|
-
id: Generated<string>;
|
|
2708
|
-
documentId: string;
|
|
2709
|
-
slug: string | null;
|
|
2710
|
-
name: string | null;
|
|
2711
|
-
scope: string;
|
|
2712
|
-
branch: string;
|
|
2713
|
-
content: unknown;
|
|
2714
|
-
documentType: string;
|
|
2715
|
-
lastOperationIndex: number;
|
|
2716
|
-
lastOperationHash: string;
|
|
2717
|
-
lastUpdatedAt: Generated<Date>;
|
|
2718
|
-
snapshotVersion: Generated<number>;
|
|
2719
|
-
identifiers: unknown;
|
|
2720
|
-
metadata: unknown;
|
|
2721
|
-
isDeleted: Generated<boolean>;
|
|
2722
|
-
deletedAt: Date | null;
|
|
2723
|
-
}
|
|
2724
|
-
interface SlugMappingTable {
|
|
2725
|
-
slug: string;
|
|
2726
|
-
documentId: string;
|
|
2727
|
-
scope: string;
|
|
2728
|
-
branch: string;
|
|
2729
|
-
createdAt: Generated<Date>;
|
|
2730
|
-
updatedAt: Generated<Date>;
|
|
2731
|
-
}
|
|
2732
|
-
interface ProcessorCursorTable {
|
|
2733
|
-
processorId: string;
|
|
2734
|
-
factoryId: string;
|
|
2735
|
-
driveId: string;
|
|
2736
|
-
processorIndex: number;
|
|
2737
|
-
lastOrdinal: Generated<number>;
|
|
2738
|
-
status: Generated<string>;
|
|
2739
|
-
lastError: string | null;
|
|
2740
|
-
lastErrorTimestamp: Date | null;
|
|
2741
|
-
createdAt: Generated<Date>;
|
|
2742
|
-
updatedAt: Generated<Date>;
|
|
2743
|
-
}
|
|
2744
|
-
interface DocumentViewDatabase {
|
|
2745
|
-
ViewState: ViewStateTable;
|
|
2746
|
-
DocumentSnapshot: DocumentSnapshotTable;
|
|
2747
|
-
SlugMapping: SlugMappingTable;
|
|
2748
|
-
ProcessorCursor: ProcessorCursorTable;
|
|
2749
|
-
}
|
|
2750
|
-
type InsertableDocumentSnapshot = Insertable<DocumentSnapshotTable>;
|
|
2751
|
-
//#endregion
|
|
2752
|
-
//#region src/core/model-sources.d.ts
|
|
2753
|
-
/** An importable file holding one or more document-model exports. */
|
|
2754
|
-
type FileModelSource = {
|
|
2755
|
-
filePath: string;
|
|
2756
|
-
exportName?: string;
|
|
2757
|
-
};
|
|
2758
|
-
/** An importable package specifier holding one or more document-model exports. */
|
|
2759
|
-
type PackageModelSource = {
|
|
2760
|
-
packageName: string;
|
|
2761
|
-
subpath?: string;
|
|
2762
|
-
exportName?: string;
|
|
2763
|
-
};
|
|
2764
|
-
/**
|
|
2765
|
-
* A source of document models: a live module, an importable file, or an
|
|
2766
|
-
* importable package. File and package sources can cross a worker-thread
|
|
2767
|
-
* boundary (workers re-import them); a live module cannot.
|
|
2768
|
-
*/
|
|
2769
|
-
type DocumentModelSource = DocumentModelModule<any> | FileModelSource | PackageModelSource;
|
|
2770
|
-
//#endregion
|
|
2771
|
-
//#region src/registry/interfaces.d.ts
|
|
2772
|
-
type RegistrationResult<T> = {
|
|
2773
|
-
status: "success";
|
|
2774
|
-
item: T;
|
|
2775
|
-
} | {
|
|
2776
|
-
status: "error";
|
|
2777
|
-
item: T;
|
|
2778
|
-
error: Error;
|
|
2779
|
-
};
|
|
2780
|
-
/**
|
|
2781
|
-
* Loader that asynchronously resolves a document type to a
|
|
2782
|
-
* {@link DocumentModelSource}. Used by the queue to gate CREATE_DOCUMENT
|
|
2783
|
-
* jobs until the required model is available in the registry.
|
|
2784
|
-
*
|
|
2785
|
-
* Return an importable source ({ filePath } or { packageName }) whenever
|
|
2786
|
-
* possible: the resolver registers the resolved models on the host registry
|
|
2787
|
-
* and broadcasts importable sources to executor workers. A live
|
|
2788
|
-
* DocumentModelModule is also valid but host-only — it cannot cross a
|
|
2789
|
-
* worker-thread boundary, so worker pools will not receive it.
|
|
2790
|
-
*/
|
|
2791
|
-
interface IDocumentModelLoader {
|
|
2792
|
-
load(documentType: string): Promise<DocumentModelSource>;
|
|
2793
|
-
}
|
|
2794
|
-
/**
|
|
2795
|
-
* Registry for managing document model modules.
|
|
2796
|
-
* Provides centralized access to document models' reducers, utils, and specifications.
|
|
2797
|
-
* Supports version-aware module storage and upgrade manifest management.
|
|
2798
|
-
*/
|
|
2799
|
-
interface IDocumentModelRegistry {
|
|
2800
|
-
/**
|
|
2801
|
-
* Register multiple modules at once.
|
|
2802
|
-
* Modules without a version field default to version 1.
|
|
2803
|
-
* Invalid or duplicate modules are skipped without breaking registration of the remaining modules.
|
|
2804
|
-
*
|
|
2805
|
-
* @param modules Document model modules to register
|
|
2806
|
-
* @returns Array of results, one per module, indicating success or failure
|
|
2807
|
-
*/
|
|
2808
|
-
registerModules(...modules: DocumentModelModule<any>[]): RegistrationResult<DocumentModelModule<any>>[];
|
|
2809
|
-
/**
|
|
2810
|
-
* Unregister all versions of the specified document types.
|
|
2811
|
-
*
|
|
2812
|
-
* @param documentTypes The document types to unregister
|
|
2813
|
-
* @returns true if all modules were unregistered, false if any were not found
|
|
2814
|
-
*/
|
|
2815
|
-
unregisterModules(...documentTypes: string[]): boolean;
|
|
2816
|
-
/**
|
|
2817
|
-
* Get a specific document model module by document type and optional version.
|
|
2818
|
-
* If version is not specified, returns the latest version.
|
|
2819
|
-
*
|
|
2820
|
-
* @param documentType The document type identifier
|
|
2821
|
-
* @param version Optional version number to retrieve
|
|
2822
|
-
* @returns The document model module
|
|
2823
|
-
* @throws ModuleNotFoundError if the document type or version is not registered
|
|
2824
|
-
*/
|
|
2825
|
-
getModule(documentType: string, version?: number): DocumentModelModule<any>;
|
|
2826
|
-
/**
|
|
2827
|
-
* Get all registered document model modules.
|
|
2828
|
-
*
|
|
2829
|
-
* @returns Array of all registered modules
|
|
2830
|
-
*/
|
|
2831
|
-
getAllModules(): DocumentModelModule<any>[];
|
|
2832
|
-
/**
|
|
2833
|
-
* Clear all registered modules and upgrade manifests.
|
|
2834
|
-
*/
|
|
2835
|
-
clear(): void;
|
|
2836
|
-
/**
|
|
2837
|
-
* Get all supported versions for a document type, sorted in ascending order.
|
|
2838
|
-
*
|
|
2839
|
-
* @param documentType The document type identifier
|
|
2840
|
-
* @returns Array of version numbers sorted ascending
|
|
2841
|
-
* @throws ModuleNotFoundError if no modules are registered for the document type
|
|
2842
|
-
*/
|
|
2843
|
-
getSupportedVersions(documentType: string): number[];
|
|
2844
|
-
/**
|
|
2845
|
-
* Get the latest (highest) version number for a document type.
|
|
2846
|
-
*
|
|
2847
|
-
* @param documentType The document type identifier
|
|
2848
|
-
* @returns The highest version number registered for this document type
|
|
2849
|
-
* @throws ModuleNotFoundError if no modules are registered for the document type
|
|
2850
|
-
*/
|
|
2851
|
-
getLatestVersion(documentType: string): number;
|
|
2852
|
-
/**
|
|
2853
|
-
* Register upgrade manifests that define upgrade paths between versions.
|
|
2854
|
-
* Invalid or duplicate manifests are skipped without breaking registration of the remaining manifests.
|
|
2855
|
-
*
|
|
2856
|
-
* @param manifests Upgrade manifests to register
|
|
2857
|
-
* @returns Array of results, one per manifest, indicating success or failure
|
|
2858
|
-
*/
|
|
2859
|
-
registerUpgradeManifests(...manifests: UpgradeManifest<readonly number[]>[]): RegistrationResult<UpgradeManifest<readonly number[]>>[];
|
|
2860
|
-
/**
|
|
2861
|
-
* Unregister upgrade manifests for the specified document types.
|
|
2862
|
-
* @param documentTypes The document types whose upgrade manifests should be unregistered
|
|
2863
|
-
* @returns true if all modules were unregistered, false if any were not found
|
|
2864
|
-
**/
|
|
2865
|
-
unregisterUpgradeManifests(...documentTypes: string[]): boolean;
|
|
2866
|
-
/**
|
|
2867
|
-
* Get the upgrade manifest for a document type.
|
|
2868
|
-
*
|
|
2869
|
-
* @param documentType The document type identifier
|
|
2870
|
-
* @returns The upgrade manifest
|
|
2871
|
-
* @throws ManifestNotFoundError if no manifest is registered for the document type
|
|
2872
|
-
*/
|
|
2873
|
-
getUpgradeManifest(documentType: string): UpgradeManifest<readonly number[]>;
|
|
2874
|
-
/**
|
|
2875
|
-
* Compute the upgrade path from one version to another.
|
|
2876
|
-
* Returns the sequence of upgrade transitions needed.
|
|
2877
|
-
*
|
|
2878
|
-
* @param documentType The document type identifier
|
|
2879
|
-
* @param fromVersion The starting version
|
|
2880
|
-
* @param toVersion The target version
|
|
2881
|
-
* @returns Array of upgrade transitions in order
|
|
2882
|
-
* @throws DowngradeNotSupportedError if toVersion is less than fromVersion
|
|
2883
|
-
* @throws ManifestNotFoundError if no upgrade manifest is registered
|
|
2884
|
-
* @throws MissingUpgradeTransitionError if any transition in the path is missing
|
|
2885
|
-
*/
|
|
2886
|
-
computeUpgradePath(documentType: string, fromVersion: number, toVersion: number): UpgradeTransition[];
|
|
4072
|
+
block(onDrained?: () => void): void;
|
|
2887
4073
|
/**
|
|
2888
|
-
*
|
|
2889
|
-
*
|
|
2890
|
-
* @param documentType The document type identifier
|
|
2891
|
-
* @param fromVersion The starting version
|
|
2892
|
-
* @param toVersion The target version (must be fromVersion + 1)
|
|
2893
|
-
* @returns The upgrade reducer function
|
|
2894
|
-
* @throws InvalidUpgradeStepError if toVersion is not fromVersion + 1
|
|
2895
|
-
* @throws ManifestNotFoundError if no upgrade manifest is registered
|
|
2896
|
-
* @throws MissingUpgradeTransitionError if the transition is not found
|
|
4074
|
+
* Unblocks the queue from accepting new jobs.
|
|
2897
4075
|
*/
|
|
2898
|
-
|
|
4076
|
+
unblock(): void;
|
|
4077
|
+
}
|
|
4078
|
+
//#endregion
|
|
4079
|
+
//#region src/core/group-reevaluation-trigger.d.ts
|
|
4080
|
+
/**
|
|
4081
|
+
* Watches committed writes for group membership changes and enqueues a
|
|
4082
|
+
* re-evaluation job for every document whose auth history references the
|
|
4083
|
+
* changed group, found through the reverse direction of the group-reference
|
|
4084
|
+
* relation. Each affected document is re-judged in its own job, so the work
|
|
4085
|
+
* runs under that document's execution slot rather than the group's.
|
|
4086
|
+
*
|
|
4087
|
+
* The job carries the earliest changed membership timestamp; the executor
|
|
4088
|
+
* skips the pass when everything the document holds sorts before it, which
|
|
4089
|
+
* keeps the common case (a membership write later than all history) free.
|
|
4090
|
+
*/
|
|
4091
|
+
declare class GroupReevaluationTrigger {
|
|
4092
|
+
private logger;
|
|
4093
|
+
private eventBus;
|
|
4094
|
+
private queue;
|
|
4095
|
+
private operationIndex;
|
|
4096
|
+
private unsubscribe?;
|
|
4097
|
+
constructor(logger: ILogger, eventBus: IEventBus, queue: IQueue, operationIndex: IOperationIndex);
|
|
4098
|
+
startup(): void;
|
|
4099
|
+
shutdown(): void;
|
|
4100
|
+
private onWriteReady;
|
|
4101
|
+
}
|
|
4102
|
+
//#endregion
|
|
4103
|
+
//#region src/read-models/types.d.ts
|
|
4104
|
+
interface ViewStateTable {
|
|
4105
|
+
readModelId: string;
|
|
4106
|
+
lastOrdinal: number;
|
|
4107
|
+
lastOperationTimestamp: Generated<Date>;
|
|
4108
|
+
}
|
|
4109
|
+
interface DocumentSnapshotTable {
|
|
4110
|
+
id: Generated<string>;
|
|
4111
|
+
documentId: string;
|
|
4112
|
+
slug: string | null;
|
|
4113
|
+
name: string | null;
|
|
4114
|
+
scope: string;
|
|
4115
|
+
branch: string;
|
|
4116
|
+
content: unknown;
|
|
4117
|
+
documentType: string;
|
|
4118
|
+
lastOperationIndex: number;
|
|
4119
|
+
lastOperationHash: string;
|
|
4120
|
+
lastUpdatedAt: Generated<Date>;
|
|
4121
|
+
snapshotVersion: Generated<number>;
|
|
4122
|
+
identifiers: unknown;
|
|
4123
|
+
metadata: unknown;
|
|
4124
|
+
isDeleted: Generated<boolean>;
|
|
4125
|
+
deletedAt: Date | null;
|
|
4126
|
+
}
|
|
4127
|
+
interface SlugMappingTable {
|
|
4128
|
+
slug: string;
|
|
4129
|
+
documentId: string;
|
|
4130
|
+
scope: string;
|
|
4131
|
+
branch: string;
|
|
4132
|
+
createdAt: Generated<Date>;
|
|
4133
|
+
updatedAt: Generated<Date>;
|
|
4134
|
+
}
|
|
4135
|
+
interface ProcessorCursorTable {
|
|
4136
|
+
processorId: string;
|
|
4137
|
+
factoryId: string;
|
|
4138
|
+
driveId: string;
|
|
4139
|
+
processorIndex: number;
|
|
4140
|
+
lastOrdinal: Generated<number>;
|
|
4141
|
+
status: Generated<string>;
|
|
4142
|
+
lastError: string | null;
|
|
4143
|
+
lastErrorTimestamp: Date | null;
|
|
4144
|
+
createdAt: Generated<Date>;
|
|
4145
|
+
updatedAt: Generated<Date>;
|
|
4146
|
+
}
|
|
4147
|
+
interface DocumentViewDatabase {
|
|
4148
|
+
ViewState: ViewStateTable;
|
|
4149
|
+
DocumentSnapshot: DocumentSnapshotTable;
|
|
4150
|
+
SlugMapping: SlugMappingTable;
|
|
4151
|
+
ProcessorCursor: ProcessorCursorTable;
|
|
2899
4152
|
}
|
|
4153
|
+
type InsertableDocumentSnapshot = Insertable<DocumentSnapshotTable>;
|
|
2900
4154
|
//#endregion
|
|
2901
4155
|
//#region src/shared/consistency-tracker.d.ts
|
|
2902
4156
|
interface IConsistencyTracker {
|
|
@@ -2946,134 +4200,6 @@ declare class ConsistencyTracker implements IConsistencyTracker {
|
|
|
2946
4200
|
private removeWaiter;
|
|
2947
4201
|
}
|
|
2948
4202
|
//#endregion
|
|
2949
|
-
//#region src/storage/kysely/types.d.ts
|
|
2950
|
-
interface OperationTable {
|
|
2951
|
-
id: Generated<number>;
|
|
2952
|
-
jobId: string;
|
|
2953
|
-
opId: string;
|
|
2954
|
-
prevOpId: string;
|
|
2955
|
-
writeTimestampUtcMs: Generated<Date>;
|
|
2956
|
-
documentId: string;
|
|
2957
|
-
documentType: string;
|
|
2958
|
-
scope: string;
|
|
2959
|
-
branch: string;
|
|
2960
|
-
timestampUtcMs: Date;
|
|
2961
|
-
index: number;
|
|
2962
|
-
action: unknown;
|
|
2963
|
-
skip: number;
|
|
2964
|
-
error?: string | null;
|
|
2965
|
-
hash: string;
|
|
2966
|
-
}
|
|
2967
|
-
interface KeyframeTable {
|
|
2968
|
-
id: Generated<number>;
|
|
2969
|
-
documentId: string;
|
|
2970
|
-
documentType: string;
|
|
2971
|
-
scope: string;
|
|
2972
|
-
branch: string;
|
|
2973
|
-
revision: number;
|
|
2974
|
-
document: unknown;
|
|
2975
|
-
createdAt: Generated<Date>;
|
|
2976
|
-
}
|
|
2977
|
-
interface DocumentCollectionTable {
|
|
2978
|
-
documentId: string;
|
|
2979
|
-
collectionId: string;
|
|
2980
|
-
joinedOrdinal: bigint;
|
|
2981
|
-
leftOrdinal: bigint | null;
|
|
2982
|
-
}
|
|
2983
|
-
interface OperationIndexOperationTable {
|
|
2984
|
-
ordinal: Generated<number>;
|
|
2985
|
-
opId: string;
|
|
2986
|
-
documentId: string;
|
|
2987
|
-
documentType: string;
|
|
2988
|
-
scope: string;
|
|
2989
|
-
branch: string;
|
|
2990
|
-
timestampUtcMs: string;
|
|
2991
|
-
writeTimestampUtcMs: Generated<Date>;
|
|
2992
|
-
index: number;
|
|
2993
|
-
skip: number;
|
|
2994
|
-
hash: string;
|
|
2995
|
-
action: unknown;
|
|
2996
|
-
sourceRemote: Generated<string>;
|
|
2997
|
-
}
|
|
2998
|
-
interface SyncRemoteTable {
|
|
2999
|
-
name: string;
|
|
3000
|
-
collection_id: string;
|
|
3001
|
-
channel_type: string;
|
|
3002
|
-
channel_id: string;
|
|
3003
|
-
remote_name: string;
|
|
3004
|
-
channel_parameters: unknown;
|
|
3005
|
-
filter_document_ids: unknown;
|
|
3006
|
-
filter_scopes: unknown;
|
|
3007
|
-
filter_branch: string;
|
|
3008
|
-
push_state: string;
|
|
3009
|
-
push_last_success_utc_ms: string | null;
|
|
3010
|
-
push_last_failure_utc_ms: string | null;
|
|
3011
|
-
push_failure_count: number;
|
|
3012
|
-
pull_state: string;
|
|
3013
|
-
pull_last_success_utc_ms: string | null;
|
|
3014
|
-
pull_last_failure_utc_ms: string | null;
|
|
3015
|
-
pull_failure_count: number;
|
|
3016
|
-
created_at: Generated<Date>;
|
|
3017
|
-
updated_at: Generated<Date>;
|
|
3018
|
-
}
|
|
3019
|
-
interface SyncCursorTable {
|
|
3020
|
-
remote_name: string;
|
|
3021
|
-
cursor_type: string;
|
|
3022
|
-
cursor_ordinal: bigint;
|
|
3023
|
-
last_synced_at_utc_ms: string | null;
|
|
3024
|
-
updated_at: Generated<Date>;
|
|
3025
|
-
}
|
|
3026
|
-
/**
|
|
3027
|
-
* Kysely table definition for the `sync_dead_letters` table.
|
|
3028
|
-
*/
|
|
3029
|
-
interface SyncDeadLetterTable {
|
|
3030
|
-
ordinal: Generated<number>;
|
|
3031
|
-
id: string;
|
|
3032
|
-
job_id: string;
|
|
3033
|
-
job_dependencies: unknown;
|
|
3034
|
-
remote_name: string;
|
|
3035
|
-
document_id: string;
|
|
3036
|
-
scopes: unknown;
|
|
3037
|
-
branch: string;
|
|
3038
|
-
operations: unknown;
|
|
3039
|
-
error_source: string;
|
|
3040
|
-
error_message: string;
|
|
3041
|
-
created_at: Generated<Date>;
|
|
3042
|
-
}
|
|
3043
|
-
interface Database$1 {
|
|
3044
|
-
Operation: OperationTable;
|
|
3045
|
-
Keyframe: KeyframeTable;
|
|
3046
|
-
document_collections: DocumentCollectionTable;
|
|
3047
|
-
operation_index_operations: OperationIndexOperationTable;
|
|
3048
|
-
sync_remotes: SyncRemoteTable;
|
|
3049
|
-
sync_cursors: SyncCursorTable;
|
|
3050
|
-
sync_dead_letters: SyncDeadLetterTable;
|
|
3051
|
-
}
|
|
3052
|
-
interface DocumentTable {
|
|
3053
|
-
id: string;
|
|
3054
|
-
createdAt: Generated<Date>;
|
|
3055
|
-
updatedAt: Generated<Date>;
|
|
3056
|
-
}
|
|
3057
|
-
interface DocumentRelationshipTable {
|
|
3058
|
-
id: Generated<string>;
|
|
3059
|
-
sourceId: string;
|
|
3060
|
-
targetId: string;
|
|
3061
|
-
relationshipType: string;
|
|
3062
|
-
metadata: unknown;
|
|
3063
|
-
createdAt: Generated<Date>;
|
|
3064
|
-
updatedAt: Generated<Date>;
|
|
3065
|
-
}
|
|
3066
|
-
interface IndexerStateTable {
|
|
3067
|
-
id: Generated<number>;
|
|
3068
|
-
lastOperationId: number;
|
|
3069
|
-
lastOperationTimestamp: Generated<Date>;
|
|
3070
|
-
}
|
|
3071
|
-
interface DocumentIndexerDatabase {
|
|
3072
|
-
Document: DocumentTable;
|
|
3073
|
-
DocumentRelationship: DocumentRelationshipTable;
|
|
3074
|
-
IndexerState: IndexerStateTable;
|
|
3075
|
-
}
|
|
3076
|
-
//#endregion
|
|
3077
4203
|
//#region src/storage/pool-instrumentation.d.ts
|
|
3078
4204
|
/**
|
|
3079
4205
|
* Snapshot of a pg.Pool's internal counters at a point in time.
|
|
@@ -3137,7 +4263,13 @@ declare class PollingChannelError extends Error {
|
|
|
3137
4263
|
declare class ChannelError extends Error {
|
|
3138
4264
|
source: ChannelErrorSource;
|
|
3139
4265
|
error: Error;
|
|
3140
|
-
|
|
4266
|
+
/**
|
|
4267
|
+
* The classification when something other than the error carries it. Absent
|
|
4268
|
+
* means derive it from `error.name`; a dead letter mirrored from a peer sets it,
|
|
4269
|
+
* because only the message crosses the wire.
|
|
4270
|
+
*/
|
|
4271
|
+
readonly errorType?: SyncOperationErrorType;
|
|
4272
|
+
constructor(source: ChannelErrorSource, error: Error, errorType?: SyncOperationErrorType);
|
|
3141
4273
|
}
|
|
3142
4274
|
//#endregion
|
|
3143
4275
|
//#region src/sync/sync-operation.d.ts
|
|
@@ -3736,6 +4868,12 @@ interface ReactorModule {
|
|
|
3736
4868
|
* integration scenarios.
|
|
3737
4869
|
*/
|
|
3738
4870
|
interface InProcessReactorModule extends ReactorModule {
|
|
4871
|
+
/**
|
|
4872
|
+
* The enforcement flags this reactor resolved, as plain booleans. Held on the
|
|
4873
|
+
* module because they select what a read enforces as well as what a write
|
|
4874
|
+
* does, and the read surface is composed outside the reactor.
|
|
4875
|
+
*/
|
|
4876
|
+
featureFlags: ReactorFeatureFlags;
|
|
3739
4877
|
queue: IQueue;
|
|
3740
4878
|
jobTracker: IJobTracker;
|
|
3741
4879
|
executorManager: IJobExecutorManager;
|
|
@@ -3754,6 +4892,12 @@ interface InProcessReactorModule extends ReactorModule {
|
|
|
3754
4892
|
processorManagerConsistencyTracker: IConsistencyTracker;
|
|
3755
4893
|
reactor: IReactor;
|
|
3756
4894
|
syncModule: InProcessSyncModule | undefined;
|
|
4895
|
+
/**
|
|
4896
|
+
* Present when authGroups is on: enqueues re-evaluation jobs for the
|
|
4897
|
+
* documents a group membership change affects. Started by the builder;
|
|
4898
|
+
* hosts shut it down alongside the sync manager.
|
|
4899
|
+
*/
|
|
4900
|
+
groupReevaluationTrigger: GroupReevaluationTrigger | undefined;
|
|
3757
4901
|
/**
|
|
3758
4902
|
* Instrumented pg.Pool handles registered with the builder, either by
|
|
3759
4903
|
* createPostgresDatabase or by withInstrumentedPool. Empty when no pg
|
|
@@ -3815,12 +4959,6 @@ declare class DriveClient implements IDriveClient {
|
|
|
3815
4959
|
private removeFileNode;
|
|
3816
4960
|
}
|
|
3817
4961
|
//#endregion
|
|
3818
|
-
//#region src/cache/collection-membership-cache.d.ts
|
|
3819
|
-
interface ICollectionMembershipCache {
|
|
3820
|
-
getCollectionsForDocuments(documentIds: string[]): Promise<Record<string, string[]>>;
|
|
3821
|
-
invalidate(documentId: string): void;
|
|
3822
|
-
}
|
|
3823
|
-
//#endregion
|
|
3824
4962
|
//#region src/registry/document-model-resolver.d.ts
|
|
3825
4963
|
interface IDocumentModelResolver {
|
|
3826
4964
|
ensureModelLoaded(documentType: string): Promise<void>;
|
|
@@ -3864,53 +5002,21 @@ declare class DocumentModelResolver implements IDocumentModelResolver {
|
|
|
3864
5002
|
/**
|
|
3865
5003
|
* No-op resolver used when no document model loader is configured.
|
|
3866
5004
|
* Checks the registry for the model and returns if found; throws if not.
|
|
3867
|
-
* Since there is no loader, missing models cannot be recovered.
|
|
3868
|
-
*/
|
|
3869
|
-
declare class NullDocumentModelResolver implements IDocumentModelResolver {
|
|
3870
|
-
private registry?;
|
|
3871
|
-
constructor(registry?: IDocumentModelRegistry | undefined);
|
|
3872
|
-
ensureModelLoaded(documentType: string): Promise<void>;
|
|
3873
|
-
}
|
|
3874
|
-
//#endregion
|
|
3875
|
-
//#region src/executor/worker-pool-job-executor-manager.d.ts
|
|
3876
|
-
/**
|
|
3877
|
-
* Factory invoked once per worker at `start()` time. The index is the
|
|
3878
|
-
* worker's position in the pool and the same value the manager will use
|
|
3879
|
-
* for sticky routing (`bucketFor(documentId) === index`).
|
|
3880
|
-
*/
|
|
3881
|
-
type WorkerFactory = (index: number) => IExecutorWorker;
|
|
3882
|
-
//#endregion
|
|
3883
|
-
//#region src/cache/write-cache-types.d.ts
|
|
3884
|
-
/**
|
|
3885
|
-
* Configuration options for the write cache
|
|
3886
|
-
*/
|
|
3887
|
-
type WriteCacheConfig = {
|
|
3888
|
-
/** Maximum number of document streams to cache (LRU eviction). Default: 1000 */maxDocuments: number; /** Number of snapshots to keep in each document's ring buffer. Default: 10 */
|
|
3889
|
-
ringBufferSize: number; /** Persist a keyframe snapshot every N revisions. Default: 10 */
|
|
3890
|
-
keyframeInterval: number;
|
|
3891
|
-
};
|
|
3892
|
-
/**
|
|
3893
|
-
* Unique identifier for a document stream
|
|
3894
|
-
*/
|
|
3895
|
-
type DocumentStreamKey = {
|
|
3896
|
-
/** Document identifier */documentId: string; /** Operation scope */
|
|
3897
|
-
scope: string; /** Branch name */
|
|
3898
|
-
branch: string;
|
|
3899
|
-
};
|
|
3900
|
-
/**
|
|
3901
|
-
* A cached document snapshot at a specific revision
|
|
3902
|
-
*/
|
|
3903
|
-
type CachedSnapshot = {
|
|
3904
|
-
/** The revision number of this snapshot */revision: number; /** The document state at this revision */
|
|
3905
|
-
document: PHDocument;
|
|
3906
|
-
};
|
|
5005
|
+
* Since there is no loader, missing models cannot be recovered.
|
|
5006
|
+
*/
|
|
5007
|
+
declare class NullDocumentModelResolver implements IDocumentModelResolver {
|
|
5008
|
+
private registry?;
|
|
5009
|
+
constructor(registry?: IDocumentModelRegistry | undefined);
|
|
5010
|
+
ensureModelLoaded(documentType: string): Promise<void>;
|
|
5011
|
+
}
|
|
5012
|
+
//#endregion
|
|
5013
|
+
//#region src/executor/worker-pool-job-executor-manager.d.ts
|
|
3907
5014
|
/**
|
|
3908
|
-
*
|
|
5015
|
+
* Factory invoked once per worker at `start()` time. The index is the
|
|
5016
|
+
* worker's position in the pool and the same value the manager will use
|
|
5017
|
+
* for sticky routing (`bucketFor(documentId) === index`).
|
|
3909
5018
|
*/
|
|
3910
|
-
type
|
|
3911
|
-
/** The revision number of this keyframe */revision: number; /** Serialized document state */
|
|
3912
|
-
document: string;
|
|
3913
|
-
};
|
|
5019
|
+
type WorkerFactory = (index: number) => IExecutorWorker;
|
|
3914
5020
|
//#endregion
|
|
3915
5021
|
//#region src/projection/protocol.d.ts
|
|
3916
5022
|
/**
|
|
@@ -4162,6 +5268,7 @@ declare class SyncBuilder {
|
|
|
4162
5268
|
* them (`BaseReadModel` subclasses, in particular).
|
|
4163
5269
|
*/
|
|
4164
5270
|
interface ReadModelFactoryDeps {
|
|
5271
|
+
documentModelRegistry: IDocumentModelRegistry;
|
|
4165
5272
|
operationIndex: IOperationIndex;
|
|
4166
5273
|
writeCache: IWriteCache;
|
|
4167
5274
|
processorManagerConsistencyTracker: IConsistencyTracker;
|
|
@@ -4383,6 +5490,7 @@ declare class ReactorClientBuilder {
|
|
|
4383
5490
|
private subscriptionManager?;
|
|
4384
5491
|
private jobAwaiter?;
|
|
4385
5492
|
private documentModelLoader?;
|
|
5493
|
+
private readGate?;
|
|
4386
5494
|
/**
|
|
4387
5495
|
* Sets the logger for the ReactorClient.
|
|
4388
5496
|
* @param logger - The logger to use.
|
|
@@ -4406,6 +5514,36 @@ declare class ReactorClientBuilder {
|
|
|
4406
5514
|
withSubscriptionManager(subscriptionManager: IReactorSubscriptionManager): this;
|
|
4407
5515
|
withJobAwaiter(jobAwaiter: IJobAwaiter): this;
|
|
4408
5516
|
withDocumentModelLoader(loader: IDocumentModelLoader): this;
|
|
5517
|
+
/**
|
|
5518
|
+
* Overrides how reads are gated. A client built from a ReactorBuilder derives
|
|
5519
|
+
* this from that reactor's flags; one built from `withReactor` cannot, because
|
|
5520
|
+
* it is handed no flags and no registry, so it gates on the policy alone
|
|
5521
|
+
* unless a gate is supplied here.
|
|
5522
|
+
*/
|
|
5523
|
+
withReadGate(readGate: IReadGate): this;
|
|
5524
|
+
/**
|
|
5525
|
+
* The gate the resolved model calls for. Below authEnforcement there is no
|
|
5526
|
+
* model to enforce -- the registered one ignores the auth scope -- so the
|
|
5527
|
+
* policy is evaluated on its own, which is what reads did before the model
|
|
5528
|
+
* existed. Group serving turns on with authGroups, because below it a
|
|
5529
|
+
* `{ group }` grant does not match, so a served roster is one no grant can
|
|
5530
|
+
* use.
|
|
5531
|
+
*/
|
|
5532
|
+
private resolveReadGate;
|
|
5533
|
+
/**
|
|
5534
|
+
* What the client answers an authorization preflight from, or undefined when
|
|
5535
|
+
* it answers none.
|
|
5536
|
+
*
|
|
5537
|
+
* Resolved from the same model reads enforce, so a preflight and a read can
|
|
5538
|
+
* never decide against different models. Undefined below authEnforcement, and
|
|
5539
|
+
* undefined on the `withReactor` path, where there are no flags and no
|
|
5540
|
+
* registry to select a model with -- a client with no model refuses the
|
|
5541
|
+
* preflight rather than answering it from the legacy host-side permission
|
|
5542
|
+
* tables. Deliberately not derived from the read gate: `withReadGate`
|
|
5543
|
+
* overrides that, so sniffing the gate's type would report enforcement from a
|
|
5544
|
+
* caller's substitution.
|
|
5545
|
+
*/
|
|
5546
|
+
private resolveActionEvaluation;
|
|
4409
5547
|
build(): Promise<ReactorClient>;
|
|
4410
5548
|
buildModule(): Promise<InProcessReactorClientModule>;
|
|
4411
5549
|
}
|
|
@@ -4478,6 +5616,28 @@ declare function parseDriveUrl(url: string): ParsedDriveUrl;
|
|
|
4478
5616
|
*/
|
|
4479
5617
|
declare function driveIdFromUrl(url: string): string;
|
|
4480
5618
|
//#endregion
|
|
5619
|
+
//#region src/shared/errors.d.ts
|
|
5620
|
+
/**
|
|
5621
|
+
* An authorization preflight was asked for while the reactor's decision model
|
|
5622
|
+
* is off, so there is no model to answer from.
|
|
5623
|
+
*
|
|
5624
|
+
* Thrown rather than answered from the legacy host-side permission tables. The
|
|
5625
|
+
* two systems do not compose: the tables record which addresses a host lets
|
|
5626
|
+
* near a drive, the policy records what a document's own grants permit, and an
|
|
5627
|
+
* answer stitched from both would report an admission verdict neither system
|
|
5628
|
+
* would reach. A caller that cannot get a prediction disables nothing, which
|
|
5629
|
+
* leaves the submit path -- and its real gate -- as the only authority.
|
|
5630
|
+
*
|
|
5631
|
+
* Detection is by `name`, not `instanceof`: the SharedWorker RPC boundary
|
|
5632
|
+
* rebuilds a thrown error from `{ name, message, stack, cause }` alone
|
|
5633
|
+
* (`reactor-browser/src/rpc/error-info.ts`), so the class identity and any
|
|
5634
|
+
* custom field are lost in transit. This error therefore carries no fields.
|
|
5635
|
+
*/
|
|
5636
|
+
declare class AuthEnforcementDisabledError extends Error {
|
|
5637
|
+
constructor();
|
|
5638
|
+
static isError(error: unknown): error is AuthEnforcementDisabledError;
|
|
5639
|
+
}
|
|
5640
|
+
//#endregion
|
|
4481
5641
|
//#region src/shared/factories.d.ts
|
|
4482
5642
|
/**
|
|
4483
5643
|
* Factory method to create a ShutdownStatus that can be updated
|
|
@@ -4500,568 +5660,229 @@ type ParsedPaging = {
|
|
|
4500
5660
|
*/
|
|
4501
5661
|
declare function parsePagingOptions(paging: PagingOptions | undefined, defaultLimit: number): ParsedPaging;
|
|
4502
5662
|
//#endregion
|
|
4503
|
-
//#region src/subs/default-error-handler.d.ts
|
|
4504
|
-
/**
|
|
4505
|
-
* Default error handler that re-throws subscription errors.
|
|
4506
|
-
* This ensures that errors are not silently swallowed.
|
|
4507
|
-
*/
|
|
4508
|
-
declare class DefaultSubscriptionErrorHandler implements ISubscriptionErrorHandler {
|
|
4509
|
-
handleError(error: unknown, context: SubscriptionErrorContext): void;
|
|
4510
|
-
}
|
|
4511
|
-
//#endregion
|
|
4512
|
-
//#region src/subs/react-subscription-manager.d.ts
|
|
4513
|
-
type DocumentCreatedCallback = (result: PagedResults<string>) => void;
|
|
4514
|
-
type DocumentDeletedCallback = (documentIds: string[]) => void;
|
|
4515
|
-
type DocumentStateUpdatedCallback = (result: PagedResults<PHDocument>) => void;
|
|
4516
|
-
type RelationshipChangedCallback = (parentId: string, childId: string, changeType: RelationshipChangeType) => void;
|
|
4517
|
-
declare class ReactorSubscriptionManager implements IReactorSubscriptionManager {
|
|
4518
|
-
private createdSubscriptions;
|
|
4519
|
-
private deletedSubscriptions;
|
|
4520
|
-
private updatedSubscriptions;
|
|
4521
|
-
private relationshipSubscriptions;
|
|
4522
|
-
private subscriptionCounter;
|
|
4523
|
-
private errorHandler;
|
|
4524
|
-
constructor(errorHandler: ISubscriptionErrorHandler);
|
|
4525
|
-
onDocumentCreated(callback: DocumentCreatedCallback, search?: SearchFilter): () => void;
|
|
4526
|
-
onDocumentDeleted(callback: DocumentDeletedCallback, search?: SearchFilter): () => void;
|
|
4527
|
-
onDocumentStateUpdated(callback: DocumentStateUpdatedCallback, search?: SearchFilter, view?: ViewFilter): () => void;
|
|
4528
|
-
onRelationshipChanged(callback: RelationshipChangedCallback, search?: SearchFilter): () => void;
|
|
4529
|
-
/**
|
|
4530
|
-
* Notify subscribers about created documents
|
|
4531
|
-
*/
|
|
4532
|
-
notifyDocumentsCreated(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
|
|
4533
|
-
/**
|
|
4534
|
-
* Notify subscribers about deleted documents
|
|
4535
|
-
*/
|
|
4536
|
-
notifyDocumentsDeleted(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
|
|
4537
|
-
/**
|
|
4538
|
-
* Notify subscribers about updated documents
|
|
4539
|
-
*/
|
|
4540
|
-
notifyDocumentsUpdated(documents: PHDocument[]): void;
|
|
4541
|
-
/**
|
|
4542
|
-
* Notify subscribers about relationship changes
|
|
4543
|
-
*/
|
|
4544
|
-
notifyRelationshipChanged(parentId: string, childId: string, changeType: RelationshipChangeType, childType?: string): void;
|
|
4545
|
-
/**
|
|
4546
|
-
* Clear all subscriptions
|
|
4547
|
-
*/
|
|
4548
|
-
clearAll(): void;
|
|
4549
|
-
private filterDocumentIds;
|
|
4550
|
-
private filterDocuments;
|
|
4551
|
-
private matchesRelationshipFilter;
|
|
4552
|
-
}
|
|
4553
|
-
//#endregion
|
|
4554
|
-
//#region src/events/event-bus.d.ts
|
|
4555
|
-
declare class EventBus implements IEventBus {
|
|
4556
|
-
readonly eventTypeToSubscribers: Map<number, Subscriber[]>;
|
|
4557
|
-
subscribe<K>(type: number, subscriber: (type: number, event: K) => void | Promise<void>): Unsubscribe;
|
|
4558
|
-
emit(type: number, data: any): Promise<void>;
|
|
4559
|
-
}
|
|
4560
|
-
//#endregion
|
|
4561
|
-
//#region src/queue/queue.d.ts
|
|
4562
|
-
/**
|
|
4563
|
-
* In-memory implementation of the IQueue interface.
|
|
4564
|
-
* Organizes jobs by documentId, scope, and branch to ensure proper ordering.
|
|
4565
|
-
* Ensures serial execution per document by tracking executing jobs.
|
|
4566
|
-
* Implements dependency management through queue hints.
|
|
4567
|
-
*/
|
|
4568
|
-
declare class InMemoryQueue implements IQueue {
|
|
4569
|
-
private eventBus;
|
|
4570
|
-
private resolver;
|
|
4571
|
-
private queues;
|
|
4572
|
-
private jobIdToQueueKey;
|
|
4573
|
-
private docIdToJobId;
|
|
4574
|
-
private jobIdToDocId;
|
|
4575
|
-
private completedJobs;
|
|
4576
|
-
private jobIndex;
|
|
4577
|
-
private isBlocked;
|
|
4578
|
-
private onDrainedCallback?;
|
|
4579
|
-
private isPausedFlag;
|
|
4580
|
-
constructor(eventBus: IEventBus, resolver: IDocumentModelResolver);
|
|
4581
|
-
private toErrorInfo;
|
|
4582
|
-
/**
|
|
4583
|
-
* Creates a unique key for a document/scope/branch combination
|
|
4584
|
-
*/
|
|
4585
|
-
private createQueueKey;
|
|
4586
|
-
/**
|
|
4587
|
-
* Gets or creates a queue for the given key
|
|
4588
|
-
*/
|
|
4589
|
-
private getQueue;
|
|
4590
|
-
/**
|
|
4591
|
-
* Check if a document has any jobs currently executing
|
|
4592
|
-
*/
|
|
4593
|
-
private isDocumentExecuting;
|
|
4594
|
-
/**
|
|
4595
|
-
* Mark a job as executing for its document
|
|
4596
|
-
*/
|
|
4597
|
-
private markJobExecuting;
|
|
4598
|
-
/**
|
|
4599
|
-
* Mark a job as no longer executing for its document
|
|
4600
|
-
*/
|
|
4601
|
-
private markJobComplete;
|
|
4602
|
-
/**
|
|
4603
|
-
* Check if all dependencies for a job have been completed
|
|
4604
|
-
*/
|
|
4605
|
-
private areDependenciesMet;
|
|
4606
|
-
/**
|
|
4607
|
-
* Returns the head of the sub-queue if its dependencies are met, or null.
|
|
4608
|
-
*
|
|
4609
|
-
* The dispatcher only ever considers the head — a dep-blocked head holds
|
|
4610
|
-
* the rest of its sub-queue. This preserves per-(documentId, scope, branch)
|
|
4611
|
-
* FIFO regardless of how dependencies are authored, and makes the queue's
|
|
4612
|
-
* documented "serialized per document" invariant hold even when callers
|
|
4613
|
-
* omit queueHint dependencies on jobs that share a sub-queue.
|
|
4614
|
-
*/
|
|
4615
|
-
private getNextJobWithMetDependencies;
|
|
4616
|
-
private getCreateDocumentType;
|
|
4617
|
-
enqueue(job: Job): Promise<void>;
|
|
4618
|
-
dequeue(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
|
|
4619
|
-
dequeueNext(signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
|
|
4620
|
-
dequeueNextMatching(predicate: (meta: JobRoutingMeta) => boolean, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
|
|
4621
|
-
size(documentId: string, scope: string, branch: string): Promise<number>;
|
|
4622
|
-
totalSize(): Promise<number>;
|
|
4623
|
-
remove(jobId: string): Promise<boolean>;
|
|
4624
|
-
clear(documentId: string, scope: string, branch: string): Promise<void>;
|
|
4625
|
-
clearAll(): Promise<void>;
|
|
4626
|
-
hasJobs(): Promise<boolean>;
|
|
4627
|
-
completeJob(jobId: string): Promise<void>;
|
|
4628
|
-
failJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
|
|
4629
|
-
deferJob(jobId: string): void;
|
|
4630
|
-
retryJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
|
|
4631
|
-
/**
|
|
4632
|
-
* Check if the queue is drained and call the callback if it is
|
|
4633
|
-
*/
|
|
4634
|
-
private checkDrained;
|
|
4635
|
-
/**
|
|
4636
|
-
* Returns true if and only if all jobs have been resolved.
|
|
4637
|
-
*/
|
|
4638
|
-
get isDrained(): boolean;
|
|
4639
|
-
/**
|
|
4640
|
-
* Blocks the queue from accepting new jobs.
|
|
4641
|
-
* @param onDrained - Optional callback to call when the queue is drained
|
|
4642
|
-
*/
|
|
4643
|
-
block(onDrained?: () => void): void;
|
|
4644
|
-
/**
|
|
4645
|
-
* Unblocks the queue from accepting new jobs.
|
|
4646
|
-
*/
|
|
4647
|
-
unblock(): void;
|
|
4648
|
-
/**
|
|
4649
|
-
* Pauses job dequeuing. Jobs can still be enqueued but dequeueNext() will return null.
|
|
4650
|
-
*/
|
|
4651
|
-
pause(): void;
|
|
4652
|
-
/**
|
|
4653
|
-
* Resumes job dequeuing and emits JOB_AVAILABLE events for pending jobs to wake up executors.
|
|
4654
|
-
*/
|
|
4655
|
-
resume(): Promise<void>;
|
|
4656
|
-
/**
|
|
4657
|
-
* Returns whether job dequeuing is paused.
|
|
4658
|
-
*/
|
|
4659
|
-
get paused(): boolean;
|
|
4660
|
-
/**
|
|
4661
|
-
* Returns all pending jobs across all queues.
|
|
4662
|
-
*/
|
|
4663
|
-
getPendingJobs(): Job[];
|
|
4664
|
-
/**
|
|
4665
|
-
* Returns a map of document IDs to sets of executing job IDs.
|
|
4666
|
-
*/
|
|
4667
|
-
getExecutingJobIds(): Map<string, Set<string>>;
|
|
4668
|
-
/**
|
|
4669
|
-
* Returns a job by ID from the job index.
|
|
4670
|
-
*/
|
|
4671
|
-
getJob(jobId: string): Job | undefined;
|
|
4672
|
-
}
|
|
4673
|
-
//#endregion
|
|
4674
|
-
//#region src/job-tracker/in-memory-job-tracker.d.ts
|
|
4675
|
-
/**
|
|
4676
|
-
* In-memory implementation of IJobTracker.
|
|
4677
|
-
* Maintains job status in a Map for synchronous access.
|
|
4678
|
-
* Subscribes to operation events to update job states.
|
|
4679
|
-
*/
|
|
4680
|
-
declare class InMemoryJobTracker implements IJobTracker {
|
|
4681
|
-
private eventBus;
|
|
4682
|
-
private jobs;
|
|
4683
|
-
private unsubscribers;
|
|
4684
|
-
constructor(eventBus: IEventBus);
|
|
4685
|
-
private subscribeToEvents;
|
|
4686
|
-
private handleWriteReady;
|
|
4687
|
-
private handleReadReady;
|
|
4688
|
-
private handleJobFailed;
|
|
4689
|
-
shutdown(): void;
|
|
4690
|
-
registerJob(jobInfo: JobInfo): void;
|
|
4691
|
-
markRunning(jobId: string): void;
|
|
4692
|
-
markFailed(jobId: string, error: ErrorInfo$1, job?: Job): void;
|
|
4693
|
-
getJobStatus(jobId: string): JobInfo | null;
|
|
4694
|
-
}
|
|
4695
|
-
//#endregion
|
|
4696
|
-
//#region src/executor/simple-job-executor-manager.d.ts
|
|
4697
|
-
type JobExecutorFactory = () => IJobExecutor;
|
|
4698
|
-
/**
|
|
4699
|
-
* Manages multiple job executors and coordinates job distribution.
|
|
4700
|
-
* Listens for job available events and dispatches jobs to executors.
|
|
4701
|
-
*/
|
|
4702
|
-
declare class SimpleJobExecutorManager implements IJobExecutorManager {
|
|
4703
|
-
private executorFactory;
|
|
4704
|
-
private eventBus;
|
|
4705
|
-
private queue;
|
|
4706
|
-
private jobTracker;
|
|
4707
|
-
private logger;
|
|
4708
|
-
private resolver;
|
|
4709
|
-
private executors;
|
|
4710
|
-
private isRunning;
|
|
4711
|
-
private activeJobs;
|
|
4712
|
-
private totalJobsProcessed;
|
|
4713
|
-
private unsubscribe?;
|
|
4714
|
-
private deferredJobs;
|
|
4715
|
-
private resultHandler;
|
|
4716
|
-
private jobTimeoutMs;
|
|
4717
|
-
constructor(executorFactory: JobExecutorFactory, eventBus: IEventBus, queue: IQueue, jobTracker: IJobTracker, logger: ILogger, resolver: IDocumentModelResolver, jobTimeoutMs?: number);
|
|
4718
|
-
start(numExecutors: number): Promise<void>;
|
|
4719
|
-
stop(graceful?: boolean): Promise<void>;
|
|
4720
|
-
getExecutors(): IJobExecutor[];
|
|
4721
|
-
getStatus(): ExecutorManagerStatus;
|
|
4722
|
-
private processNextJob;
|
|
4723
|
-
private checkForMoreJobs;
|
|
4724
|
-
private processExistingJobs;
|
|
4725
|
-
private flushDeferredJobs;
|
|
4726
|
-
}
|
|
4727
|
-
//#endregion
|
|
4728
|
-
//#region src/cache/document-meta-cache-types.d.ts
|
|
5663
|
+
//#region src/subs/default-error-handler.d.ts
|
|
4729
5664
|
/**
|
|
4730
|
-
*
|
|
4731
|
-
*
|
|
4732
|
-
* This lightweight structure holds essential document information needed by
|
|
4733
|
-
* the job executor without fetching full scope state. It provides an explicit
|
|
4734
|
-
* cross-scope contract for accessing document scope metadata.
|
|
5665
|
+
* Default error handler that re-throws subscription errors.
|
|
5666
|
+
* This ensures that errors are not silently swallowed.
|
|
4735
5667
|
*/
|
|
4736
|
-
|
|
5668
|
+
declare class DefaultSubscriptionErrorHandler implements ISubscriptionErrorHandler {
|
|
5669
|
+
handleError(error: unknown, context: SubscriptionErrorContext): void;
|
|
5670
|
+
}
|
|
5671
|
+
//#endregion
|
|
5672
|
+
//#region src/subs/react-subscription-manager.d.ts
|
|
5673
|
+
type DocumentCreatedCallback = (result: PagedResults<string>) => void;
|
|
5674
|
+
type DocumentDeletedCallback = (documentIds: string[]) => void;
|
|
5675
|
+
type DocumentStateUpdatedCallback = (result: PagedResults<PHDocument>) => void;
|
|
5676
|
+
type RelationshipChangedCallback = (parentId: string, childId: string, changeType: RelationshipChangeType) => void;
|
|
5677
|
+
declare class ReactorSubscriptionManager implements IReactorSubscriptionManager {
|
|
5678
|
+
private createdSubscriptions;
|
|
5679
|
+
private deletedSubscriptions;
|
|
5680
|
+
private updatedSubscriptions;
|
|
5681
|
+
private relationshipSubscriptions;
|
|
5682
|
+
private subscriptionCounter;
|
|
5683
|
+
private errorHandler;
|
|
5684
|
+
constructor(errorHandler: ISubscriptionErrorHandler);
|
|
5685
|
+
onDocumentCreated(callback: DocumentCreatedCallback, search?: SearchFilter): () => void;
|
|
5686
|
+
onDocumentDeleted(callback: DocumentDeletedCallback, search?: SearchFilter): () => void;
|
|
5687
|
+
onDocumentStateUpdated(callback: DocumentStateUpdatedCallback, search?: SearchFilter, view?: ViewFilter): () => void;
|
|
5688
|
+
onRelationshipChanged(callback: RelationshipChangedCallback, search?: SearchFilter): () => void;
|
|
4737
5689
|
/**
|
|
4738
|
-
*
|
|
4739
|
-
* Contains version, hash, isDeleted, deletedAtUtcIso, etc.
|
|
5690
|
+
* Notify subscribers about created documents
|
|
4740
5691
|
*/
|
|
4741
|
-
|
|
5692
|
+
notifyDocumentsCreated(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
|
|
4742
5693
|
/**
|
|
4743
|
-
*
|
|
5694
|
+
* Notify subscribers about deleted documents
|
|
4744
5695
|
*/
|
|
4745
|
-
|
|
5696
|
+
notifyDocumentsDeleted(documentIds: string[], documentTypes?: Map<string, string>, parentIds?: Map<string, string | null>): void;
|
|
4746
5697
|
/**
|
|
4747
|
-
*
|
|
4748
|
-
* Used for cache invalidation and consistency checks.
|
|
5698
|
+
* Notify subscribers about updated documents
|
|
4749
5699
|
*/
|
|
4750
|
-
|
|
4751
|
-
};
|
|
4752
|
-
/**
|
|
4753
|
-
* Interface for the document metadata cache.
|
|
4754
|
-
*
|
|
4755
|
-
* This cache provides an explicit cross-scope contract for accessing document
|
|
4756
|
-
* scope metadata. It solves the problem where job execution in one scope (e.g.,
|
|
4757
|
-
* "global") needs access to document scope state (version, isDeleted, etc.)
|
|
4758
|
-
* which may be stale in scope-specific caches or keyframes.
|
|
4759
|
-
*
|
|
4760
|
-
* The cache supports:
|
|
4761
|
-
* - Latest metadata retrieval with LRU caching
|
|
4762
|
-
* - Historical metadata reconstruction for reshuffling scenarios
|
|
4763
|
-
* - Eager updates after document scope operations
|
|
4764
|
-
*/
|
|
4765
|
-
interface IDocumentMetaCache {
|
|
5700
|
+
notifyDocumentsUpdated(documents: PHDocument[]): void;
|
|
4766
5701
|
/**
|
|
4767
|
-
*
|
|
4768
|
-
*
|
|
4769
|
-
* On cache miss, fetches all document scope operations and reconstructs the
|
|
4770
|
-
* current PHDocumentState by applying UPGRADE_DOCUMENT and DELETE_DOCUMENT
|
|
4771
|
-
* operations.
|
|
4772
|
-
*
|
|
4773
|
-
* @param documentId - The document identifier
|
|
4774
|
-
* @param branch - Branch name
|
|
4775
|
-
* @param signal - Optional abort signal to cancel the operation
|
|
4776
|
-
* @returns The cached or rebuilt document metadata
|
|
4777
|
-
* @throws {Error} "Operation aborted" if signal is aborted
|
|
4778
|
-
* @throws {Error} If document not found (no CREATE_DOCUMENT operation)
|
|
5702
|
+
* Notify subscribers about relationship changes
|
|
4779
5703
|
*/
|
|
4780
|
-
|
|
5704
|
+
notifyRelationshipChanged(parentId: string, childId: string, changeType: RelationshipChangeType, childType?: string): void;
|
|
4781
5705
|
/**
|
|
4782
|
-
*
|
|
4783
|
-
*
|
|
4784
|
-
* Used during reshuffling when operations need to be inserted at a previous
|
|
4785
|
-
* revision and we need the document scope state as of that point in time.
|
|
4786
|
-
*
|
|
4787
|
-
* @param documentId - The document identifier
|
|
4788
|
-
* @param branch - Branch name
|
|
4789
|
-
* @param targetRevision - The document scope revision to reconstruct up to
|
|
4790
|
-
* @param signal - Optional abort signal to cancel the operation
|
|
4791
|
-
* @returns Document metadata as of the target revision
|
|
4792
|
-
* @throws {Error} "Operation aborted" if signal is aborted
|
|
4793
|
-
* @throws {Error} If document not found
|
|
5706
|
+
* Clear all subscriptions
|
|
4794
5707
|
*/
|
|
4795
|
-
|
|
5708
|
+
clearAll(): void;
|
|
5709
|
+
private filterDocumentIds;
|
|
5710
|
+
private filterDocuments;
|
|
5711
|
+
private matchesRelationshipFilter;
|
|
5712
|
+
}
|
|
5713
|
+
//#endregion
|
|
5714
|
+
//#region src/events/event-bus.d.ts
|
|
5715
|
+
declare class EventBus implements IEventBus {
|
|
5716
|
+
readonly eventTypeToSubscribers: Map<number, Subscriber[]>;
|
|
5717
|
+
subscribe<K>(type: number, subscriber: (type: number, event: K) => void | Promise<void>): Unsubscribe;
|
|
5718
|
+
emit(type: number, data: any): Promise<void>;
|
|
5719
|
+
}
|
|
5720
|
+
//#endregion
|
|
5721
|
+
//#region src/queue/queue.d.ts
|
|
5722
|
+
/**
|
|
5723
|
+
* In-memory implementation of the IQueue interface.
|
|
5724
|
+
* Organizes jobs by documentId, scope, and branch to ensure proper ordering.
|
|
5725
|
+
* Ensures serial execution per document by tracking executing jobs.
|
|
5726
|
+
* Implements dependency management through queue hints.
|
|
5727
|
+
*/
|
|
5728
|
+
declare class InMemoryQueue implements IQueue {
|
|
5729
|
+
private eventBus;
|
|
5730
|
+
private resolver;
|
|
5731
|
+
private queues;
|
|
5732
|
+
private jobIdToQueueKey;
|
|
5733
|
+
private docIdToJobId;
|
|
5734
|
+
private jobIdToDocId;
|
|
5735
|
+
private completedJobs;
|
|
5736
|
+
private jobIndex;
|
|
5737
|
+
private isBlocked;
|
|
5738
|
+
private onDrainedCallback?;
|
|
5739
|
+
private isPausedFlag;
|
|
5740
|
+
constructor(eventBus: IEventBus, resolver: IDocumentModelResolver);
|
|
5741
|
+
private toErrorInfo;
|
|
4796
5742
|
/**
|
|
4797
|
-
*
|
|
4798
|
-
*
|
|
4799
|
-
* Called by the job executor after CREATE_DOCUMENT, UPGRADE_DOCUMENT, or
|
|
4800
|
-
* DELETE_DOCUMENT operations to keep the cache current.
|
|
4801
|
-
*
|
|
4802
|
-
* @param documentId - The document identifier
|
|
4803
|
-
* @param branch - Branch name
|
|
4804
|
-
* @param meta - The new metadata to cache
|
|
5743
|
+
* Creates a unique key for a document/scope/branch combination
|
|
4805
5744
|
*/
|
|
4806
|
-
|
|
5745
|
+
private createQueueKey;
|
|
4807
5746
|
/**
|
|
4808
|
-
*
|
|
4809
|
-
*
|
|
4810
|
-
* Call before reshuffling operations that modify the document scope, or
|
|
4811
|
-
* when document state may have changed externally.
|
|
4812
|
-
*
|
|
4813
|
-
* @param documentId - The document identifier
|
|
4814
|
-
* @param branch - Optional branch to narrow invalidation (if omitted, all branches)
|
|
4815
|
-
* @returns Number of entries invalidated
|
|
5747
|
+
* Gets or creates a queue for the given key
|
|
4816
5748
|
*/
|
|
4817
|
-
|
|
5749
|
+
private getQueue;
|
|
4818
5750
|
/**
|
|
4819
|
-
*
|
|
5751
|
+
* Check if a document has any jobs currently executing
|
|
4820
5752
|
*/
|
|
4821
|
-
|
|
5753
|
+
private isDocumentExecuting;
|
|
4822
5754
|
/**
|
|
4823
|
-
*
|
|
5755
|
+
* Mark a job as executing for its document
|
|
4824
5756
|
*/
|
|
4825
|
-
|
|
5757
|
+
private markJobExecuting;
|
|
4826
5758
|
/**
|
|
4827
|
-
*
|
|
5759
|
+
* Mark a job as no longer executing for its document
|
|
4828
5760
|
*/
|
|
4829
|
-
|
|
4830
|
-
}
|
|
4831
|
-
//#endregion
|
|
4832
|
-
//#region src/cache/buffer/ring-buffer.d.ts
|
|
4833
|
-
/**
|
|
4834
|
-
* RingBuffer is a generic circular buffer implementation that stores a fixed number
|
|
4835
|
-
* of items. When the buffer is full, new items overwrite the oldest items.
|
|
4836
|
-
*
|
|
4837
|
-
* This implementation maintains O(1) time complexity for push operations and provides
|
|
4838
|
-
* items in chronological order (oldest to newest) via getAll().
|
|
4839
|
-
*
|
|
4840
|
-
* @template T - The type of items stored in the buffer
|
|
4841
|
-
*/
|
|
4842
|
-
declare class RingBuffer<T> {
|
|
4843
|
-
private buffer;
|
|
4844
|
-
private head;
|
|
4845
|
-
private size;
|
|
4846
|
-
private capacity;
|
|
4847
|
-
constructor(capacity: number);
|
|
5761
|
+
private markJobComplete;
|
|
4848
5762
|
/**
|
|
4849
|
-
*
|
|
4850
|
-
*
|
|
4851
|
-
* @param item - The item to add
|
|
5763
|
+
* Check if all dependencies for a job have been completed
|
|
4852
5764
|
*/
|
|
4853
|
-
|
|
5765
|
+
private areDependenciesMet;
|
|
4854
5766
|
/**
|
|
4855
|
-
* Returns
|
|
5767
|
+
* Returns the head of the sub-queue if its dependencies are met, or null.
|
|
4856
5768
|
*
|
|
4857
|
-
*
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
*
|
|
4862
|
-
*/
|
|
4863
|
-
clear(): void;
|
|
4864
|
-
/**
|
|
4865
|
-
* Gets the current number of items in the buffer.
|
|
5769
|
+
* The dispatcher only ever considers the head — a dep-blocked head holds
|
|
5770
|
+
* the rest of its sub-queue. This preserves per-(documentId, scope, branch)
|
|
5771
|
+
* FIFO regardless of how dependencies are authored, and makes the queue's
|
|
5772
|
+
* documented "serialized per document" invariant hold even when callers
|
|
5773
|
+
* omit queueHint dependencies on jobs that share a sub-queue.
|
|
4866
5774
|
*/
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
* - Cold miss: O(n) where n is total operation count, or O(k) where k is operations since keyframe
|
|
4884
|
-
* - Warm miss: O(m) where m is operations since cached revision
|
|
4885
|
-
* - Eviction: O(1) for LRU tracking and removal
|
|
4886
|
-
*
|
|
4887
|
-
* **Thread Safety:**
|
|
4888
|
-
* Not thread-safe. Designed for single-threaded job executor environment.
|
|
4889
|
-
* External synchronization required for concurrent access across multiple executors.
|
|
4890
|
-
*
|
|
4891
|
-
* **Example:**
|
|
4892
|
-
* ```typescript
|
|
4893
|
-
* const cache = new KyselyWriteCache(
|
|
4894
|
-
* keyframeStore,
|
|
4895
|
-
* operationStore,
|
|
4896
|
-
* registry,
|
|
4897
|
-
* { maxDocuments: 1000, ringBufferSize: 10, keyframeInterval: 10 }
|
|
4898
|
-
* );
|
|
4899
|
-
*
|
|
4900
|
-
* await cache.startup();
|
|
4901
|
-
*
|
|
4902
|
-
* // Retrieve or rebuild document
|
|
4903
|
-
* const doc = await cache.getState(docId, docType, scope, branch, revision);
|
|
4904
|
-
*
|
|
4905
|
-
* // Cache result after job execution
|
|
4906
|
-
* cache.putState(docId, docType, scope, branch, newRevision, updatedDoc);
|
|
4907
|
-
*
|
|
4908
|
-
* await cache.shutdown();
|
|
4909
|
-
* ```
|
|
4910
|
-
*/
|
|
4911
|
-
declare class KyselyWriteCache implements IWriteCache {
|
|
4912
|
-
private streams;
|
|
4913
|
-
private lruTracker;
|
|
4914
|
-
private keyframeStore;
|
|
4915
|
-
private operationStore;
|
|
4916
|
-
private registry;
|
|
4917
|
-
private config;
|
|
4918
|
-
constructor(keyframeStore: IKeyframeStore, operationStore: IOperationStore, registry: IDocumentModelRegistry, config: WriteCacheConfig);
|
|
4919
|
-
withScopedStores(operationStore: IOperationStore, keyframeStore: IKeyframeStore): KyselyWriteCache;
|
|
5775
|
+
private getNextJobWithMetDependencies;
|
|
5776
|
+
private getCreateDocumentType;
|
|
5777
|
+
enqueue(job: Job): Promise<void>;
|
|
5778
|
+
dequeue(documentId: string, scope: string, branch: string, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
|
|
5779
|
+
dequeueNext(signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
|
|
5780
|
+
dequeueNextMatching(predicate: (meta: JobRoutingMeta) => boolean, signal?: AbortSignal): Promise<IJobExecutionHandle | null>;
|
|
5781
|
+
size(documentId: string, scope: string, branch: string): Promise<number>;
|
|
5782
|
+
totalSize(): Promise<number>;
|
|
5783
|
+
remove(jobId: string): Promise<boolean>;
|
|
5784
|
+
clear(documentId: string, scope: string, branch: string): Promise<void>;
|
|
5785
|
+
clearAll(): Promise<void>;
|
|
5786
|
+
hasJobs(): Promise<boolean>;
|
|
5787
|
+
completeJob(jobId: string): Promise<void>;
|
|
5788
|
+
failJob(jobId: string, error?: ErrorInfo$1): Promise<void>;
|
|
5789
|
+
deferJob(jobId: string): void;
|
|
5790
|
+
retryJob(jobId: string, error?: ErrorInfo$1, accounting?: RetryAccounting): Promise<void>;
|
|
4920
5791
|
/**
|
|
4921
|
-
*
|
|
4922
|
-
* Currently a no-op as keyframe store lifecycle is managed externally.
|
|
5792
|
+
* Check if the queue is drained and call the callback if it is
|
|
4923
5793
|
*/
|
|
4924
|
-
|
|
5794
|
+
private checkDrained;
|
|
4925
5795
|
/**
|
|
4926
|
-
*
|
|
4927
|
-
* Currently a no-op as keyframe store lifecycle is managed externally.
|
|
5796
|
+
* Returns true if and only if all jobs have been resolved.
|
|
4928
5797
|
*/
|
|
4929
|
-
|
|
5798
|
+
get isDrained(): boolean;
|
|
4930
5799
|
/**
|
|
4931
|
-
*
|
|
4932
|
-
*
|
|
4933
|
-
* Cache hit path: Returns cached snapshot if available (O(1))
|
|
4934
|
-
* Warm miss path: Rebuilds from cached base revision + incremental ops
|
|
4935
|
-
* Cold miss path: Rebuilds from keyframe or from scratch using all operations
|
|
4936
|
-
*
|
|
4937
|
-
* @param documentId - The document identifier
|
|
4938
|
-
* @param scope - The operation scope
|
|
4939
|
-
* @param branch - The operation branch
|
|
4940
|
-
* @param targetRevision - The target revision, or undefined for newest
|
|
4941
|
-
* @param signal - Optional abort signal to cancel the operation
|
|
4942
|
-
* @returns The document at the target revision
|
|
4943
|
-
* @throws {Error} "Operation aborted" if signal is aborted
|
|
4944
|
-
* @throws {ModuleNotFoundError} If document type not registered in registry
|
|
4945
|
-
* @throws {Error} "Failed to rebuild document" if operation store fails
|
|
4946
|
-
* @throws {Error} If reducer throws during operation application
|
|
4947
|
-
* @throws {Error} If document serialization fails
|
|
5800
|
+
* Blocks the queue from accepting new jobs.
|
|
5801
|
+
* @param onDrained - Optional callback to call when the queue is drained
|
|
4948
5802
|
*/
|
|
4949
|
-
|
|
5803
|
+
block(onDrained?: () => void): void;
|
|
4950
5804
|
/**
|
|
4951
|
-
*
|
|
4952
|
-
*
|
|
4953
|
-
* The cached document is a shallow copy of the input with its operation history
|
|
4954
|
-
* truncated to the last operation per scope and its clipboard cleared. This keeps
|
|
4955
|
-
* memory use and copy costs constant regardless of operation count. Consumers of
|
|
4956
|
-
* getState() must not rely on the full operation history being present; the only
|
|
4957
|
-
* guaranteed invariant is that operations[scope].at(-1) reflects the latest
|
|
4958
|
-
* operation index for each scope.
|
|
4959
|
-
*
|
|
4960
|
-
* Updates LRU tracker and may evict least recently used stream if at capacity.
|
|
4961
|
-
* Asynchronously persists keyframes at configured intervals (fire-and-forget).
|
|
4962
|
-
*
|
|
4963
|
-
* @param documentId - The document identifier
|
|
4964
|
-
* @param scope - The operation scope
|
|
4965
|
-
* @param branch - The operation branch
|
|
4966
|
-
* @param revision - The revision number
|
|
4967
|
-
* @param document - The document to cache
|
|
4968
|
-
* @throws {Error} If document serialization fails
|
|
5805
|
+
* Unblocks the queue from accepting new jobs.
|
|
4969
5806
|
*/
|
|
4970
|
-
|
|
5807
|
+
unblock(): void;
|
|
4971
5808
|
/**
|
|
4972
|
-
*
|
|
4973
|
-
*
|
|
4974
|
-
* Supports three invalidation scopes:
|
|
4975
|
-
* - Document-level: invalidate(documentId) - removes all streams for document
|
|
4976
|
-
* - Scope-level: invalidate(documentId, scope) - removes all branches for scope
|
|
4977
|
-
* - Stream-level: invalidate(documentId, scope, branch) - removes specific stream
|
|
4978
|
-
*
|
|
4979
|
-
* @param documentId - The document identifier
|
|
4980
|
-
* @param scope - Optional scope to narrow invalidation
|
|
4981
|
-
* @param branch - Optional branch to narrow invalidation (requires scope)
|
|
4982
|
-
* @returns The number of streams evicted
|
|
5809
|
+
* Pauses job dequeuing. Jobs can still be enqueued but dequeueNext() will return null.
|
|
4983
5810
|
*/
|
|
4984
|
-
|
|
5811
|
+
pause(): void;
|
|
4985
5812
|
/**
|
|
4986
|
-
*
|
|
4987
|
-
* Resets LRU tracking state. This operation always succeeds.
|
|
5813
|
+
* Resumes job dequeuing and emits JOB_AVAILABLE events for pending jobs to wake up executors.
|
|
4988
5814
|
*/
|
|
4989
|
-
|
|
5815
|
+
resume(): Promise<void>;
|
|
4990
5816
|
/**
|
|
4991
|
-
*
|
|
4992
|
-
* for testing, but not on the interface.
|
|
4993
|
-
*
|
|
4994
|
-
* @internal
|
|
5817
|
+
* Returns whether job dequeuing is paused.
|
|
4995
5818
|
*/
|
|
4996
|
-
|
|
4997
|
-
private findNearestKeyframe;
|
|
4998
|
-
private coldMissRebuild;
|
|
5819
|
+
get paused(): boolean;
|
|
4999
5820
|
/**
|
|
5000
|
-
*
|
|
5001
|
-
*
|
|
5002
|
-
* Uses the validated-upgrade boundary rules from D7:
|
|
5003
|
-
* - If `input.revision` is present: op.index < revision[scope] → before the upgrade boundary
|
|
5004
|
-
* - Otherwise: timestamp fallback
|
|
5005
|
-
* - Falls back to final module version when neither is decidable
|
|
5821
|
+
* Returns all pending jobs across all queues.
|
|
5006
5822
|
*/
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
declare class KyselyOperationStore implements IOperationStore {
|
|
5017
|
-
private db;
|
|
5018
|
-
private trx?;
|
|
5019
|
-
constructor(db: Kysely<Database$1>);
|
|
5020
|
-
private get queryExecutor();
|
|
5021
|
-
withTransaction(trx: Transaction<Database$1>): KyselyOperationStore;
|
|
5022
|
-
apply(documentId: string, documentType: string, scope: string, branch: string, revision: number, fn: (txn: AtomicTxn) => void | Promise<void>, signal?: AbortSignal): Promise<Operation[]>;
|
|
5023
|
-
private resolveUniqueConstraint;
|
|
5024
|
-
private executeApply;
|
|
5025
|
-
private findIdempotentReplay;
|
|
5026
|
-
getSince(documentId: string, scope: string, branch: string, revision: number, filter?: OperationFilter, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
|
|
5027
|
-
getSinceId(id: number, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<OperationWithContext$1>>;
|
|
5028
|
-
getConflicting(documentId: string, scope: string, branch: string, minTimestamp: string, paging?: PagingOptions, signal?: AbortSignal): Promise<PagedResults<Operation>>;
|
|
5029
|
-
getRevisions(documentId: string, branch: string, signal?: AbortSignal): Promise<DocumentRevisions>;
|
|
5030
|
-
private rowToOperation;
|
|
5031
|
-
private rowToOperationWithContext;
|
|
5823
|
+
getPendingJobs(): Job[];
|
|
5824
|
+
/**
|
|
5825
|
+
* Returns a map of document IDs to sets of executing job IDs.
|
|
5826
|
+
*/
|
|
5827
|
+
getExecutingJobIds(): Map<string, Set<string>>;
|
|
5828
|
+
/**
|
|
5829
|
+
* Returns a job by ID from the job index.
|
|
5830
|
+
*/
|
|
5831
|
+
getJob(jobId: string): Job | undefined;
|
|
5032
5832
|
}
|
|
5033
5833
|
//#endregion
|
|
5034
|
-
//#region src/
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5834
|
+
//#region src/job-tracker/in-memory-job-tracker.d.ts
|
|
5835
|
+
/**
|
|
5836
|
+
* In-memory implementation of IJobTracker.
|
|
5837
|
+
* Maintains job status in a Map for synchronous access.
|
|
5838
|
+
* Subscribes to operation events to update job states.
|
|
5839
|
+
*/
|
|
5840
|
+
declare class InMemoryJobTracker implements IJobTracker {
|
|
5841
|
+
private eventBus;
|
|
5842
|
+
private jobs;
|
|
5843
|
+
private unsubscribers;
|
|
5844
|
+
constructor(eventBus: IEventBus);
|
|
5845
|
+
private subscribeToEvents;
|
|
5846
|
+
private handleWriteReady;
|
|
5847
|
+
private handleReadReady;
|
|
5848
|
+
private handleJobFailed;
|
|
5849
|
+
shutdown(): void;
|
|
5850
|
+
registerJob(jobInfo: JobInfo): void;
|
|
5851
|
+
markRunning(jobId: string): void;
|
|
5852
|
+
markFailed(jobId: string, error: ErrorInfo$1, job?: Job): void;
|
|
5853
|
+
getJobStatus(jobId: string): JobInfo | null;
|
|
5053
5854
|
}
|
|
5054
5855
|
//#endregion
|
|
5055
|
-
//#region src/executor/
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5856
|
+
//#region src/executor/simple-job-executor-manager.d.ts
|
|
5857
|
+
type JobExecutorFactory = () => IJobExecutor;
|
|
5858
|
+
/**
|
|
5859
|
+
* Manages multiple job executors and coordinates job distribution.
|
|
5860
|
+
* Listens for job available events and dispatches jobs to executors.
|
|
5861
|
+
*/
|
|
5862
|
+
declare class SimpleJobExecutorManager implements IJobExecutorManager {
|
|
5863
|
+
private executorFactory;
|
|
5864
|
+
private eventBus;
|
|
5865
|
+
private queue;
|
|
5866
|
+
private jobTracker;
|
|
5867
|
+
private logger;
|
|
5868
|
+
private resolver;
|
|
5869
|
+
private executors;
|
|
5870
|
+
private isRunning;
|
|
5871
|
+
private activeJobs;
|
|
5872
|
+
private totalJobsProcessed;
|
|
5873
|
+
private unsubscribe?;
|
|
5874
|
+
private deferredJobs;
|
|
5875
|
+
private resultHandler;
|
|
5876
|
+
private jobTimeoutMs;
|
|
5877
|
+
constructor(executorFactory: JobExecutorFactory, eventBus: IEventBus, queue: IQueue, jobTracker: IJobTracker, logger: ILogger, resolver: IDocumentModelResolver, jobTimeoutMs?: number);
|
|
5878
|
+
start(numExecutors: number): Promise<void>;
|
|
5879
|
+
stop(graceful?: boolean): Promise<void>;
|
|
5880
|
+
getExecutors(): IJobExecutor[];
|
|
5881
|
+
getStatus(): ExecutorManagerStatus;
|
|
5882
|
+
private processNextJob;
|
|
5883
|
+
private checkForMoreJobs;
|
|
5884
|
+
private processExistingJobs;
|
|
5885
|
+
private flushDeferredJobs;
|
|
5065
5886
|
}
|
|
5066
5887
|
//#endregion
|
|
5067
5888
|
//#region src/executor/simple-job-executor.d.ts
|
|
@@ -5079,6 +5900,8 @@ declare class SimpleJobExecutor implements IJobExecutor {
|
|
|
5079
5900
|
private collectionMembershipCache;
|
|
5080
5901
|
private driveContainerTypes;
|
|
5081
5902
|
private config;
|
|
5903
|
+
private featureFlags;
|
|
5904
|
+
private decisionModel;
|
|
5082
5905
|
private signatureVerifierModule;
|
|
5083
5906
|
private documentActionHandler;
|
|
5084
5907
|
private executionScope;
|
|
@@ -5091,6 +5914,69 @@ declare class SimpleJobExecutor implements IJobExecutor {
|
|
|
5091
5914
|
private getCollectionMembershipsForOperations;
|
|
5092
5915
|
private processActions;
|
|
5093
5916
|
private executeRegularAction;
|
|
5917
|
+
/**
|
|
5918
|
+
* Orders a write by timestamp and decides it where it lands. The caller
|
|
5919
|
+
* supplies the timestamp, so a write can belong before operations already
|
|
5920
|
+
* stored; those are re-appended alongside it, the way a load reshuffles.
|
|
5921
|
+
*
|
|
5922
|
+
* Deciding a backdated write at the stream heads instead of at its position
|
|
5923
|
+
* would overwrite the verdict every other replica computes for it.
|
|
5924
|
+
*/
|
|
5925
|
+
private positionByTimestamp;
|
|
5926
|
+
/**
|
|
5927
|
+
* Decides each operation where it lands and carries the verdict on it. A
|
|
5928
|
+
* refused submitted action is reported to the caller and nothing is stored; a
|
|
5929
|
+
* refused operation the reshuffle merely moved keeps its verdict, because it
|
|
5930
|
+
* already holds a position.
|
|
5931
|
+
*
|
|
5932
|
+
* The operations carry the indexes and skips they will be stored at, because
|
|
5933
|
+
* the walk resolves skips before it orders them.
|
|
5934
|
+
*/
|
|
5935
|
+
private evaluatePositioned;
|
|
5936
|
+
/**
|
|
5937
|
+
* The scopes a re-evaluation pass visits, in a fixed order.
|
|
5938
|
+
*
|
|
5939
|
+
* The revisions map comes from a query with no ORDER BY, and the order is
|
|
5940
|
+
* load-bearing: each scope's pass re-reads the auth stream, and the walk skips
|
|
5941
|
+
* an operation by its stored denial, so a denial this pass just wrote is
|
|
5942
|
+
* visible to a later-visited scope and invisible to an earlier one. The model's
|
|
5943
|
+
* own projection order leads, then the rest sorted, so the pass is reproducible
|
|
5944
|
+
* across replicas and across runs.
|
|
5945
|
+
*/
|
|
5946
|
+
private evaluationOrder;
|
|
5947
|
+
/**
|
|
5948
|
+
* The first timestamp in the batch that does not strictly exceed everything
|
|
5949
|
+
* ahead of it, or undefined when the whole batch is monotonic.
|
|
5950
|
+
*
|
|
5951
|
+
* The bound is carried forward rather than compared against one stored maximum,
|
|
5952
|
+
* because a single execute can carry several auth actions stamped in the same
|
|
5953
|
+
* millisecond. Letting a tie through would store a stream the position walk
|
|
5954
|
+
* then refuses to read, with no repair path.
|
|
5955
|
+
*/
|
|
5956
|
+
private firstNonMonotonicTimestamp;
|
|
5957
|
+
/** The operations a batch of submitted actions appends at the scope's tail. */
|
|
5958
|
+
private appendedOperations;
|
|
5959
|
+
/**
|
|
5960
|
+
* Re-evaluates the document when a write meets both criteria: it was written
|
|
5961
|
+
* to a stream the model reads, and it is timestamped before an operation
|
|
5962
|
+
* already stored. The caller supplies the timestamp and the reactor does not replace
|
|
5963
|
+
* it, so a mutation job can write such an operation just as a load job can,
|
|
5964
|
+
* which is why both executeJob and executeLoadJob call this.
|
|
5965
|
+
*/
|
|
5966
|
+
private reevaluateIfCriteriaMet;
|
|
5967
|
+
/**
|
|
5968
|
+
* Re-evaluates every scope the model evaluates. Where an operation's
|
|
5969
|
+
* evaluation differs from what is stored, the tail from that operation is
|
|
5970
|
+
* re-appended, carrying a skip that spans the indices it supersedes.
|
|
5971
|
+
*/
|
|
5972
|
+
private reevaluateDocument;
|
|
5973
|
+
/**
|
|
5974
|
+
* Re-judges a document's stored operations because a read-set stream in
|
|
5975
|
+
* another document (a group) gained an operation. The trigger timestamp
|
|
5976
|
+
* bounds the work: an operation later than everything this document holds
|
|
5977
|
+
* cannot change any evaluation, so the pass is skipped.
|
|
5978
|
+
*/
|
|
5979
|
+
private executeReevaluationJob;
|
|
5094
5980
|
private executeLoadJob;
|
|
5095
5981
|
private accumulateResultOrReturnError;
|
|
5096
5982
|
}
|
|
@@ -5159,6 +6045,49 @@ declare class DocumentModelRegistry implements IDocumentModelRegistry {
|
|
|
5159
6045
|
getUpgradeReducer(documentType: string, fromVersion: number, toVersion: number): UpgradeReducer<any, any>;
|
|
5160
6046
|
}
|
|
5161
6047
|
//#endregion
|
|
6048
|
+
//#region src/decision/build-decision-model.d.ts
|
|
6049
|
+
/**
|
|
6050
|
+
* Reads each projection's stream through the supplied reader, recording the
|
|
6051
|
+
* revision observed. Static projections resolve first; derived projections
|
|
6052
|
+
* see only those and contribute a map from document id to state. Each
|
|
6053
|
+
* distinct stream is read once and yields one append condition entry.
|
|
6054
|
+
*/
|
|
6055
|
+
declare function buildDecisionModel<M>(reader: IStreamStateReader, definition: (target: DecisionTarget) => DecisionModel<M>, target: DecisionTarget, signal?: AbortSignal): Promise<BuiltDecisionModel<M>>;
|
|
6056
|
+
//#endregion
|
|
6057
|
+
//#region src/decision/auth-decision-model.d.ts
|
|
6058
|
+
type AuthDecisionModel = {
|
|
6059
|
+
document: PHDocumentState;
|
|
6060
|
+
auth: PHAuthState;
|
|
6061
|
+
};
|
|
6062
|
+
/** This decision model uses both the document and the auth streams. */
|
|
6063
|
+
declare function authDecisionModel(target: DecisionTarget): DecisionModel<AuthDecisionModel>;
|
|
6064
|
+
//#endregion
|
|
6065
|
+
//#region src/decision/stream-order.d.ts
|
|
6066
|
+
/** Where a stream's stored order contradicts its timestamps. */
|
|
6067
|
+
type OutOfOrderPair = {
|
|
6068
|
+
previous: Operation;
|
|
6069
|
+
current: Operation;
|
|
6070
|
+
/**
|
|
6071
|
+
* `descending` cannot be walked at all. `tied` walks fine — the intra-stream
|
|
6072
|
+
* rule breaks the tie by index — but violates the monotonic auth rule, so a
|
|
6073
|
+
* stream holding one can never be replicated to a peer that lacks it.
|
|
6074
|
+
*/
|
|
6075
|
+
kind: "descending" | "tied";
|
|
6076
|
+
};
|
|
6077
|
+
/**
|
|
6078
|
+
* The first pair of effective operations whose stored order contradicts their
|
|
6079
|
+
* timestamps, or undefined when the stream is in position order.
|
|
6080
|
+
*
|
|
6081
|
+
* Such a stream cannot be walked, and the auth stream is never reshuffled once
|
|
6082
|
+
* the monotonic rule is on, so run this before enabling enforcement on a fleet.
|
|
6083
|
+
*
|
|
6084
|
+
* `requireStrict` additionally rejects a tie, which is what the auth stream's
|
|
6085
|
+
* monotonic rule requires and what the walk alone does not care about.
|
|
6086
|
+
*/
|
|
6087
|
+
declare function firstOutOfOrderPair(operations: Operation[], options?: {
|
|
6088
|
+
requireStrict?: boolean;
|
|
6089
|
+
}): OutOfOrderPair | undefined;
|
|
6090
|
+
//#endregion
|
|
5162
6091
|
//#region src/read-models/base-read-model.d.ts
|
|
5163
6092
|
type BaseReadModelConfig = {
|
|
5164
6093
|
readModelId: string;
|
|
@@ -5243,7 +6172,7 @@ declare class KyselyDocumentIndexer extends BaseReadModel implements IDocumentIn
|
|
|
5243
6172
|
* serialized so the executor can return to dispatch without holding ordering
|
|
5244
6173
|
* implicitly.
|
|
5245
6174
|
*/
|
|
5246
|
-
declare class ReadModelCoordinator implements
|
|
6175
|
+
declare class ReadModelCoordinator implements ILiveReadModelCoordinator {
|
|
5247
6176
|
private eventBus;
|
|
5248
6177
|
readonly preReady: IReadModel[];
|
|
5249
6178
|
readonly postReady: IReadModel[];
|
|
@@ -5262,6 +6191,7 @@ declare class ReadModelCoordinator implements IReadModelCoordinator {
|
|
|
5262
6191
|
*/
|
|
5263
6192
|
drain(): Promise<void>;
|
|
5264
6193
|
getChainDepth(): number;
|
|
6194
|
+
addReadModel(readModel: IReadModel, stage: ReadModelRegistrationStage): void;
|
|
5265
6195
|
private handleWriteReady;
|
|
5266
6196
|
private emitEmptyReadReady;
|
|
5267
6197
|
private runChain;
|
|
@@ -5275,8 +6205,31 @@ declare class ReadModelCoordinator implements IReadModelCoordinator {
|
|
|
5275
6205
|
type Database$2 = Database$1 & DocumentViewDatabase;
|
|
5276
6206
|
declare class KyselyDocumentView extends BaseReadModel implements IDocumentView {
|
|
5277
6207
|
private operationStore;
|
|
6208
|
+
/**
|
|
6209
|
+
* Whether a single-document read serves a deleted document's state as of the
|
|
6210
|
+
* deletion rather than hiding it. Only meaningful with `documentDecisions`,
|
|
6211
|
+
* which is what makes deletion positional. Listings omit it either way.
|
|
6212
|
+
*/
|
|
6213
|
+
private readonly servesDeletionBoundary;
|
|
5278
6214
|
private _db;
|
|
5279
|
-
constructor(db: Kysely<Database$2>, operationStore: IOperationStore, operationIndex: IOperationIndex, writeCache: IWriteCache, consistencyTracker: IConsistencyTracker
|
|
6215
|
+
constructor(db: Kysely<Database$2>, operationStore: IOperationStore, operationIndex: IOperationIndex, writeCache: IWriteCache, consistencyTracker: IConsistencyTracker,
|
|
6216
|
+
/**
|
|
6217
|
+
* Whether a single-document read serves a deleted document's state as of the
|
|
6218
|
+
* deletion rather than hiding it. Only meaningful with `documentDecisions`,
|
|
6219
|
+
* which is what makes deletion positional. Listings omit it either way.
|
|
6220
|
+
*/
|
|
6221
|
+
|
|
6222
|
+
servesDeletionBoundary: boolean);
|
|
6223
|
+
/**
|
|
6224
|
+
* Indexes committed operations into DocumentSnapshot rows. CREATE_DOCUMENT
|
|
6225
|
+
* only seeds header/document/auth. UPGRADE_DOCUMENT reindexes every scope
|
|
6226
|
+
* present in resultingState when the operation vouches for them — a seed
|
|
6227
|
+
* carrying initialState or a migration stamped with the __migrated marker
|
|
6228
|
+
* — since the upgrade reducer may have reshaped any of them; upgrades
|
|
6229
|
+
* without either fall back to header/document/auth, because their sibling
|
|
6230
|
+
* echoes may be stale. All other action types index only header and their
|
|
6231
|
+
* own scope.
|
|
6232
|
+
*/
|
|
5280
6233
|
protected commitOperations(items: OperationWithContext$1[]): Promise<void>;
|
|
5281
6234
|
exists(documentIds: string[], consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<boolean[]>;
|
|
5282
6235
|
get<TDocument extends PHDocument>(documentId: string, view?: ViewFilter$1, consistencyToken?: ConsistencyToken, signal?: AbortSignal): Promise<TDocument>;
|
|
@@ -5408,6 +6361,8 @@ declare class GqlRequestChannel implements IChannel {
|
|
|
5408
6361
|
private isPushing;
|
|
5409
6362
|
private pendingDrain;
|
|
5410
6363
|
private receivingPages;
|
|
6364
|
+
/** Cleared for good the first time the remote rejects {@link DECISION_FIELDS}. */
|
|
6365
|
+
private peerServesDecisionFields;
|
|
5411
6366
|
private isRecovering;
|
|
5412
6367
|
private connectionState;
|
|
5413
6368
|
/** Latest unrecoverable error was an auth rejection; cleared on connect. */
|
|
@@ -5454,6 +6409,18 @@ declare class GqlRequestChannel implements IChannel {
|
|
|
5454
6409
|
* Queries the remote GraphQL endpoint for sync envelopes.
|
|
5455
6410
|
*/
|
|
5456
6411
|
private pollSyncEnvelopes;
|
|
6412
|
+
/**
|
|
6413
|
+
* True when the remote rejected the query for naming a field it does not
|
|
6414
|
+
* have. Selecting an unknown field fails validation for the whole query, so
|
|
6415
|
+
* an unhandled one takes the channel's polling down until the process
|
|
6416
|
+
* restarts rather than degrading.
|
|
6417
|
+
*/
|
|
6418
|
+
private rejectsDecisionFields;
|
|
6419
|
+
/**
|
|
6420
|
+
* The poll query. `withDecisionFields` selects the two fields added with the
|
|
6421
|
+
* auth projection; a remote on the previous schema is polled without them.
|
|
6422
|
+
*/
|
|
6423
|
+
private pollQuery;
|
|
5457
6424
|
/**
|
|
5458
6425
|
* Registers or updates this channel on the remote server via GraphQL mutation.
|
|
5459
6426
|
* Returns the remote's ack ordinal so the client can trim its outbox.
|
|
@@ -5616,6 +6583,18 @@ declare function batchOperationsByDocument(operations: OperationWithContext$1[])
|
|
|
5616
6583
|
* jobId; all other jobIds are remapped so external dependencies still resolve.
|
|
5617
6584
|
*/
|
|
5618
6585
|
declare function consolidateSyncOperations(syncOps: SyncOperation[]): SyncOperation[];
|
|
6586
|
+
/**
|
|
6587
|
+
* Classifies a failure by error name rather than `instanceof`, because a failure
|
|
6588
|
+
* that crossed the pooled-worker boundary arrives as plain data.
|
|
6589
|
+
*/
|
|
6590
|
+
declare function classifyJobFailure(errorName: string): SyncOperationErrorType;
|
|
6591
|
+
/** The explicit type when something else carried it, else derived by name. */
|
|
6592
|
+
declare function syncOperationErrorType(error: ChannelError | undefined): SyncOperationErrorType;
|
|
6593
|
+
/**
|
|
6594
|
+
* A held auth operation must not quarantine: reconciling the two policies needs
|
|
6595
|
+
* the traffic a quarantine would stop.
|
|
6596
|
+
*/
|
|
6597
|
+
declare function quarantinesDocument(errorType: SyncOperationErrorType): boolean;
|
|
5619
6598
|
//#endregion
|
|
5620
6599
|
//#region src/admin/types.d.ts
|
|
5621
6600
|
type KeyframeValidationIssue = {
|
|
@@ -5631,11 +6610,20 @@ type SnapshotValidationIssue = {
|
|
|
5631
6610
|
snapshotHash: string;
|
|
5632
6611
|
replayedHash: string;
|
|
5633
6612
|
};
|
|
6613
|
+
/** Effective operations whose stored order contradicts their timestamps. */
|
|
6614
|
+
type StreamOrderIssue = {
|
|
6615
|
+
scope: string;
|
|
6616
|
+
branch: string;
|
|
6617
|
+
previous: Operation;
|
|
6618
|
+
current: Operation;
|
|
6619
|
+
kind: OutOfOrderPair["kind"];
|
|
6620
|
+
};
|
|
5634
6621
|
type ValidationResult = {
|
|
5635
6622
|
documentId: string;
|
|
5636
6623
|
isConsistent: boolean;
|
|
5637
6624
|
keyframeIssues: KeyframeValidationIssue[];
|
|
5638
6625
|
snapshotIssues: SnapshotValidationIssue[];
|
|
6626
|
+
streamOrderIssues: StreamOrderIssue[];
|
|
5639
6627
|
};
|
|
5640
6628
|
type RebuildResult = {
|
|
5641
6629
|
documentId: string;
|
|
@@ -5659,6 +6647,7 @@ declare class DocumentIntegrityService implements IDocumentIntegrityService {
|
|
|
5659
6647
|
validateDocument(documentId: string, branch?: string, signal?: AbortSignal): Promise<ValidationResult>;
|
|
5660
6648
|
rebuildKeyframes(documentId: string, branch?: string, signal?: AbortSignal): Promise<RebuildResult>;
|
|
5661
6649
|
rebuildSnapshots(documentId: string, branch?: string, signal?: AbortSignal): Promise<RebuildResult>;
|
|
6650
|
+
private findStreamOrderIssues;
|
|
5662
6651
|
private discoverScopes;
|
|
5663
6652
|
}
|
|
5664
6653
|
//#endregion
|
|
@@ -5707,5 +6696,5 @@ declare class ProcessorManager extends BaseReadModel implements IProcessorManage
|
|
|
5707
6696
|
private deleteProcessorCursors;
|
|
5708
6697
|
}
|
|
5709
6698
|
//#endregion
|
|
5710
|
-
export { type AbortMessage, type AtomicTxn, type AttachmentHash, type AttachmentRef, BaseReadModel, type BatchExecutionRequest, type BatchExecutionResult, type BatchLoadRequest, type BatchLoadResult, type BuiltInReadModelKind, type CachedSnapshot, type ChannelConfig, ChannelError, ChannelErrorSource, type ChannelHealth, type ChannelMeta, ChannelScheme, type ConnectionState, type ConnectionStateChangeCallback, type ConnectionStateChangedEvent, type ConnectionStateSnapshot, type ConsistencyCoordinate, type ConsistencyKey, type ConsistencyToken, ConsistencyTracker, DEFAULT_DRIVE_CONTAINER_TYPES, DRIVE_AUTH_ERROR_MESSAGES, type Database, type DbConfig, type DeadLetterAddedEvent, DefaultSubscriptionErrorHandler, type DocumentChangeEvent, DocumentChangeType, type DocumentGraphEdge, type DocumentIndexerDatabase, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, type DocumentModelSource, type DocumentModelSpec, type DocumentRelationship, type DocumentRevisions, type DocumentStreamKey, type DocumentViewDatabase, DriveClient, DriveCollectionId, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, EventBus, EventBusAggregateError, type ExecuteMessage, type ExecutionJobPlan, type ExecutorStartedEvent, type ExecutorStoppedEvent, type FactorySpec, type FileModelSource, type GqlChannelConfig, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, type HeartbeatMessage, type IChannel, type IChannelFactory, type IConsistencyTracker, type IDocumentGraph, type IDocumentIndexer, type IDocumentIntegrityService, type IDocumentModelLoader, type IDocumentModelRegistry, type IDocumentModelResolver, type IDocumentView, type IDriveClient, type IEventBus, type IJobAwaiter, type IJobExecutor, type IJobExecutorManager, type IJobTracker, type IKeyframeStore, type IMailbox, type IOperationIndex, type IOperationStore, type IPollTimer, type IProcessor, type IProcessorHostModule, type IProcessorManager, type IProjectionTransport, type IQueue, type IReactor, type IReactorClient, type IReactorSubscriptionManager, type IReadModel, type IReadModelCoordinator, type IRelationalDb, type ISubscriptionErrorHandler, type ISyncCursorStorage, type ISyncManager, type ISyncRemoteStorage, type ISyncStatusTracker, type IWriteCache, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, type InProcessReactorClientModule, type InProcessReactorModule, type InProcessSyncModule, type InitMessage, type InsertableDocumentSnapshot, IntervalPollTimer, InvalidModuleError, type Job, type JobAvailableEvent, JobAwaiter, type JobCompletedEvent, type JobExecutorConfig, JobExecutorEventTypes, type JobExecutorFactory, type JobFailedEvent, type JobInfo, type JobPendingEvent, type JobReadReadyEvent, type JobResult, type JobRunningEvent, type JobStartedEvent, JobStatus, type JobWriteReadyEvent, type JobWriteReadyPayload, type JwtHandler, type KeyframeSnapshot, type KeyframeValidationIssue, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, type LoadJobPlan, type LoadModelMessage, type LogMessage, Mailbox, type MetricsMessage, type ModelLoadFailedMessage, type ModelLoadedEvent, type ModelLoadedMessage, type ModelManifestEntry, ModuleNotFoundError, type ModuleRef, NullDocumentModelResolver, type OperationBatch, type OperationContext, type OperationFilter, type OperationIndexEntry, type OperationTable, type OperationWithContext, OptimisticLockError, type PackageModelSource, type PagedResults, type PagingOptions, type ParentMessage, type ParsedDriveUrl, type ParsedPaging, PollBehavior, PollingChannelError, type PoolInstrumentation, type PoolStats, type ProcessorApp, type ProcessorFactory, type ProcessorFactoryBuilder, type ProcessorFilter, ProcessorManager, type ProcessorRecord, type ProcessorStatus, type ProjectionShardBuilderConfig, type ProjectionShardManagerConfig, type ProjectionWorkerFactory, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, type ReactorClientModule, ReactorEventTypes, type ReactorFeatures, type JobFailedEvent$1 as ReactorJobFailedEvent, type ReactorModule, ReactorSubscriptionManager, type ReadModelBatchCompletedEvent, ReadModelCoordinator, type ReadModelFactory, type ReadModelFactoryDeps, type ReadModelIndexedEvent, type ReadModelIndexingStage, type ReadModelStage, type ReadyMessage, type RebuildResult, RelationalDbProcessor, RelationshipChangeType, type Remote, type RemoteCursor, type RemoteFilter, type RemoteMeta, type RemoteOptions, type RemoteRecord, type RemoteStatus, type ResultMessage, RevisionMismatchError, type SanitizedArg, type SearchFilter, type ShutdownMessage, type ShutdownStatus, type SignatureVerificationHandler, type SignatureVerifierSpec, type SignerConfig, SimpleJobExecutorManager, type SnapshotValidationIssue, type Database$1 as StorageDatabase, type SubscriptionErrorContext, SyncBuilder, type SyncEnvelope, type SyncEnvelopeType, SyncEventTypes, type SyncFailedEvent, type SyncModule, SyncOperation, SyncOperationAggregateError, type SyncOperationErrorType, SyncOperationStatus, type SyncPendingEvent, SyncStatus, type SyncStatusChangeCallback, SyncStatusTracker, type SyncSucceededEvent, type TrackedProcessor, type Unsubscribe, type ValidationResult, type ViewFilter, type ErrorInfo as WorkerErrorInfo, type WorkerMessage, type WorkerPoolConfig, type WorkerPoolOptions, type WriteCacheConfig, addRelationshipAction, batchOperationsByDocument, consolidateSyncOperations, createDocumentAction, createForwardingLogger, createMutableShutdownStatus, createRelationalDb, deleteDocumentAction, documentActions, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, getMigrationStatus, instrumentPgPool, isDriveAuthError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, removeRelationshipAction, runMigrations, sanitizeArg, trimMailboxFromAckOrdinal, updateRelationshipAction, upgradeDocumentAction, workerEntryPath };
|
|
6699
|
+
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 BatchExecutionRequest, type BatchExecutionResult, type BatchLoadRequest, type BatchLoadResult, type BuiltDecisionModel, type BuiltInReadModelKind, type CachedSnapshot, type ChannelConfig, ChannelError, ChannelErrorSource, type ChannelHealth, type ChannelMeta, ChannelScheme, type ConnectionState, type ConnectionStateChangeCallback, type ConnectionStateChangedEvent, type ConnectionStateSnapshot, type ConsistencyCoordinate, type ConsistencyKey, type ConsistencyToken, ConsistencyTracker, DEFAULT_DRIVE_CONTAINER_TYPES, DRIVE_AUTH_ERROR_MESSAGES, type Database, type DbConfig, type DeadLetterAddedEvent, type DecisionContext, type DecisionModel, type DecisionTarget, DefaultSubscriptionErrorHandler, type DocumentChangeEvent, DocumentChangeType, type DocumentDecisionModel, type DocumentGraphEdge, type DocumentIndexerDatabase, DocumentIntegrityService, DocumentModelRegistry, DocumentModelResolver, type DocumentModelSource, type DocumentModelSpec, type DocumentRelationship, type DocumentRevisions, type DocumentStreamKey, type DocumentViewDatabase, DriveClient, DriveCollectionId, DuplicateManifestError, DuplicateModuleError, DuplicateOperationError, type Evaluation, EventBus, EventBusAggregateError, type ExecuteMessage, type ExecutionJobPlan, type ExecutorStartedEvent, type ExecutorStoppedEvent, type FactorySpec, type FileModelSource, type GqlChannelConfig, GqlRequestChannel, GqlRequestChannelFactory, GqlResponseChannel, GqlResponseChannelFactory, type HeartbeatMessage, type IChannel, type IChannelFactory, type IConsistencyTracker, type IDocumentGraph, type IDocumentIndexer, type IDocumentIntegrityService, type IDocumentModelLoader, type IDocumentModelRegistry, type IDocumentModelResolver, type IDocumentView, type IDriveClient, type IEventBus, type IJobAwaiter, type IJobExecutor, type IJobExecutorManager, type IJobTracker, type IKeyframeStore, type ILiveReadModelCoordinator, type IMailbox, type IOperationIndex, type IOperationStore, type IPollTimer, type IProcessor, type IProcessorHostModule, type IProcessorManager, type IProjectionTransport, type IQueue, type IReactor, type IReactorClient, type IReactorSubscriptionManager, type IReadGate, type IReadModel, type IReadModelCoordinator, type IRelationalDb, type IStreamStateReader, type ISubscriptionErrorHandler, type ISyncCursorStorage, type ISyncManager, type ISyncRemoteStorage, type ISyncStatusTracker, type IWriteCache, SimpleJobExecutor as InMemoryJobExecutor, SimpleJobExecutor, InMemoryJobTracker, InMemoryQueue, type InProcessReactorClientModule, type InProcessReactorModule, type InProcessSyncModule, type InitMessage, type InsertableDocumentSnapshot, IntervalPollTimer, InvalidModuleError, type Job, type JobAvailableEvent, JobAwaiter, type JobCompletedEvent, type JobExecutorConfig, JobExecutorEventTypes, type JobExecutorFactory, type JobFailedEvent, type JobInfo, type JobPendingEvent, type JobReadReadyEvent, type JobResult, type JobRunningEvent, type JobStartedEvent, JobStatus, type JobWriteReadyEvent, type JobWriteReadyPayload, type JwtHandler, type KeyframeSnapshot, type KeyframeValidationIssue, KyselyDocumentIndexer, KyselyDocumentView, KyselyKeyframeStore, KyselyOperationStore, KyselySyncCursorStorage, KyselySyncRemoteStorage, KyselyWriteCache, type LoadJobPlan, type LoadModelMessage, type LogMessage, Mailbox, type MetricsMessage, type ModelLoadFailedMessage, type ModelLoadedEvent, type ModelLoadedMessage, type ModelManifestEntry, ModelReadGate, ModuleNotFoundError, type ModuleRef, NullDocumentModelResolver, type OperationBatch, type OperationContext, type OperationFilter, type OperationIndexEntry, type OperationTable, type OperationWithContext, OptimisticLockError, type OutOfOrderPair, type PackageModelSource, type PagedResults, type PagingOptions, type ParentMessage, type ParsedDriveUrl, type ParsedPaging, PollBehavior, PollingChannelError, type PoolInstrumentation, type PoolStats, type ProcessorApp, type ProcessorFactory, type ProcessorFactoryBuilder, type ProcessorFilter, ProcessorManager, type ProcessorRecord, type ProcessorStatus, type Projection, type ProjectionShardBuilderConfig, type ProjectionShardManagerConfig, type ProjectionWorkerFactory, PropagationMode, QueueEventTypes, REACTOR_SCHEMA, Reactor, ReactorBuilder, ReactorClient, ReactorClientBuilder, type ReactorClientModule, ReactorEventTypes, type ReactorFeatureFlags, type ReactorFeatures, type JobFailedEvent$1 as ReactorJobFailedEvent, type ReactorModule, ReactorSubscriptionManager, type ReadModelBatchCompletedEvent, ReadModelCoordinator, type ReadModelFactory, type ReadModelFactoryDeps, type ReadModelIndexedEvent, type ReadModelIndexingStage, type ReadModelRegistrationStage, type ReadModelStage, type ReadyMessage, type RebuildResult, type RegisteredDecisionModel, RelationalDbProcessor, RelationshipChangeType, type Remote, type RemoteCursor, type RemoteFilter, type RemoteMeta, type RemoteOptions, type RemoteRecord, type RemoteStatus, type ResultMessage, RetryAccounting, RevisionMismatchError, type SanitizedArg, type SearchFilter, SeededStateReader, type ShutdownMessage, type ShutdownStatus, type SignatureVerificationHandler, type SignatureVerifierSpec, type SignerConfig, SimpleJobExecutorManager, type SnapshotValidationIssue, type Database$1 as StorageDatabase, type StreamOrderIssue, type StreamQuery, type SubscriptionErrorContext, SyncBuilder, type SyncEnvelope, type SyncEnvelopeType, SyncEventTypes, type SyncFailedEvent, type SyncModule, SyncOperation, SyncOperationAggregateError, type SyncOperationErrorType, SyncOperationStatus, type SyncPendingEvent, SyncStatus, type SyncStatusChangeCallback, SyncStatusTracker, type SyncSucceededEvent, type TrackedProcessor, type Unsubscribe, type ValidationResult, type ViewFilter, type ErrorInfo as WorkerErrorInfo, type WorkerMessage, type WorkerPoolConfig, type WorkerPoolOptions, type WriteCacheConfig, addRelationshipAction, authDecisionModel, batchOperationsByDocument, buildDecisionModel, classifyJobFailure, consolidateSyncOperations, createDocumentAction, createForwardingLogger, createMutableShutdownStatus, createRelationalDb, decideAtHead, deleteDocumentAction, documentActions, documentDecisionModel, driveIdFromUrl, envelopesToSyncOperations, errorToInfo, firstOutOfOrderPair, getMigrationStatus, instrumentPgPool, isDriveAuthError, makeConsistencyKey, parseDriveUrl, parsePagingOptions, quarantinesDocument, readDecisionModel, removeRelationshipAction, runMigrations, sanitizeArg, selectDecisionModel, supportsLiveReadModelRegistration, syncOperationErrorType, trimMailboxFromAckOrdinal, updateRelationshipAction, upgradeDocumentAction, workerEntryPath };
|
|
5711
6700
|
//# sourceMappingURL=index.d.ts.map
|