@git-stunts/git-warp 12.3.0 → 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.
Files changed (114) hide show
  1. package/README.md +5 -6
  2. package/bin/cli/commands/info.js +1 -5
  3. package/bin/cli/infrastructure.js +6 -9
  4. package/bin/cli/shared.js +8 -0
  5. package/bin/warp-graph.js +6 -6
  6. package/package.json +1 -1
  7. package/src/domain/WarpGraph.js +5 -35
  8. package/src/domain/crdt/VersionVector.js +1 -1
  9. package/src/domain/entities/GraphNode.js +1 -6
  10. package/src/domain/errors/ForkError.js +1 -1
  11. package/src/domain/errors/IndexError.js +1 -1
  12. package/src/domain/errors/OperationAbortedError.js +1 -1
  13. package/src/domain/errors/PatchError.js +1 -1
  14. package/src/domain/errors/PersistenceError.js +45 -0
  15. package/src/domain/errors/QueryError.js +1 -1
  16. package/src/domain/errors/SchemaUnsupportedError.js +1 -1
  17. package/src/domain/errors/SyncError.js +1 -1
  18. package/src/domain/errors/TraversalError.js +1 -1
  19. package/src/domain/errors/TrustError.js +1 -1
  20. package/src/domain/errors/WormholeError.js +1 -1
  21. package/src/domain/errors/index.js +1 -0
  22. package/src/domain/services/AdjacencyNeighborProvider.js +1 -4
  23. package/src/domain/services/AnchorMessageCodec.js +1 -3
  24. package/src/domain/services/AuditMessageCodec.js +1 -5
  25. package/src/domain/services/AuditReceiptService.js +2 -17
  26. package/src/domain/services/AuditVerifierService.js +2 -7
  27. package/src/domain/services/BitmapIndexBuilder.js +6 -12
  28. package/src/domain/services/BitmapIndexReader.js +7 -20
  29. package/src/domain/services/BitmapNeighborProvider.js +1 -3
  30. package/src/domain/services/BoundaryTransitionRecord.js +6 -23
  31. package/src/domain/services/CheckpointMessageCodec.js +1 -6
  32. package/src/domain/services/CheckpointSerializerV5.js +8 -12
  33. package/src/domain/services/CheckpointService.js +9 -39
  34. package/src/domain/services/CommitDagTraversalService.js +1 -3
  35. package/src/domain/services/DagPathFinding.js +9 -59
  36. package/src/domain/services/DagTopology.js +4 -16
  37. package/src/domain/services/DagTraversal.js +7 -31
  38. package/src/domain/services/Frontier.js +4 -6
  39. package/src/domain/services/GitLogParser.js +1 -2
  40. package/src/domain/services/GraphTraversal.js +14 -114
  41. package/src/domain/services/HealthCheckService.js +3 -9
  42. package/src/domain/services/HookInstaller.js +2 -8
  43. package/src/domain/services/HttpSyncServer.js +24 -25
  44. package/src/domain/services/IncrementalIndexUpdater.js +4 -6
  45. package/src/domain/services/IndexRebuildService.js +6 -52
  46. package/src/domain/services/IndexStalenessChecker.js +2 -3
  47. package/src/domain/services/JoinReducer.js +39 -65
  48. package/src/domain/services/LogicalBitmapIndexBuilder.js +1 -2
  49. package/src/domain/services/LogicalIndexBuildService.js +2 -6
  50. package/src/domain/services/LogicalIndexReader.js +1 -2
  51. package/src/domain/services/LogicalTraversal.js +13 -64
  52. package/src/domain/services/MaterializedViewService.js +4 -18
  53. package/src/domain/services/MigrationService.js +1 -4
  54. package/src/domain/services/ObserverView.js +1 -7
  55. package/src/domain/services/PatchBuilderV2.js +6 -18
  56. package/src/domain/services/PatchMessageCodec.js +1 -6
  57. package/src/domain/services/PropertyIndexBuilder.js +1 -2
  58. package/src/domain/services/PropertyIndexReader.js +1 -4
  59. package/src/domain/services/ProvenanceIndex.js +5 -7
  60. package/src/domain/services/ProvenancePayload.js +1 -1
  61. package/src/domain/services/QueryBuilder.js +3 -16
  62. package/src/domain/services/StateDiff.js +3 -9
  63. package/src/domain/services/StateSerializerV5.js +10 -10
  64. package/src/domain/services/StreamingBitmapIndexBuilder.js +13 -41
  65. package/src/domain/services/SyncAuthService.js +5 -32
  66. package/src/domain/services/SyncController.js +5 -25
  67. package/src/domain/services/SyncProtocol.js +4 -8
  68. package/src/domain/services/SyncTrustGate.js +4 -9
  69. package/src/domain/services/TemporalQuery.js +9 -27
  70. package/src/domain/services/TranslationCost.js +2 -8
  71. package/src/domain/services/WarpStateIndexBuilder.js +2 -4
  72. package/src/domain/services/WormholeService.js +9 -25
  73. package/src/domain/trust/TrustCrypto.js +1 -5
  74. package/src/domain/trust/TrustEvaluator.js +1 -8
  75. package/src/domain/trust/TrustRecordService.js +5 -10
  76. package/src/domain/types/TickReceipt.js +3 -7
  77. package/src/domain/types/WarpTypes.js +1 -5
  78. package/src/domain/types/WarpTypesV2.js +1 -8
  79. package/src/domain/utils/CachedValue.js +1 -4
  80. package/src/domain/utils/MinHeap.js +3 -3
  81. package/src/domain/utils/RefLayout.js +26 -0
  82. package/src/domain/utils/WriterId.js +2 -7
  83. package/src/domain/utils/canonicalCbor.js +1 -1
  84. package/src/domain/utils/defaultCodec.js +1 -1
  85. package/src/domain/utils/parseCursorBlob.js +4 -4
  86. package/src/domain/warp/PatchSession.js +3 -8
  87. package/src/domain/warp/Writer.js +3 -12
  88. package/src/domain/warp/_wire.js +2 -2
  89. package/src/domain/warp/_wiredMethods.d.ts +5 -7
  90. package/src/domain/warp/checkpoint.methods.js +1 -1
  91. package/src/domain/warp/fork.methods.js +1 -5
  92. package/src/domain/warp/materializeAdvanced.methods.js +3 -3
  93. package/src/domain/warp/patch.methods.js +6 -8
  94. package/src/domain/warp/provenance.methods.js +5 -5
  95. package/src/domain/warp/query.methods.js +9 -18
  96. package/src/domain/warp/subscribe.methods.js +2 -8
  97. package/src/globals.d.ts +7 -0
  98. package/src/infrastructure/adapters/BunHttpAdapter.js +14 -18
  99. package/src/infrastructure/adapters/ConsoleLogger.js +2 -9
  100. package/src/infrastructure/adapters/DenoHttpAdapter.js +15 -15
  101. package/src/infrastructure/adapters/GitGraphAdapter.js +234 -58
  102. package/src/infrastructure/adapters/InMemoryGraphAdapter.js +9 -2
  103. package/src/infrastructure/adapters/NodeHttpAdapter.js +14 -14
  104. package/src/infrastructure/adapters/WebCryptoAdapter.js +1 -2
  105. package/src/ports/BlobPort.js +2 -2
  106. package/src/ports/HttpServerPort.js +24 -2
  107. package/src/ports/RefPort.js +2 -1
  108. package/src/visualization/renderers/ascii/box.js +1 -1
  109. package/src/visualization/renderers/ascii/check.js +1 -5
  110. package/src/visualization/renderers/ascii/history.js +1 -6
  111. package/src/visualization/renderers/ascii/path.js +4 -22
  112. package/src/visualization/renderers/ascii/progress.js +1 -4
  113. package/src/visualization/renderers/ascii/seek.js +1 -5
  114. package/src/visualization/renderers/ascii/table.js +1 -3
package/README.md CHANGED
@@ -8,13 +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.3.0
11
+ ## What's New in v12.4.1
12
12
 
13
- - **M13 ADR 1 — canonical edge property ops** — internal model now uses honest `NodePropSet`/`EdgePropSet` semantics. Legacy raw `PropSet` is normalized at reducer entry points and lowered back at write time. No wire-format change — persisted patches remain backward-compatible.
14
- - **Wire gate hardened** — sync boundary now explicitly rejects canonical-only op types (`NodePropSet`, `EdgePropSet`) arriving over the wire, preventing premature schema migration before ADR 2 capability cutover.
15
- - **Reserved-byte validation** — new writes reject node IDs containing `\0` or starting with `\x01`, preventing ambiguous legacy edge-property encoding.
16
- - **Version namespace separation** — patch schema and checkpoint schema constants are now distinct (`PATCH_SCHEMA_V2`/`V3` vs `CHECKPOINT_SCHEMA_STANDARD`/`INDEX_TREE`).
17
- - **ADR governance** — ADR 3 readiness gates formalize when the persisted wire-format migration may proceed, with GitHub issue template and go/no-go checklist.
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.
18
17
 
19
18
  See the [full changelog](CHANGELOG.md) for details.
20
19
 
@@ -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 {Object} [options]
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 {Object} [options]
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 {Object} config - parseArgs options config
342
- * @param {import('zod').ZodType} schema - Zod schema to validate/transform parsed values
343
- * @param {Object} [opts]
344
- * @param {boolean} [opts.allowPositionals=false] - Whether to allow positional arguments
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/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 {Function} */ (handler)({
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: *, exitCode: number}} */
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@git-stunts/git-warp",
3
- "version": "12.3.0",
3
+ "version": "12.4.1",
4
4
  "description": "Deterministic WARP graph over Git: graph-native storage, traversal, and tooling.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -50,21 +50,7 @@ const DEFAULT_ADJACENCY_CACHE_SIZE = 3;
50
50
  export default class WarpGraph {
51
51
  /**
52
52
  * @private
53
- * @param {Object} options
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 {Object} */
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 {Object} [opts] - Options
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 {Object} options
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 {Object} The GC policy configuration
350
+ * @returns {import('./services/GCPolicy.js').GCPolicy} The GC policy configuration
381
351
  */
382
352
  get gcPolicy() {
383
353
  return { ...this._gcPolicy };
@@ -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 {Object<string, number>}
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 {Object} data - Node data
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 {Object} context - Serializable context object with error details
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 {Object} context - Serializable context object for debugging
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 {Object} context - Serializable context object for debugging
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 {Object} context - Serializable context object with error details
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 {Object} context - Serializable context object with error details
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 {Object} context - Serializable context object for debugging
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 {Object} context - Serializable context object with error details
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 {Object} context - Serializable context object for debugging
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 {Object} context - Serializable context object with error details
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 {Object} context - Serializable context object with error details
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 {Object} params
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 {Object} options - The anchor message options
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 {Object} options
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 {Object} fields
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 {Object} options
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;
@@ -211,10 +211,7 @@ function validateTrailerConsistency(receipt, decoded) {
211
211
 
212
212
  export class AuditVerifierService {
213
213
  /**
214
- * @param {Object} options
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;
@@ -658,9 +655,7 @@ export class AuditVerifierService {
658
655
  * and returns a TrustAssessment.
659
656
  *
660
657
  * @param {string} graphName
661
- * @param {Object} [options]
662
- * @param {string} [options.pin] - Pinned trust chain commit SHA
663
- * @param {string} [options.mode] - Policy mode ('warn' or 'enforce')
658
+ * @param {{ pin?: string, mode?: string }} [options]
664
659
  * @returns {Promise<import('../trust/TrustEvaluator.js').TrustAssessment>}
665
660
  */
666
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 {Object} data - The data object to checksum
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 {Object} data - The data to wrap
45
+ * @param {Record<string, unknown>} data - The data to wrap
46
46
  * @param {import('../../ports/CryptoPort.js').default} crypto - CryptoPort instance
47
- * @returns {Promise<Object>} Envelope with version, checksum, and data
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 {Object} [options] - Configuration options
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 {Object} [options] - Serialization options
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 {Object} opts - Options
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 }) {
@@ -29,7 +29,7 @@ const DEFAULT_MAX_CACHED_SHARDS = 100;
29
29
  * Computes a SHA-256 checksum of the given data.
30
30
  * Used to verify shard integrity on load.
31
31
  *
32
- * @param {Object} data - The data object to checksum
32
+ * @param {Record<string, unknown>} data - The data object to checksum
33
33
  * @param {number} version - Shard version (1 uses JSON.stringify, 2+ uses canonicalStringify)
34
34
  * @param {import('../../ports/CryptoPort.js').default} crypto - CryptoPort instance
35
35
  * @returns {Promise<string>} Hex-encoded SHA-256 hash
@@ -82,16 +82,9 @@ const computeChecksum = async (data, version, crypto) => {
82
82
  export default class BitmapIndexReader {
83
83
  /**
84
84
  * Creates a BitmapIndexReader instance.
85
- * @param {Object} options
86
- * @param {IndexStoragePort} options.storage - Storage adapter for reading index data
87
- * @param {boolean} [options.strict=true] - If true, throw errors on validation failures; if false, log warnings and return empty shards
88
- * @param {import('../../ports/LoggerPort.js').default} [options.logger] - Logger for structured logging.
89
- * Defaults to NoOpLogger (no logging).
90
- * @param {number} [options.maxCachedShards=100] - Maximum number of shards to keep in the LRU cache.
91
- * When exceeded, least recently used shards are evicted to free memory.
92
- * @param {import('../../ports/CryptoPort.js').default} [options.crypto] - CryptoPort instance for checksum verification.
85
+ * @param {{ storage: IndexStoragePort, strict?: boolean, logger?: import('../../ports/LoggerPort.js').default, maxCachedShards?: number, crypto?: import('../../ports/CryptoPort.js').default }} options
93
86
  */
94
- constructor({ storage, strict = true, logger = nullLogger, maxCachedShards = DEFAULT_MAX_CACHED_SHARDS, crypto } = /** @type {{ storage: IndexStoragePort, strict?: boolean, logger?: LoggerPort, maxCachedShards?: number, crypto?: CryptoPort }} */ ({})) {
87
+ constructor({ storage, strict = true, logger = nullLogger, maxCachedShards = DEFAULT_MAX_CACHED_SHARDS, crypto }) {
95
88
  if (!storage) {
96
89
  throw new Error('BitmapIndexReader requires a storage adapter');
97
90
  }
@@ -321,10 +314,7 @@ export default class BitmapIndexReader {
321
314
  /**
322
315
  * Handles validation/corruption errors based on strict mode.
323
316
  * @param {ShardCorruptionError|ShardValidationError} err - The error to handle
324
- * @param {Object} context - Error context
325
- * @param {string} context.path - Shard path
326
- * @param {string} context.oid - Object ID
327
- * @param {string} context.format - 'json' or 'bitmap'
317
+ * @param {{ path: string, oid: string, format: string }} context - Error context
328
318
  * @returns {Record<string, string | number> | import('../utils/roaring.js').RoaringBitmapSubset} Empty shard (non-strict mode only)
329
319
  * @throws {ShardCorruptionError|ShardValidationError} In strict mode
330
320
  * @private
@@ -356,7 +346,7 @@ export default class BitmapIndexReader {
356
346
 
357
347
  /**
358
348
  * Parses and validates a shard buffer.
359
- * @param {Buffer} buffer - Raw shard buffer
349
+ * @param {Uint8Array} buffer - Raw shard buffer
360
350
  * @param {string} path - Shard path (for error context)
361
351
  * @param {string} oid - Object ID (for error context)
362
352
  * @returns {Promise<Record<string, string | number>>} The validated data from the shard
@@ -373,7 +363,7 @@ export default class BitmapIndexReader {
373
363
  * Loads raw buffer from storage.
374
364
  * @param {string} path - Shard path
375
365
  * @param {string} oid - Object ID
376
- * @returns {Promise<Buffer>} Raw buffer
366
+ * @returns {Promise<Uint8Array>} Raw buffer
377
367
  * @throws {ShardLoadError} When storage.readBlob fails
378
368
  * @private
379
369
  */
@@ -413,10 +403,7 @@ export default class BitmapIndexReader {
413
403
  * Attempts to handle a shard error based on its type.
414
404
  * Returns handled result for validation/corruption errors, null otherwise.
415
405
  * @param {unknown} err - The error to handle
416
- * @param {Object} context - Error context
417
- * @param {string} context.path - Shard path
418
- * @param {string} context.oid - Object ID
419
- * @param {string} context.format - 'json' or 'bitmap'
406
+ * @param {{ path: string, oid: string, format: string }} context - Error context
420
407
  * @returns {Record<string, string | number> | import('../utils/roaring.js').RoaringBitmapSubset | null} Handled result or null if error should be re-thrown
421
408
  * @private
422
409
  */
@@ -59,9 +59,7 @@ function dedupSorted(edges) {
59
59
 
60
60
  export default class BitmapNeighborProvider extends NeighborProviderPort {
61
61
  /**
62
- * @param {Object} params
63
- * @param {BitmapIndexReader} [params.indexReader] - For commit DAG mode
64
- * @param {LogicalIndex} [params.logicalIndex] - For logical graph mode
62
+ * @param {{ indexReader?: BitmapIndexReader, logicalIndex?: LogicalIndex }} params
65
63
  */
66
64
  constructor({ indexReader, logicalIndex }) {
67
65
  super();