@git-stunts/git-warp 10.1.1
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/LICENSE +201 -0
- package/NOTICE +16 -0
- package/README.md +480 -0
- package/SECURITY.md +30 -0
- package/bin/git-warp +24 -0
- package/bin/warp-graph.js +1574 -0
- package/index.d.ts +2366 -0
- package/index.js +180 -0
- package/package.json +129 -0
- package/scripts/install-git-warp.sh +258 -0
- package/scripts/uninstall-git-warp.sh +139 -0
- package/src/domain/WarpGraph.js +3157 -0
- package/src/domain/crdt/Dot.js +160 -0
- package/src/domain/crdt/LWW.js +154 -0
- package/src/domain/crdt/ORSet.js +371 -0
- package/src/domain/crdt/VersionVector.js +222 -0
- package/src/domain/entities/GraphNode.js +60 -0
- package/src/domain/errors/EmptyMessageError.js +47 -0
- package/src/domain/errors/ForkError.js +30 -0
- package/src/domain/errors/IndexError.js +23 -0
- package/src/domain/errors/OperationAbortedError.js +22 -0
- package/src/domain/errors/QueryError.js +39 -0
- package/src/domain/errors/SchemaUnsupportedError.js +17 -0
- package/src/domain/errors/ShardCorruptionError.js +56 -0
- package/src/domain/errors/ShardLoadError.js +57 -0
- package/src/domain/errors/ShardValidationError.js +61 -0
- package/src/domain/errors/StorageError.js +57 -0
- package/src/domain/errors/SyncError.js +30 -0
- package/src/domain/errors/TraversalError.js +23 -0
- package/src/domain/errors/WarpError.js +31 -0
- package/src/domain/errors/WormholeError.js +28 -0
- package/src/domain/errors/WriterError.js +39 -0
- package/src/domain/errors/index.js +21 -0
- package/src/domain/services/AnchorMessageCodec.js +99 -0
- package/src/domain/services/BitmapIndexBuilder.js +225 -0
- package/src/domain/services/BitmapIndexReader.js +435 -0
- package/src/domain/services/BoundaryTransitionRecord.js +463 -0
- package/src/domain/services/CheckpointMessageCodec.js +147 -0
- package/src/domain/services/CheckpointSerializerV5.js +281 -0
- package/src/domain/services/CheckpointService.js +384 -0
- package/src/domain/services/CommitDagTraversalService.js +156 -0
- package/src/domain/services/DagPathFinding.js +712 -0
- package/src/domain/services/DagTopology.js +239 -0
- package/src/domain/services/DagTraversal.js +245 -0
- package/src/domain/services/Frontier.js +108 -0
- package/src/domain/services/GCMetrics.js +101 -0
- package/src/domain/services/GCPolicy.js +122 -0
- package/src/domain/services/GitLogParser.js +205 -0
- package/src/domain/services/HealthCheckService.js +246 -0
- package/src/domain/services/HookInstaller.js +326 -0
- package/src/domain/services/HttpSyncServer.js +262 -0
- package/src/domain/services/IndexRebuildService.js +426 -0
- package/src/domain/services/IndexStalenessChecker.js +103 -0
- package/src/domain/services/JoinReducer.js +582 -0
- package/src/domain/services/KeyCodec.js +113 -0
- package/src/domain/services/LegacyAnchorDetector.js +67 -0
- package/src/domain/services/LogicalTraversal.js +351 -0
- package/src/domain/services/MessageCodecInternal.js +132 -0
- package/src/domain/services/MessageSchemaDetector.js +145 -0
- package/src/domain/services/MigrationService.js +55 -0
- package/src/domain/services/ObserverView.js +265 -0
- package/src/domain/services/PatchBuilderV2.js +669 -0
- package/src/domain/services/PatchMessageCodec.js +140 -0
- package/src/domain/services/ProvenanceIndex.js +337 -0
- package/src/domain/services/ProvenancePayload.js +242 -0
- package/src/domain/services/QueryBuilder.js +835 -0
- package/src/domain/services/StateDiff.js +300 -0
- package/src/domain/services/StateSerializerV5.js +156 -0
- package/src/domain/services/StreamingBitmapIndexBuilder.js +709 -0
- package/src/domain/services/SyncProtocol.js +593 -0
- package/src/domain/services/TemporalQuery.js +201 -0
- package/src/domain/services/TranslationCost.js +221 -0
- package/src/domain/services/TraversalService.js +8 -0
- package/src/domain/services/WarpMessageCodec.js +29 -0
- package/src/domain/services/WarpStateIndexBuilder.js +127 -0
- package/src/domain/services/WormholeService.js +353 -0
- package/src/domain/types/TickReceipt.js +285 -0
- package/src/domain/types/WarpTypes.js +209 -0
- package/src/domain/types/WarpTypesV2.js +200 -0
- package/src/domain/utils/CachedValue.js +140 -0
- package/src/domain/utils/EventId.js +89 -0
- package/src/domain/utils/LRUCache.js +112 -0
- package/src/domain/utils/MinHeap.js +114 -0
- package/src/domain/utils/RefLayout.js +280 -0
- package/src/domain/utils/WriterId.js +205 -0
- package/src/domain/utils/cancellation.js +33 -0
- package/src/domain/utils/canonicalStringify.js +42 -0
- package/src/domain/utils/defaultClock.js +20 -0
- package/src/domain/utils/defaultCodec.js +51 -0
- package/src/domain/utils/nullLogger.js +21 -0
- package/src/domain/utils/roaring.js +181 -0
- package/src/domain/utils/shardVersion.js +9 -0
- package/src/domain/warp/PatchSession.js +217 -0
- package/src/domain/warp/Writer.js +181 -0
- package/src/hooks/post-merge.sh +60 -0
- package/src/infrastructure/adapters/BunHttpAdapter.js +225 -0
- package/src/infrastructure/adapters/ClockAdapter.js +57 -0
- package/src/infrastructure/adapters/ConsoleLogger.js +150 -0
- package/src/infrastructure/adapters/DenoHttpAdapter.js +230 -0
- package/src/infrastructure/adapters/GitGraphAdapter.js +787 -0
- package/src/infrastructure/adapters/GlobalClockAdapter.js +5 -0
- package/src/infrastructure/adapters/NoOpLogger.js +62 -0
- package/src/infrastructure/adapters/NodeCryptoAdapter.js +32 -0
- package/src/infrastructure/adapters/NodeHttpAdapter.js +98 -0
- package/src/infrastructure/adapters/PerformanceClockAdapter.js +5 -0
- package/src/infrastructure/adapters/WebCryptoAdapter.js +121 -0
- package/src/infrastructure/codecs/CborCodec.js +384 -0
- package/src/ports/BlobPort.js +30 -0
- package/src/ports/ClockPort.js +25 -0
- package/src/ports/CodecPort.js +25 -0
- package/src/ports/CommitPort.js +114 -0
- package/src/ports/ConfigPort.js +31 -0
- package/src/ports/CryptoPort.js +38 -0
- package/src/ports/GraphPersistencePort.js +57 -0
- package/src/ports/HttpServerPort.js +25 -0
- package/src/ports/IndexStoragePort.js +39 -0
- package/src/ports/LoggerPort.js +68 -0
- package/src/ports/RefPort.js +51 -0
- package/src/ports/TreePort.js +51 -0
- package/src/visualization/index.js +26 -0
- package/src/visualization/layouts/converters.js +75 -0
- package/src/visualization/layouts/elkAdapter.js +86 -0
- package/src/visualization/layouts/elkLayout.js +95 -0
- package/src/visualization/layouts/index.js +29 -0
- package/src/visualization/renderers/ascii/box.js +16 -0
- package/src/visualization/renderers/ascii/check.js +271 -0
- package/src/visualization/renderers/ascii/colors.js +13 -0
- package/src/visualization/renderers/ascii/formatters.js +73 -0
- package/src/visualization/renderers/ascii/graph.js +344 -0
- package/src/visualization/renderers/ascii/history.js +335 -0
- package/src/visualization/renderers/ascii/index.js +14 -0
- package/src/visualization/renderers/ascii/info.js +245 -0
- package/src/visualization/renderers/ascii/materialize.js +255 -0
- package/src/visualization/renderers/ascii/path.js +240 -0
- package/src/visualization/renderers/ascii/progress.js +32 -0
- package/src/visualization/renderers/ascii/symbols.js +33 -0
- package/src/visualization/renderers/ascii/table.js +19 -0
- package/src/visualization/renderers/browser/index.js +1 -0
- package/src/visualization/renderers/svg/index.js +159 -0
- package/src/visualization/utils/ansi.js +14 -0
- package/src/visualization/utils/time.js +40 -0
- package/src/visualization/utils/truncate.js +40 -0
- package/src/visualization/utils/unicode.js +52 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,2366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @git-stunts/git-warp - A graph database where every node is a Git commit pointing to the Empty Tree.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Result of a ping health check.
|
|
7
|
+
*/
|
|
8
|
+
export interface PingResult {
|
|
9
|
+
/** Whether the ping succeeded */
|
|
10
|
+
ok: boolean;
|
|
11
|
+
/** Latency in milliseconds */
|
|
12
|
+
latencyMs: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Health status of a repository component.
|
|
17
|
+
*/
|
|
18
|
+
export interface RepositoryHealth {
|
|
19
|
+
/** Repository status */
|
|
20
|
+
status: 'healthy' | 'unhealthy';
|
|
21
|
+
/** Ping latency in milliseconds */
|
|
22
|
+
latencyMs: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Health status of the index component.
|
|
27
|
+
*/
|
|
28
|
+
export interface IndexHealth {
|
|
29
|
+
/** Index status */
|
|
30
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
31
|
+
/** Whether an index is loaded */
|
|
32
|
+
loaded: boolean;
|
|
33
|
+
/** Number of shards (if loaded) */
|
|
34
|
+
shardCount?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Complete health check result.
|
|
39
|
+
*/
|
|
40
|
+
export interface HealthResult {
|
|
41
|
+
/** Overall health status */
|
|
42
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
43
|
+
/** Component health breakdown */
|
|
44
|
+
components: {
|
|
45
|
+
/** Repository health */
|
|
46
|
+
repository: RepositoryHealth;
|
|
47
|
+
/** Index health */
|
|
48
|
+
index: IndexHealth;
|
|
49
|
+
};
|
|
50
|
+
/** ISO timestamp if result is cached */
|
|
51
|
+
cachedAt?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Health status constants.
|
|
56
|
+
*/
|
|
57
|
+
export const HealthStatus: {
|
|
58
|
+
readonly HEALTHY: 'healthy';
|
|
59
|
+
readonly DEGRADED: 'degraded';
|
|
60
|
+
readonly UNHEALTHY: 'unhealthy';
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Options for creating a new graph node.
|
|
65
|
+
*/
|
|
66
|
+
export interface CreateNodeOptions {
|
|
67
|
+
/** The node's message/data */
|
|
68
|
+
message: string;
|
|
69
|
+
/** Array of parent commit SHAs */
|
|
70
|
+
parents?: string[];
|
|
71
|
+
/** Whether to GPG-sign the commit */
|
|
72
|
+
sign?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Specification for a node to be created in bulk.
|
|
77
|
+
* Parents can include placeholder references like '$0', '$1' to reference
|
|
78
|
+
* nodes created earlier in the same batch (by their array index).
|
|
79
|
+
*/
|
|
80
|
+
export interface BulkNodeSpec {
|
|
81
|
+
/** The node's message/data */
|
|
82
|
+
message: string;
|
|
83
|
+
/** Array of parent commit SHAs or placeholder references ('$0', '$1', etc.) */
|
|
84
|
+
parents?: string[];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Options for listing nodes.
|
|
89
|
+
*/
|
|
90
|
+
export interface ListNodesOptions {
|
|
91
|
+
/** Git ref to start from (HEAD, branch, SHA) */
|
|
92
|
+
ref: string;
|
|
93
|
+
/** Maximum nodes to return (default: 50) */
|
|
94
|
+
limit?: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Options for iterating nodes.
|
|
99
|
+
*/
|
|
100
|
+
export interface IterateNodesOptions {
|
|
101
|
+
/** Git ref to start from */
|
|
102
|
+
ref: string;
|
|
103
|
+
/** Maximum nodes to yield (default: 1000000) */
|
|
104
|
+
limit?: number;
|
|
105
|
+
/** Optional AbortSignal for cancellation support */
|
|
106
|
+
signal?: AbortSignal;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Options for rebuilding the index.
|
|
111
|
+
*/
|
|
112
|
+
export interface RebuildOptions {
|
|
113
|
+
/** Maximum nodes to process (default: 10000000, max: 10000000) */
|
|
114
|
+
limit?: number;
|
|
115
|
+
/** Enable streaming mode with this memory threshold in bytes */
|
|
116
|
+
maxMemoryBytes?: number;
|
|
117
|
+
/** Optional AbortSignal for cancellation support */
|
|
118
|
+
signal?: AbortSignal;
|
|
119
|
+
/** Callback invoked on each flush (streaming mode only) */
|
|
120
|
+
onFlush?: (info: { flushedBytes: number; totalFlushedBytes: number; flushCount: number }) => void;
|
|
121
|
+
/** Callback invoked periodically during processing */
|
|
122
|
+
onProgress?: (info: { processedNodes: number; currentMemoryBytes: number | null }) => void;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Options for loading a previously built index.
|
|
127
|
+
*/
|
|
128
|
+
export interface LoadOptions {
|
|
129
|
+
/** Enable strict integrity verification (fail-closed). Default: true */
|
|
130
|
+
strict?: boolean;
|
|
131
|
+
/** Frontier to compare for staleness (maps writer IDs to their current tip SHAs) */
|
|
132
|
+
currentFrontier?: Map<string, string>;
|
|
133
|
+
/** Auto-rebuild when a stale index is detected. Requires rebuildRef. Default: false */
|
|
134
|
+
autoRebuild?: boolean;
|
|
135
|
+
/** Git ref to rebuild from when autoRebuild is true */
|
|
136
|
+
rebuildRef?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Direction for graph traversal.
|
|
141
|
+
*/
|
|
142
|
+
export type TraversalDirection = 'forward' | 'reverse';
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Node yielded during graph traversal.
|
|
146
|
+
*/
|
|
147
|
+
export interface TraversalNode {
|
|
148
|
+
/** The node's SHA */
|
|
149
|
+
sha: string;
|
|
150
|
+
/** Distance from start node */
|
|
151
|
+
depth: number;
|
|
152
|
+
/** SHA of the node that led to this one, or null for start */
|
|
153
|
+
parent: string | null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Result of a path-finding operation.
|
|
158
|
+
*/
|
|
159
|
+
export interface PathResult {
|
|
160
|
+
/** Whether a path was found */
|
|
161
|
+
found: boolean;
|
|
162
|
+
/** Array of SHAs from source to target (empty if not found) */
|
|
163
|
+
path: string[];
|
|
164
|
+
/** Path length (-1 if not found) */
|
|
165
|
+
length: number;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Snapshot of a node passed into query predicates.
|
|
170
|
+
*/
|
|
171
|
+
export interface QueryNodeSnapshot {
|
|
172
|
+
id: string;
|
|
173
|
+
props: Record<string, unknown>;
|
|
174
|
+
edgesOut: Array<{ label: string; to: string }>;
|
|
175
|
+
edgesIn: Array<{ label: string; from: string }>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Query result (standard).
|
|
180
|
+
*/
|
|
181
|
+
export interface QueryResultV1 {
|
|
182
|
+
stateHash: string;
|
|
183
|
+
nodes: Array<{
|
|
184
|
+
id?: string;
|
|
185
|
+
props?: Record<string, unknown>;
|
|
186
|
+
}>;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Aggregation specification for query results.
|
|
191
|
+
*/
|
|
192
|
+
export interface AggregateSpec {
|
|
193
|
+
/** Count matched nodes */
|
|
194
|
+
count?: boolean;
|
|
195
|
+
/** Sum a numeric property (dot-notation path, e.g. 'props.total') */
|
|
196
|
+
sum?: string;
|
|
197
|
+
/** Average a numeric property */
|
|
198
|
+
avg?: string;
|
|
199
|
+
/** Minimum of a numeric property */
|
|
200
|
+
min?: string;
|
|
201
|
+
/** Maximum of a numeric property */
|
|
202
|
+
max?: string;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Result of an aggregate query.
|
|
207
|
+
*/
|
|
208
|
+
export interface AggregateResult {
|
|
209
|
+
stateHash: string;
|
|
210
|
+
count?: number;
|
|
211
|
+
sum?: number;
|
|
212
|
+
avg?: number;
|
|
213
|
+
min?: number;
|
|
214
|
+
max?: number;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Depth option for multi-hop traversal.
|
|
219
|
+
*/
|
|
220
|
+
export interface HopOptions {
|
|
221
|
+
/** Number of hops or [min, max] range. Default: [1, 1] (single hop). */
|
|
222
|
+
depth?: number | [number, number];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Fluent query builder.
|
|
227
|
+
*/
|
|
228
|
+
export class QueryBuilder {
|
|
229
|
+
match(pattern: string): QueryBuilder;
|
|
230
|
+
where(fn: ((node: QueryNodeSnapshot) => boolean) | Record<string, unknown>): QueryBuilder;
|
|
231
|
+
outgoing(label?: string, options?: HopOptions): QueryBuilder;
|
|
232
|
+
incoming(label?: string, options?: HopOptions): QueryBuilder;
|
|
233
|
+
select(fields?: Array<'id' | 'props'>): QueryBuilder;
|
|
234
|
+
aggregate(spec: AggregateSpec): QueryBuilder;
|
|
235
|
+
run(): Promise<QueryResultV1 | AggregateResult>;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Logical graph traversal module.
|
|
240
|
+
*/
|
|
241
|
+
export interface LogicalTraversal {
|
|
242
|
+
bfs(start: string, options?: {
|
|
243
|
+
maxDepth?: number;
|
|
244
|
+
dir?: 'out' | 'in' | 'both';
|
|
245
|
+
labelFilter?: string | string[];
|
|
246
|
+
}): Promise<string[]>;
|
|
247
|
+
dfs(start: string, options?: {
|
|
248
|
+
maxDepth?: number;
|
|
249
|
+
dir?: 'out' | 'in' | 'both';
|
|
250
|
+
labelFilter?: string | string[];
|
|
251
|
+
}): Promise<string[]>;
|
|
252
|
+
shortestPath(from: string, to: string, options?: {
|
|
253
|
+
maxDepth?: number;
|
|
254
|
+
dir?: 'out' | 'in' | 'both';
|
|
255
|
+
labelFilter?: string | string[];
|
|
256
|
+
}): Promise<{ found: boolean; path: string[]; length: number }>;
|
|
257
|
+
connectedComponent(start: string, options?: {
|
|
258
|
+
maxDepth?: number;
|
|
259
|
+
labelFilter?: string | string[];
|
|
260
|
+
}): Promise<string[]>;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Options for BFS/DFS traversal.
|
|
265
|
+
*/
|
|
266
|
+
export interface TraversalOptions {
|
|
267
|
+
/** Starting node SHA */
|
|
268
|
+
start: string;
|
|
269
|
+
/** Maximum nodes to visit (default: 100000) */
|
|
270
|
+
maxNodes?: number;
|
|
271
|
+
/** Maximum depth to traverse (default: 1000) */
|
|
272
|
+
maxDepth?: number;
|
|
273
|
+
/** Traversal direction (default: 'forward') */
|
|
274
|
+
direction?: TraversalDirection;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Options for ancestor/descendant traversal.
|
|
279
|
+
*/
|
|
280
|
+
export interface AncestorOptions {
|
|
281
|
+
/** Starting node SHA */
|
|
282
|
+
sha: string;
|
|
283
|
+
/** Maximum nodes to visit (default: 100000) */
|
|
284
|
+
maxNodes?: number;
|
|
285
|
+
/** Maximum depth to traverse (default: 1000) */
|
|
286
|
+
maxDepth?: number;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Options for path-finding operations.
|
|
291
|
+
*/
|
|
292
|
+
export interface PathOptions {
|
|
293
|
+
/** Source node SHA */
|
|
294
|
+
from: string;
|
|
295
|
+
/** Target node SHA */
|
|
296
|
+
to: string;
|
|
297
|
+
/** Maximum search depth (default: 1000) */
|
|
298
|
+
maxDepth?: number;
|
|
299
|
+
/** Maximum nodes to visit */
|
|
300
|
+
maxNodes?: number;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Options for finding common ancestors.
|
|
305
|
+
*/
|
|
306
|
+
export interface CommonAncestorsOptions {
|
|
307
|
+
/** Array of node SHAs */
|
|
308
|
+
shas: string[];
|
|
309
|
+
/** Maximum ancestors to return (default: 100) */
|
|
310
|
+
maxResults?: number;
|
|
311
|
+
/** Maximum depth to search (default: 1000) */
|
|
312
|
+
maxDepth?: number;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Options for topological sort.
|
|
317
|
+
*/
|
|
318
|
+
export interface TopologicalSortOptions {
|
|
319
|
+
/** Starting node SHA */
|
|
320
|
+
start: string;
|
|
321
|
+
/** Maximum nodes to yield (default: 100000) */
|
|
322
|
+
maxNodes?: number;
|
|
323
|
+
/** Direction determines dependency order (default: 'forward') */
|
|
324
|
+
direction?: TraversalDirection;
|
|
325
|
+
/** If true, throws TraversalError when cycle detected (default: false) */
|
|
326
|
+
throwOnCycle?: boolean;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Immutable entity representing a graph node.
|
|
331
|
+
*/
|
|
332
|
+
export class GraphNode {
|
|
333
|
+
/** Commit SHA */
|
|
334
|
+
readonly sha: string;
|
|
335
|
+
/** Author name */
|
|
336
|
+
readonly author: string | undefined;
|
|
337
|
+
/** Commit date */
|
|
338
|
+
readonly date: string | undefined;
|
|
339
|
+
/** Node message/data */
|
|
340
|
+
readonly message: string;
|
|
341
|
+
/** Array of parent SHAs */
|
|
342
|
+
readonly parents: readonly string[];
|
|
343
|
+
|
|
344
|
+
constructor(data: {
|
|
345
|
+
sha: string;
|
|
346
|
+
message: string;
|
|
347
|
+
author?: string;
|
|
348
|
+
date?: string;
|
|
349
|
+
parents?: string[];
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Port interface for graph persistence operations.
|
|
355
|
+
* @abstract
|
|
356
|
+
*/
|
|
357
|
+
/**
|
|
358
|
+
* Full commit metadata returned by getNodeInfo.
|
|
359
|
+
*/
|
|
360
|
+
export interface NodeInfo {
|
|
361
|
+
/** Commit SHA */
|
|
362
|
+
sha: string;
|
|
363
|
+
/** Commit message */
|
|
364
|
+
message: string;
|
|
365
|
+
/** Author name */
|
|
366
|
+
author: string;
|
|
367
|
+
/** Commit date */
|
|
368
|
+
date: string;
|
|
369
|
+
/** Parent commit SHAs */
|
|
370
|
+
parents: string[];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export abstract class GraphPersistencePort {
|
|
374
|
+
/** The empty tree SHA */
|
|
375
|
+
abstract get emptyTree(): string;
|
|
376
|
+
|
|
377
|
+
abstract commitNode(options: CreateNodeOptions): Promise<string>;
|
|
378
|
+
abstract showNode(sha: string): Promise<string>;
|
|
379
|
+
/** Gets full commit metadata for a node */
|
|
380
|
+
abstract getNodeInfo(sha: string): Promise<NodeInfo>;
|
|
381
|
+
abstract logNodesStream(options: ListNodesOptions & { format: string }): Promise<AsyncIterable<Uint8Array | string>>;
|
|
382
|
+
abstract logNodes(options: ListNodesOptions & { format: string }): Promise<string>;
|
|
383
|
+
/** Pings the repository to verify accessibility */
|
|
384
|
+
abstract ping(): Promise<PingResult>;
|
|
385
|
+
/** Counts nodes reachable from a ref without loading them into memory */
|
|
386
|
+
abstract countNodes(ref: string): Promise<number>;
|
|
387
|
+
/** Checks if a node exists by SHA */
|
|
388
|
+
nodeExists(sha: string): Promise<boolean>;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Port interface for index storage operations.
|
|
393
|
+
* @abstract
|
|
394
|
+
*/
|
|
395
|
+
export abstract class IndexStoragePort {
|
|
396
|
+
/** Writes a blob and returns its OID */
|
|
397
|
+
abstract writeBlob(content: Buffer | string): Promise<string>;
|
|
398
|
+
/** Writes a tree from entries and returns its OID */
|
|
399
|
+
abstract writeTree(entries: string[]): Promise<string>;
|
|
400
|
+
/** Reads a blob by OID */
|
|
401
|
+
abstract readBlob(oid: string): Promise<Buffer>;
|
|
402
|
+
/** Reads a tree and returns a map of path to blob OID */
|
|
403
|
+
abstract readTreeOids(treeOid: string): Promise<Record<string, string>>;
|
|
404
|
+
/** Updates a ref to point to an OID */
|
|
405
|
+
abstract updateRef(ref: string, oid: string): Promise<void>;
|
|
406
|
+
/** Reads the OID a ref points to */
|
|
407
|
+
abstract readRef(ref: string): Promise<string | null>;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Log levels in order of severity.
|
|
412
|
+
*/
|
|
413
|
+
export const LogLevel: {
|
|
414
|
+
readonly DEBUG: 0;
|
|
415
|
+
readonly INFO: 1;
|
|
416
|
+
readonly WARN: 2;
|
|
417
|
+
readonly ERROR: 3;
|
|
418
|
+
readonly SILENT: 4;
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
export type LogLevelValue = 0 | 1 | 2 | 3 | 4;
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Port interface for cryptographic operations.
|
|
425
|
+
* @abstract
|
|
426
|
+
*/
|
|
427
|
+
export abstract class CryptoPort {
|
|
428
|
+
/** Computes a hash digest of the given data */
|
|
429
|
+
abstract hash(algorithm: string, data: string | Buffer | Uint8Array): Promise<string>;
|
|
430
|
+
/** Computes an HMAC of the given data */
|
|
431
|
+
abstract hmac(algorithm: string, key: string | Buffer | Uint8Array, data: string | Buffer | Uint8Array): Promise<Buffer | Uint8Array>;
|
|
432
|
+
/** Constant-time comparison of two buffers */
|
|
433
|
+
abstract timingSafeEqual(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Port interface for time-related operations.
|
|
438
|
+
* @abstract
|
|
439
|
+
*/
|
|
440
|
+
export abstract class ClockPort {
|
|
441
|
+
/** Returns a high-resolution timestamp in milliseconds */
|
|
442
|
+
abstract now(): number;
|
|
443
|
+
/** Returns the current wall-clock time as an ISO string */
|
|
444
|
+
abstract timestamp(): string;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Unified clock adapter supporting both Node.js and global performance APIs.
|
|
449
|
+
*
|
|
450
|
+
* Use the static factory methods for common cases:
|
|
451
|
+
* - `ClockAdapter.node()` -- Node.js `perf_hooks.performance`
|
|
452
|
+
* - `ClockAdapter.global()` -- `globalThis.performance` (Bun/Deno/browsers)
|
|
453
|
+
*/
|
|
454
|
+
export class ClockAdapter extends ClockPort {
|
|
455
|
+
constructor(options?: { performanceImpl?: Performance });
|
|
456
|
+
static node(): ClockAdapter;
|
|
457
|
+
static global(): ClockAdapter;
|
|
458
|
+
now(): number;
|
|
459
|
+
timestamp(): string;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* @deprecated Use ClockAdapter instead. Backward-compatibility re-export.
|
|
464
|
+
*/
|
|
465
|
+
export class PerformanceClockAdapter extends ClockPort {
|
|
466
|
+
now(): number;
|
|
467
|
+
timestamp(): string;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* @deprecated Use ClockAdapter instead. Backward-compatibility re-export.
|
|
472
|
+
*/
|
|
473
|
+
export class GlobalClockAdapter extends ClockPort {
|
|
474
|
+
now(): number;
|
|
475
|
+
timestamp(): string;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Port interface for structured logging operations.
|
|
480
|
+
* @abstract
|
|
481
|
+
*/
|
|
482
|
+
export abstract class LoggerPort {
|
|
483
|
+
/** Log a debug-level message */
|
|
484
|
+
abstract debug(message: string, context?: Record<string, unknown>): void;
|
|
485
|
+
/** Log an info-level message */
|
|
486
|
+
abstract info(message: string, context?: Record<string, unknown>): void;
|
|
487
|
+
/** Log a warning-level message */
|
|
488
|
+
abstract warn(message: string, context?: Record<string, unknown>): void;
|
|
489
|
+
/** Log an error-level message */
|
|
490
|
+
abstract error(message: string, context?: Record<string, unknown>): void;
|
|
491
|
+
/** Create a child logger with additional base context */
|
|
492
|
+
abstract child(context: Record<string, unknown>): LoggerPort;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* No-operation logger adapter.
|
|
497
|
+
* Discards all log messages. Zero overhead.
|
|
498
|
+
*/
|
|
499
|
+
export class NoOpLogger extends LoggerPort {
|
|
500
|
+
debug(message: string, context?: Record<string, unknown>): void;
|
|
501
|
+
info(message: string, context?: Record<string, unknown>): void;
|
|
502
|
+
warn(message: string, context?: Record<string, unknown>): void;
|
|
503
|
+
error(message: string, context?: Record<string, unknown>): void;
|
|
504
|
+
child(context: Record<string, unknown>): NoOpLogger;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Console logger adapter with structured JSON output.
|
|
509
|
+
* Supports log level filtering, timestamps, and child loggers.
|
|
510
|
+
*/
|
|
511
|
+
export class ConsoleLogger extends LoggerPort {
|
|
512
|
+
constructor(options?: {
|
|
513
|
+
/** Minimum log level to output (default: LogLevel.INFO) */
|
|
514
|
+
level?: LogLevelValue | 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
515
|
+
/** Base context for all log entries */
|
|
516
|
+
context?: Record<string, unknown>;
|
|
517
|
+
/** Custom timestamp function (defaults to ISO string) */
|
|
518
|
+
timestampFn?: () => string;
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
debug(message: string, context?: Record<string, unknown>): void;
|
|
522
|
+
info(message: string, context?: Record<string, unknown>): void;
|
|
523
|
+
warn(message: string, context?: Record<string, unknown>): void;
|
|
524
|
+
error(message: string, context?: Record<string, unknown>): void;
|
|
525
|
+
child(context: Record<string, unknown>): ConsoleLogger;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Git plumbing interface (from @git-stunts/plumbing).
|
|
530
|
+
*/
|
|
531
|
+
export interface GitPlumbing {
|
|
532
|
+
readonly emptyTree: string;
|
|
533
|
+
execute(options: { args: string[]; input?: string | Buffer }): Promise<string>;
|
|
534
|
+
executeStream(options: { args: string[] }): Promise<AsyncIterable<Uint8Array> & { collect(opts?: { asString?: boolean }): Promise<Buffer | string> }>;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Implementation of GraphPersistencePort and IndexStoragePort using GitPlumbing.
|
|
539
|
+
*/
|
|
540
|
+
export class GitGraphAdapter extends GraphPersistencePort implements IndexStoragePort {
|
|
541
|
+
constructor(options: { plumbing: GitPlumbing });
|
|
542
|
+
|
|
543
|
+
get emptyTree(): string;
|
|
544
|
+
commitNode(options: CreateNodeOptions): Promise<string>;
|
|
545
|
+
showNode(sha: string): Promise<string>;
|
|
546
|
+
getNodeInfo(sha: string): Promise<NodeInfo>;
|
|
547
|
+
logNodesStream(options: ListNodesOptions & { format: string }): Promise<AsyncIterable<Uint8Array | string>>;
|
|
548
|
+
logNodes(options: ListNodesOptions & { format: string }): Promise<string>;
|
|
549
|
+
writeBlob(content: Buffer | string): Promise<string>;
|
|
550
|
+
writeTree(entries: string[]): Promise<string>;
|
|
551
|
+
readTree(treeOid: string): Promise<Record<string, Buffer>>;
|
|
552
|
+
readTreeOids(treeOid: string): Promise<Record<string, string>>;
|
|
553
|
+
readBlob(oid: string): Promise<Buffer>;
|
|
554
|
+
updateRef(ref: string, oid: string): Promise<void>;
|
|
555
|
+
readRef(ref: string): Promise<string | null>;
|
|
556
|
+
deleteRef(ref: string): Promise<void>;
|
|
557
|
+
/** Checks if a node (commit) exists in the repository */
|
|
558
|
+
nodeExists(sha: string): Promise<boolean>;
|
|
559
|
+
ping(): Promise<PingResult>;
|
|
560
|
+
/** Counts nodes reachable from a ref without loading them into memory */
|
|
561
|
+
countNodes(ref: string): Promise<number>;
|
|
562
|
+
/** Reads a git config value */
|
|
563
|
+
configGet(key: string): Promise<string | null>;
|
|
564
|
+
/** Sets a git config value */
|
|
565
|
+
configSet(key: string, value: string): Promise<void>;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Node.js crypto adapter implementing CryptoPort.
|
|
570
|
+
*
|
|
571
|
+
* Uses Node.js built-in crypto module for hash and HMAC operations.
|
|
572
|
+
*/
|
|
573
|
+
export class NodeCryptoAdapter extends CryptoPort {
|
|
574
|
+
constructor();
|
|
575
|
+
hash(algorithm: string, data: string | Buffer | Uint8Array): Promise<string>;
|
|
576
|
+
hmac(algorithm: string, key: string | Buffer | Uint8Array, data: string | Buffer | Uint8Array): Promise<Buffer | Uint8Array>;
|
|
577
|
+
timingSafeEqual(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Web Crypto API adapter implementing CryptoPort.
|
|
582
|
+
*
|
|
583
|
+
* Uses the standard Web Crypto API (globalThis.crypto.subtle) which is
|
|
584
|
+
* available in browsers, Deno, Bun, and Node.js 20+.
|
|
585
|
+
*/
|
|
586
|
+
export class WebCryptoAdapter extends CryptoPort {
|
|
587
|
+
constructor(options?: { subtle?: SubtleCrypto });
|
|
588
|
+
hash(algorithm: string, data: string | Buffer | Uint8Array): Promise<string>;
|
|
589
|
+
hmac(algorithm: string, key: string | Buffer | Uint8Array, data: string | Buffer | Uint8Array): Promise<Buffer | Uint8Array>;
|
|
590
|
+
timingSafeEqual(a: Buffer | Uint8Array, b: Buffer | Uint8Array): boolean;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Port interface for HTTP server operations.
|
|
595
|
+
* @abstract
|
|
596
|
+
*/
|
|
597
|
+
export abstract class HttpServerPort {
|
|
598
|
+
abstract createServer(requestHandler: (request: {
|
|
599
|
+
method: string;
|
|
600
|
+
url: string;
|
|
601
|
+
headers: Record<string, string>;
|
|
602
|
+
body?: Buffer | Uint8Array;
|
|
603
|
+
}) => Promise<{ status?: number; headers?: Record<string, string>; body?: string | Uint8Array }>): {
|
|
604
|
+
listen(port: number, callback?: (err?: Error | null) => void): void;
|
|
605
|
+
listen(port: number, host: string, callback?: (err?: Error | null) => void): void;
|
|
606
|
+
close(callback?: (err?: Error | null) => void): void;
|
|
607
|
+
address(): { address: string; port: number; family: string } | null;
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Bun HTTP adapter implementing HttpServerPort.
|
|
613
|
+
*
|
|
614
|
+
* Uses globalThis.Bun.serve() to create an HTTP server.
|
|
615
|
+
*/
|
|
616
|
+
export class BunHttpAdapter extends HttpServerPort {
|
|
617
|
+
constructor(options?: { logger?: { error: (msg: string, ...args: unknown[]) => void } });
|
|
618
|
+
createServer(requestHandler: (request: {
|
|
619
|
+
method: string;
|
|
620
|
+
url: string;
|
|
621
|
+
headers: Record<string, string>;
|
|
622
|
+
body?: Buffer | Uint8Array;
|
|
623
|
+
}) => Promise<{ status?: number; headers?: Record<string, string>; body?: string | Uint8Array }>): {
|
|
624
|
+
listen(port: number, callback?: (err?: Error | null) => void): void;
|
|
625
|
+
listen(port: number, host: string, callback?: (err?: Error | null) => void): void;
|
|
626
|
+
close(callback?: (err?: Error | null) => void): void;
|
|
627
|
+
address(): { address: string; port: number; family: string } | null;
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Deno HTTP adapter implementing HttpServerPort.
|
|
633
|
+
*
|
|
634
|
+
* Uses globalThis.Deno.serve() (Deno 1.35+) to create an HTTP server.
|
|
635
|
+
*/
|
|
636
|
+
export class DenoHttpAdapter extends HttpServerPort {
|
|
637
|
+
constructor(options?: { logger?: { error: (msg: string, ...args: unknown[]) => void } });
|
|
638
|
+
createServer(requestHandler: (request: {
|
|
639
|
+
method: string;
|
|
640
|
+
url: string;
|
|
641
|
+
headers: Record<string, string>;
|
|
642
|
+
body?: Buffer | Uint8Array;
|
|
643
|
+
}) => Promise<{ status?: number; headers?: Record<string, string>; body?: string | Uint8Array }>): {
|
|
644
|
+
listen(port: number, callback?: (err?: Error | null) => void): void;
|
|
645
|
+
listen(port: number, host: string, callback?: (err?: Error | null) => void): void;
|
|
646
|
+
close(callback?: (err?: Error | null) => void): void;
|
|
647
|
+
address(): { address: string; port: number; family: string } | null;
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Builder for constructing bitmap indexes in memory.
|
|
653
|
+
*
|
|
654
|
+
* Pure domain class with no infrastructure dependencies.
|
|
655
|
+
*/
|
|
656
|
+
export class BitmapIndexBuilder {
|
|
657
|
+
/** SHA to numeric ID mappings */
|
|
658
|
+
readonly shaToId: Map<string, number>;
|
|
659
|
+
/** Numeric ID to SHA mappings */
|
|
660
|
+
readonly idToSha: string[];
|
|
661
|
+
|
|
662
|
+
constructor();
|
|
663
|
+
|
|
664
|
+
/** Registers a node and returns its numeric ID */
|
|
665
|
+
registerNode(sha: string): number;
|
|
666
|
+
|
|
667
|
+
/** Adds a directed edge from source to target */
|
|
668
|
+
addEdge(srcSha: string, tgtSha: string): void;
|
|
669
|
+
|
|
670
|
+
/** Serializes the index to a tree structure of buffers */
|
|
671
|
+
serialize(options?: { frontier?: Map<string, string> }): Promise<Record<string, Buffer>>;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Builder for constructing bitmap indexes from materialized WARP state.
|
|
676
|
+
*
|
|
677
|
+
* This builder creates adjacency indexes from WarpStateV5.edgeAlive OR-Set,
|
|
678
|
+
* NOT from Git commit DAG topology.
|
|
679
|
+
*/
|
|
680
|
+
export class WarpStateIndexBuilder {
|
|
681
|
+
constructor(options?: { crypto?: CryptoPort });
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Builds an index from materialized WARP state.
|
|
685
|
+
*/
|
|
686
|
+
buildFromState(state: WarpStateV5): { builder: BitmapIndexBuilder; stats: { nodes: number; edges: number } };
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Serializes the index to a tree structure of buffers.
|
|
690
|
+
*/
|
|
691
|
+
serialize(): Promise<Record<string, Buffer>>;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Builds a bitmap index from materialized WARP state.
|
|
696
|
+
*
|
|
697
|
+
* Convenience function that creates a WarpStateIndexBuilder, builds from state,
|
|
698
|
+
* and returns the serialized tree and stats.
|
|
699
|
+
*/
|
|
700
|
+
export function buildWarpStateIndex(state: WarpStateV5, options?: { crypto?: CryptoPort }): Promise<{ tree: Record<string, Buffer>; stats: { nodes: number; edges: number } }>;
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Computes a deterministic hash of a WarpStateV5 state.
|
|
704
|
+
*
|
|
705
|
+
* Uses canonical serialization to ensure the same state always produces
|
|
706
|
+
* the same hash regardless of property iteration order.
|
|
707
|
+
*/
|
|
708
|
+
export function computeStateHashV5(state: WarpStateV5, options?: { crypto?: CryptoPort; codec?: unknown }): Promise<string | null>;
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Service for querying a loaded bitmap index.
|
|
712
|
+
*
|
|
713
|
+
* Provides O(1) lookups via lazy-loaded sharded bitmap data.
|
|
714
|
+
*/
|
|
715
|
+
export class BitmapIndexReader {
|
|
716
|
+
constructor(options: {
|
|
717
|
+
storage: IndexStoragePort;
|
|
718
|
+
/** If true, throw on validation failures; if false, log and return empty (default: false) */
|
|
719
|
+
strict?: boolean;
|
|
720
|
+
/** Logger for structured logging (default: NoOpLogger) */
|
|
721
|
+
logger?: LoggerPort;
|
|
722
|
+
/** CryptoPort instance for checksum verification. When not provided, checksum validation is skipped. */
|
|
723
|
+
crypto?: CryptoPort;
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Configures the reader with shard OID mappings for lazy loading.
|
|
728
|
+
*
|
|
729
|
+
* The shardOids object maps shard filenames to their Git blob OIDs:
|
|
730
|
+
* - `meta_XX.json` - SHA→ID mappings for nodes with SHA prefix XX
|
|
731
|
+
* - `shards_fwd_XX.json` - Forward edge bitmaps (parent→children)
|
|
732
|
+
* - `shards_rev_XX.json` - Reverse edge bitmaps (child→parents)
|
|
733
|
+
*
|
|
734
|
+
* @example
|
|
735
|
+
* reader.setup({
|
|
736
|
+
* 'meta_ab.json': 'a1b2c3d4e5f6...',
|
|
737
|
+
* 'shards_fwd_ab.json': '1234567890ab...',
|
|
738
|
+
* 'shards_rev_ab.json': 'abcdef123456...'
|
|
739
|
+
* });
|
|
740
|
+
*/
|
|
741
|
+
setup(shardOids: Record<string, string>): void;
|
|
742
|
+
|
|
743
|
+
/** Looks up the numeric ID for a SHA */
|
|
744
|
+
lookupId(sha: string): Promise<number | undefined>;
|
|
745
|
+
|
|
746
|
+
/** Gets parent SHAs for a node (O(1) via reverse bitmap) */
|
|
747
|
+
getParents(sha: string): Promise<string[]>;
|
|
748
|
+
|
|
749
|
+
/** Gets child SHAs for a node (O(1) via forward bitmap) */
|
|
750
|
+
getChildren(sha: string): Promise<string[]>;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Service for building and loading the bitmap index from the graph.
|
|
755
|
+
*/
|
|
756
|
+
export class IndexRebuildService {
|
|
757
|
+
constructor(options: {
|
|
758
|
+
/** Graph service providing iterateNodes() for walking the graph */
|
|
759
|
+
graphService: { iterateNodes(options: IterateNodesOptions): AsyncGenerator<GraphNode, void, unknown> };
|
|
760
|
+
storage: IndexStoragePort;
|
|
761
|
+
/** Logger for structured logging (default: NoOpLogger) */
|
|
762
|
+
logger?: LoggerPort;
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Rebuilds the bitmap index by walking the graph from a ref.
|
|
767
|
+
*
|
|
768
|
+
* **Memory**: O(N) where N is nodes. ~150-200MB for 1M nodes.
|
|
769
|
+
* **Time**: O(N) single pass.
|
|
770
|
+
*/
|
|
771
|
+
rebuild(ref: string, options?: RebuildOptions): Promise<string>;
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Loads a previously built index from a tree OID.
|
|
775
|
+
*
|
|
776
|
+
* **Memory**: Lazy loading - O(1) initial, shards loaded on demand.
|
|
777
|
+
*/
|
|
778
|
+
load(treeOid: string, options?: LoadOptions): Promise<BitmapIndexReader>;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Service for performing health checks on the graph system.
|
|
783
|
+
*
|
|
784
|
+
* Follows hexagonal architecture by depending on ports, not adapters.
|
|
785
|
+
* Provides K8s-style probes (liveness vs readiness) and detailed component health.
|
|
786
|
+
*/
|
|
787
|
+
export class HealthCheckService {
|
|
788
|
+
constructor(options: {
|
|
789
|
+
/** Persistence port for repository checks */
|
|
790
|
+
persistence: GraphPersistencePort;
|
|
791
|
+
/** Clock port for timing operations */
|
|
792
|
+
clock: ClockPort;
|
|
793
|
+
/** How long to cache health results in milliseconds (default: 5000) */
|
|
794
|
+
cacheTtlMs?: number;
|
|
795
|
+
/** Logger for structured logging (default: NoOpLogger) */
|
|
796
|
+
logger?: LoggerPort;
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Sets the index reader for index health checks.
|
|
801
|
+
* Call this when an index is loaded.
|
|
802
|
+
*/
|
|
803
|
+
setIndexReader(reader: BitmapIndexReader | null): void;
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* K8s-style liveness probe: Is the service running?
|
|
807
|
+
* Returns true if the repository is accessible.
|
|
808
|
+
*/
|
|
809
|
+
isAlive(): Promise<boolean>;
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* K8s-style readiness probe: Can the service serve requests?
|
|
813
|
+
* Returns true if all critical components are healthy.
|
|
814
|
+
*/
|
|
815
|
+
isReady(): Promise<boolean>;
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Gets detailed health information for all components.
|
|
819
|
+
* Results are cached for the configured TTL.
|
|
820
|
+
*/
|
|
821
|
+
getHealth(): Promise<HealthResult>;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Service for commit DAG traversal operations.
|
|
826
|
+
*
|
|
827
|
+
* Provides BFS, DFS, path finding, and topological sort algorithms
|
|
828
|
+
* using O(1) bitmap index lookups.
|
|
829
|
+
*/
|
|
830
|
+
export class CommitDagTraversalService {
|
|
831
|
+
constructor(options: {
|
|
832
|
+
/** Index reader for O(1) lookups */
|
|
833
|
+
indexReader: BitmapIndexReader;
|
|
834
|
+
/** Logger for structured logging (default: NoOpLogger) */
|
|
835
|
+
logger?: LoggerPort;
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Breadth-first traversal from a starting node.
|
|
840
|
+
*/
|
|
841
|
+
bfs(options: TraversalOptions): AsyncGenerator<TraversalNode, void, unknown>;
|
|
842
|
+
|
|
843
|
+
/**
|
|
844
|
+
* Depth-first pre-order traversal from a starting node.
|
|
845
|
+
*/
|
|
846
|
+
dfs(options: TraversalOptions): AsyncGenerator<TraversalNode, void, unknown>;
|
|
847
|
+
|
|
848
|
+
/**
|
|
849
|
+
* Yields all ancestors of a node (transitive closure going backwards).
|
|
850
|
+
*/
|
|
851
|
+
ancestors(options: AncestorOptions): AsyncGenerator<TraversalNode, void, unknown>;
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Yields all descendants of a node (transitive closure going forwards).
|
|
855
|
+
*/
|
|
856
|
+
descendants(options: AncestorOptions): AsyncGenerator<TraversalNode, void, unknown>;
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Finds ANY path between two nodes using BFS.
|
|
860
|
+
*/
|
|
861
|
+
findPath(options: PathOptions): Promise<PathResult>;
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* Finds the shortest path between two nodes using bidirectional BFS.
|
|
865
|
+
*/
|
|
866
|
+
shortestPath(options: PathOptions): Promise<PathResult>;
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Checks if there is any path from one node to another.
|
|
870
|
+
*/
|
|
871
|
+
isReachable(options: PathOptions): Promise<boolean>;
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Finds common ancestors of multiple nodes.
|
|
875
|
+
*/
|
|
876
|
+
commonAncestors(options: CommonAncestorsOptions): Promise<string[]>;
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Yields nodes in topological order using Kahn's algorithm.
|
|
880
|
+
*/
|
|
881
|
+
topologicalSort(options: TopologicalSortOptions): AsyncGenerator<TraversalNode, void, unknown>;
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Finds shortest path using Dijkstra's algorithm with custom edge weights.
|
|
885
|
+
*/
|
|
886
|
+
weightedShortestPath(options: {
|
|
887
|
+
from: string;
|
|
888
|
+
to: string;
|
|
889
|
+
weightProvider?: (fromSha: string, toSha: string) => number | Promise<number>;
|
|
890
|
+
direction?: 'children' | 'parents';
|
|
891
|
+
}): Promise<{ path: string[]; totalCost: number }>;
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Finds shortest path using A* algorithm with heuristic guidance.
|
|
895
|
+
*/
|
|
896
|
+
aStarSearch(options: {
|
|
897
|
+
from: string;
|
|
898
|
+
to: string;
|
|
899
|
+
weightProvider?: (fromSha: string, toSha: string) => number | Promise<number>;
|
|
900
|
+
heuristicProvider?: (sha: string, targetSha: string) => number | Promise<number>;
|
|
901
|
+
direction?: 'children' | 'parents';
|
|
902
|
+
}): Promise<{ path: string[]; totalCost: number; nodesExplored: number }>;
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Bi-directional A* search - meets in the middle from both ends.
|
|
906
|
+
*/
|
|
907
|
+
bidirectionalAStar(options: {
|
|
908
|
+
from: string;
|
|
909
|
+
to: string;
|
|
910
|
+
weightProvider?: (fromSha: string, toSha: string) => number | Promise<number>;
|
|
911
|
+
forwardHeuristic?: (sha: string, targetSha: string) => number | Promise<number>;
|
|
912
|
+
backwardHeuristic?: (sha: string, targetSha: string) => number | Promise<number>;
|
|
913
|
+
}): Promise<{ path: string[]; totalCost: number; nodesExplored: number }>;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* @deprecated Use CommitDagTraversalService instead.
|
|
918
|
+
*/
|
|
919
|
+
export { CommitDagTraversalService as TraversalService };
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Error class for graph traversal operations.
|
|
923
|
+
*/
|
|
924
|
+
export class TraversalError extends Error {
|
|
925
|
+
/** Error name */
|
|
926
|
+
readonly name: 'TraversalError';
|
|
927
|
+
/** Error code for programmatic handling */
|
|
928
|
+
readonly code: string;
|
|
929
|
+
/** Serializable context for debugging */
|
|
930
|
+
readonly context: Record<string, unknown>;
|
|
931
|
+
|
|
932
|
+
constructor(message: string, options?: {
|
|
933
|
+
code?: string;
|
|
934
|
+
context?: Record<string, unknown>;
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Error thrown when an operation is aborted via AbortSignal.
|
|
940
|
+
*/
|
|
941
|
+
export class OperationAbortedError extends Error {
|
|
942
|
+
readonly name: 'OperationAbortedError';
|
|
943
|
+
readonly code: string;
|
|
944
|
+
readonly operation?: string;
|
|
945
|
+
readonly reason: string;
|
|
946
|
+
readonly context: Record<string, unknown>;
|
|
947
|
+
|
|
948
|
+
constructor(operation?: string, options?: {
|
|
949
|
+
reason?: string;
|
|
950
|
+
code?: string;
|
|
951
|
+
context?: Record<string, unknown>;
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* Error class for query builder operations.
|
|
957
|
+
*/
|
|
958
|
+
export class QueryError extends Error {
|
|
959
|
+
readonly name: 'QueryError';
|
|
960
|
+
readonly code: string;
|
|
961
|
+
readonly context: Record<string, unknown>;
|
|
962
|
+
|
|
963
|
+
constructor(message: string, options?: {
|
|
964
|
+
code?: string;
|
|
965
|
+
context?: Record<string, unknown>;
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Error thrown when a patch contains operations unsupported by the current schema version.
|
|
971
|
+
* Raised during sync when a v2 reader encounters edge property ops (schema v3).
|
|
972
|
+
*/
|
|
973
|
+
export class SchemaUnsupportedError extends Error {
|
|
974
|
+
readonly name: 'SchemaUnsupportedError';
|
|
975
|
+
readonly code: 'E_SCHEMA_UNSUPPORTED';
|
|
976
|
+
readonly context: Record<string, unknown>;
|
|
977
|
+
|
|
978
|
+
constructor(message: string, options?: {
|
|
979
|
+
context?: Record<string, unknown>;
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* Error class for sync transport operations.
|
|
985
|
+
*/
|
|
986
|
+
export class SyncError extends Error {
|
|
987
|
+
readonly name: 'SyncError';
|
|
988
|
+
readonly code: string;
|
|
989
|
+
readonly context: Record<string, unknown>;
|
|
990
|
+
|
|
991
|
+
constructor(message: string, options?: {
|
|
992
|
+
code?: string;
|
|
993
|
+
context?: Record<string, unknown>;
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/**
|
|
998
|
+
* Base error class for bitmap index operations.
|
|
999
|
+
*/
|
|
1000
|
+
export class IndexError extends Error {
|
|
1001
|
+
readonly name: 'IndexError';
|
|
1002
|
+
readonly code: string;
|
|
1003
|
+
readonly context: Record<string, unknown>;
|
|
1004
|
+
|
|
1005
|
+
constructor(message: string, options?: {
|
|
1006
|
+
code?: string;
|
|
1007
|
+
context?: Record<string, unknown>;
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* Error thrown when a shard fails to load.
|
|
1013
|
+
*/
|
|
1014
|
+
export class ShardLoadError extends IndexError {
|
|
1015
|
+
readonly name: 'ShardLoadError';
|
|
1016
|
+
readonly shardPath?: string;
|
|
1017
|
+
readonly oid?: string;
|
|
1018
|
+
readonly cause?: Error;
|
|
1019
|
+
|
|
1020
|
+
constructor(message: string, options?: {
|
|
1021
|
+
shardPath?: string;
|
|
1022
|
+
oid?: string;
|
|
1023
|
+
cause?: Error;
|
|
1024
|
+
context?: Record<string, unknown>;
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Error thrown when shard data is corrupted or invalid.
|
|
1030
|
+
*/
|
|
1031
|
+
export class ShardCorruptionError extends IndexError {
|
|
1032
|
+
readonly name: 'ShardCorruptionError';
|
|
1033
|
+
readonly shardPath?: string;
|
|
1034
|
+
readonly oid?: string;
|
|
1035
|
+
readonly reason?: string;
|
|
1036
|
+
|
|
1037
|
+
constructor(message: string, options?: {
|
|
1038
|
+
shardPath?: string;
|
|
1039
|
+
oid?: string;
|
|
1040
|
+
reason?: string;
|
|
1041
|
+
context?: Record<string, unknown>;
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* Error thrown when shard validation fails.
|
|
1047
|
+
*/
|
|
1048
|
+
export class ShardValidationError extends IndexError {
|
|
1049
|
+
readonly name: 'ShardValidationError';
|
|
1050
|
+
readonly shardPath?: string;
|
|
1051
|
+
readonly expected?: unknown;
|
|
1052
|
+
readonly actual?: unknown;
|
|
1053
|
+
readonly field?: string;
|
|
1054
|
+
|
|
1055
|
+
constructor(message: string, options?: {
|
|
1056
|
+
shardPath?: string;
|
|
1057
|
+
expected?: unknown;
|
|
1058
|
+
actual?: unknown;
|
|
1059
|
+
field?: string;
|
|
1060
|
+
context?: Record<string, unknown>;
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/**
|
|
1065
|
+
* Error thrown when a storage operation fails.
|
|
1066
|
+
*/
|
|
1067
|
+
export class StorageError extends IndexError {
|
|
1068
|
+
readonly name: 'StorageError';
|
|
1069
|
+
readonly operation?: 'read' | 'write';
|
|
1070
|
+
readonly oid?: string;
|
|
1071
|
+
readonly cause?: Error;
|
|
1072
|
+
|
|
1073
|
+
constructor(message: string, options?: {
|
|
1074
|
+
operation?: 'read' | 'write';
|
|
1075
|
+
oid?: string;
|
|
1076
|
+
cause?: Error;
|
|
1077
|
+
context?: Record<string, unknown>;
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* Checks if an AbortSignal is aborted and throws OperationAbortedError if so.
|
|
1083
|
+
*/
|
|
1084
|
+
export function checkAborted(signal?: AbortSignal, operation?: string): void;
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Creates an AbortSignal that automatically aborts after the specified timeout.
|
|
1088
|
+
*/
|
|
1089
|
+
export function createTimeoutSignal(ms: number): AbortSignal;
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* Encodes an edge property key for Map storage.
|
|
1093
|
+
* Format: \x01from\0to\0label\0propKey
|
|
1094
|
+
*/
|
|
1095
|
+
export function encodeEdgePropKey(from: string, to: string, label: string, propKey: string): string;
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Decodes an edge property key string.
|
|
1099
|
+
*/
|
|
1100
|
+
export function decodeEdgePropKey(encoded: string): { from: string; to: string; label: string; propKey: string };
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* Returns true if the encoded key is an edge property key.
|
|
1104
|
+
*/
|
|
1105
|
+
export function isEdgePropKey(key: string): boolean;
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* Configuration for an observer view.
|
|
1109
|
+
*/
|
|
1110
|
+
export interface ObserverConfig {
|
|
1111
|
+
/** Glob pattern for visible nodes (e.g. 'user:*') */
|
|
1112
|
+
match: string;
|
|
1113
|
+
/** Property keys to include (whitelist). If omitted, all non-redacted properties are visible. */
|
|
1114
|
+
expose?: string[];
|
|
1115
|
+
/** Property keys to exclude (blacklist). Takes precedence over expose. */
|
|
1116
|
+
redact?: string[];
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Read-only observer view of a materialized WarpGraph state.
|
|
1121
|
+
*
|
|
1122
|
+
* Provides the same query/traverse API as WarpGraph, but filtered
|
|
1123
|
+
* by observer configuration (match pattern, expose, redact).
|
|
1124
|
+
* Edges are only visible when both endpoints pass the match filter.
|
|
1125
|
+
*
|
|
1126
|
+
* @see Paper IV, Section 3 -- Observers as resource-bounded functors
|
|
1127
|
+
*/
|
|
1128
|
+
export class ObserverView {
|
|
1129
|
+
/** Observer name */
|
|
1130
|
+
readonly name: string;
|
|
1131
|
+
|
|
1132
|
+
/** Logical graph traversal helpers scoped to this observer */
|
|
1133
|
+
traverse: LogicalTraversal;
|
|
1134
|
+
|
|
1135
|
+
/** Checks if a node exists and is visible to this observer */
|
|
1136
|
+
hasNode(nodeId: string): Promise<boolean>;
|
|
1137
|
+
|
|
1138
|
+
/** Gets all visible nodes that match the observer pattern */
|
|
1139
|
+
getNodes(): Promise<string[]>;
|
|
1140
|
+
|
|
1141
|
+
/** Gets filtered properties for a visible node (null if hidden or missing) */
|
|
1142
|
+
getNodeProps(nodeId: string): Promise<Map<string, unknown> | null>;
|
|
1143
|
+
|
|
1144
|
+
/** Gets all visible edges (both endpoints must match the observer pattern) */
|
|
1145
|
+
getEdges(): Promise<Array<{ from: string; to: string; label: string; props: Record<string, unknown> }>>;
|
|
1146
|
+
|
|
1147
|
+
/** Creates a fluent query builder operating on the filtered view */
|
|
1148
|
+
query(): QueryBuilder;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* Breakdown of MDL translation cost components.
|
|
1153
|
+
*/
|
|
1154
|
+
export interface TranslationCostBreakdown {
|
|
1155
|
+
/** Fraction of A's nodes not visible to B */
|
|
1156
|
+
nodeLoss: number;
|
|
1157
|
+
/** Fraction of A's edges not visible to B */
|
|
1158
|
+
edgeLoss: number;
|
|
1159
|
+
/** Fraction of A's properties not visible to B */
|
|
1160
|
+
propLoss: number;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* Result of a directed MDL translation cost computation.
|
|
1165
|
+
*/
|
|
1166
|
+
export interface TranslationCostResult {
|
|
1167
|
+
/** Weighted cost normalized to [0, 1] */
|
|
1168
|
+
cost: number;
|
|
1169
|
+
/** Per-component breakdown */
|
|
1170
|
+
breakdown: TranslationCostBreakdown;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
/**
|
|
1174
|
+
* Computes the directed MDL translation cost from observer A to observer B.
|
|
1175
|
+
*
|
|
1176
|
+
* @param configA - Observer configuration for A
|
|
1177
|
+
* @param configB - Observer configuration for B
|
|
1178
|
+
* @param state - WarpStateV5 materialized state
|
|
1179
|
+
* @see Paper IV, Section 4 -- Directed rulial cost
|
|
1180
|
+
*/
|
|
1181
|
+
export function computeTranslationCost(
|
|
1182
|
+
configA: ObserverConfig,
|
|
1183
|
+
configB: ObserverConfig,
|
|
1184
|
+
state: WarpStateV5
|
|
1185
|
+
): TranslationCostResult;
|
|
1186
|
+
|
|
1187
|
+
// ============================================================================
|
|
1188
|
+
// State Diff (PULSE subscriptions)
|
|
1189
|
+
// ============================================================================
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Edge change in a state diff.
|
|
1193
|
+
*/
|
|
1194
|
+
export interface EdgeChange {
|
|
1195
|
+
from: string;
|
|
1196
|
+
to: string;
|
|
1197
|
+
label: string;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
/**
|
|
1201
|
+
* Property set/changed entry in a state diff.
|
|
1202
|
+
*/
|
|
1203
|
+
export interface PropSet {
|
|
1204
|
+
key: string;
|
|
1205
|
+
nodeId: string;
|
|
1206
|
+
propKey: string;
|
|
1207
|
+
oldValue: unknown;
|
|
1208
|
+
newValue: unknown;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
/**
|
|
1212
|
+
* Property removed entry in a state diff.
|
|
1213
|
+
*/
|
|
1214
|
+
export interface PropRemoved {
|
|
1215
|
+
key: string;
|
|
1216
|
+
nodeId: string;
|
|
1217
|
+
propKey: string;
|
|
1218
|
+
oldValue: unknown;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* Deterministic diff between two materialized states.
|
|
1223
|
+
*/
|
|
1224
|
+
export interface StateDiffResult {
|
|
1225
|
+
nodes: { added: string[]; removed: string[] };
|
|
1226
|
+
edges: { added: EdgeChange[]; removed: EdgeChange[] };
|
|
1227
|
+
props: { set: PropSet[]; removed: PropRemoved[] };
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
// ============================================================================
|
|
1231
|
+
// Temporal Query (Paper IV CTL* operators)
|
|
1232
|
+
// ============================================================================
|
|
1233
|
+
|
|
1234
|
+
/**
|
|
1235
|
+
* Node snapshot passed to temporal predicates.
|
|
1236
|
+
*/
|
|
1237
|
+
export interface TemporalNodeSnapshot {
|
|
1238
|
+
id: string;
|
|
1239
|
+
exists: boolean;
|
|
1240
|
+
props: Record<string, unknown>;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* CTL*-style temporal operators over WARP graph history.
|
|
1245
|
+
*/
|
|
1246
|
+
export interface TemporalQuery {
|
|
1247
|
+
/** True iff predicate holds at every tick since `since` where the node exists. */
|
|
1248
|
+
always(
|
|
1249
|
+
nodeId: string,
|
|
1250
|
+
predicate: (snapshot: TemporalNodeSnapshot) => boolean,
|
|
1251
|
+
options?: { since?: number },
|
|
1252
|
+
): Promise<boolean>;
|
|
1253
|
+
|
|
1254
|
+
/** True iff predicate holds at some tick since `since`. */
|
|
1255
|
+
eventually(
|
|
1256
|
+
nodeId: string,
|
|
1257
|
+
predicate: (snapshot: TemporalNodeSnapshot) => boolean,
|
|
1258
|
+
options?: { since?: number },
|
|
1259
|
+
): Promise<boolean>;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// ============================================================================
|
|
1263
|
+
// Writer & PatchSession
|
|
1264
|
+
// ============================================================================
|
|
1265
|
+
|
|
1266
|
+
/**
|
|
1267
|
+
* Fluent patch session for building and committing graph mutations.
|
|
1268
|
+
*/
|
|
1269
|
+
export class PatchSession {
|
|
1270
|
+
/** Adds a node to the graph. */
|
|
1271
|
+
addNode(nodeId: string): this;
|
|
1272
|
+
/** Removes a node from the graph. */
|
|
1273
|
+
removeNode(nodeId: string): this;
|
|
1274
|
+
/** Adds an edge between two nodes. */
|
|
1275
|
+
addEdge(from: string, to: string, label: string): this;
|
|
1276
|
+
/** Removes an edge between two nodes. */
|
|
1277
|
+
removeEdge(from: string, to: string, label: string): this;
|
|
1278
|
+
/** Sets a property on a node. */
|
|
1279
|
+
setProperty(nodeId: string, key: string, value: unknown): this;
|
|
1280
|
+
/** Builds the patch object without committing. */
|
|
1281
|
+
build(): unknown;
|
|
1282
|
+
/** Commits the patch with CAS protection. */
|
|
1283
|
+
commit(): Promise<string>;
|
|
1284
|
+
/** Number of operations in this patch. */
|
|
1285
|
+
readonly opCount: number;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Writer - WARP writer abstraction for safe graph mutations.
|
|
1290
|
+
*/
|
|
1291
|
+
export class Writer {
|
|
1292
|
+
/** The writer's ID. */
|
|
1293
|
+
readonly writerId: string;
|
|
1294
|
+
/** The graph namespace. */
|
|
1295
|
+
readonly graphName: string;
|
|
1296
|
+
/** Gets the current writer head SHA. */
|
|
1297
|
+
head(): Promise<string | null>;
|
|
1298
|
+
/** Begins a new patch session. */
|
|
1299
|
+
beginPatch(): Promise<PatchSession>;
|
|
1300
|
+
/** Builds and commits a patch in one call. */
|
|
1301
|
+
commitPatch(build: (p: PatchSession) => void | Promise<void>): Promise<string>;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
/**
|
|
1305
|
+
* Error class for Writer operations.
|
|
1306
|
+
*/
|
|
1307
|
+
export class WriterError extends Error {
|
|
1308
|
+
readonly name: 'WriterError';
|
|
1309
|
+
readonly code: string;
|
|
1310
|
+
readonly cause?: Error;
|
|
1311
|
+
|
|
1312
|
+
constructor(code: string, message: string, cause?: Error);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// ============================================================================
|
|
1316
|
+
// GC Types
|
|
1317
|
+
// ============================================================================
|
|
1318
|
+
|
|
1319
|
+
/**
|
|
1320
|
+
* GC policy configuration.
|
|
1321
|
+
*/
|
|
1322
|
+
export interface GCPolicyConfig {
|
|
1323
|
+
enabled: boolean;
|
|
1324
|
+
tombstoneRatioThreshold: number;
|
|
1325
|
+
entryCountThreshold: number;
|
|
1326
|
+
minPatchesSinceCompaction: number;
|
|
1327
|
+
maxTimeSinceCompaction: number;
|
|
1328
|
+
compactOnCheckpoint: boolean;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
/**
|
|
1332
|
+
* Result of a GC execution.
|
|
1333
|
+
*/
|
|
1334
|
+
export interface GCExecuteResult {
|
|
1335
|
+
nodesCompacted: number;
|
|
1336
|
+
edgesCompacted: number;
|
|
1337
|
+
tombstonesRemoved: number;
|
|
1338
|
+
durationMs: number;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* GC metrics for the cached state.
|
|
1343
|
+
*/
|
|
1344
|
+
export interface GCMetrics {
|
|
1345
|
+
nodeCount: number;
|
|
1346
|
+
edgeCount: number;
|
|
1347
|
+
tombstoneCount: number;
|
|
1348
|
+
tombstoneRatio: number;
|
|
1349
|
+
patchesSinceCompaction: number;
|
|
1350
|
+
lastCompactionTime: number;
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
/**
|
|
1354
|
+
* Result of maybeRunGC().
|
|
1355
|
+
*/
|
|
1356
|
+
export interface MaybeGCResult {
|
|
1357
|
+
ran: boolean;
|
|
1358
|
+
result: GCExecuteResult | null;
|
|
1359
|
+
reasons: string[];
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
// ============================================================================
|
|
1363
|
+
// Sync Protocol Types
|
|
1364
|
+
// ============================================================================
|
|
1365
|
+
|
|
1366
|
+
/**
|
|
1367
|
+
* Sync request message.
|
|
1368
|
+
*/
|
|
1369
|
+
export interface SyncRequest {
|
|
1370
|
+
type: 'sync-request';
|
|
1371
|
+
frontier: Record<string, string>;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
/**
|
|
1375
|
+
* Sync response message.
|
|
1376
|
+
*/
|
|
1377
|
+
export interface SyncResponse {
|
|
1378
|
+
type: 'sync-response';
|
|
1379
|
+
frontier: Record<string, string>;
|
|
1380
|
+
patches: Array<{ writerId: string; sha: string; patch: unknown }>;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
/**
|
|
1384
|
+
* Result of applySyncResponse().
|
|
1385
|
+
*/
|
|
1386
|
+
export interface ApplySyncResult {
|
|
1387
|
+
state: WarpStateV5;
|
|
1388
|
+
frontier: Map<string, number>;
|
|
1389
|
+
applied: number;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
// ============================================================================
|
|
1393
|
+
// Status snapshot
|
|
1394
|
+
// ============================================================================
|
|
1395
|
+
|
|
1396
|
+
/**
|
|
1397
|
+
* Lightweight status snapshot of the graph.
|
|
1398
|
+
*/
|
|
1399
|
+
export interface WarpGraphStatus {
|
|
1400
|
+
cachedState: 'fresh' | 'stale' | 'none';
|
|
1401
|
+
patchesSinceCheckpoint: number;
|
|
1402
|
+
tombstoneRatio: number;
|
|
1403
|
+
writers: number;
|
|
1404
|
+
frontier: Record<string, string>;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
// ============================================================================
|
|
1408
|
+
// Join Receipt
|
|
1409
|
+
// ============================================================================
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* Receipt from a join (CRDT merge) operation.
|
|
1413
|
+
*/
|
|
1414
|
+
export interface JoinReceipt {
|
|
1415
|
+
nodesAdded: number;
|
|
1416
|
+
nodesRemoved: number;
|
|
1417
|
+
edgesAdded: number;
|
|
1418
|
+
edgesRemoved: number;
|
|
1419
|
+
propsChanged: number;
|
|
1420
|
+
frontierMerged: boolean;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
/**
|
|
1424
|
+
* Multi-writer graph database using WARP CRDT protocol.
|
|
1425
|
+
*
|
|
1426
|
+
* V7 primary API - uses patch-based storage with OR-Set semantics.
|
|
1427
|
+
* See docs/V7_CONTRACT.md for architecture details.
|
|
1428
|
+
*/
|
|
1429
|
+
export default class WarpGraph {
|
|
1430
|
+
/**
|
|
1431
|
+
* Opens or creates a multi-writer graph.
|
|
1432
|
+
*/
|
|
1433
|
+
static open(options: {
|
|
1434
|
+
graphName: string;
|
|
1435
|
+
persistence: GraphPersistencePort;
|
|
1436
|
+
writerId: string;
|
|
1437
|
+
logger?: LoggerPort;
|
|
1438
|
+
adjacencyCacheSize?: number;
|
|
1439
|
+
gcPolicy?: {
|
|
1440
|
+
enabled?: boolean;
|
|
1441
|
+
tombstoneRatioThreshold?: number;
|
|
1442
|
+
entryCountThreshold?: number;
|
|
1443
|
+
minPatchesSinceCompaction?: number;
|
|
1444
|
+
maxTimeSinceCompaction?: number;
|
|
1445
|
+
compactOnCheckpoint?: boolean;
|
|
1446
|
+
};
|
|
1447
|
+
checkpointPolicy?: { every: number };
|
|
1448
|
+
autoMaterialize?: boolean;
|
|
1449
|
+
onDeleteWithData?: 'reject' | 'cascade' | 'warn';
|
|
1450
|
+
clock?: ClockPort;
|
|
1451
|
+
crypto?: CryptoPort;
|
|
1452
|
+
codec?: unknown;
|
|
1453
|
+
}): Promise<WarpGraph>;
|
|
1454
|
+
|
|
1455
|
+
/**
|
|
1456
|
+
* The graph namespace.
|
|
1457
|
+
*/
|
|
1458
|
+
readonly graphName: string;
|
|
1459
|
+
|
|
1460
|
+
/**
|
|
1461
|
+
* This writer's ID.
|
|
1462
|
+
*/
|
|
1463
|
+
readonly writerId: string;
|
|
1464
|
+
|
|
1465
|
+
/**
|
|
1466
|
+
* Creates a new patch for adding operations.
|
|
1467
|
+
*/
|
|
1468
|
+
createPatch(): Promise<unknown>;
|
|
1469
|
+
|
|
1470
|
+
/**
|
|
1471
|
+
* Returns patches from a writer's ref chain.
|
|
1472
|
+
*/
|
|
1473
|
+
getWriterPatches(
|
|
1474
|
+
writerId: string,
|
|
1475
|
+
stopAtSha?: string | null
|
|
1476
|
+
): Promise<Array<{ patch: unknown; sha: string }>>;
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* Gets all visible nodes in the materialized state.
|
|
1480
|
+
*/
|
|
1481
|
+
getNodes(): Promise<string[]>;
|
|
1482
|
+
|
|
1483
|
+
/**
|
|
1484
|
+
* Gets all visible edges in the materialized state.
|
|
1485
|
+
*/
|
|
1486
|
+
getEdges(): Promise<Array<{ from: string; to: string; label: string; props: Record<string, unknown> }>>;
|
|
1487
|
+
|
|
1488
|
+
/**
|
|
1489
|
+
* Gets all properties for a node from the materialized state.
|
|
1490
|
+
*/
|
|
1491
|
+
getNodeProps(nodeId: string): Promise<Map<string, unknown> | null>;
|
|
1492
|
+
|
|
1493
|
+
/**
|
|
1494
|
+
* Returns the number of property entries in the materialized state.
|
|
1495
|
+
*/
|
|
1496
|
+
getPropertyCount(): Promise<number>;
|
|
1497
|
+
|
|
1498
|
+
/**
|
|
1499
|
+
* Gets all properties for an edge from the materialized state.
|
|
1500
|
+
* Returns null if the edge does not exist or is tombstoned.
|
|
1501
|
+
*/
|
|
1502
|
+
getEdgeProps(from: string, to: string, label: string): Promise<Record<string, unknown> | null>;
|
|
1503
|
+
|
|
1504
|
+
/**
|
|
1505
|
+
* Checks if a node exists in the materialized state.
|
|
1506
|
+
*/
|
|
1507
|
+
hasNode(nodeId: string): Promise<boolean>;
|
|
1508
|
+
|
|
1509
|
+
/**
|
|
1510
|
+
* Gets neighbors of a node from the materialized state.
|
|
1511
|
+
*/
|
|
1512
|
+
neighbors(
|
|
1513
|
+
nodeId: string,
|
|
1514
|
+
direction?: 'outgoing' | 'incoming' | 'both',
|
|
1515
|
+
edgeLabel?: string,
|
|
1516
|
+
): Promise<Array<{ nodeId: string; label: string; direction: 'outgoing' | 'incoming' }>>;
|
|
1517
|
+
|
|
1518
|
+
/**
|
|
1519
|
+
* Discovers all writers that have contributed to this graph.
|
|
1520
|
+
*/
|
|
1521
|
+
discoverWriters(): Promise<string[]>;
|
|
1522
|
+
|
|
1523
|
+
/**
|
|
1524
|
+
* Gets the current frontier (map of writerId to tip SHA).
|
|
1525
|
+
*/
|
|
1526
|
+
getFrontier(): Promise<Map<string, string>>;
|
|
1527
|
+
|
|
1528
|
+
/**
|
|
1529
|
+
* Checks whether any writer tip has changed since the last materialize.
|
|
1530
|
+
* O(writers) comparison — cheap "has anything changed?" check without materialization.
|
|
1531
|
+
*/
|
|
1532
|
+
hasFrontierChanged(): Promise<boolean>;
|
|
1533
|
+
|
|
1534
|
+
/**
|
|
1535
|
+
* Creates a checkpoint snapshot of the current materialized state.
|
|
1536
|
+
*/
|
|
1537
|
+
createCheckpoint(): Promise<string>;
|
|
1538
|
+
|
|
1539
|
+
/**
|
|
1540
|
+
* Materializes graph state from a checkpoint, applying incremental patches.
|
|
1541
|
+
*/
|
|
1542
|
+
materializeAt(checkpointSha: string): Promise<unknown>;
|
|
1543
|
+
|
|
1544
|
+
/**
|
|
1545
|
+
* Logical graph traversal helpers.
|
|
1546
|
+
*/
|
|
1547
|
+
traverse: LogicalTraversal;
|
|
1548
|
+
|
|
1549
|
+
/**
|
|
1550
|
+
* Creates a fluent query builder for the logical graph.
|
|
1551
|
+
*/
|
|
1552
|
+
query(): QueryBuilder;
|
|
1553
|
+
|
|
1554
|
+
/**
|
|
1555
|
+
* Creates a read-only observer view of the current materialized state.
|
|
1556
|
+
*
|
|
1557
|
+
* The observer sees only nodes matching the `match` glob pattern, with
|
|
1558
|
+
* property visibility controlled by `expose` and `redact` lists.
|
|
1559
|
+
* Edges are only visible when both endpoints pass the match filter.
|
|
1560
|
+
*/
|
|
1561
|
+
observer(name: string, config: ObserverConfig): Promise<ObserverView>;
|
|
1562
|
+
|
|
1563
|
+
/**
|
|
1564
|
+
* Computes the directed MDL translation cost from observer A to observer B.
|
|
1565
|
+
*
|
|
1566
|
+
* The cost measures how much information is lost when translating from
|
|
1567
|
+
* A's view to B's view. It is asymmetric: cost(A->B) != cost(B->A).
|
|
1568
|
+
*
|
|
1569
|
+
* @see Paper IV, Section 4 -- Directed rulial cost
|
|
1570
|
+
*/
|
|
1571
|
+
translationCost(configA: ObserverConfig, configB: ObserverConfig): Promise<TranslationCostResult>;
|
|
1572
|
+
|
|
1573
|
+
/**
|
|
1574
|
+
* Materializes the current graph state from all patches.
|
|
1575
|
+
*/
|
|
1576
|
+
materialize(): Promise<unknown>;
|
|
1577
|
+
|
|
1578
|
+
/**
|
|
1579
|
+
* Starts a built-in sync server for this graph.
|
|
1580
|
+
*/
|
|
1581
|
+
serve(options: {
|
|
1582
|
+
port: number;
|
|
1583
|
+
host?: string;
|
|
1584
|
+
path?: string;
|
|
1585
|
+
maxRequestBytes?: number;
|
|
1586
|
+
httpPort: HttpServerPort;
|
|
1587
|
+
}): Promise<{ close(): Promise<void>; url: string }>;
|
|
1588
|
+
|
|
1589
|
+
/**
|
|
1590
|
+
* Syncs with a remote peer (HTTP URL or another WarpGraph instance).
|
|
1591
|
+
*/
|
|
1592
|
+
syncWith(remote: string | WarpGraph, options?: {
|
|
1593
|
+
path?: string;
|
|
1594
|
+
retries?: number;
|
|
1595
|
+
baseDelayMs?: number;
|
|
1596
|
+
maxDelayMs?: number;
|
|
1597
|
+
timeoutMs?: number;
|
|
1598
|
+
signal?: AbortSignal;
|
|
1599
|
+
onStatus?: (event: {
|
|
1600
|
+
type: string;
|
|
1601
|
+
attempt: number;
|
|
1602
|
+
durationMs?: number;
|
|
1603
|
+
status?: number;
|
|
1604
|
+
error?: Error;
|
|
1605
|
+
}) => void;
|
|
1606
|
+
}): Promise<{ applied: number; attempts: number }>;
|
|
1607
|
+
|
|
1608
|
+
/**
|
|
1609
|
+
* Creates a fork of this graph at a specific point in a writer's history.
|
|
1610
|
+
*
|
|
1611
|
+
* A fork creates a new WarpGraph instance that shares history up to the
|
|
1612
|
+
* specified patch SHA. Due to Git's content-addressed storage, the shared
|
|
1613
|
+
* history is automatically deduplicated.
|
|
1614
|
+
*/
|
|
1615
|
+
fork(options: {
|
|
1616
|
+
/** Writer ID whose chain to fork from */
|
|
1617
|
+
from: string;
|
|
1618
|
+
/** Patch SHA to fork at (must be in the writer's chain) */
|
|
1619
|
+
at: string;
|
|
1620
|
+
/** Name for the forked graph. Defaults to `<graphName>-fork-<timestamp>` */
|
|
1621
|
+
forkName?: string;
|
|
1622
|
+
/** Writer ID for the fork. Defaults to a new canonical ID. */
|
|
1623
|
+
forkWriterId?: string;
|
|
1624
|
+
}): Promise<WarpGraph>;
|
|
1625
|
+
|
|
1626
|
+
/**
|
|
1627
|
+
* Creates a wormhole compressing a range of patches.
|
|
1628
|
+
*
|
|
1629
|
+
* The range is specified by two patch SHAs from the same writer. The `fromSha`
|
|
1630
|
+
* must be an ancestor of `toSha` in the writer's patch chain.
|
|
1631
|
+
*/
|
|
1632
|
+
createWormhole(fromSha: string, toSha: string): Promise<WormholeEdge>;
|
|
1633
|
+
|
|
1634
|
+
/**
|
|
1635
|
+
* Returns patch SHAs that affected a given entity (node or edge).
|
|
1636
|
+
*
|
|
1637
|
+
* If autoMaterialize is enabled, automatically materializes if state is dirty.
|
|
1638
|
+
*
|
|
1639
|
+
* @throws {QueryError} If no provenance index exists and autoMaterialize is off
|
|
1640
|
+
*/
|
|
1641
|
+
patchesFor(entityId: string): Promise<string[]>;
|
|
1642
|
+
|
|
1643
|
+
/**
|
|
1644
|
+
* Materializes only the backward causal cone for a specific node.
|
|
1645
|
+
*
|
|
1646
|
+
* Uses the provenance index to identify which patches contributed to the
|
|
1647
|
+
* target node's state, then replays only those patches.
|
|
1648
|
+
*
|
|
1649
|
+
* @throws {QueryError} If no provenance index exists (call materialize first)
|
|
1650
|
+
*/
|
|
1651
|
+
materializeSlice(nodeId: string, options?: {
|
|
1652
|
+
/** If true, collect tick receipts */
|
|
1653
|
+
receipts?: boolean;
|
|
1654
|
+
}): Promise<{
|
|
1655
|
+
state: WarpStateV5;
|
|
1656
|
+
patchCount: number;
|
|
1657
|
+
receipts?: TickReceipt[];
|
|
1658
|
+
}>;
|
|
1659
|
+
|
|
1660
|
+
/**
|
|
1661
|
+
* The provenance index mapping entities to contributing patches.
|
|
1662
|
+
* Available after materialize() has been called.
|
|
1663
|
+
*/
|
|
1664
|
+
readonly provenanceIndex: ProvenanceIndex | null;
|
|
1665
|
+
|
|
1666
|
+
/** Gets the persistence adapter. */
|
|
1667
|
+
get persistence(): GraphPersistencePort;
|
|
1668
|
+
|
|
1669
|
+
/** Gets the onDeleteWithData policy. */
|
|
1670
|
+
get onDeleteWithData(): 'reject' | 'cascade' | 'warn';
|
|
1671
|
+
|
|
1672
|
+
/** Synchronous CRDT merge of another state into the cached state. */
|
|
1673
|
+
join(otherState: WarpStateV5): { state: WarpStateV5; receipt: JoinReceipt };
|
|
1674
|
+
|
|
1675
|
+
/** Creates an octopus anchor commit recording all writer tips. */
|
|
1676
|
+
syncCoverage(): Promise<void>;
|
|
1677
|
+
|
|
1678
|
+
/** Returns a lightweight status snapshot of the graph. */
|
|
1679
|
+
status(): Promise<WarpGraphStatus>;
|
|
1680
|
+
|
|
1681
|
+
/** Subscribes to graph changes after each materialize(). */
|
|
1682
|
+
subscribe(options: {
|
|
1683
|
+
onChange: (diff: StateDiffResult) => void;
|
|
1684
|
+
onError?: (error: Error) => void;
|
|
1685
|
+
replay?: boolean;
|
|
1686
|
+
}): { unsubscribe: () => void };
|
|
1687
|
+
|
|
1688
|
+
/** Filtered watcher that only fires for changes matching a glob pattern. */
|
|
1689
|
+
watch(
|
|
1690
|
+
pattern: string,
|
|
1691
|
+
options: {
|
|
1692
|
+
onChange: (diff: StateDiffResult) => void;
|
|
1693
|
+
onError?: (error: Error) => void;
|
|
1694
|
+
poll?: number;
|
|
1695
|
+
},
|
|
1696
|
+
): { unsubscribe: () => void };
|
|
1697
|
+
|
|
1698
|
+
/** Creates a sync request containing the local frontier. */
|
|
1699
|
+
createSyncRequest(): Promise<SyncRequest>;
|
|
1700
|
+
|
|
1701
|
+
/** Processes an incoming sync request and returns patches the requester needs. */
|
|
1702
|
+
processSyncRequest(request: SyncRequest): Promise<SyncResponse>;
|
|
1703
|
+
|
|
1704
|
+
/** Applies a sync response to the cached state. */
|
|
1705
|
+
applySyncResponse(response: SyncResponse): ApplySyncResult;
|
|
1706
|
+
|
|
1707
|
+
/** Checks if sync is needed with a remote frontier. */
|
|
1708
|
+
syncNeeded(remoteFrontier: Map<string, string>): Promise<boolean>;
|
|
1709
|
+
|
|
1710
|
+
/** Gets or creates a Writer, optionally resolving from git config. */
|
|
1711
|
+
writer(writerId?: string): Promise<Writer>;
|
|
1712
|
+
|
|
1713
|
+
/**
|
|
1714
|
+
* Creates a new Writer with a fresh canonical ID.
|
|
1715
|
+
* @deprecated Use writer() or writer(id) instead.
|
|
1716
|
+
*/
|
|
1717
|
+
createWriter(opts?: {
|
|
1718
|
+
persist?: 'config' | 'none';
|
|
1719
|
+
alias?: string;
|
|
1720
|
+
}): Promise<Writer>;
|
|
1721
|
+
|
|
1722
|
+
/** Checks GC thresholds and runs GC if needed. */
|
|
1723
|
+
maybeRunGC(): MaybeGCResult;
|
|
1724
|
+
|
|
1725
|
+
/** Explicitly runs GC on the cached state. */
|
|
1726
|
+
runGC(): GCExecuteResult;
|
|
1727
|
+
|
|
1728
|
+
/** Gets current GC metrics for the cached state. */
|
|
1729
|
+
getGCMetrics(): GCMetrics | null;
|
|
1730
|
+
|
|
1731
|
+
/** Gets the current GC policy configuration. */
|
|
1732
|
+
get gcPolicy(): GCPolicyConfig;
|
|
1733
|
+
|
|
1734
|
+
/** CTL*-style temporal operators over graph history. */
|
|
1735
|
+
get temporal(): TemporalQuery;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
/**
|
|
1739
|
+
* Index mapping entities (nodes/edges) to the patches that affected them.
|
|
1740
|
+
*
|
|
1741
|
+
* Used for provenance queries and slice materialization. Implements HG/IO/2
|
|
1742
|
+
* from the AION Foundations Series, enabling quick answers to "which patches
|
|
1743
|
+
* affected node X?" without replaying all patches.
|
|
1744
|
+
*/
|
|
1745
|
+
export class ProvenanceIndex {
|
|
1746
|
+
constructor(initialIndex?: Map<string, Set<string>>);
|
|
1747
|
+
|
|
1748
|
+
/**
|
|
1749
|
+
* Creates an empty ProvenanceIndex.
|
|
1750
|
+
*/
|
|
1751
|
+
static empty(): ProvenanceIndex;
|
|
1752
|
+
|
|
1753
|
+
/**
|
|
1754
|
+
* Adds a patch to the index, recording which entities it read/wrote.
|
|
1755
|
+
* Both reads and writes are indexed because both indicate the patch
|
|
1756
|
+
* "affected" the entity.
|
|
1757
|
+
*
|
|
1758
|
+
* @returns This index for chaining
|
|
1759
|
+
*/
|
|
1760
|
+
addPatch(patchSha: string, reads?: string[], writes?: string[]): this;
|
|
1761
|
+
|
|
1762
|
+
/**
|
|
1763
|
+
* Returns patch SHAs that affected a given entity.
|
|
1764
|
+
* The returned array is sorted alphabetically for determinism.
|
|
1765
|
+
*/
|
|
1766
|
+
patchesFor(entityId: string): string[];
|
|
1767
|
+
|
|
1768
|
+
/**
|
|
1769
|
+
* Returns whether the index has any entries for a given entity.
|
|
1770
|
+
*/
|
|
1771
|
+
has(entityId: string): boolean;
|
|
1772
|
+
|
|
1773
|
+
/**
|
|
1774
|
+
* Number of entities tracked in the index.
|
|
1775
|
+
*/
|
|
1776
|
+
readonly size: number;
|
|
1777
|
+
|
|
1778
|
+
/**
|
|
1779
|
+
* Returns all entity IDs in the index, sorted alphabetically.
|
|
1780
|
+
*/
|
|
1781
|
+
entities(): string[];
|
|
1782
|
+
|
|
1783
|
+
/**
|
|
1784
|
+
* Clears all entries from the index.
|
|
1785
|
+
*
|
|
1786
|
+
* @returns This index for chaining
|
|
1787
|
+
*/
|
|
1788
|
+
clear(): this;
|
|
1789
|
+
|
|
1790
|
+
/**
|
|
1791
|
+
* Merges another index into this one. All entries from the other index
|
|
1792
|
+
* are added to this index.
|
|
1793
|
+
*
|
|
1794
|
+
* @returns This index for chaining
|
|
1795
|
+
*/
|
|
1796
|
+
merge(other: ProvenanceIndex): this;
|
|
1797
|
+
|
|
1798
|
+
/**
|
|
1799
|
+
* Creates a deep clone of this index.
|
|
1800
|
+
*/
|
|
1801
|
+
clone(): ProvenanceIndex;
|
|
1802
|
+
|
|
1803
|
+
/**
|
|
1804
|
+
* Serializes the index to CBOR format for checkpoint storage.
|
|
1805
|
+
*/
|
|
1806
|
+
serialize(): Buffer;
|
|
1807
|
+
|
|
1808
|
+
/**
|
|
1809
|
+
* Deserializes an index from CBOR format.
|
|
1810
|
+
*
|
|
1811
|
+
* @throws Error if the buffer contains an unsupported version
|
|
1812
|
+
*/
|
|
1813
|
+
static deserialize(buffer: Buffer): ProvenanceIndex;
|
|
1814
|
+
|
|
1815
|
+
/**
|
|
1816
|
+
* Returns a JSON-serializable representation of this index.
|
|
1817
|
+
*/
|
|
1818
|
+
toJSON(): { version: number; entries: Array<[string, string[]]> };
|
|
1819
|
+
|
|
1820
|
+
/**
|
|
1821
|
+
* Creates a ProvenanceIndex from a JSON representation.
|
|
1822
|
+
*
|
|
1823
|
+
* @throws Error if the JSON contains an unsupported version
|
|
1824
|
+
*/
|
|
1825
|
+
static fromJSON(json: { version: number; entries: Array<[string, string[]]> }): ProvenanceIndex;
|
|
1826
|
+
|
|
1827
|
+
/**
|
|
1828
|
+
* Iterator over [entityId, patchShas[]] pairs in deterministic order.
|
|
1829
|
+
*/
|
|
1830
|
+
[Symbol.iterator](): IterableIterator<[string, string[]]>;
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
/**
|
|
1834
|
+
* Error thrown when a fork operation fails.
|
|
1835
|
+
*/
|
|
1836
|
+
export class ForkError extends Error {
|
|
1837
|
+
readonly name: 'ForkError';
|
|
1838
|
+
readonly code: string;
|
|
1839
|
+
readonly context: Record<string, unknown>;
|
|
1840
|
+
|
|
1841
|
+
constructor(message: string, options?: {
|
|
1842
|
+
code?: string;
|
|
1843
|
+
context?: Record<string, unknown>;
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
// ============================================================================
|
|
1848
|
+
// Tick Receipts (LIGHTHOUSE)
|
|
1849
|
+
// ============================================================================
|
|
1850
|
+
|
|
1851
|
+
/**
|
|
1852
|
+
* Valid operation types that can appear in a tick receipt.
|
|
1853
|
+
*/
|
|
1854
|
+
export type TickReceiptOpType = 'NodeAdd' | 'NodeTombstone' | 'EdgeAdd' | 'EdgeTombstone' | 'PropSet' | 'BlobValue';
|
|
1855
|
+
|
|
1856
|
+
/**
|
|
1857
|
+
* Valid result values for an operation outcome.
|
|
1858
|
+
*/
|
|
1859
|
+
export type TickReceiptResult = 'applied' | 'superseded' | 'redundant';
|
|
1860
|
+
|
|
1861
|
+
/**
|
|
1862
|
+
* Per-operation outcome within a tick receipt.
|
|
1863
|
+
*/
|
|
1864
|
+
export interface OpOutcome {
|
|
1865
|
+
/** Operation type */
|
|
1866
|
+
readonly op: TickReceiptOpType;
|
|
1867
|
+
/** Node ID or edge key */
|
|
1868
|
+
readonly target: string;
|
|
1869
|
+
/** Outcome of the operation */
|
|
1870
|
+
readonly result: TickReceiptResult;
|
|
1871
|
+
/** Human-readable explanation */
|
|
1872
|
+
readonly reason?: string;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
/**
|
|
1876
|
+
* Immutable record of per-operation outcomes from a single patch application.
|
|
1877
|
+
*
|
|
1878
|
+
* @see Paper II, Section 5 -- Tick receipts
|
|
1879
|
+
*/
|
|
1880
|
+
export interface TickReceipt {
|
|
1881
|
+
/** SHA of the patch commit */
|
|
1882
|
+
readonly patchSha: string;
|
|
1883
|
+
/** Writer ID that produced the patch */
|
|
1884
|
+
readonly writer: string;
|
|
1885
|
+
/** Lamport timestamp of the patch */
|
|
1886
|
+
readonly lamport: number;
|
|
1887
|
+
/** Per-operation outcomes (frozen) */
|
|
1888
|
+
readonly ops: readonly Readonly<OpOutcome>[];
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
/**
|
|
1892
|
+
* Creates an immutable TickReceipt.
|
|
1893
|
+
*
|
|
1894
|
+
* @throws {Error} If any parameter is invalid
|
|
1895
|
+
*/
|
|
1896
|
+
export function createTickReceipt(params: {
|
|
1897
|
+
patchSha: string;
|
|
1898
|
+
writer: string;
|
|
1899
|
+
lamport: number;
|
|
1900
|
+
ops: Array<{
|
|
1901
|
+
op: TickReceiptOpType;
|
|
1902
|
+
target: string;
|
|
1903
|
+
result: TickReceiptResult;
|
|
1904
|
+
reason?: string;
|
|
1905
|
+
}>;
|
|
1906
|
+
}): Readonly<TickReceipt>;
|
|
1907
|
+
|
|
1908
|
+
/**
|
|
1909
|
+
* Produces a deterministic JSON string for a TickReceipt (sorted keys at every level).
|
|
1910
|
+
*/
|
|
1911
|
+
export function tickReceiptCanonicalJson(receipt: TickReceipt): string;
|
|
1912
|
+
|
|
1913
|
+
/**
|
|
1914
|
+
* Valid operation types that can appear in a tick receipt.
|
|
1915
|
+
*/
|
|
1916
|
+
export const TICK_RECEIPT_OP_TYPES: readonly TickReceiptOpType[];
|
|
1917
|
+
|
|
1918
|
+
/**
|
|
1919
|
+
* Valid result values for an operation outcome.
|
|
1920
|
+
*/
|
|
1921
|
+
export const TICK_RECEIPT_RESULT_TYPES: readonly TickReceiptResult[];
|
|
1922
|
+
|
|
1923
|
+
// ============================================================================
|
|
1924
|
+
// WARP Type Constructors
|
|
1925
|
+
// ============================================================================
|
|
1926
|
+
|
|
1927
|
+
/** Operation: node add */
|
|
1928
|
+
export interface OpNodeAdd {
|
|
1929
|
+
readonly type: 'NodeAdd';
|
|
1930
|
+
readonly node: string;
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/** Operation: node tombstone */
|
|
1934
|
+
export interface OpNodeTombstone {
|
|
1935
|
+
readonly type: 'NodeTombstone';
|
|
1936
|
+
readonly node: string;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
/** Operation: edge add */
|
|
1940
|
+
export interface OpEdgeAdd {
|
|
1941
|
+
readonly type: 'EdgeAdd';
|
|
1942
|
+
readonly from: string;
|
|
1943
|
+
readonly to: string;
|
|
1944
|
+
readonly label: string;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
/** Operation: edge tombstone */
|
|
1948
|
+
export interface OpEdgeTombstone {
|
|
1949
|
+
readonly type: 'EdgeTombstone';
|
|
1950
|
+
readonly from: string;
|
|
1951
|
+
readonly to: string;
|
|
1952
|
+
readonly label: string;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
/** Operation: property set */
|
|
1956
|
+
export interface OpPropSet {
|
|
1957
|
+
readonly type: 'PropSet';
|
|
1958
|
+
readonly node: string;
|
|
1959
|
+
readonly key: string;
|
|
1960
|
+
readonly value: ValueRef;
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
/** Inline value reference */
|
|
1964
|
+
export interface ValueRefInline {
|
|
1965
|
+
readonly type: 'inline';
|
|
1966
|
+
readonly value: unknown;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
/** Blob value reference */
|
|
1970
|
+
export interface ValueRefBlob {
|
|
1971
|
+
readonly type: 'blob';
|
|
1972
|
+
readonly oid: string;
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
/** Value reference -- either inline or blob */
|
|
1976
|
+
export type ValueRef = ValueRefInline | ValueRefBlob;
|
|
1977
|
+
|
|
1978
|
+
/** EventId for total ordering of operations across patches */
|
|
1979
|
+
export interface EventId {
|
|
1980
|
+
readonly lamport: number;
|
|
1981
|
+
readonly writerId: string;
|
|
1982
|
+
readonly patchSha: string;
|
|
1983
|
+
readonly opIndex: number;
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
/** Creates a NodeAdd operation. */
|
|
1987
|
+
export function createNodeAdd(node: string): OpNodeAdd;
|
|
1988
|
+
|
|
1989
|
+
/** Creates a NodeTombstone operation. */
|
|
1990
|
+
export function createNodeTombstone(node: string): OpNodeTombstone;
|
|
1991
|
+
|
|
1992
|
+
/** Creates an EdgeAdd operation. */
|
|
1993
|
+
export function createEdgeAdd(from: string, to: string, label: string): OpEdgeAdd;
|
|
1994
|
+
|
|
1995
|
+
/** Creates an EdgeTombstone operation. */
|
|
1996
|
+
export function createEdgeTombstone(from: string, to: string, label: string): OpEdgeTombstone;
|
|
1997
|
+
|
|
1998
|
+
/** Creates a PropSet operation. */
|
|
1999
|
+
export function createPropSet(node: string, key: string, value: ValueRef): OpPropSet;
|
|
2000
|
+
|
|
2001
|
+
/** Creates an inline value reference. */
|
|
2002
|
+
export function createInlineValue(value: unknown): ValueRefInline;
|
|
2003
|
+
|
|
2004
|
+
/** Creates a blob value reference. */
|
|
2005
|
+
export function createBlobValue(oid: string): ValueRefBlob;
|
|
2006
|
+
|
|
2007
|
+
/** Creates an EventId for total ordering of operations. */
|
|
2008
|
+
export function createEventId(options: {
|
|
2009
|
+
lamport: number;
|
|
2010
|
+
writerId: string;
|
|
2011
|
+
patchSha: string;
|
|
2012
|
+
opIndex: number;
|
|
2013
|
+
}): EventId;
|
|
2014
|
+
|
|
2015
|
+
// ============================================================================
|
|
2016
|
+
// WARP Migration
|
|
2017
|
+
// ============================================================================
|
|
2018
|
+
|
|
2019
|
+
/** Migrates a V4 visible-projection state to a V5 state with ORSet internals. */
|
|
2020
|
+
export function migrateV4toV5(v4State: {
|
|
2021
|
+
nodeAlive: Map<string, { value: boolean }>;
|
|
2022
|
+
edgeAlive: Map<string, { value: boolean }>;
|
|
2023
|
+
prop: Map<string, unknown>;
|
|
2024
|
+
}, migrationWriterId: string): WarpStateV5;
|
|
2025
|
+
|
|
2026
|
+
/**
|
|
2027
|
+
* A patch entry in a provenance payload.
|
|
2028
|
+
*/
|
|
2029
|
+
export interface PatchEntry {
|
|
2030
|
+
/** The decoded patch object */
|
|
2031
|
+
patch: {
|
|
2032
|
+
schema: 2 | 3;
|
|
2033
|
+
writer: string;
|
|
2034
|
+
lamport: number;
|
|
2035
|
+
context: Record<string, number> | Map<string, number>;
|
|
2036
|
+
ops: unknown[];
|
|
2037
|
+
/** Node/edge IDs read by this patch (V2 provenance) */
|
|
2038
|
+
reads?: string[];
|
|
2039
|
+
/** Node/edge IDs written by this patch (V2 provenance) */
|
|
2040
|
+
writes?: string[];
|
|
2041
|
+
};
|
|
2042
|
+
/** The Git SHA of the patch commit */
|
|
2043
|
+
sha: string;
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
/**
|
|
2047
|
+
* WARP V5 materialized state.
|
|
2048
|
+
*/
|
|
2049
|
+
export interface WarpStateV5 {
|
|
2050
|
+
nodeAlive: unknown;
|
|
2051
|
+
edgeAlive: unknown;
|
|
2052
|
+
prop: Map<string, unknown>;
|
|
2053
|
+
observedFrontier: Map<string, number>;
|
|
2054
|
+
edgeBirthEvent: Map<string, unknown>;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
/**
|
|
2058
|
+
* ProvenancePayload - Transferable provenance as a monoid.
|
|
2059
|
+
*
|
|
2060
|
+
* Implements the provenance payload from Paper III (Computational Holography):
|
|
2061
|
+
* P = (mu_0, ..., mu_{n-1}) - an ordered sequence of tick patches.
|
|
2062
|
+
*
|
|
2063
|
+
* The payload monoid (Payload, ., epsilon):
|
|
2064
|
+
* - Composition is concatenation
|
|
2065
|
+
* - Identity is empty sequence
|
|
2066
|
+
*
|
|
2067
|
+
* @see Paper III, Section 4 -- Computational Holography
|
|
2068
|
+
*/
|
|
2069
|
+
export class ProvenancePayload {
|
|
2070
|
+
/**
|
|
2071
|
+
* Creates a new ProvenancePayload from an ordered sequence of patches.
|
|
2072
|
+
*
|
|
2073
|
+
* @param patches - Ordered sequence of patch entries
|
|
2074
|
+
* @throws {TypeError} If patches is not an array
|
|
2075
|
+
*/
|
|
2076
|
+
constructor(patches?: PatchEntry[]);
|
|
2077
|
+
|
|
2078
|
+
/**
|
|
2079
|
+
* Returns the identity element of the payload monoid (empty payload).
|
|
2080
|
+
*/
|
|
2081
|
+
static identity(): ProvenancePayload;
|
|
2082
|
+
|
|
2083
|
+
/**
|
|
2084
|
+
* Returns the number of patches in this payload.
|
|
2085
|
+
*/
|
|
2086
|
+
readonly length: number;
|
|
2087
|
+
|
|
2088
|
+
/**
|
|
2089
|
+
* Concatenates this payload with another, forming a new payload.
|
|
2090
|
+
*
|
|
2091
|
+
* @param other - The payload to append
|
|
2092
|
+
* @throws {TypeError} If other is not a ProvenancePayload
|
|
2093
|
+
*/
|
|
2094
|
+
concat(other: ProvenancePayload): ProvenancePayload;
|
|
2095
|
+
|
|
2096
|
+
/**
|
|
2097
|
+
* Replays the payload to produce a materialized state.
|
|
2098
|
+
*
|
|
2099
|
+
* @param initialState - Optional initial state to replay from
|
|
2100
|
+
*/
|
|
2101
|
+
replay(initialState?: WarpStateV5): WarpStateV5;
|
|
2102
|
+
|
|
2103
|
+
/**
|
|
2104
|
+
* Returns the patch entry at the given index.
|
|
2105
|
+
*/
|
|
2106
|
+
at(index: number): PatchEntry | undefined;
|
|
2107
|
+
|
|
2108
|
+
/**
|
|
2109
|
+
* Returns a new payload containing a slice of this payload's patches.
|
|
2110
|
+
*/
|
|
2111
|
+
slice(start?: number, end?: number): ProvenancePayload;
|
|
2112
|
+
|
|
2113
|
+
/**
|
|
2114
|
+
* Returns an iterator over the patch entries.
|
|
2115
|
+
*/
|
|
2116
|
+
[Symbol.iterator](): Iterator<PatchEntry>;
|
|
2117
|
+
|
|
2118
|
+
/**
|
|
2119
|
+
* Returns a JSON-serializable representation of this payload.
|
|
2120
|
+
*/
|
|
2121
|
+
toJSON(): PatchEntry[];
|
|
2122
|
+
|
|
2123
|
+
/**
|
|
2124
|
+
* Creates a ProvenancePayload from a JSON-serialized array.
|
|
2125
|
+
*/
|
|
2126
|
+
static fromJSON(json: PatchEntry[]): ProvenancePayload;
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
// ============================================================================
|
|
2130
|
+
// Boundary Transition Records (HOLOGRAM)
|
|
2131
|
+
// ============================================================================
|
|
2132
|
+
|
|
2133
|
+
/**
|
|
2134
|
+
* Boundary Transition Record - Tamper-evident provenance packaging.
|
|
2135
|
+
*
|
|
2136
|
+
* Binds (h_in, h_out, U_0, P, t, kappa) for auditable exchange of graph
|
|
2137
|
+
* segments between parties who don't share full history.
|
|
2138
|
+
*
|
|
2139
|
+
* @see Paper III, Section 4 -- Boundary Transition Records
|
|
2140
|
+
*/
|
|
2141
|
+
export interface BTR {
|
|
2142
|
+
/** BTR format version */
|
|
2143
|
+
readonly version: number;
|
|
2144
|
+
/** Hash of input state (hex SHA-256) */
|
|
2145
|
+
readonly h_in: string;
|
|
2146
|
+
/** Hash of output state (hex SHA-256) */
|
|
2147
|
+
readonly h_out: string;
|
|
2148
|
+
/** Serialized initial state (CBOR) */
|
|
2149
|
+
readonly U_0: Uint8Array;
|
|
2150
|
+
/** Serialized provenance payload */
|
|
2151
|
+
readonly P: PatchEntry[];
|
|
2152
|
+
/** ISO 8601 timestamp */
|
|
2153
|
+
readonly t: string;
|
|
2154
|
+
/** Authentication tag (hex HMAC-SHA256) */
|
|
2155
|
+
readonly kappa: string;
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
/**
|
|
2159
|
+
* Result of BTR verification.
|
|
2160
|
+
*/
|
|
2161
|
+
export interface BTRVerificationResult {
|
|
2162
|
+
/** Whether the BTR is valid */
|
|
2163
|
+
valid: boolean;
|
|
2164
|
+
/** Reason for failure (if invalid) */
|
|
2165
|
+
reason?: string;
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
/**
|
|
2169
|
+
* Options for creating a BTR.
|
|
2170
|
+
*/
|
|
2171
|
+
export interface CreateBTROptions {
|
|
2172
|
+
/** HMAC key for authentication */
|
|
2173
|
+
key: string | Uint8Array;
|
|
2174
|
+
/** Custom ISO timestamp (defaults to now) */
|
|
2175
|
+
timestamp?: string;
|
|
2176
|
+
/** CryptoPort instance for HMAC computation */
|
|
2177
|
+
crypto?: CryptoPort;
|
|
2178
|
+
/** Custom codec for serialization */
|
|
2179
|
+
codec?: unknown;
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
/**
|
|
2183
|
+
* Options for verifying a BTR.
|
|
2184
|
+
*/
|
|
2185
|
+
export interface VerifyBTROptions {
|
|
2186
|
+
/** Also verify replay produces h_out (default: false) */
|
|
2187
|
+
verifyReplay?: boolean;
|
|
2188
|
+
/** CryptoPort instance for HMAC verification */
|
|
2189
|
+
crypto?: CryptoPort;
|
|
2190
|
+
/** Custom codec for serialization */
|
|
2191
|
+
codec?: unknown;
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
/**
|
|
2195
|
+
* Creates a Boundary Transition Record from an initial state and payload.
|
|
2196
|
+
*
|
|
2197
|
+
* @param initialState - The input state U_0
|
|
2198
|
+
* @param payload - The provenance payload P
|
|
2199
|
+
* @param options - Creation options including key and optional timestamp
|
|
2200
|
+
* @throws {TypeError} If payload is not a ProvenancePayload
|
|
2201
|
+
*/
|
|
2202
|
+
export function createBTR(
|
|
2203
|
+
initialState: WarpStateV5,
|
|
2204
|
+
payload: ProvenancePayload,
|
|
2205
|
+
options: CreateBTROptions
|
|
2206
|
+
): Promise<BTR>;
|
|
2207
|
+
|
|
2208
|
+
/**
|
|
2209
|
+
* Verifies a Boundary Transition Record.
|
|
2210
|
+
*
|
|
2211
|
+
* @param btr - The BTR to verify
|
|
2212
|
+
* @param key - HMAC key
|
|
2213
|
+
* @param options - Verification options
|
|
2214
|
+
*/
|
|
2215
|
+
export function verifyBTR(
|
|
2216
|
+
btr: BTR,
|
|
2217
|
+
key: string | Uint8Array,
|
|
2218
|
+
options?: VerifyBTROptions
|
|
2219
|
+
): Promise<BTRVerificationResult>;
|
|
2220
|
+
|
|
2221
|
+
/**
|
|
2222
|
+
* Replays a BTR to produce the final state.
|
|
2223
|
+
*
|
|
2224
|
+
* @param btr - The BTR to replay
|
|
2225
|
+
* @returns The final state and its hash
|
|
2226
|
+
*/
|
|
2227
|
+
export function replayBTR(btr: BTR, options?: { crypto?: CryptoPort; codec?: unknown }): Promise<{ state: WarpStateV5; h_out: string }>;
|
|
2228
|
+
|
|
2229
|
+
/**
|
|
2230
|
+
* Serializes a BTR to CBOR bytes for transport.
|
|
2231
|
+
*
|
|
2232
|
+
* @param btr - The BTR to serialize
|
|
2233
|
+
*/
|
|
2234
|
+
export function serializeBTR(btr: BTR): Uint8Array;
|
|
2235
|
+
|
|
2236
|
+
/**
|
|
2237
|
+
* Deserializes a BTR from CBOR bytes.
|
|
2238
|
+
*
|
|
2239
|
+
* @param bytes - CBOR-encoded BTR
|
|
2240
|
+
* @throws {Error} If the bytes are not valid CBOR or missing required fields
|
|
2241
|
+
*/
|
|
2242
|
+
export function deserializeBTR(bytes: Uint8Array): BTR;
|
|
2243
|
+
|
|
2244
|
+
// ============================================================================
|
|
2245
|
+
// Wormhole Compression (HOLOGRAM)
|
|
2246
|
+
// ============================================================================
|
|
2247
|
+
|
|
2248
|
+
/**
|
|
2249
|
+
* Error thrown when a wormhole operation fails.
|
|
2250
|
+
*/
|
|
2251
|
+
export class WormholeError extends Error {
|
|
2252
|
+
readonly name: 'WormholeError';
|
|
2253
|
+
readonly code: string;
|
|
2254
|
+
readonly context: Record<string, unknown>;
|
|
2255
|
+
|
|
2256
|
+
constructor(message: string, options?: {
|
|
2257
|
+
code?: string;
|
|
2258
|
+
context?: Record<string, unknown>;
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
/**
|
|
2263
|
+
* A compressed range of patches (wormhole).
|
|
2264
|
+
*
|
|
2265
|
+
* A WormholeEdge contains:
|
|
2266
|
+
* - The SHA of the first (oldest) patch in the range (fromSha)
|
|
2267
|
+
* - The SHA of the last (newest) patch in the range (toSha)
|
|
2268
|
+
* - The writer ID who created all patches in the range
|
|
2269
|
+
* - A ProvenancePayload containing all patches for replay
|
|
2270
|
+
*/
|
|
2271
|
+
export interface WormholeEdge {
|
|
2272
|
+
/** SHA of the first (oldest) patch commit */
|
|
2273
|
+
readonly fromSha: string;
|
|
2274
|
+
/** SHA of the last (newest) patch commit */
|
|
2275
|
+
readonly toSha: string;
|
|
2276
|
+
/** Writer ID of all patches in the range */
|
|
2277
|
+
readonly writerId: string;
|
|
2278
|
+
/** Sub-payload for replay */
|
|
2279
|
+
readonly payload: ProvenancePayload;
|
|
2280
|
+
/** Number of patches compressed */
|
|
2281
|
+
readonly patchCount: number;
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
/**
|
|
2285
|
+
* Options for creating a wormhole.
|
|
2286
|
+
*/
|
|
2287
|
+
export interface CreateWormholeOptions {
|
|
2288
|
+
/** Git persistence adapter */
|
|
2289
|
+
persistence: GraphPersistencePort;
|
|
2290
|
+
/** Name of the graph */
|
|
2291
|
+
graphName: string;
|
|
2292
|
+
/** SHA of the first (oldest) patch commit */
|
|
2293
|
+
fromSha: string;
|
|
2294
|
+
/** SHA of the last (newest) patch commit */
|
|
2295
|
+
toSha: string;
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
/**
|
|
2299
|
+
* Options for composing wormholes.
|
|
2300
|
+
*/
|
|
2301
|
+
export interface ComposeWormholesOptions {
|
|
2302
|
+
/** Git persistence adapter (for validation) */
|
|
2303
|
+
persistence?: GraphPersistencePort;
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
/**
|
|
2307
|
+
* Creates a wormhole compressing a range of patches.
|
|
2308
|
+
*
|
|
2309
|
+
* The range is specified by two patch SHAs from the same writer. The `fromSha`
|
|
2310
|
+
* must be an ancestor of `toSha` in the writer's patch chain. Both endpoints
|
|
2311
|
+
* are inclusive in the wormhole.
|
|
2312
|
+
*
|
|
2313
|
+
* @throws {WormholeError} If fromSha or toSha doesn't exist (E_WORMHOLE_SHA_NOT_FOUND)
|
|
2314
|
+
* @throws {WormholeError} If fromSha is not an ancestor of toSha (E_WORMHOLE_INVALID_RANGE)
|
|
2315
|
+
* @throws {WormholeError} If commits span multiple writers (E_WORMHOLE_MULTI_WRITER)
|
|
2316
|
+
* @throws {WormholeError} If a commit is not a patch commit (E_WORMHOLE_NOT_PATCH)
|
|
2317
|
+
*/
|
|
2318
|
+
export function createWormhole(options: CreateWormholeOptions): Promise<WormholeEdge>;
|
|
2319
|
+
|
|
2320
|
+
/**
|
|
2321
|
+
* Composes two consecutive wormholes into a single wormhole.
|
|
2322
|
+
*
|
|
2323
|
+
* The wormholes must be from the same writer. When persistence is provided,
|
|
2324
|
+
* validates that the wormholes are actually consecutive in the commit chain.
|
|
2325
|
+
*
|
|
2326
|
+
* @throws {WormholeError} If wormholes are from different writers (E_WORMHOLE_MULTI_WRITER)
|
|
2327
|
+
* @throws {WormholeError} If wormholes are not consecutive (E_WORMHOLE_INVALID_RANGE)
|
|
2328
|
+
*/
|
|
2329
|
+
export function composeWormholes(
|
|
2330
|
+
first: WormholeEdge,
|
|
2331
|
+
second: WormholeEdge,
|
|
2332
|
+
options?: ComposeWormholesOptions
|
|
2333
|
+
): Promise<WormholeEdge>;
|
|
2334
|
+
|
|
2335
|
+
/**
|
|
2336
|
+
* Replays a wormhole's sub-payload to materialize the compressed state.
|
|
2337
|
+
*
|
|
2338
|
+
* @param wormhole - The wormhole to replay
|
|
2339
|
+
* @param initialState - Optional initial state to start from
|
|
2340
|
+
*/
|
|
2341
|
+
export function replayWormhole(
|
|
2342
|
+
wormhole: WormholeEdge,
|
|
2343
|
+
initialState?: WarpStateV5
|
|
2344
|
+
): WarpStateV5;
|
|
2345
|
+
|
|
2346
|
+
/**
|
|
2347
|
+
* Serializes a wormhole to a JSON-serializable object.
|
|
2348
|
+
*/
|
|
2349
|
+
export function serializeWormhole(wormhole: WormholeEdge): {
|
|
2350
|
+
fromSha: string;
|
|
2351
|
+
toSha: string;
|
|
2352
|
+
writerId: string;
|
|
2353
|
+
patchCount: number;
|
|
2354
|
+
payload: PatchEntry[];
|
|
2355
|
+
};
|
|
2356
|
+
|
|
2357
|
+
/**
|
|
2358
|
+
* Deserializes a wormhole from a JSON object.
|
|
2359
|
+
*/
|
|
2360
|
+
export function deserializeWormhole(json: {
|
|
2361
|
+
fromSha: string;
|
|
2362
|
+
toSha: string;
|
|
2363
|
+
writerId: string;
|
|
2364
|
+
patchCount: number;
|
|
2365
|
+
payload: PatchEntry[];
|
|
2366
|
+
}): WormholeEdge;
|