@git-stunts/git-warp 11.2.1 → 11.3.3

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 (111) hide show
  1. package/bin/cli/commands/check.js +2 -2
  2. package/bin/cli/commands/doctor/checks.js +12 -12
  3. package/bin/cli/commands/doctor/index.js +2 -2
  4. package/bin/cli/commands/doctor/types.js +1 -1
  5. package/bin/cli/commands/history.js +12 -5
  6. package/bin/cli/commands/install-hooks.js +5 -5
  7. package/bin/cli/commands/materialize.js +2 -2
  8. package/bin/cli/commands/patch.js +142 -0
  9. package/bin/cli/commands/path.js +4 -4
  10. package/bin/cli/commands/query.js +54 -13
  11. package/bin/cli/commands/registry.js +4 -0
  12. package/bin/cli/commands/seek.js +17 -11
  13. package/bin/cli/commands/tree.js +230 -0
  14. package/bin/cli/commands/trust.js +3 -3
  15. package/bin/cli/commands/verify-audit.js +8 -7
  16. package/bin/cli/commands/view.js +6 -5
  17. package/bin/cli/infrastructure.js +26 -12
  18. package/bin/cli/shared.js +2 -2
  19. package/bin/cli/types.js +19 -8
  20. package/bin/presenters/index.js +35 -9
  21. package/bin/presenters/json.js +14 -12
  22. package/bin/presenters/text.js +155 -33
  23. package/index.d.ts +82 -22
  24. package/package.json +3 -2
  25. package/src/domain/WarpGraph.js +4 -1
  26. package/src/domain/crdt/ORSet.js +8 -8
  27. package/src/domain/errors/EmptyMessageError.js +2 -2
  28. package/src/domain/errors/ForkError.js +1 -1
  29. package/src/domain/errors/IndexError.js +1 -1
  30. package/src/domain/errors/OperationAbortedError.js +1 -1
  31. package/src/domain/errors/QueryError.js +1 -1
  32. package/src/domain/errors/SchemaUnsupportedError.js +1 -1
  33. package/src/domain/errors/ShardCorruptionError.js +2 -2
  34. package/src/domain/errors/ShardLoadError.js +2 -2
  35. package/src/domain/errors/ShardValidationError.js +4 -4
  36. package/src/domain/errors/StorageError.js +2 -2
  37. package/src/domain/errors/SyncError.js +1 -1
  38. package/src/domain/errors/TraversalError.js +1 -1
  39. package/src/domain/errors/TrustError.js +1 -1
  40. package/src/domain/errors/WarpError.js +2 -2
  41. package/src/domain/errors/WormholeError.js +1 -1
  42. package/src/domain/services/AuditReceiptService.js +6 -6
  43. package/src/domain/services/AuditVerifierService.js +52 -38
  44. package/src/domain/services/BitmapIndexBuilder.js +3 -3
  45. package/src/domain/services/BitmapIndexReader.js +28 -19
  46. package/src/domain/services/BoundaryTransitionRecord.js +18 -17
  47. package/src/domain/services/CheckpointSerializerV5.js +17 -16
  48. package/src/domain/services/CheckpointService.js +2 -2
  49. package/src/domain/services/CommitDagTraversalService.js +13 -13
  50. package/src/domain/services/DagPathFinding.js +7 -7
  51. package/src/domain/services/DagTopology.js +1 -1
  52. package/src/domain/services/DagTraversal.js +1 -1
  53. package/src/domain/services/HealthCheckService.js +1 -1
  54. package/src/domain/services/HookInstaller.js +1 -1
  55. package/src/domain/services/HttpSyncServer.js +92 -41
  56. package/src/domain/services/IndexRebuildService.js +7 -7
  57. package/src/domain/services/IndexStalenessChecker.js +4 -3
  58. package/src/domain/services/JoinReducer.js +11 -11
  59. package/src/domain/services/LogicalTraversal.js +1 -1
  60. package/src/domain/services/MessageCodecInternal.js +1 -1
  61. package/src/domain/services/MigrationService.js +1 -1
  62. package/src/domain/services/ObserverView.js +8 -8
  63. package/src/domain/services/PatchBuilderV2.js +42 -26
  64. package/src/domain/services/ProvenanceIndex.js +1 -1
  65. package/src/domain/services/ProvenancePayload.js +1 -1
  66. package/src/domain/services/QueryBuilder.js +3 -3
  67. package/src/domain/services/StateDiff.js +14 -11
  68. package/src/domain/services/StateSerializerV5.js +2 -2
  69. package/src/domain/services/StreamingBitmapIndexBuilder.js +26 -24
  70. package/src/domain/services/SyncAuthService.js +3 -2
  71. package/src/domain/services/SyncProtocol.js +25 -11
  72. package/src/domain/services/TemporalQuery.js +9 -6
  73. package/src/domain/services/TranslationCost.js +7 -5
  74. package/src/domain/services/WormholeService.js +16 -7
  75. package/src/domain/trust/TrustCanonical.js +3 -3
  76. package/src/domain/trust/TrustEvaluator.js +18 -3
  77. package/src/domain/trust/TrustRecordService.js +30 -23
  78. package/src/domain/trust/TrustStateBuilder.js +21 -8
  79. package/src/domain/trust/canonical.js +6 -6
  80. package/src/domain/types/TickReceipt.js +1 -1
  81. package/src/domain/types/WarpErrors.js +45 -0
  82. package/src/domain/types/WarpOptions.js +29 -0
  83. package/src/domain/types/WarpPersistence.js +41 -0
  84. package/src/domain/types/WarpTypes.js +2 -2
  85. package/src/domain/types/WarpTypesV2.js +2 -2
  86. package/src/domain/utils/MinHeap.js +6 -5
  87. package/src/domain/utils/canonicalStringify.js +5 -4
  88. package/src/domain/utils/roaring.js +31 -5
  89. package/src/domain/warp/PatchSession.js +9 -18
  90. package/src/domain/warp/_wiredMethods.d.ts +199 -45
  91. package/src/domain/warp/checkpoint.methods.js +5 -1
  92. package/src/domain/warp/fork.methods.js +2 -2
  93. package/src/domain/warp/materialize.methods.js +55 -5
  94. package/src/domain/warp/materializeAdvanced.methods.js +15 -4
  95. package/src/domain/warp/patch.methods.js +54 -29
  96. package/src/domain/warp/provenance.methods.js +5 -3
  97. package/src/domain/warp/query.methods.js +6 -5
  98. package/src/domain/warp/sync.methods.js +16 -11
  99. package/src/globals.d.ts +64 -0
  100. package/src/infrastructure/adapters/BunHttpAdapter.js +14 -9
  101. package/src/infrastructure/adapters/CasSeekCacheAdapter.js +9 -4
  102. package/src/infrastructure/adapters/DenoHttpAdapter.js +5 -6
  103. package/src/infrastructure/adapters/GitGraphAdapter.js +14 -12
  104. package/src/infrastructure/adapters/NodeHttpAdapter.js +2 -2
  105. package/src/infrastructure/adapters/WebCryptoAdapter.js +2 -2
  106. package/src/visualization/layouts/converters.js +2 -2
  107. package/src/visualization/layouts/elkAdapter.js +1 -1
  108. package/src/visualization/layouts/elkLayout.js +10 -7
  109. package/src/visualization/layouts/index.js +1 -1
  110. package/src/visualization/renderers/ascii/seek.js +16 -6
  111. package/src/visualization/renderers/svg/index.js +1 -1
@@ -91,7 +91,7 @@ import { vvContains } from './VersionVector.js';
91
91
  * An element is present if it has at least one non-tombstoned dot.
92
92
  *
93
93
  * @typedef {Object} ORSet
94
- * @property {Map<*, Set<string>>} entries - element -> dots that added it
94
+ * @property {Map<string, Set<string>>} entries - element -> dots that added it
95
95
  * @property {Set<string>} tombstones - global tombstones
96
96
  */
97
97
 
@@ -112,7 +112,7 @@ export function createORSet() {
112
112
  * Mutates the set.
113
113
  *
114
114
  * @param {ORSet} set - The ORSet to mutate
115
- * @param {*} element - The element to add
115
+ * @param {string} element - The element to add
116
116
  * @param {import('./Dot.js').Dot} dot - The dot representing this add operation
117
117
  */
118
118
  export function orsetAdd(set, element, dot) {
@@ -145,7 +145,7 @@ export function orsetRemove(set, observedDots) {
145
145
  * An element is present if it has at least one non-tombstoned dot.
146
146
  *
147
147
  * @param {ORSet} set - The ORSet to check
148
- * @param {*} element - The element to check
148
+ * @param {string} element - The element to check
149
149
  * @returns {boolean}
150
150
  */
151
151
  export function orsetContains(set, element) {
@@ -168,7 +168,7 @@ export function orsetContains(set, element) {
168
168
  * Only returns elements that have at least one non-tombstoned dot.
169
169
  *
170
170
  * @param {ORSet} set - The ORSet
171
- * @returns {Array<*>} Array of present elements
171
+ * @returns {string[]} Array of present elements
172
172
  */
173
173
  export function orsetElements(set) {
174
174
  const result = [];
@@ -186,7 +186,7 @@ export function orsetElements(set) {
186
186
  * Returns the non-tombstoned dots for an element.
187
187
  *
188
188
  * @param {ORSet} set - The ORSet
189
- * @param {*} element - The element
189
+ * @param {string} element - The element
190
190
  * @returns {Set<string>} Set of encoded dots that are not tombstoned
191
191
  */
192
192
  export function orsetGetDots(set, element) {
@@ -311,11 +311,11 @@ export function orsetCompact(set, includedVV) {
311
311
  * Tombstones are sorted.
312
312
  *
313
313
  * @param {ORSet} set
314
- * @returns {{entries: Array<[*, string[]]>, tombstones: string[]}}
314
+ * @returns {{entries: Array<[string, string[]]>, tombstones: string[]}}
315
315
  */
316
316
  export function orsetSerialize(set) {
317
317
  // Serialize entries: convert Map to array of [element, sortedDots]
318
- /** @type {Array<[any, string[]]>} */
318
+ /** @type {Array<[string, string[]]>} */
319
319
  const entriesArray = [];
320
320
  for (const [element, dots] of set.entries) {
321
321
  const sortedDots = [...dots].sort((a, b) => {
@@ -349,7 +349,7 @@ export function orsetSerialize(set) {
349
349
  /**
350
350
  * Deserializes a plain object back to an ORSet.
351
351
  *
352
- * @param {{entries?: Array<[*, string[]]>, tombstones?: string[]}} obj
352
+ * @param {{entries?: Array<[string, string[]]>, tombstones?: string[]}} obj
353
353
  * @returns {ORSet}
354
354
  */
355
355
  export function orsetDeserialize(obj) {
@@ -12,7 +12,7 @@ import IndexError from './IndexError.js';
12
12
  * @property {string} name - The error name ('EmptyMessageError')
13
13
  * @property {string} code - Error code ('EMPTY_MESSAGE')
14
14
  * @property {string} operation - The operation that failed due to empty message
15
- * @property {Record<string, *>} context - Serializable context object for debugging
15
+ * @property {Record<string, unknown>} context - Serializable context object for debugging
16
16
  *
17
17
  * @example
18
18
  * if (!message || message.trim() === '') {
@@ -27,7 +27,7 @@ export default class EmptyMessageError extends IndexError {
27
27
  * Creates a new EmptyMessageError.
28
28
  *
29
29
  * @param {string} message - Human-readable error message
30
- * @param {{ operation?: string, context?: Record<string, *> }} [options={}] - Error options
30
+ * @param {{ operation?: string, context?: Record<string, unknown> }} [options={}] - Error options
31
31
  */
32
32
  constructor(message, options = {}) {
33
33
  const context = {
@@ -26,7 +26,7 @@ import WarpError from './WarpError.js';
26
26
  export default class ForkError extends WarpError {
27
27
  /**
28
28
  * @param {string} message
29
- * @param {{ code?: string, context?: Object }} [options={}]
29
+ * @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
30
30
  */
31
31
  constructor(message, options = {}) {
32
32
  super(message, 'FORK_ERROR', options);
@@ -19,7 +19,7 @@ import WarpError from './WarpError.js';
19
19
  export default class IndexError extends WarpError {
20
20
  /**
21
21
  * @param {string} message
22
- * @param {{ code?: string, context?: Object }} [options={}]
22
+ * @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
23
23
  */
24
24
  constructor(message, options = {}) {
25
25
  super(message, 'INDEX_ERROR', options);
@@ -15,7 +15,7 @@ import WarpError from './WarpError.js';
15
15
  export default class OperationAbortedError extends WarpError {
16
16
  /**
17
17
  * @param {string} operation
18
- * @param {{ code?: string, context?: Object, reason?: string }} [options={}]
18
+ * @param {{ code?: string, context?: Record<string, unknown>, reason?: string }} [options={}]
19
19
  */
20
20
  constructor(operation, options = {}) {
21
21
  const reason = options.reason || 'Operation was aborted';
@@ -35,7 +35,7 @@ import WarpError from './WarpError.js';
35
35
  export default class QueryError extends WarpError {
36
36
  /**
37
37
  * @param {string} message
38
- * @param {{ code?: string, context?: Object }} [options={}]
38
+ * @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
39
39
  */
40
40
  constructor(message, options = {}) {
41
41
  super(message, 'QUERY_ERROR', options);
@@ -13,7 +13,7 @@ import WarpError from './WarpError.js';
13
13
  export default class SchemaUnsupportedError extends WarpError {
14
14
  /**
15
15
  * @param {string} message
16
- * @param {{ code?: string, context?: Object }} [options={}]
16
+ * @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
17
17
  */
18
18
  constructor(message, options = {}) {
19
19
  super(message, 'E_SCHEMA_UNSUPPORTED', options);
@@ -14,7 +14,7 @@ import IndexError from './IndexError.js';
14
14
  * @property {string} shardPath - Path to the corrupted shard file
15
15
  * @property {string} oid - Object ID associated with the shard
16
16
  * @property {string} reason - Reason for corruption (e.g., 'invalid_checksum', 'invalid_version', 'parse_error')
17
- * @property {Record<string, *>} context - Serializable context object for debugging
17
+ * @property {Record<string, unknown>} context - Serializable context object for debugging
18
18
  *
19
19
  * @example
20
20
  * if (!validateChecksum(data)) {
@@ -30,7 +30,7 @@ export default class ShardCorruptionError extends IndexError {
30
30
  * Creates a new ShardCorruptionError.
31
31
  *
32
32
  * @param {string} message - Human-readable error message
33
- * @param {{ shardPath?: string, oid?: string, reason?: string, context?: Record<string, *> }} [options={}] - Error options
33
+ * @param {{ shardPath?: string, oid?: string, reason?: string, context?: Record<string, unknown> }} [options={}] - Error options
34
34
  */
35
35
  constructor(message, options = {}) {
36
36
  const context = {
@@ -14,7 +14,7 @@ import IndexError from './IndexError.js';
14
14
  * @property {string} shardPath - Path to the shard file that failed to load
15
15
  * @property {string} oid - Object ID associated with the shard
16
16
  * @property {Error} cause - The original error that caused the load failure
17
- * @property {Record<string, *>} context - Serializable context object for debugging
17
+ * @property {Record<string, unknown>} context - Serializable context object for debugging
18
18
  *
19
19
  * @example
20
20
  * try {
@@ -32,7 +32,7 @@ export default class ShardLoadError extends IndexError {
32
32
  * Creates a new ShardLoadError.
33
33
  *
34
34
  * @param {string} message - Human-readable error message
35
- * @param {{ shardPath?: string, oid?: string, cause?: Error, context?: Record<string, *> }} [options={}] - Error options
35
+ * @param {{ shardPath?: string, oid?: string, cause?: Error, context?: Record<string, unknown> }} [options={}] - Error options
36
36
  */
37
37
  constructor(message, options = {}) {
38
38
  const context = {
@@ -12,10 +12,10 @@ import IndexError from './IndexError.js';
12
12
  * @property {string} name - The error name ('ShardValidationError')
13
13
  * @property {string} code - Error code ('SHARD_VALIDATION_ERROR')
14
14
  * @property {string} shardPath - Path to the shard file that failed validation
15
- * @property {*} expected - The expected value for the field
16
- * @property {*} actual - The actual value found in the shard
15
+ * @property {unknown} expected - The expected value for the field
16
+ * @property {unknown} actual - The actual value found in the shard
17
17
  * @property {string} field - The field that failed validation (e.g., 'checksum', 'version')
18
- * @property {Record<string, *>} context - Serializable context object for debugging
18
+ * @property {Record<string, unknown>} context - Serializable context object for debugging
19
19
  *
20
20
  * @example
21
21
  * if (shard.version !== EXPECTED_VERSION) {
@@ -32,7 +32,7 @@ export default class ShardValidationError extends IndexError {
32
32
  * Creates a new ShardValidationError.
33
33
  *
34
34
  * @param {string} message - Human-readable error message
35
- * @param {{ shardPath?: string, expected?: *, actual?: *, field?: string, context?: Record<string, *> }} [options={}] - Error options
35
+ * @param {{ shardPath?: string, expected?: unknown, actual?: unknown, field?: string, context?: Record<string, unknown> }} [options={}] - Error options
36
36
  */
37
37
  constructor(message, options = {}) {
38
38
  const context = {
@@ -14,7 +14,7 @@ import IndexError from './IndexError.js';
14
14
  * @property {string} operation - The operation that failed ('read' or 'write')
15
15
  * @property {string} oid - Object ID associated with the operation
16
16
  * @property {Error} cause - The original error that caused the failure
17
- * @property {Record<string, *>} context - Serializable context object for debugging
17
+ * @property {Record<string, unknown>} context - Serializable context object for debugging
18
18
  *
19
19
  * @example
20
20
  * try {
@@ -32,7 +32,7 @@ export default class StorageError extends IndexError {
32
32
  * Creates a new StorageError.
33
33
  *
34
34
  * @param {string} message - Human-readable error message
35
- * @param {{ operation?: string, oid?: string, cause?: Error, context?: Record<string, *> }} [options={}] - Error options
35
+ * @param {{ operation?: string, oid?: string, cause?: Error, context?: Record<string, unknown> }} [options={}] - Error options
36
36
  */
37
37
  constructor(message, options = {}) {
38
38
  const context = {
@@ -26,7 +26,7 @@ import WarpError from './WarpError.js';
26
26
  export default class SyncError extends WarpError {
27
27
  /**
28
28
  * @param {string} message
29
- * @param {{ code?: string, context?: Object }} [options={}]
29
+ * @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
30
30
  */
31
31
  constructor(message, options = {}) {
32
32
  super(message, 'SYNC_ERROR', options);
@@ -19,7 +19,7 @@ import WarpError from './WarpError.js';
19
19
  export default class TraversalError extends WarpError {
20
20
  /**
21
21
  * @param {string} message
22
- * @param {{ code?: string, context?: Object }} [options={}]
22
+ * @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
23
23
  */
24
24
  constructor(message, options = {}) {
25
25
  super(message, 'TRAVERSAL_ERROR', options);
@@ -21,7 +21,7 @@ import WarpError from './WarpError.js';
21
21
  export default class TrustError extends WarpError {
22
22
  /**
23
23
  * @param {string} message
24
- * @param {{ code?: string, context?: Object }} [options={}]
24
+ * @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
25
25
  */
26
26
  constructor(message, options = {}) {
27
27
  super(message, 'TRUST_ERROR', options);
@@ -10,13 +10,13 @@
10
10
  *
11
11
  * @property {string} name - Error name (set from constructor.name)
12
12
  * @property {string} code - Machine-readable error code
13
- * @property {Record<string, *>} context - Serializable context for debugging
13
+ * @property {Record<string, unknown>} context - Serializable context for debugging
14
14
  */
15
15
  export default class WarpError extends Error {
16
16
  /**
17
17
  * @param {string} message - Human-readable error message
18
18
  * @param {string} defaultCode - Default error code if not overridden by options
19
- * @param {{ code?: string, context?: Record<string, *> }} [options={}] - Error options
19
+ * @param {{ code?: string, context?: Record<string, unknown> }} [options={}] - Error options
20
20
  */
21
21
  constructor(message, defaultCode, options = {}) {
22
22
  super(message);
@@ -24,7 +24,7 @@ import WarpError from './WarpError.js';
24
24
  export default class WormholeError extends WarpError {
25
25
  /**
26
26
  * @param {string} message
27
- * @param {{ code?: string, context?: Object }} [options={}]
27
+ * @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
28
28
  */
29
29
  constructor(message, options = {}) {
30
30
  super(message, 'WORMHOLE_ERROR', options);
@@ -290,12 +290,12 @@ export class AuditReceiptService {
290
290
 
291
291
  try {
292
292
  return await this._commitInner(tickReceipt);
293
- } catch (/** @type {*} */ err) { // TODO(ts-cleanup): narrow catch type
293
+ } catch (err) {
294
294
  this._failed++;
295
295
  this._logger?.warn('[warp:audit]', {
296
296
  code: 'AUDIT_COMMIT_FAILED',
297
297
  writerId: this._writerId,
298
- error: err?.message,
298
+ error: err instanceof Error ? err.message : String(err),
299
299
  });
300
300
  return null;
301
301
  }
@@ -366,11 +366,11 @@ export class AuditReceiptService {
366
366
  let blobOid;
367
367
  try {
368
368
  blobOid = await this._persistence.writeBlob(Buffer.from(cborBytes));
369
- } catch (/** @type {*} */ err) { // TODO(ts-cleanup): narrow catch type
369
+ } catch (err) {
370
370
  this._logger?.warn('[warp:audit]', {
371
371
  code: 'AUDIT_WRITE_BLOB_FAILED',
372
372
  writerId: this._writerId,
373
- error: err?.message,
373
+ error: err instanceof Error ? err.message : String(err),
374
374
  });
375
375
  throw err;
376
376
  }
@@ -381,11 +381,11 @@ export class AuditReceiptService {
381
381
  treeOid = await this._persistence.writeTree([
382
382
  `100644 blob ${blobOid}\treceipt.cbor`,
383
383
  ]);
384
- } catch (/** @type {*} */ err) { // TODO(ts-cleanup): narrow catch type
384
+ } catch (err) {
385
385
  this._logger?.warn('[warp:audit]', {
386
386
  code: 'AUDIT_WRITE_TREE_FAILED',
387
387
  writerId: this._writerId,
388
- error: err?.message,
388
+ error: err instanceof Error ? err.message : String(err),
389
389
  });
390
390
  throw err;
391
391
  }
@@ -16,6 +16,19 @@
16
16
  * @see docs/specs/AUDIT_RECEIPT.md Section 8
17
17
  */
18
18
 
19
+ /**
20
+ * @typedef {Object} AuditReceipt
21
+ * @property {number} version
22
+ * @property {string} graphName
23
+ * @property {string} writerId
24
+ * @property {string} dataCommit
25
+ * @property {string} opsDigest
26
+ * @property {string} prevAuditCommit
27
+ * @property {number} tickStart
28
+ * @property {number} tickEnd
29
+ * @property {number} timestamp
30
+ */
31
+
19
32
  import { buildAuditPrefix, buildAuditRef } from '../utils/RefLayout.js';
20
33
  import { decodeAuditMessage } from './AuditMessageCodec.js';
21
34
  import { TrustRecordService } from '../trust/TrustRecordService.js';
@@ -67,14 +80,15 @@ function validateOidFormat(value) {
67
80
 
68
81
  /**
69
82
  * Checks whether a receipt object has the expected 9 fields with correct types.
70
- * @param {*} receipt
83
+ * @param {unknown} receipt
71
84
  * @returns {string|null} Error message or null if valid
72
85
  */
73
86
  function validateReceiptSchema(receipt) {
74
87
  if (!receipt || typeof receipt !== 'object') {
75
88
  return 'receipt is not an object';
76
89
  }
77
- const keys = Object.keys(receipt);
90
+ const rec = /** @type {Record<string, unknown>} */ (receipt);
91
+ const keys = Object.keys(rec);
78
92
  if (keys.length !== 9) {
79
93
  return `expected 9 fields, got ${keys.length}`;
80
94
  }
@@ -83,46 +97,46 @@ function validateReceiptSchema(receipt) {
83
97
  'tickEnd', 'tickStart', 'timestamp', 'version', 'writerId',
84
98
  ];
85
99
  for (const k of required) {
86
- if (!(k in receipt)) {
100
+ if (!(k in rec)) {
87
101
  return `missing field: ${k}`;
88
102
  }
89
103
  }
90
- if (receipt.version !== 1) {
91
- return `unsupported version: ${receipt.version}`;
104
+ if (rec.version !== 1) {
105
+ return `unsupported version: ${rec.version}`;
92
106
  }
93
- if (typeof receipt.graphName !== 'string' || receipt.graphName.length === 0) {
107
+ if (typeof rec.graphName !== 'string' || rec.graphName.length === 0) {
94
108
  return 'graphName must be a non-empty string';
95
109
  }
96
- if (typeof receipt.writerId !== 'string' || receipt.writerId.length === 0) {
110
+ if (typeof rec.writerId !== 'string' || rec.writerId.length === 0) {
97
111
  return 'writerId must be a non-empty string';
98
112
  }
99
- if (typeof receipt.dataCommit !== 'string') {
113
+ if (typeof rec.dataCommit !== 'string') {
100
114
  return 'dataCommit must be a string';
101
115
  }
102
- if (typeof receipt.opsDigest !== 'string') {
116
+ if (typeof rec.opsDigest !== 'string') {
103
117
  return 'opsDigest must be a string';
104
118
  }
105
- if (typeof receipt.prevAuditCommit !== 'string') {
119
+ if (typeof rec.prevAuditCommit !== 'string') {
106
120
  return 'prevAuditCommit must be a string';
107
121
  }
108
- if (!Number.isInteger(receipt.tickStart) || receipt.tickStart < 1) {
109
- return `tickStart must be integer >= 1, got ${receipt.tickStart}`;
122
+ if (!Number.isInteger(rec.tickStart) || /** @type {number} */ (rec.tickStart) < 1) {
123
+ return `tickStart must be integer >= 1, got ${rec.tickStart}`;
110
124
  }
111
- if (!Number.isInteger(receipt.tickEnd) || receipt.tickEnd < receipt.tickStart) {
112
- return `tickEnd must be integer >= tickStart, got ${receipt.tickEnd}`;
125
+ if (!Number.isInteger(rec.tickEnd) || /** @type {number} */ (rec.tickEnd) < /** @type {number} */ (rec.tickStart)) {
126
+ return `tickEnd must be integer >= tickStart, got ${rec.tickEnd}`;
113
127
  }
114
- if (receipt.version === 1 && receipt.tickStart !== receipt.tickEnd) {
115
- return `v1 requires tickStart === tickEnd, got ${receipt.tickStart} !== ${receipt.tickEnd}`;
128
+ if (rec.version === 1 && rec.tickStart !== rec.tickEnd) {
129
+ return `v1 requires tickStart === tickEnd, got ${rec.tickStart} !== ${rec.tickEnd}`;
116
130
  }
117
- if (!Number.isInteger(receipt.timestamp) || receipt.timestamp < 0) {
118
- return `timestamp must be non-negative integer, got ${receipt.timestamp}`;
131
+ if (!Number.isInteger(rec.timestamp) || /** @type {number} */ (rec.timestamp) < 0) {
132
+ return `timestamp must be non-negative integer, got ${rec.timestamp}`;
119
133
  }
120
134
  return null;
121
135
  }
122
136
 
123
137
  /**
124
138
  * Validates trailers against the CBOR receipt fields.
125
- * @param {*} receipt
139
+ * @param {AuditReceipt} receipt
126
140
  * @param {{ graph: string, writer: string, dataCommit: string, opsDigest: string, schema: number }} decoded
127
141
  * @returns {string|null} Error message or null if consistent
128
142
  */
@@ -312,7 +326,7 @@ export class AuditVerifierService {
312
326
  */
313
327
  async _walkChain(graphName, writerId, tip, since, result) {
314
328
  let current = tip;
315
- /** @type {Record<string, *>|null} */ let prevReceipt = null;
329
+ /** @type {AuditReceipt|null} */ let prevReceipt = null;
316
330
  /** @type {number|null} */ let chainOidLen = null;
317
331
 
318
332
  while (current) {
@@ -322,8 +336,8 @@ export class AuditVerifierService {
322
336
  let commitInfo;
323
337
  try {
324
338
  commitInfo = await this._persistence.getNodeInfo(current);
325
- } catch (/** @type {*} */ err) { // TODO(ts-cleanup): narrow catch type
326
- this._addError(result, 'MISSING_RECEIPT_BLOB', `Cannot read commit ${current}: ${err?.message}`, current);
339
+ } catch (err) {
340
+ this._addError(result, 'MISSING_RECEIPT_BLOB', `Cannot read commit ${current}: ${err instanceof Error ? err.message : String(err)}`, current);
327
341
  return;
328
342
  }
329
343
 
@@ -456,7 +470,7 @@ export class AuditVerifierService {
456
470
  * @param {string} commitSha
457
471
  * @param {{ message: string }} commitInfo
458
472
  * @param {ChainResult} result
459
- * @returns {Promise<{ receipt: *, decodedTrailers: * }|null>}
473
+ * @returns {Promise<{ receipt: AuditReceipt, decodedTrailers: { graph: string, writer: string, dataCommit: string, opsDigest: string, schema: number } }|null>}
460
474
  * @private
461
475
  */
462
476
  async _readReceipt(commitSha, commitInfo, result) {
@@ -464,9 +478,9 @@ export class AuditVerifierService {
464
478
  let treeOid;
465
479
  try {
466
480
  treeOid = await this._persistence.getCommitTree(commitSha);
467
- } catch (/** @type {*} */ err) { // TODO(ts-cleanup): narrow catch type
481
+ } catch (err) {
468
482
  this._addError(result, 'MISSING_RECEIPT_BLOB',
469
- `Cannot read tree for ${commitSha}: ${err?.message}`, commitSha);
483
+ `Cannot read tree for ${commitSha}: ${err instanceof Error ? err.message : String(err)}`, commitSha);
470
484
  return null;
471
485
  }
472
486
 
@@ -474,9 +488,9 @@ export class AuditVerifierService {
474
488
  let treeEntries;
475
489
  try {
476
490
  treeEntries = await this._persistence.readTreeOids(treeOid);
477
- } catch (/** @type {*} */ err) { // TODO(ts-cleanup): narrow catch type
491
+ } catch (err) {
478
492
  this._addError(result, 'RECEIPT_TREE_INVALID',
479
- `Cannot read tree ${treeOid}: ${err?.message}`, commitSha);
493
+ `Cannot read tree ${treeOid}: ${err instanceof Error ? err.message : String(err)}`, commitSha);
480
494
  return null;
481
495
  }
482
496
 
@@ -493,19 +507,19 @@ export class AuditVerifierService {
493
507
  let blobContent;
494
508
  try {
495
509
  blobContent = await this._persistence.readBlob(blobOid);
496
- } catch (/** @type {*} */ err) { // TODO(ts-cleanup): narrow catch type
510
+ } catch (err) {
497
511
  this._addError(result, 'MISSING_RECEIPT_BLOB',
498
- `Cannot read receipt blob ${blobOid}: ${err?.message}`, commitSha);
512
+ `Cannot read receipt blob ${blobOid}: ${err instanceof Error ? err.message : String(err)}`, commitSha);
499
513
  return null;
500
514
  }
501
515
 
502
516
  // Decode CBOR
503
517
  let receipt;
504
518
  try {
505
- receipt = this._codec.decode(blobContent);
506
- } catch (/** @type {*} */ err) { // TODO(ts-cleanup): narrow catch type
519
+ receipt = /** @type {AuditReceipt} */ (this._codec.decode(blobContent));
520
+ } catch (err) {
507
521
  this._addError(result, 'CBOR_DECODE_FAILED',
508
- `CBOR decode failed: ${err?.message}`, commitSha);
522
+ `CBOR decode failed: ${err instanceof Error ? err.message : String(err)}`, commitSha);
509
523
  result.status = STATUS_ERROR;
510
524
  return null;
511
525
  }
@@ -514,9 +528,9 @@ export class AuditVerifierService {
514
528
  let decodedTrailers;
515
529
  try {
516
530
  decodedTrailers = decodeAuditMessage(commitInfo.message);
517
- } catch (/** @type {*} */ err) { // TODO(ts-cleanup): narrow catch type
531
+ } catch (err) {
518
532
  this._addError(result, 'TRAILER_MISMATCH',
519
- `Trailer decode failed: ${err?.message}`, commitSha);
533
+ `Trailer decode failed: ${err instanceof Error ? err.message : String(err)}`, commitSha);
520
534
  result.status = STATUS_DATA_MISMATCH;
521
535
  return null;
522
536
  }
@@ -526,7 +540,7 @@ export class AuditVerifierService {
526
540
 
527
541
  /**
528
542
  * Validates OID format for dataCommit, prevAuditCommit, and opsDigest.
529
- * @param {*} receipt
543
+ * @param {AuditReceipt} receipt
530
544
  * @param {ChainResult} result
531
545
  * @param {string} commitSha
532
546
  * @returns {boolean} true if valid
@@ -556,8 +570,8 @@ export class AuditVerifierService {
556
570
 
557
571
  /**
558
572
  * Validates chain linking between current and previous (newer) receipt.
559
- * @param {*} currentReceipt - The older receipt being validated
560
- * @param {*} prevReceipt - The newer receipt (closer to tip)
573
+ * @param {AuditReceipt} currentReceipt - The older receipt being validated
574
+ * @param {AuditReceipt} prevReceipt - The newer receipt (closer to tip)
561
575
  * @param {string} commitSha
562
576
  * @param {ChainResult} result
563
577
  * @returns {boolean} true if valid
@@ -645,7 +659,7 @@ export class AuditVerifierService {
645
659
  * @param {Object} [options]
646
660
  * @param {string} [options.pin] - Pinned trust chain commit SHA
647
661
  * @param {string} [options.mode] - Policy mode ('warn' or 'enforce')
648
- * @returns {Promise<Record<string, *>>}
662
+ * @returns {Promise<import('../trust/TrustEvaluator.js').TrustAssessment>}
649
663
  */
650
664
  async evaluateTrust(graphName, options = {}) {
651
665
  const recordService = new TrustRecordService({
@@ -103,7 +103,7 @@ export default class BitmapIndexBuilder {
103
103
  this.shaToId = new Map();
104
104
  /** @type {string[]} */
105
105
  this.idToSha = [];
106
- /** @type {Map<string, any>} */
106
+ /** @type {Map<string, import('../utils/roaring.js').RoaringBitmapSubset>} */
107
107
  this.bitmaps = new Map();
108
108
  }
109
109
 
@@ -178,7 +178,7 @@ export default class BitmapIndexBuilder {
178
178
  bitmapShards[type][prefix] = {};
179
179
  }
180
180
  // Encode bitmap as base64 for JSON storage
181
- bitmapShards[type][prefix][sha] = bitmap.serialize(true).toString('base64');
181
+ bitmapShards[type][prefix][sha] = Buffer.from(bitmap.serialize(true)).toString('base64');
182
182
  }
183
183
 
184
184
  for (const type of ['fwd', 'rev']) {
@@ -224,6 +224,6 @@ export default class BitmapIndexBuilder {
224
224
  const RoaringBitmap32 = ensureRoaringBitmap32();
225
225
  this.bitmaps.set(key, new RoaringBitmap32());
226
226
  }
227
- this.bitmaps.get(key).add(id);
227
+ /** @type {import('../utils/roaring.js').RoaringBitmapSubset} */ (this.bitmaps.get(key)).add(id);
228
228
  }
229
229
  }