@git-stunts/git-warp 12.2.1 → 12.4.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/README.md +5 -5
- package/bin/cli/commands/info.js +1 -5
- package/bin/cli/infrastructure.js +6 -9
- package/bin/cli/shared.js +8 -0
- package/bin/presenters/text.js +10 -3
- package/bin/warp-graph.js +6 -6
- package/package.json +1 -1
- package/src/domain/WarpGraph.js +5 -35
- package/src/domain/crdt/ORSet.js +3 -0
- package/src/domain/crdt/VersionVector.js +1 -1
- package/src/domain/entities/GraphNode.js +1 -6
- package/src/domain/errors/ForkError.js +1 -1
- package/src/domain/errors/IndexError.js +1 -1
- package/src/domain/errors/OperationAbortedError.js +1 -1
- package/src/domain/errors/PatchError.js +1 -1
- package/src/domain/errors/PersistenceError.js +45 -0
- package/src/domain/errors/QueryError.js +1 -1
- package/src/domain/errors/SchemaUnsupportedError.js +1 -1
- package/src/domain/errors/SyncError.js +1 -1
- package/src/domain/errors/TraversalError.js +1 -1
- package/src/domain/errors/TrustError.js +1 -1
- package/src/domain/errors/WormholeError.js +1 -1
- package/src/domain/errors/index.js +1 -0
- package/src/domain/services/AdjacencyNeighborProvider.js +1 -4
- package/src/domain/services/AnchorMessageCodec.js +1 -3
- package/src/domain/services/AuditMessageCodec.js +1 -5
- package/src/domain/services/AuditReceiptService.js +4 -18
- package/src/domain/services/AuditVerifierService.js +3 -7
- package/src/domain/services/BitmapIndexBuilder.js +6 -12
- package/src/domain/services/BitmapIndexReader.js +7 -20
- package/src/domain/services/BitmapNeighborProvider.js +1 -3
- package/src/domain/services/BoundaryTransitionRecord.js +7 -23
- package/src/domain/services/CheckpointMessageCodec.js +6 -6
- package/src/domain/services/CheckpointSerializerV5.js +8 -12
- package/src/domain/services/CheckpointService.js +28 -40
- package/src/domain/services/CommitDagTraversalService.js +1 -3
- package/src/domain/services/DagPathFinding.js +9 -59
- package/src/domain/services/DagTopology.js +4 -16
- package/src/domain/services/DagTraversal.js +7 -31
- package/src/domain/services/Frontier.js +4 -6
- package/src/domain/services/GitLogParser.js +1 -2
- package/src/domain/services/GraphTraversal.js +14 -114
- package/src/domain/services/HealthCheckService.js +3 -9
- package/src/domain/services/HookInstaller.js +2 -8
- package/src/domain/services/HttpSyncServer.js +24 -25
- package/src/domain/services/IncrementalIndexUpdater.js +4 -6
- package/src/domain/services/IndexRebuildService.js +6 -52
- package/src/domain/services/IndexStalenessChecker.js +2 -3
- package/src/domain/services/JoinReducer.js +200 -100
- package/src/domain/services/KeyCodec.js +48 -0
- package/src/domain/services/LogicalBitmapIndexBuilder.js +1 -2
- package/src/domain/services/LogicalIndexBuildService.js +2 -6
- package/src/domain/services/LogicalIndexReader.js +1 -2
- package/src/domain/services/LogicalTraversal.js +13 -64
- package/src/domain/services/MaterializedViewService.js +5 -19
- package/src/domain/services/MessageSchemaDetector.js +35 -5
- package/src/domain/services/MigrationService.js +1 -4
- package/src/domain/services/ObserverView.js +1 -7
- package/src/domain/services/OpNormalizer.js +79 -0
- package/src/domain/services/PatchBuilderV2.js +67 -38
- package/src/domain/services/PatchMessageCodec.js +1 -6
- package/src/domain/services/PropertyIndexBuilder.js +1 -2
- package/src/domain/services/PropertyIndexReader.js +1 -4
- package/src/domain/services/ProvenanceIndex.js +5 -7
- package/src/domain/services/ProvenancePayload.js +1 -1
- package/src/domain/services/QueryBuilder.js +3 -16
- package/src/domain/services/StateDiff.js +3 -9
- package/src/domain/services/StateSerializerV5.js +10 -10
- package/src/domain/services/StreamingBitmapIndexBuilder.js +13 -41
- package/src/domain/services/SyncAuthService.js +8 -32
- package/src/domain/services/SyncController.js +5 -25
- package/src/domain/services/SyncProtocol.js +10 -13
- package/src/domain/services/SyncTrustGate.js +4 -9
- package/src/domain/services/TemporalQuery.js +9 -27
- package/src/domain/services/TranslationCost.js +2 -8
- package/src/domain/services/WarpMessageCodec.js +2 -0
- package/src/domain/services/WarpStateIndexBuilder.js +2 -4
- package/src/domain/services/WormholeService.js +9 -25
- package/src/domain/trust/TrustCrypto.js +9 -10
- package/src/domain/trust/TrustEvaluator.js +1 -8
- package/src/domain/trust/TrustRecordService.js +5 -10
- package/src/domain/types/TickReceipt.js +9 -11
- package/src/domain/types/WarpTypes.js +1 -5
- package/src/domain/types/WarpTypesV2.js +78 -13
- package/src/domain/utils/CachedValue.js +1 -4
- package/src/domain/utils/MinHeap.js +3 -3
- package/src/domain/utils/RefLayout.js +26 -0
- package/src/domain/utils/WriterId.js +2 -7
- package/src/domain/utils/canonicalCbor.js +1 -1
- package/src/domain/utils/defaultClock.js +1 -0
- package/src/domain/utils/defaultCodec.js +1 -1
- package/src/domain/utils/parseCursorBlob.js +4 -4
- package/src/domain/warp/PatchSession.js +3 -8
- package/src/domain/warp/Writer.js +9 -12
- package/src/domain/warp/_wire.js +2 -2
- package/src/domain/warp/_wiredMethods.d.ts +5 -7
- package/src/domain/warp/checkpoint.methods.js +1 -1
- package/src/domain/warp/fork.methods.js +2 -6
- package/src/domain/warp/materializeAdvanced.methods.js +3 -3
- package/src/domain/warp/patch.methods.js +8 -8
- package/src/domain/warp/provenance.methods.js +5 -5
- package/src/domain/warp/query.methods.js +9 -18
- package/src/domain/warp/subscribe.methods.js +2 -8
- package/src/globals.d.ts +7 -0
- package/src/infrastructure/adapters/BunHttpAdapter.js +14 -18
- package/src/infrastructure/adapters/ConsoleLogger.js +2 -9
- package/src/infrastructure/adapters/DenoHttpAdapter.js +15 -15
- package/src/infrastructure/adapters/GitGraphAdapter.js +234 -58
- package/src/infrastructure/adapters/InMemoryGraphAdapter.js +9 -2
- package/src/infrastructure/adapters/NodeHttpAdapter.js +14 -14
- package/src/infrastructure/adapters/WebCryptoAdapter.js +1 -2
- package/src/ports/BlobPort.js +2 -2
- package/src/ports/HttpServerPort.js +24 -2
- package/src/ports/RefPort.js +2 -1
- package/src/visualization/renderers/ascii/box.js +1 -1
- package/src/visualization/renderers/ascii/check.js +1 -5
- package/src/visualization/renderers/ascii/history.js +1 -6
- package/src/visualization/renderers/ascii/path.js +4 -22
- package/src/visualization/renderers/ascii/progress.js +1 -4
- package/src/visualization/renderers/ascii/seek.js +1 -5
- package/src/visualization/renderers/ascii/table.js +1 -3
package/README.md
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
<img src="docs/images/hero.gif" alt="git-warp CLI demo" width="600">
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
-
## What's New in v12.
|
|
11
|
+
## What's New in v12.4.1
|
|
12
12
|
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
-
|
|
13
|
+
- **JSDoc total coverage** — eliminated all unsafe `{Object}`, `{Function}`, `{*}` type patterns across 135 files (190+ sites), replacing them with precise inline typed shapes.
|
|
14
|
+
- **Zero tsc errors** — fixed tsconfig split-config includes and type divergences; 0 errors across all three tsconfig targets.
|
|
15
|
+
- **JSR dry-run fix** — worked around a deno_ast 0.52.0 panic caused by overlapping text-change entries for duplicate import specifiers.
|
|
16
|
+
- **`check-dts-surface.js` regex fix** — default-export parsing now correctly captures identifiers instead of keywords for `export default class/function` patterns.
|
|
17
17
|
|
|
18
18
|
See the [full changelog](CHANGELOG.md) for details.
|
|
19
19
|
|
package/bin/cli/commands/info.js
CHANGED
|
@@ -17,11 +17,7 @@ import { createPersistence, listGraphNames, readActiveCursor, readCheckpointDate
|
|
|
17
17
|
* Collects metadata about a single graph (writer count, refs, patches, checkpoint).
|
|
18
18
|
* @param {Persistence} persistence
|
|
19
19
|
* @param {string} graphName
|
|
20
|
-
* @param {
|
|
21
|
-
* @param {boolean} [options.includeWriterIds=false]
|
|
22
|
-
* @param {boolean} [options.includeRefs=false]
|
|
23
|
-
* @param {boolean} [options.includeWriterPatches=false]
|
|
24
|
-
* @param {boolean} [options.includeCheckpointDate=false]
|
|
20
|
+
* @param {{ includeWriterIds?: boolean, includeRefs?: boolean, includeWriterPatches?: boolean, includeCheckpointDate?: boolean }} [options]
|
|
25
21
|
* @returns {Promise<GraphInfoResult>}
|
|
26
22
|
*/
|
|
27
23
|
async function getGraphInfo(persistence, graphName, {
|
|
@@ -127,10 +127,7 @@ Tree options:
|
|
|
127
127
|
export class CliError extends Error {
|
|
128
128
|
/**
|
|
129
129
|
* @param {string} message - Human-readable error message
|
|
130
|
-
* @param {
|
|
131
|
-
* @param {string} [options.code='E_CLI'] - Machine-readable error code
|
|
132
|
-
* @param {number} [options.exitCode=3] - Process exit code
|
|
133
|
-
* @param {Error} [options.cause] - Underlying cause
|
|
130
|
+
* @param {{ code?: string, exitCode?: number, cause?: Error }} [options]
|
|
134
131
|
*/
|
|
135
132
|
constructor(message, { code = 'E_CLI', exitCode = EXIT_CODES.INTERNAL, cause } = {}) {
|
|
136
133
|
super(message);
|
|
@@ -337,12 +334,12 @@ export function parseArgs(argv) {
|
|
|
337
334
|
/**
|
|
338
335
|
* Parses command-level args using node:util.parseArgs + Zod validation.
|
|
339
336
|
*
|
|
337
|
+
* @template T
|
|
340
338
|
* @param {string[]} args - Command-specific args (after command name)
|
|
341
|
-
* @param {
|
|
342
|
-
* @param {import('zod').ZodType} schema - Zod schema to validate/transform parsed values
|
|
343
|
-
* @param {
|
|
344
|
-
* @
|
|
345
|
-
* @returns {{values: *, positionals: string[]}}
|
|
339
|
+
* @param {Record<string, {type: string, short?: string, default?: unknown, multiple?: boolean}>} config - parseArgs options config
|
|
340
|
+
* @param {import('zod').ZodType<T, import('zod').ZodTypeDef, unknown>} schema - Zod schema to validate/transform parsed values
|
|
341
|
+
* @param {{ allowPositionals?: boolean }} [opts]
|
|
342
|
+
* @returns {{values: T, positionals: string[]}}
|
|
346
343
|
*/
|
|
347
344
|
export function parseCommandArgs(args, config, schema, { allowPositionals = false } = {}) {
|
|
348
345
|
/** @type {{ values: Record<string, string|boolean|string[]|boolean[]|undefined>, positionals: string[] }} */
|
package/bin/cli/shared.js
CHANGED
|
@@ -177,6 +177,10 @@ export async function readCheckpointDate(persistence, checkpointSha) {
|
|
|
177
177
|
return info.date || null;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Create a HookInstaller wired with real filesystem dependencies.
|
|
182
|
+
* @returns {import('../../src/domain/services/HookInstaller.js').HookInstaller}
|
|
183
|
+
*/
|
|
180
184
|
export function createHookInstaller() {
|
|
181
185
|
const __filename = new URL(import.meta.url).pathname;
|
|
182
186
|
const __dirname = path.dirname(__filename);
|
|
@@ -211,6 +215,10 @@ export function execGitConfigValue(repoPath, key) {
|
|
|
211
215
|
}
|
|
212
216
|
}
|
|
213
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Check whether stderr is a TTY (interactive terminal).
|
|
220
|
+
* @returns {boolean}
|
|
221
|
+
*/
|
|
214
222
|
export function isInteractive() {
|
|
215
223
|
return Boolean(process.stderr.isTTY);
|
|
216
224
|
}
|
package/bin/presenters/text.js
CHANGED
|
@@ -291,7 +291,8 @@ function formatOpSummaryPlain(summary) {
|
|
|
291
291
|
const order = [
|
|
292
292
|
['NodeAdd', '+', 'node'],
|
|
293
293
|
['EdgeAdd', '+', 'edge'],
|
|
294
|
-
['
|
|
294
|
+
['prop', '~', 'prop'], // coalesced PropSet + NodePropSet
|
|
295
|
+
['EdgePropSet', '~', 'eprop'],
|
|
295
296
|
['NodeTombstone', '-', 'node'],
|
|
296
297
|
['EdgeTombstone', '-', 'edge'],
|
|
297
298
|
['BlobValue', '+', 'blob'],
|
|
@@ -299,7 +300,10 @@ function formatOpSummaryPlain(summary) {
|
|
|
299
300
|
|
|
300
301
|
const parts = [];
|
|
301
302
|
for (const [opType, symbol, label] of order) {
|
|
302
|
-
|
|
303
|
+
// Coalesce PropSet + NodePropSet into one bucket
|
|
304
|
+
const n = opType === 'prop'
|
|
305
|
+
? (summary?.PropSet || 0) + (summary?.NodePropSet || 0) || undefined
|
|
306
|
+
: summary?.[opType];
|
|
303
307
|
if (typeof n === 'number' && Number.isFinite(n) && n > 0) {
|
|
304
308
|
parts.push(`${symbol}${n}${label}`);
|
|
305
309
|
}
|
|
@@ -612,9 +616,12 @@ function formatPatchOp(op) {
|
|
|
612
616
|
if (op.type === 'EdgeTombstone') {
|
|
613
617
|
return ` - edge ${op.from} -[${op.label}]-> ${op.to}`;
|
|
614
618
|
}
|
|
615
|
-
if (op.type === 'PropSet') {
|
|
619
|
+
if (op.type === 'PropSet' || op.type === 'NodePropSet') {
|
|
616
620
|
return ` ~ ${op.node}.${op.key} = ${JSON.stringify(op.value)}`;
|
|
617
621
|
}
|
|
622
|
+
if (op.type === 'EdgePropSet') {
|
|
623
|
+
return ` ~ edge(${op.from} -[${op.label}]-> ${op.to}).${op.key} = ${JSON.stringify(op.value)}`;
|
|
624
|
+
}
|
|
618
625
|
if (op.type === 'BlobValue') {
|
|
619
626
|
return ` + blob ${op.node}`;
|
|
620
627
|
}
|
package/bin/warp-graph.js
CHANGED
|
@@ -55,20 +55,20 @@ async function main() {
|
|
|
55
55
|
throw usageError(`--view is not supported for '${command}'. Supported commands: ${VIEW_SUPPORTED_COMMANDS.join(', ')}`);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
const result = await /** @type {
|
|
58
|
+
const result = await /** @type {(opts: {command: string, args: string[], options: Record<string, unknown>}) => Promise<unknown>} */ (handler)({
|
|
59
59
|
command,
|
|
60
60
|
args: commandArgs,
|
|
61
61
|
options,
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
/** @type {{payload:
|
|
65
|
-
const normalized = result && typeof result === 'object' && 'payload' in result
|
|
66
|
-
? result
|
|
64
|
+
/** @type {{payload: unknown, exitCode: number}} */
|
|
65
|
+
const normalized = result && typeof result === 'object' && 'payload' in /** @type {Record<string, unknown>} */ (result)
|
|
66
|
+
? /** @type {{payload: unknown, exitCode: number}} */ (result)
|
|
67
67
|
: { payload: result, exitCode: EXIT_CODES.OK };
|
|
68
68
|
|
|
69
69
|
if (normalized.payload !== undefined) {
|
|
70
70
|
const format = options.ndjson ? 'ndjson' : options.json ? 'json' : 'text';
|
|
71
|
-
present(normalized.payload, { format, command, view: options.view });
|
|
71
|
+
present(/** @type {Record<string, unknown>} */ (normalized.payload), { format, command, view: /** @type {string | null | boolean} */ (options.view ?? null) });
|
|
72
72
|
}
|
|
73
73
|
// Use process.exit() to avoid waiting for fire-and-forget I/O (e.g. seek cache writes).
|
|
74
74
|
process.exit(normalized.exitCode ?? EXIT_CODES.OK);
|
|
@@ -78,7 +78,7 @@ main().catch((error) => {
|
|
|
78
78
|
const exitCode = error instanceof CliError ? error.exitCode : EXIT_CODES.INTERNAL;
|
|
79
79
|
const code = error instanceof CliError ? error.code : 'E_INTERNAL';
|
|
80
80
|
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
81
|
-
/** @type {{error: {code: string, message: string, cause?:
|
|
81
|
+
/** @type {{error: {code: string, message: string, cause?: unknown}}} */
|
|
82
82
|
const payload = { error: { code, message } };
|
|
83
83
|
|
|
84
84
|
if (error && error.cause) {
|
package/package.json
CHANGED
package/src/domain/WarpGraph.js
CHANGED
|
@@ -50,21 +50,7 @@ const DEFAULT_ADJACENCY_CACHE_SIZE = 3;
|
|
|
50
50
|
export default class WarpGraph {
|
|
51
51
|
/**
|
|
52
52
|
* @private
|
|
53
|
-
* @param {
|
|
54
|
-
* @param {import('../ports/GraphPersistencePort.js').default} options.persistence - Git adapter
|
|
55
|
-
* @param {string} options.graphName - Graph namespace
|
|
56
|
-
* @param {string} options.writerId - This writer's ID
|
|
57
|
-
* @param {Object} [options.gcPolicy] - GC policy configuration (overrides defaults)
|
|
58
|
-
* @param {number} [options.adjacencyCacheSize] - Max materialized adjacency cache entries
|
|
59
|
-
* @param {{every: number}} [options.checkpointPolicy] - Auto-checkpoint policy; creates a checkpoint every N patches
|
|
60
|
-
* @param {boolean} [options.autoMaterialize=true] - If true, query methods auto-materialize instead of throwing
|
|
61
|
-
* @param {'reject'|'cascade'|'warn'} [options.onDeleteWithData='warn'] - Policy when deleting a node that still has edges or properties
|
|
62
|
-
* @param {import('../ports/LoggerPort.js').default} [options.logger] - Logger for structured logging
|
|
63
|
-
* @param {import('../ports/ClockPort.js').default} [options.clock] - Clock for timing instrumentation (defaults to performance-based clock)
|
|
64
|
-
* @param {import('../ports/CryptoPort.js').default} [options.crypto] - Crypto adapter for hashing
|
|
65
|
-
* @param {import('../ports/CodecPort.js').default} [options.codec] - Codec for CBOR serialization (defaults to domain-local codec)
|
|
66
|
-
* @param {import('../ports/SeekCachePort.js').default} [options.seekCache] - Persistent cache for seek materialization (optional)
|
|
67
|
-
* @param {boolean} [options.audit=false] - If true, creates audit receipts for each data commit
|
|
53
|
+
* @param {{ persistence: import('../ports/GraphPersistencePort.js').default, graphName: string, writerId: string, gcPolicy?: Record<string, unknown>, adjacencyCacheSize?: number, checkpointPolicy?: {every: number}, autoMaterialize?: boolean, onDeleteWithData?: 'reject'|'cascade'|'warn', logger?: import('../ports/LoggerPort.js').default, clock?: import('../ports/ClockPort.js').default, crypto?: import('../ports/CryptoPort.js').default, codec?: import('../ports/CodecPort.js').default, seekCache?: import('../ports/SeekCachePort.js').default, audit?: boolean }} options
|
|
68
54
|
*/
|
|
69
55
|
constructor({ persistence, graphName, writerId, gcPolicy = {}, adjacencyCacheSize = DEFAULT_ADJACENCY_CACHE_SIZE, checkpointPolicy, autoMaterialize = true, onDeleteWithData = 'warn', logger, clock, crypto, codec, seekCache, audit = false }) {
|
|
70
56
|
/** @type {FullPersistence} */
|
|
@@ -85,7 +71,7 @@ export default class WarpGraph {
|
|
|
85
71
|
/** @type {boolean} */
|
|
86
72
|
this._stateDirty = false;
|
|
87
73
|
|
|
88
|
-
/** @type {
|
|
74
|
+
/** @type {import('./services/GCPolicy.js').GCPolicy} */
|
|
89
75
|
this._gcPolicy = { ...DEFAULT_GC_POLICY, ...gcPolicy };
|
|
90
76
|
|
|
91
77
|
/** @type {number} */
|
|
@@ -224,9 +210,7 @@ export default class WarpGraph {
|
|
|
224
210
|
* Logs a timing message for a completed or failed operation.
|
|
225
211
|
* @param {string} op - Operation name (e.g. 'materialize')
|
|
226
212
|
* @param {number} t0 - Start timestamp from this._clock.now()
|
|
227
|
-
* @param {
|
|
228
|
-
* @param {string} [opts.metrics] - Extra metrics string to append in parentheses
|
|
229
|
-
* @param {Error} [opts.error] - If set, logs a failure message instead
|
|
213
|
+
* @param {{ metrics?: string, error?: Error }} [opts] - Options
|
|
230
214
|
*/
|
|
231
215
|
_logTiming(op, t0, { metrics, error } = {}) {
|
|
232
216
|
if (!this._logger) {
|
|
@@ -259,21 +243,7 @@ export default class WarpGraph {
|
|
|
259
243
|
/**
|
|
260
244
|
* Opens a multi-writer graph.
|
|
261
245
|
*
|
|
262
|
-
* @param {
|
|
263
|
-
* @param {import('../ports/GraphPersistencePort.js').default} options.persistence - Git adapter
|
|
264
|
-
* @param {string} options.graphName - Graph namespace
|
|
265
|
-
* @param {string} options.writerId - This writer's ID
|
|
266
|
-
* @param {Object} [options.gcPolicy] - GC policy configuration (overrides defaults)
|
|
267
|
-
* @param {number} [options.adjacencyCacheSize] - Max materialized adjacency cache entries
|
|
268
|
-
* @param {{every: number}} [options.checkpointPolicy] - Auto-checkpoint policy; creates a checkpoint every N patches
|
|
269
|
-
* @param {boolean} [options.autoMaterialize] - If true, query methods auto-materialize instead of throwing
|
|
270
|
-
* @param {'reject'|'cascade'|'warn'} [options.onDeleteWithData] - Policy when deleting a node that still has edges or properties (default: 'warn')
|
|
271
|
-
* @param {import('../ports/LoggerPort.js').default} [options.logger] - Logger for structured logging
|
|
272
|
-
* @param {import('../ports/ClockPort.js').default} [options.clock] - Clock for timing instrumentation (defaults to performance-based clock)
|
|
273
|
-
* @param {import('../ports/CryptoPort.js').default} [options.crypto] - Crypto adapter for hashing
|
|
274
|
-
* @param {import('../ports/CodecPort.js').default} [options.codec] - Codec for CBOR serialization (defaults to domain-local codec)
|
|
275
|
-
* @param {import('../ports/SeekCachePort.js').default} [options.seekCache] - Persistent cache for seek materialization (optional)
|
|
276
|
-
* @param {boolean} [options.audit=false] - If true, creates audit receipts for each data commit
|
|
246
|
+
* @param {{ persistence: import('../ports/GraphPersistencePort.js').default, graphName: string, writerId: string, gcPolicy?: Record<string, unknown>, adjacencyCacheSize?: number, checkpointPolicy?: {every: number}, autoMaterialize?: boolean, onDeleteWithData?: 'reject'|'cascade'|'warn', logger?: import('../ports/LoggerPort.js').default, clock?: import('../ports/ClockPort.js').default, crypto?: import('../ports/CryptoPort.js').default, codec?: import('../ports/CodecPort.js').default, seekCache?: import('../ports/SeekCachePort.js').default, audit?: boolean }} options
|
|
277
247
|
* @returns {Promise<WarpGraph>} The opened graph instance
|
|
278
248
|
* @throws {Error} If graphName, writerId, checkpointPolicy, or onDeleteWithData is invalid
|
|
279
249
|
*
|
|
@@ -377,7 +347,7 @@ export default class WarpGraph {
|
|
|
377
347
|
/**
|
|
378
348
|
* Gets the current GC policy.
|
|
379
349
|
*
|
|
380
|
-
* @returns {
|
|
350
|
+
* @returns {import('./services/GCPolicy.js').GCPolicy} The GC policy configuration
|
|
381
351
|
*/
|
|
382
352
|
get gcPolicy() {
|
|
383
353
|
return { ...this._gcPolicy };
|
package/src/domain/crdt/ORSet.js
CHANGED
|
@@ -116,6 +116,9 @@ export function createORSet() {
|
|
|
116
116
|
* @param {import('./Dot.js').Dot} dot - The dot representing this add operation
|
|
117
117
|
*/
|
|
118
118
|
export function orsetAdd(set, element, dot) {
|
|
119
|
+
if (!dot || typeof dot.writerId !== 'string' || !Number.isInteger(dot.counter)) {
|
|
120
|
+
throw new Error(`orsetAdd: invalid dot -- expected {writerId: string, counter: integer}, got ${JSON.stringify(dot)}`);
|
|
121
|
+
}
|
|
119
122
|
const encoded = encodeDot(dot);
|
|
120
123
|
|
|
121
124
|
let dots = set.entries.get(element);
|
|
@@ -155,7 +155,7 @@ export function vvContains(vv, dot) {
|
|
|
155
155
|
* Keys are sorted for deterministic serialization.
|
|
156
156
|
*
|
|
157
157
|
* @param {VersionVector} vv
|
|
158
|
-
* @returns {
|
|
158
|
+
* @returns {Record<string, number>}
|
|
159
159
|
*/
|
|
160
160
|
export function vvSerialize(vv) {
|
|
161
161
|
/** @type {Record<string, number>} */
|
|
@@ -38,12 +38,7 @@ export default class GraphNode {
|
|
|
38
38
|
/**
|
|
39
39
|
* Creates a new immutable GraphNode.
|
|
40
40
|
*
|
|
41
|
-
* @param {
|
|
42
|
-
* @param {string} data.sha - The commit SHA (40 hex characters). Required.
|
|
43
|
-
* @param {string} data.message - The commit message/payload. Required.
|
|
44
|
-
* @param {string} [data.author] - The commit author name. Optional.
|
|
45
|
-
* @param {string} [data.date] - The commit date string. Optional.
|
|
46
|
-
* @param {string[]} [data.parents=[]] - Array of parent commit SHAs. Defaults to empty array.
|
|
41
|
+
* @param {{ sha: string, message: string, author?: string, date?: string, parents?: string[] }} data - Node data
|
|
47
42
|
* @throws {Error} If sha is missing or not a string
|
|
48
43
|
* @throws {Error} If message is missing or not a string
|
|
49
44
|
* @throws {Error} If parents is not an array
|
|
@@ -21,7 +21,7 @@ import WarpError from './WarpError.js';
|
|
|
21
21
|
*
|
|
22
22
|
* @property {string} name - Always 'ForkError' for instanceof checks
|
|
23
23
|
* @property {string} code - Machine-readable error code for programmatic handling
|
|
24
|
-
* @property {
|
|
24
|
+
* @property {Record<string, unknown>} context - Serializable context object with error details
|
|
25
25
|
*/
|
|
26
26
|
export default class ForkError extends WarpError {
|
|
27
27
|
/**
|
|
@@ -8,7 +8,7 @@ import WarpError from './WarpError.js';
|
|
|
8
8
|
*
|
|
9
9
|
* @property {string} name - The error name ('IndexError')
|
|
10
10
|
* @property {string} code - Error code for programmatic handling (default: 'INDEX_ERROR')
|
|
11
|
-
* @property {
|
|
11
|
+
* @property {Record<string, unknown>} context - Serializable context object for debugging
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* throw new IndexError('Failed to process index', {
|
|
@@ -10,7 +10,7 @@ import WarpError from './WarpError.js';
|
|
|
10
10
|
* @property {string} code - Error code for programmatic handling (default: 'OPERATION_ABORTED')
|
|
11
11
|
* @property {string} operation - The name of the operation that was aborted
|
|
12
12
|
* @property {string} reason - The reason the operation was aborted
|
|
13
|
-
* @property {
|
|
13
|
+
* @property {Record<string, unknown>} context - Serializable context object for debugging
|
|
14
14
|
*/
|
|
15
15
|
export default class OperationAbortedError extends WarpError {
|
|
16
16
|
/**
|
|
@@ -14,7 +14,7 @@ import WarpError from './WarpError.js';
|
|
|
14
14
|
*
|
|
15
15
|
* @property {string} name - Always 'PatchError' for instanceof checks
|
|
16
16
|
* @property {string} code - Machine-readable error code for programmatic handling
|
|
17
|
-
* @property {
|
|
17
|
+
* @property {Record<string, unknown>} context - Serializable context object with error details
|
|
18
18
|
*/
|
|
19
19
|
export default class PatchError extends WarpError {
|
|
20
20
|
/**
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import WarpError from './WarpError.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Typed error codes for persistence adapter boundary failures.
|
|
5
|
+
*
|
|
6
|
+
* Replaces generic `Error` throws with machine-readable codes so callers
|
|
7
|
+
* can branch on `err.code` instead of brittle `err.message.includes()`.
|
|
8
|
+
*
|
|
9
|
+
* ## Error Codes
|
|
10
|
+
*
|
|
11
|
+
* | Code | Description |
|
|
12
|
+
* |------|-------------|
|
|
13
|
+
* | `E_MISSING_OBJECT` | Stored object (commit, blob, tree) does not exist |
|
|
14
|
+
* | `E_REF_NOT_FOUND` | Ref does not resolve to any object |
|
|
15
|
+
* | `E_REF_IO` | Ref update/delete failed (lock contention, permission, etc.) |
|
|
16
|
+
*
|
|
17
|
+
* @class PersistenceError
|
|
18
|
+
* @extends WarpError
|
|
19
|
+
*
|
|
20
|
+
* @property {string} name - Always 'PersistenceError' for instanceof checks
|
|
21
|
+
* @property {string} code - Machine-readable error code for programmatic handling
|
|
22
|
+
* @property {Record<string, unknown>} context - Serializable context object with error details
|
|
23
|
+
*/
|
|
24
|
+
export default class PersistenceError extends WarpError {
|
|
25
|
+
/** Stored object (commit, blob, tree) does not exist. */
|
|
26
|
+
static E_MISSING_OBJECT = 'E_MISSING_OBJECT';
|
|
27
|
+
|
|
28
|
+
/** Ref does not resolve to any object. */
|
|
29
|
+
static E_REF_NOT_FOUND = 'E_REF_NOT_FOUND';
|
|
30
|
+
|
|
31
|
+
/** Ref update/delete failed (lock contention, permission, etc.). */
|
|
32
|
+
static E_REF_IO = 'E_REF_IO';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} message - Human-readable error message
|
|
36
|
+
* @param {string} code - One of the E_* constants
|
|
37
|
+
* @param {{ cause?: Error, context?: Record<string, unknown> }} [options={}]
|
|
38
|
+
*/
|
|
39
|
+
constructor(message, code, options = {}) {
|
|
40
|
+
super(message, code, { context: options.context });
|
|
41
|
+
if (options.cause) {
|
|
42
|
+
this.cause = options.cause;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -30,7 +30,7 @@ import WarpError from './WarpError.js';
|
|
|
30
30
|
*
|
|
31
31
|
* @property {string} name - Always 'QueryError' for instanceof checks
|
|
32
32
|
* @property {string} code - Machine-readable error code for programmatic handling
|
|
33
|
-
* @property {
|
|
33
|
+
* @property {Record<string, unknown>} context - Serializable context object with error details
|
|
34
34
|
*/
|
|
35
35
|
export default class QueryError extends WarpError {
|
|
36
36
|
/**
|
|
@@ -8,7 +8,7 @@ import WarpError from './WarpError.js';
|
|
|
8
8
|
*
|
|
9
9
|
* @property {string} name - The error name ('SchemaUnsupportedError')
|
|
10
10
|
* @property {string} code - Error code ('E_SCHEMA_UNSUPPORTED')
|
|
11
|
-
* @property {
|
|
11
|
+
* @property {Record<string, unknown>} context - Serializable context object for debugging
|
|
12
12
|
*/
|
|
13
13
|
export default class SchemaUnsupportedError extends WarpError {
|
|
14
14
|
/**
|
|
@@ -22,7 +22,7 @@ import WarpError from './WarpError.js';
|
|
|
22
22
|
*
|
|
23
23
|
* @property {string} name - Always 'SyncError' for instanceof checks
|
|
24
24
|
* @property {string} code - Machine-readable error code for programmatic handling
|
|
25
|
-
* @property {
|
|
25
|
+
* @property {Record<string, unknown>} context - Serializable context object with error details
|
|
26
26
|
*/
|
|
27
27
|
export default class SyncError extends WarpError {
|
|
28
28
|
/**
|
|
@@ -8,7 +8,7 @@ import WarpError from './WarpError.js';
|
|
|
8
8
|
*
|
|
9
9
|
* @property {string} name - The error name ('TraversalError')
|
|
10
10
|
* @property {string} code - Error code for programmatic handling (default: 'TRAVERSAL_ERROR')
|
|
11
|
-
* @property {
|
|
11
|
+
* @property {Record<string, unknown>} context - Serializable context object for debugging
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* throw new TraversalError('Node not found in index', {
|
|
@@ -18,7 +18,7 @@ import WarpError from './WarpError.js';
|
|
|
18
18
|
*
|
|
19
19
|
* @property {string} name - Always 'TrustError' for instanceof checks
|
|
20
20
|
* @property {string} code - Machine-readable error code for programmatic handling
|
|
21
|
-
* @property {
|
|
21
|
+
* @property {Record<string, unknown>} context - Serializable context object with error details
|
|
22
22
|
*/
|
|
23
23
|
export default class TrustError extends WarpError {
|
|
24
24
|
/**
|
|
@@ -19,7 +19,7 @@ import WarpError from './WarpError.js';
|
|
|
19
19
|
*
|
|
20
20
|
* @property {string} name - Always 'WormholeError' for instanceof checks
|
|
21
21
|
* @property {string} code - Machine-readable error code for programmatic handling
|
|
22
|
-
* @property {
|
|
22
|
+
* @property {Record<string, unknown>} context - Serializable context object with error details
|
|
23
23
|
*/
|
|
24
24
|
export default class WormholeError extends WarpError {
|
|
25
25
|
/**
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export { default as EmptyMessageError } from './EmptyMessageError.js';
|
|
8
|
+
export { default as PersistenceError } from './PersistenceError.js';
|
|
8
9
|
export { default as WarpError } from './WarpError.js';
|
|
9
10
|
export { default as ForkError } from './ForkError.js';
|
|
10
11
|
export { default as IndexError } from './IndexError.js';
|
|
@@ -86,10 +86,7 @@ function mergeSorted(a, b) {
|
|
|
86
86
|
|
|
87
87
|
export default class AdjacencyNeighborProvider extends NeighborProviderPort {
|
|
88
88
|
/**
|
|
89
|
-
* @param {
|
|
90
|
-
* @param {Map<string, Array<{neighborId: string, label: string}>>} params.outgoing
|
|
91
|
-
* @param {Map<string, Array<{neighborId: string, label: string}>>} params.incoming
|
|
92
|
-
* @param {Set<string>} params.aliveNodes - Set of alive nodeIds for hasNode()
|
|
89
|
+
* @param {{ outgoing: Map<string, Array<{neighborId: string, label: string}>>, incoming: Map<string, Array<{neighborId: string, label: string}>>, aliveNodes: Set<string> }} params
|
|
93
90
|
*/
|
|
94
91
|
constructor({ outgoing, incoming, aliveNodes }) {
|
|
95
92
|
super();
|
|
@@ -23,9 +23,7 @@ import {
|
|
|
23
23
|
/**
|
|
24
24
|
* Encodes an anchor commit message.
|
|
25
25
|
*
|
|
26
|
-
* @param {
|
|
27
|
-
* @param {string} options.graph - The graph name
|
|
28
|
-
* @param {number} [options.schema=2] - The schema version (defaults to 2 for new messages)
|
|
26
|
+
* @param {{ graph: string, schema?: number }} options - The anchor message options
|
|
29
27
|
* @returns {string} The encoded commit message
|
|
30
28
|
* @throws {Error} If any validation fails
|
|
31
29
|
*
|
|
@@ -24,11 +24,7 @@ import {
|
|
|
24
24
|
/**
|
|
25
25
|
* Encodes an audit commit message with trailers.
|
|
26
26
|
*
|
|
27
|
-
* @param {
|
|
28
|
-
* @param {string} options.graph - The graph name
|
|
29
|
-
* @param {string} options.writer - The writer ID
|
|
30
|
-
* @param {string} options.dataCommit - The OID of the data commit being audited
|
|
31
|
-
* @param {string} options.opsDigest - SHA-256 hex digest of the canonical ops JSON
|
|
27
|
+
* @param {{ graph: string, writer: string, dataCommit: string, opsDigest: string }} options
|
|
32
28
|
* @returns {string} The encoded commit message
|
|
33
29
|
* @throws {Error} If any validation fails
|
|
34
30
|
*/
|
|
@@ -90,16 +90,7 @@ const OID_HEX_PATTERN = /^[0-9a-f]{40}([0-9a-f]{24})?$/;
|
|
|
90
90
|
/**
|
|
91
91
|
* Validates and builds a frozen receipt record with keys in sorted order.
|
|
92
92
|
*
|
|
93
|
-
* @param {
|
|
94
|
-
* @param {number} fields.version
|
|
95
|
-
* @param {string} fields.graphName
|
|
96
|
-
* @param {string} fields.writerId
|
|
97
|
-
* @param {string} fields.dataCommit
|
|
98
|
-
* @param {number} fields.tickStart
|
|
99
|
-
* @param {number} fields.tickEnd
|
|
100
|
-
* @param {string} fields.opsDigest
|
|
101
|
-
* @param {string} fields.prevAuditCommit
|
|
102
|
-
* @param {number} fields.timestamp
|
|
93
|
+
* @param {{ version: number, graphName: string, writerId: string, dataCommit: string, tickStart: number, tickEnd: number, opsDigest: string, prevAuditCommit: string, timestamp: number }} fields
|
|
103
94
|
* @returns {Readonly<Record<string, unknown>>}
|
|
104
95
|
* @throws {Error} If any field is invalid
|
|
105
96
|
*/
|
|
@@ -206,13 +197,7 @@ export function buildReceiptRecord(fields) {
|
|
|
206
197
|
*/
|
|
207
198
|
export class AuditReceiptService {
|
|
208
199
|
/**
|
|
209
|
-
* @param {
|
|
210
|
-
* @param {import('../../ports/RefPort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default & import('../../ports/CommitPort.js').default} options.persistence
|
|
211
|
-
* @param {string} options.graphName
|
|
212
|
-
* @param {string} options.writerId
|
|
213
|
-
* @param {import('../../ports/CodecPort.js').default} options.codec
|
|
214
|
-
* @param {import('../../ports/CryptoPort.js').default} options.crypto
|
|
215
|
-
* @param {import('../../ports/LoggerPort.js').default} [options.logger]
|
|
200
|
+
* @param {{ persistence: import('../../ports/RefPort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default & import('../../ports/CommitPort.js').default, graphName: string, writerId: string, codec: import('../../ports/CodecPort.js').default, crypto: import('../../ports/CryptoPort.js').default, logger?: import('../../ports/LoggerPort.js').default }} options
|
|
216
201
|
*/
|
|
217
202
|
constructor({ persistence, graphName, writerId, codec, crypto, logger }) {
|
|
218
203
|
this._persistence = persistence;
|
|
@@ -339,7 +324,8 @@ export class AuditReceiptService {
|
|
|
339
324
|
// Compute opsDigest
|
|
340
325
|
const opsDigest = await computeOpsDigest(ops, this._crypto);
|
|
341
326
|
|
|
342
|
-
//
|
|
327
|
+
// Wall-clock timestamp for audit receipt (not a perf timer)
|
|
328
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
343
329
|
const timestamp = Date.now();
|
|
344
330
|
|
|
345
331
|
// Determine prevAuditCommit
|
|
@@ -211,10 +211,7 @@ function validateTrailerConsistency(receipt, decoded) {
|
|
|
211
211
|
|
|
212
212
|
export class AuditVerifierService {
|
|
213
213
|
/**
|
|
214
|
-
* @param {
|
|
215
|
-
* @param {import('../../ports/CommitPort.js').default & import('../../ports/RefPort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default} options.persistence
|
|
216
|
-
* @param {import('../../ports/CodecPort.js').default} options.codec
|
|
217
|
-
* @param {import('../../ports/LoggerPort.js').default} [options.logger]
|
|
214
|
+
* @param {{ persistence: import('../../ports/CommitPort.js').default & import('../../ports/RefPort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default, codec: import('../../ports/CodecPort.js').default, logger?: import('../../ports/LoggerPort.js').default }} options
|
|
218
215
|
*/
|
|
219
216
|
constructor({ persistence, codec, logger }) {
|
|
220
217
|
this._persistence = persistence;
|
|
@@ -257,6 +254,7 @@ export class AuditVerifierService {
|
|
|
257
254
|
|
|
258
255
|
return {
|
|
259
256
|
graph: graphName,
|
|
257
|
+
// eslint-disable-next-line no-restricted-syntax -- wall-clock timestamp for audit report
|
|
260
258
|
verifiedAt: new Date().toISOString(),
|
|
261
259
|
summary: { total: chains.length, valid, partial, invalid },
|
|
262
260
|
chains,
|
|
@@ -657,9 +655,7 @@ export class AuditVerifierService {
|
|
|
657
655
|
* and returns a TrustAssessment.
|
|
658
656
|
*
|
|
659
657
|
* @param {string} graphName
|
|
660
|
-
* @param {
|
|
661
|
-
* @param {string} [options.pin] - Pinned trust chain commit SHA
|
|
662
|
-
* @param {string} [options.mode] - Policy mode ('warn' or 'enforce')
|
|
658
|
+
* @param {{ pin?: string, mode?: string }} [options]
|
|
663
659
|
* @returns {Promise<import('../trust/TrustEvaluator.js').TrustAssessment>}
|
|
664
660
|
*/
|
|
665
661
|
async evaluateTrust(graphName, options = {}) {
|
|
@@ -12,7 +12,7 @@ export { SHARD_VERSION };
|
|
|
12
12
|
* Uses canonical JSON stringification for deterministic output
|
|
13
13
|
* across different JavaScript engines.
|
|
14
14
|
*
|
|
15
|
-
* @param {
|
|
15
|
+
* @param {Record<string, unknown>} data - The data object to checksum
|
|
16
16
|
* @param {import('../../ports/CryptoPort.js').default} crypto - CryptoPort instance
|
|
17
17
|
* @returns {Promise<string>} Hex-encoded SHA-256 hash
|
|
18
18
|
*/
|
|
@@ -42,9 +42,9 @@ const ensureRoaringBitmap32 = () => {
|
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Wraps data in a version/checksum envelope.
|
|
45
|
-
* @param {
|
|
45
|
+
* @param {Record<string, unknown>} data - The data to wrap
|
|
46
46
|
* @param {import('../../ports/CryptoPort.js').default} crypto - CryptoPort instance
|
|
47
|
-
* @returns {Promise<
|
|
47
|
+
* @returns {Promise<{version: number, checksum: string, data: Record<string, unknown>}>} Envelope with version, checksum, and data
|
|
48
48
|
*/
|
|
49
49
|
const wrapShard = async (data, crypto) => ({
|
|
50
50
|
version: SHARD_VERSION,
|
|
@@ -95,9 +95,7 @@ export default class BitmapIndexBuilder {
|
|
|
95
95
|
* - Forward edge bitmaps (parent → children)
|
|
96
96
|
* - Reverse edge bitmaps (child → parents)
|
|
97
97
|
*
|
|
98
|
-
* @param {
|
|
99
|
-
* @param {import('../../ports/CryptoPort.js').default} [options.crypto] - CryptoPort instance for hashing
|
|
100
|
-
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for serialization
|
|
98
|
+
* @param {{ crypto?: import('../../ports/CryptoPort.js').default, codec?: import('../../ports/CodecPort.js').default }} [options] - Configuration options
|
|
101
99
|
*/
|
|
102
100
|
constructor({ crypto, codec } = {}) {
|
|
103
101
|
/** @type {import('../../ports/CryptoPort.js').default} */
|
|
@@ -149,8 +147,7 @@ export default class BitmapIndexBuilder {
|
|
|
149
147
|
*
|
|
150
148
|
* Each shard is wrapped in a version/checksum envelope for integrity verification.
|
|
151
149
|
*
|
|
152
|
-
* @param {
|
|
153
|
-
* @param {Map<string, string>} [options.frontier] - Writer→tip SHA map to include in the tree
|
|
150
|
+
* @param {{ frontier?: Map<string, string> }} [options] - Serialization options
|
|
154
151
|
* @returns {Promise<Record<string, Buffer>>} Map of path → serialized content
|
|
155
152
|
*/
|
|
156
153
|
async serialize({ frontier } = {}) {
|
|
@@ -217,10 +214,7 @@ export default class BitmapIndexBuilder {
|
|
|
217
214
|
|
|
218
215
|
/**
|
|
219
216
|
* Adds an ID to a node's bitmap.
|
|
220
|
-
* @param {
|
|
221
|
-
* @param {string} opts.sha - The SHA to use as key
|
|
222
|
-
* @param {number} opts.id - The ID to add to the bitmap
|
|
223
|
-
* @param {string} opts.type - 'fwd' or 'rev'
|
|
217
|
+
* @param {{ sha: string, id: number, type: string }} opts - Options
|
|
224
218
|
* @private
|
|
225
219
|
*/
|
|
226
220
|
_addToBitmap({ sha, id, type }) {
|