@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
@@ -8,15 +8,56 @@
8
8
  * @module domain/services/HttpSyncServer
9
9
  */
10
10
 
11
+ import { z } from 'zod';
11
12
  import SyncAuthService from './SyncAuthService.js';
12
13
 
13
14
  const DEFAULT_MAX_REQUEST_BYTES = 4 * 1024 * 1024;
15
+ const MAX_REQUEST_BYTES_CEILING = 128 * 1024 * 1024; // 134217728
16
+
17
+ /**
18
+ * Zod schema for HttpSyncServer constructor options.
19
+ * @private
20
+ */
21
+ const authSchema = z.object({
22
+ mode: z.enum(['enforce', 'log-only']).default('enforce'),
23
+ keys: z.record(z.string()).refine(
24
+ (obj) => Object.keys(obj).length > 0,
25
+ 'auth.keys must not be empty',
26
+ ),
27
+ crypto: /** @type {z.ZodType<import('../../ports/CryptoPort.js').default>} */ (z.custom((v) => v === undefined || (typeof v === 'object' && v !== null))).optional(),
28
+ logger: /** @type {z.ZodType<import('../../ports/LoggerPort.js').default>} */ (z.custom((v) => v === undefined || (typeof v === 'object' && v !== null))).optional(),
29
+ wallClockMs: /** @type {z.ZodType<() => number>} */ (z.custom((v) => v === undefined || typeof v === 'function')).optional(),
30
+ }).strict();
31
+
32
+ const optionsSchema = z.object({
33
+ httpPort: /** @type {z.ZodType<import('../../ports/HttpServerPort.js').default>} */ (z.custom(
34
+ (v) => v !== null && v !== undefined && typeof v === 'object',
35
+ 'httpPort must be a non-null object',
36
+ )),
37
+ graph: /** @type {z.ZodType<import('../WarpGraph.js').default>} */ (z.custom(
38
+ (v) => v !== null && v !== undefined && typeof v === 'object',
39
+ 'graph must be a non-null object',
40
+ )),
41
+ maxRequestBytes: z.number().int().positive().max(MAX_REQUEST_BYTES_CEILING).default(DEFAULT_MAX_REQUEST_BYTES),
42
+ path: z.string().startsWith('/').default('/sync'),
43
+ host: z.string().min(1).default('127.0.0.1'),
44
+ auth: authSchema.optional(),
45
+ allowedWriters: z.array(z.string()).optional(),
46
+ }).strict().superRefine((data, ctx) => {
47
+ if (data.allowedWriters && data.allowedWriters.length > 0 && !data.auth) {
48
+ ctx.addIssue({
49
+ code: z.ZodIssueCode.custom,
50
+ message: 'allowedWriters requires auth.keys to be configured',
51
+ path: ['allowedWriters'],
52
+ });
53
+ }
54
+ });
14
55
 
15
56
  /**
16
57
  * Recursively sorts object keys for deterministic JSON output.
17
58
  *
18
- * @param {*} value - Any JSON-serializable value
19
- * @returns {*} The canonicalized value with sorted object keys
59
+ * @param {unknown} value - Any JSON-serializable value
60
+ * @returns {unknown} The canonicalized value with sorted object keys
20
61
  * @private
21
62
  */
22
63
  function canonicalizeJson(value) {
@@ -24,10 +65,10 @@ function canonicalizeJson(value) {
24
65
  return value.map(canonicalizeJson);
25
66
  }
26
67
  if (value && typeof value === 'object') {
27
- /** @type {{ [x: string]: * }} */
68
+ /** @type {{ [x: string]: unknown }} */
28
69
  const sorted = {};
29
70
  for (const key of Object.keys(value).sort()) {
30
- sorted[key] = canonicalizeJson(/** @type {{ [x: string]: * }} */ (value)[key]);
71
+ sorted[key] = canonicalizeJson(/** @type {{ [x: string]: unknown }} */ (value)[key]);
31
72
  }
32
73
  return sorted;
33
74
  }
@@ -37,7 +78,7 @@ function canonicalizeJson(value) {
37
78
  /**
38
79
  * Produces a canonical JSON string with sorted keys.
39
80
  *
40
- * @param {*} value - Any JSON-serializable value
81
+ * @param {unknown} value - Any JSON-serializable value
41
82
  * @returns {string} Canonical JSON string
42
83
  * @private
43
84
  */
@@ -64,7 +105,7 @@ function errorResponse(status, message) {
64
105
  /**
65
106
  * Builds a JSON success response with canonical key ordering.
66
107
  *
67
- * @param {*} data - Response payload
108
+ * @param {unknown} data - Response payload
68
109
  * @returns {{ status: number, headers: Object, body: string }}
69
110
  * @private
70
111
  */
@@ -79,7 +120,7 @@ function jsonResponse(data) {
79
120
  /**
80
121
  * Validates that a sync request object has the expected shape.
81
122
  *
82
- * @param {*} parsed - Parsed JSON body
123
+ * @param {unknown} parsed - Parsed JSON body
83
124
  * @returns {boolean} True if valid
84
125
  * @private
85
126
  */
@@ -87,10 +128,11 @@ function isValidSyncRequest(parsed) {
87
128
  if (!parsed || typeof parsed !== 'object') {
88
129
  return false;
89
130
  }
90
- if (parsed.type !== 'sync-request') {
131
+ const rec = /** @type {Record<string, unknown>} */ (parsed);
132
+ if (rec.type !== 'sync-request') {
91
133
  return false;
92
134
  }
93
- if (!parsed.frontier || typeof parsed.frontier !== 'object' || Array.isArray(parsed.frontier)) {
135
+ if (!rec.frontier || typeof rec.frontier !== 'object' || Array.isArray(rec.frontier)) {
94
136
  return false;
95
137
  }
96
138
  return true;
@@ -160,7 +202,7 @@ function checkBodySize(body, maxBytes) {
160
202
  * Parses and validates the request body as a sync request.
161
203
  *
162
204
  * @param {Buffer|undefined} body
163
- * @returns {{ error: { status: number, headers: Object, body: string }, parsed: null } | { error: null, parsed: Object }}
205
+ * @returns {{ error: { status: number, headers: Object, body: string }, parsed: null } | { error: null, parsed: import('./SyncProtocol.js').SyncRequest }}
164
206
  * @private
165
207
  */
166
208
  function parseBody(body) {
@@ -183,19 +225,14 @@ function parseBody(body) {
183
225
  /**
184
226
  * Initializes auth service from config if present.
185
227
  *
186
- * @param {{ keys: Record<string, string>, mode?: 'enforce'|'log-only', crypto?: *, logger?: *, wallClockMs?: () => number }|undefined} auth
228
+ * @param {z.infer<typeof authSchema>} [auth]
187
229
  * @param {string[]} [allowedWriters]
188
230
  * @returns {{ auth: SyncAuthService|null, authMode: string|null }}
189
231
  * @private
190
232
  */
191
233
  function initAuth(auth, allowedWriters) {
192
- if (auth && auth.keys) {
193
- const VALID_MODES = new Set(['enforce', 'log-only']);
194
- const mode = auth.mode || 'enforce';
195
- if (!VALID_MODES.has(mode)) {
196
- throw new Error(`Invalid auth.mode: '${mode}'. Must be 'enforce' or 'log-only'.`);
197
- }
198
- return { auth: new SyncAuthService({ ...auth, allowedWriters }), authMode: mode };
234
+ if (auth) {
235
+ return { auth: new SyncAuthService({ ...auth, allowedWriters }), authMode: auth.mode };
199
236
  }
200
237
  return { auth: null, authMode: null };
201
238
  }
@@ -204,26 +241,35 @@ export default class HttpSyncServer {
204
241
  /**
205
242
  * @param {Object} options
206
243
  * @param {import('../../ports/HttpServerPort.js').default} options.httpPort - HTTP server port abstraction
207
- * @param {{ processSyncRequest: (request: *) => Promise<*> }} options.graph - WarpGraph instance (must expose processSyncRequest)
244
+ * @param {{ processSyncRequest: Function }} options.graph - WarpGraph instance (must expose processSyncRequest)
208
245
  * @param {string} [options.path='/sync'] - URL path to handle sync requests on
209
246
  * @param {string} [options.host='127.0.0.1'] - Host to bind
210
247
  * @param {number} [options.maxRequestBytes=4194304] - Maximum request body size in bytes
211
248
  * @param {{ keys: Record<string, string>, mode?: 'enforce'|'log-only', crypto?: import('../../ports/CryptoPort.js').default, logger?: import('../../ports/LoggerPort.js').default, wallClockMs?: () => number }} [options.auth] - Auth configuration
212
249
  * @param {string[]} [options.allowedWriters] - Optional whitelist of allowed writer IDs
213
250
  */
214
- constructor({ httpPort, graph, path = '/sync', host = '127.0.0.1', maxRequestBytes = DEFAULT_MAX_REQUEST_BYTES, auth, allowedWriters } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
215
- this._httpPort = httpPort;
216
- this._graph = graph;
217
- this._path = path && path.startsWith('/') ? path : `/${path || 'sync'}`;
218
- this._host = host;
219
- this._maxRequestBytes = maxRequestBytes;
251
+ constructor(options) {
252
+ /** @type {z.infer<typeof optionsSchema>} */
253
+ let parsed;
254
+ try {
255
+ parsed = optionsSchema.parse(options);
256
+ } catch (err) {
257
+ if (err instanceof z.ZodError) {
258
+ const messages = err.issues.map((i) => i.message).join('; ');
259
+ throw new Error(`HttpSyncServer config: ${messages}`);
260
+ }
261
+ throw err;
262
+ }
263
+
264
+ this._httpPort = parsed.httpPort;
265
+ this._graph = parsed.graph;
266
+ this._path = parsed.path;
267
+ this._host = parsed.host;
268
+ this._maxRequestBytes = parsed.maxRequestBytes;
220
269
  this._server = null;
221
- const authInit = initAuth(auth, allowedWriters);
270
+ const authInit = initAuth(parsed.auth, parsed.allowedWriters);
222
271
  this._auth = authInit.auth;
223
272
  this._authMode = authInit.authMode;
224
- if (allowedWriters && !authInit.auth) {
225
- throw new Error('allowedWriters requires auth.keys to be configured');
226
- }
227
273
  }
228
274
 
229
275
  /**
@@ -234,7 +280,7 @@ export default class HttpSyncServer {
234
280
  * null so the request proceeds.
235
281
  *
236
282
  * @param {{ method: string, url: string, headers: { [x: string]: string }, body: Buffer|undefined }} request
237
- * @param {*} parsed - Parsed sync request body
283
+ * @param {Record<string, unknown>} parsed - Parsed sync request body
238
284
  * @returns {Promise<{ status: number, headers: Object, body: string }|null>}
239
285
  * @private
240
286
  */
@@ -264,29 +310,31 @@ export default class HttpSyncServer {
264
310
  return null;
265
311
  }
266
312
 
267
- /** @param {{ method: string, url: string, headers: { [x: string]: string }, body: Buffer|undefined }} request */
313
+ /** @param {{ method: string, url: string, headers: Object, body: Buffer|undefined }} request */
268
314
  async _handleRequest(request) {
269
- const contentTypeError = checkContentType(request.headers);
315
+ /** @type {{ method: string, url: string, headers: Record<string, string>, body: Buffer|undefined }} */
316
+ const req = { ...request, headers: /** @type {Record<string, string>} */ (request.headers) };
317
+ const contentTypeError = checkContentType(req.headers);
270
318
  if (contentTypeError) {
271
319
  return contentTypeError;
272
320
  }
273
321
 
274
- const routeError = validateRoute(request, this._path, this._host);
322
+ const routeError = validateRoute(req, this._path, this._host);
275
323
  if (routeError) {
276
324
  return routeError;
277
325
  }
278
326
 
279
- const sizeError = checkBodySize(request.body, this._maxRequestBytes);
327
+ const sizeError = checkBodySize(req.body, this._maxRequestBytes);
280
328
  if (sizeError) {
281
329
  return sizeError;
282
330
  }
283
331
 
284
- const { error, parsed } = parseBody(request.body);
332
+ const { error, parsed } = parseBody(req.body);
285
333
  if (error) {
286
334
  return error;
287
335
  }
288
336
 
289
- const authError = await this._authorize(request, parsed);
337
+ const authError = await this._authorize(req, parsed);
290
338
  if (authError) {
291
339
  return authError;
292
340
  }
@@ -294,8 +342,8 @@ export default class HttpSyncServer {
294
342
  try {
295
343
  const response = await this._graph.processSyncRequest(parsed);
296
344
  return jsonResponse(response);
297
- } catch (err) {
298
- return errorResponse(500, /** @type {any} */ (err)?.message || 'Sync failed'); // TODO(ts-cleanup): type error
345
+ } catch (/** @type {unknown} */ err) {
346
+ return errorResponse(500, err instanceof Error ? err.message : 'Sync failed');
299
347
  }
300
348
  }
301
349
 
@@ -311,11 +359,14 @@ export default class HttpSyncServer {
311
359
  throw new Error('listen() requires a numeric port');
312
360
  }
313
361
 
314
- const server = this._httpPort.createServer((/** @type {*} */ request) => this._handleRequest(request)); // TODO(ts-cleanup): type http callback
362
+ /** @type {{ listen: Function, close: Function, address: Function }} */
363
+ const server = this._httpPort.createServer(
364
+ (/** @type {{ method: string, url: string, headers: Object, body: Buffer|undefined }} */ request) => this._handleRequest(request),
365
+ );
315
366
  this._server = server;
316
367
 
317
368
  await /** @type {Promise<void>} */ (new Promise((resolve, reject) => {
318
- server.listen(port, this._host, (/** @type {*} */ err) => { // TODO(ts-cleanup): type http callback
369
+ server.listen(port, this._host, (/** @type {Error|null} */ err) => {
319
370
  if (err) {
320
371
  reject(err);
321
372
  } else {
@@ -332,7 +383,7 @@ export default class HttpSyncServer {
332
383
  url,
333
384
  close: () =>
334
385
  /** @type {Promise<void>} */ (new Promise((resolve, reject) => {
335
- server.close((/** @type {*} */ err) => { // TODO(ts-cleanup): type http callback
386
+ server.close((/** @type {Error|null} */ err) => {
336
387
  if (err) {
337
388
  reject(err);
338
389
  } else {
@@ -50,7 +50,7 @@ export default class IndexRebuildService {
50
50
  * @throws {Error} If graphService is not provided
51
51
  * @throws {Error} If storage adapter is not provided
52
52
  */
53
- constructor({ graphService, storage, logger = nullLogger, codec, crypto } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
53
+ constructor({ graphService, storage, logger = nullLogger, codec, crypto } = /** @type {{ graphService: { iterateNodes: (opts: { ref: string, limit: number }) => AsyncIterable<{ sha: string, parents: string[] }> }, storage: import('../../ports/IndexStoragePort.js').default }} */ ({})) {
54
54
  if (!graphService) {
55
55
  throw new Error('IndexRebuildService requires a graphService');
56
56
  }
@@ -156,7 +156,7 @@ export default class IndexRebuildService {
156
156
  operation: 'rebuild',
157
157
  ref,
158
158
  mode,
159
- error: /** @type {any} */ (err).message, // TODO(ts-cleanup): type error
159
+ error: err instanceof Error ? err.message : String(err),
160
160
  durationMs,
161
161
  });
162
162
  throw err;
@@ -247,12 +247,12 @@ export default class IndexRebuildService {
247
247
  * @private
248
248
  */
249
249
  async _rebuildStreaming(ref, { limit, maxMemoryBytes, onFlush, onProgress, signal, frontier }) {
250
- const builder = new StreamingBitmapIndexBuilder(/** @type {*} */ ({ // TODO(ts-cleanup): narrow port type
250
+ const builder = new StreamingBitmapIndexBuilder({
251
251
  storage: this.storage,
252
252
  maxMemoryBytes,
253
253
  onFlush,
254
254
  crypto: this._crypto,
255
- }));
255
+ });
256
256
 
257
257
  let processedNodes = 0;
258
258
 
@@ -266,7 +266,7 @@ export default class IndexRebuildService {
266
266
  if (processedNodes % 10000 === 0) {
267
267
  checkAborted(signal, 'rebuild');
268
268
  if (onProgress) {
269
- const stats = /** @type {any} */ (builder).getMemoryStats(); // TODO(ts-cleanup): narrow port type
269
+ const stats = /** @type {{ estimatedBitmapBytes: number }} */ (builder.getMemoryStats());
270
270
  onProgress({
271
271
  processedNodes,
272
272
  currentMemoryBytes: stats.estimatedBitmapBytes,
@@ -275,7 +275,7 @@ export default class IndexRebuildService {
275
275
  }
276
276
  }
277
277
 
278
- return await /** @type {any} */ (builder).finalize({ signal, frontier }); // TODO(ts-cleanup): narrow port type
278
+ return await builder.finalize({ signal, frontier });
279
279
  }
280
280
 
281
281
  /**
@@ -389,7 +389,7 @@ export default class IndexRebuildService {
389
389
 
390
390
  // Staleness check
391
391
  if (currentFrontier) {
392
- const indexFrontier = await loadIndexFrontier(shardOids, /** @type {*} */ (this.storage), { codec: this._codec }); // TODO(ts-cleanup): narrow port type
392
+ const indexFrontier = await loadIndexFrontier(shardOids, /** @type {import('../../ports/IndexStoragePort.js').default & import('../../ports/BlobPort.js').default} */ (this.storage), { codec: this._codec });
393
393
  if (indexFrontier) {
394
394
  const result = checkStaleness(indexFrontier, currentFrontier);
395
395
  if (result.stale) {
@@ -6,12 +6,13 @@
6
6
  import defaultCodec from '../utils/defaultCodec.js';
7
7
 
8
8
  /**
9
- * @param {*} envelope
9
+ * @param {unknown} envelope
10
10
  * @param {string} label
11
11
  * @private
12
12
  */
13
13
  function validateEnvelope(envelope, label) {
14
- if (!envelope || typeof envelope !== 'object' || !envelope.frontier || typeof envelope.frontier !== 'object') {
14
+ const rec = /** @type {Record<string, unknown>} */ (envelope);
15
+ if (!rec || typeof rec !== 'object' || !rec.frontier || typeof rec.frontier !== 'object') {
15
16
  throw new Error(`invalid frontier envelope for ${label}`);
16
17
  }
17
18
  }
@@ -25,7 +26,7 @@ function validateEnvelope(envelope, label) {
25
26
  * @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for deserialization
26
27
  * @returns {Promise<Map<string, string>|null>} Frontier map, or null if not present (legacy index)
27
28
  */
28
- export async function loadIndexFrontier(shardOids, storage, { codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
29
+ export async function loadIndexFrontier(shardOids, storage, { codec } = {}) {
29
30
  const c = codec || defaultCodec;
30
31
  const cborOid = shardOids['frontier.cbor'];
31
32
  if (cborOid) {
@@ -29,7 +29,7 @@ export {
29
29
  * @typedef {Object} WarpStateV5
30
30
  * @property {import('../crdt/ORSet.js').ORSet} nodeAlive - ORSet of alive nodes
31
31
  * @property {import('../crdt/ORSet.js').ORSet} edgeAlive - ORSet of alive edges
32
- * @property {Map<string, import('../crdt/LWW.js').LWWRegister<*>>} prop - Properties with LWW
32
+ * @property {Map<string, import('../crdt/LWW.js').LWWRegister<unknown>>} prop - Properties with LWW
33
33
  * @property {import('../crdt/VersionVector.js').VersionVector} observedFrontier - Observed version vector
34
34
  * @property {Map<string, import('../utils/EventId.js').EventId>} edgeBirthEvent - EdgeKey → EventId of most recent EdgeAdd (for clean-slate prop visibility)
35
35
  */
@@ -81,7 +81,7 @@ export function createEmptyStateV5() {
81
81
  * @param {string} [op.to] - Target node ID (for EdgeAdd, EdgeRemove)
82
82
  * @param {string} [op.label] - Edge label (for EdgeAdd, EdgeRemove)
83
83
  * @param {string} [op.key] - Property key (for PropSet)
84
- * @param {*} [op.value] - Property value (for PropSet)
84
+ * @param {unknown} [op.value] - Property value (for PropSet)
85
85
  * @param {import('../utils/EventId.js').EventId} eventId - Event ID for causality tracking
86
86
  * @returns {void}
87
87
  */
@@ -114,7 +114,7 @@ export function applyOpV2(state, op, eventId) {
114
114
  // Uses EventId-based LWW, same as v4
115
115
  const key = encodePropKey(/** @type {string} */ (op.node), /** @type {string} */ (op.key));
116
116
  const current = state.prop.get(key);
117
- state.prop.set(key, /** @type {import('../crdt/LWW.js').LWWRegister<*>} */ (lwwMax(current, lwwSet(eventId, op.value))));
117
+ state.prop.set(key, /** @type {import('../crdt/LWW.js').LWWRegister<unknown>} */ (lwwMax(current, lwwSet(eventId, op.value))));
118
118
  break;
119
119
  }
120
120
  default:
@@ -290,11 +290,11 @@ function edgeRemoveOutcome(orset, op) {
290
290
  * - `superseded`: An existing value with higher EventId wins
291
291
  * - `redundant`: Exact same write (identical EventId)
292
292
  *
293
- * @param {Map<string, import('../crdt/LWW.js').LWWRegister<*>>} propMap - The properties map keyed by encoded prop keys
293
+ * @param {Map<string, import('../crdt/LWW.js').LWWRegister<unknown>>} propMap - The properties map keyed by encoded prop keys
294
294
  * @param {Object} op - The PropSet operation
295
295
  * @param {string} op.node - Node ID owning the property
296
296
  * @param {string} op.key - Property key/name
297
- * @param {*} op.value - Property value to set
297
+ * @param {unknown} op.value - Property value to set
298
298
  * @param {import('../utils/EventId.js').EventId} eventId - The event ID for this operation, used for LWW comparison
299
299
  * @returns {{target: string, result: 'applied'|'superseded'|'redundant', reason?: string}}
300
300
  * Outcome with encoded prop key as target; includes reason when superseded
@@ -347,7 +347,7 @@ function propSetOutcome(propMap, op, eventId) {
347
347
  * @param {Object} patch - The patch to apply
348
348
  * @param {string} patch.writer - Writer ID who created this patch
349
349
  * @param {number} patch.lamport - Lamport timestamp of this patch
350
- * @param {Array<{type: string, node?: string, dot?: import('../crdt/Dot.js').Dot, observedDots?: string[], from?: string, to?: string, label?: string, key?: string, value?: *, oid?: string}>} patch.ops - Array of operations to apply
350
+ * @param {Array<{type: string, node?: string, dot?: import('../crdt/Dot.js').Dot, observedDots?: string[], from?: string, to?: string, label?: string, key?: string, value?: unknown, oid?: string}>} patch.ops - Array of operations to apply
351
351
  * @param {Map<string, number>|{[x: string]: number}} patch.context - Version vector context (Map or serialized form)
352
352
  * @param {string} patchSha - The Git SHA of the patch commit (used for EventId creation)
353
353
  * @param {boolean} [collectReceipts=false] - When true, computes and returns receipt data
@@ -470,16 +470,16 @@ export function joinStates(a, b) {
470
470
  *
471
471
  * This is a pure function that does not mutate its inputs.
472
472
  *
473
- * @param {Map<string, import('../crdt/LWW.js').LWWRegister<*>>} a - First property map
474
- * @param {Map<string, import('../crdt/LWW.js').LWWRegister<*>>} b - Second property map
475
- * @returns {Map<string, import('../crdt/LWW.js').LWWRegister<*>>} New map containing merged properties
473
+ * @param {Map<string, import('../crdt/LWW.js').LWWRegister<unknown>>} a - First property map
474
+ * @param {Map<string, import('../crdt/LWW.js').LWWRegister<unknown>>} b - Second property map
475
+ * @returns {Map<string, import('../crdt/LWW.js').LWWRegister<unknown>>} New map containing merged properties
476
476
  */
477
477
  function mergeProps(a, b) {
478
478
  const result = new Map(a);
479
479
 
480
480
  for (const [key, regB] of b) {
481
481
  const regA = result.get(key);
482
- result.set(key, /** @type {import('../crdt/LWW.js').LWWRegister<*>} */ (lwwMax(regA, regB)));
482
+ result.set(key, /** @type {import('../crdt/LWW.js').LWWRegister<unknown>} */ (lwwMax(regA, regB)));
483
483
  }
484
484
 
485
485
  return result;
@@ -530,7 +530,7 @@ function mergeEdgeBirthEvent(a, b) {
530
530
  * - When `options.receipts` is true, returns a TickReceipt per patch for
531
531
  * provenance tracking and debugging.
532
532
  *
533
- * @param {Array<{patch: {writer: string, lamport: number, ops: Array<{type: string, node?: string, dot?: import('../crdt/Dot.js').Dot, observedDots?: string[], from?: string, to?: string, label?: string, key?: string, value?: *, oid?: string}>, context: Map<string, number>|{[x: string]: number}}, sha: string}>} patches - Array of patch objects with their Git SHAs
533
+ * @param {Array<{patch: {writer: string, lamport: number, ops: Array<{type: string, node?: string, dot?: import('../crdt/Dot.js').Dot, observedDots?: string[], from?: string, to?: string, label?: string, key?: string, value?: unknown, oid?: string}>, context: Map<string, number>|{[x: string]: number}}, sha: string}>} patches - Array of patch objects with their Git SHAs
534
534
  * @param {WarpStateV5} [initialState] - Optional starting state (for incremental materialization from checkpoint)
535
535
  * @param {Object} [options] - Optional configuration
536
536
  * @param {boolean} [options.receipts=false] - When true, collect and return TickReceipts
@@ -152,7 +152,7 @@ export default class LogicalTraversal {
152
152
  * @throws {TraversalError} If the labelFilter is invalid (INVALID_LABEL_FILTER)
153
153
  */
154
154
  async _prepare(start, { dir, labelFilter, maxDepth }) {
155
- const materialized = await /** @type {any} */ (this._graph)._materializeGraph(); // TODO(ts-cleanup): narrow port type
155
+ const materialized = await /** @type {{ _materializeGraph: () => Promise<{adjacency: {outgoing: Map<string, Array<{neighborId: string, label: string}>>, incoming: Map<string, Array<{neighborId: string, label: string}>>}}> }} */ (this._graph)._materializeGraph();
156
156
 
157
157
  if (!(await this._graph.hasNode(start))) {
158
158
  throw new TraversalError(`Start node not found: ${start}`, {
@@ -66,7 +66,7 @@ const SHA256_PATTERN = /^[0-9a-f]{64}$/;
66
66
  // -----------------------------------------------------------------------------
67
67
 
68
68
  // Lazy singleton codec instance
69
- /** @type {*} */ // TODO(ts-cleanup): type lazy singleton
69
+ /** @type {TrailerCodec|null} */
70
70
  let _codec = null;
71
71
 
72
72
  /**
@@ -16,7 +16,7 @@ import { createVersionVector, vvIncrement } from '../crdt/VersionVector.js';
16
16
  * @param {Object} v4State - The V4 materialized state (visible projection)
17
17
  * @param {Map<string, {value: boolean}>} v4State.nodeAlive - V4 node alive map
18
18
  * @param {Map<string, {value: boolean}>} v4State.edgeAlive - V4 edge alive map
19
- * @param {Map<string, *>} v4State.prop - V4 property map
19
+ * @param {Map<string, import('../crdt/LWW.js').LWWRegister<unknown>>} v4State.prop - V4 property map
20
20
  * @param {string} migrationWriterId - Writer ID to use for synthetic dots
21
21
  * @returns {import('./JoinReducer.js').WarpStateV5} The migrated V5 state
22
22
  */
@@ -43,10 +43,10 @@ function matchGlob(pattern, str) {
43
43
  * - If `expose` is provided and non-empty, only keys in `expose` are included.
44
44
  * - If `expose` is absent/empty, all non-redacted keys are included.
45
45
  *
46
- * @param {Map<string, *>} propsMap - The full properties Map
46
+ * @param {Map<string, unknown>} propsMap - The full properties Map
47
47
  * @param {string[]|undefined} expose - Whitelist of property keys to include
48
48
  * @param {string[]|undefined} redact - Blacklist of property keys to exclude
49
- * @returns {Map<string, *>} Filtered properties Map
49
+ * @returns {Map<string, unknown>} Filtered properties Map
50
50
  */
51
51
  function filterProps(propsMap, expose, redact) {
52
52
  const redactSet = redact && redact.length > 0 ? new Set(redact) : null;
@@ -102,7 +102,7 @@ export default class ObserverView {
102
102
  this._graph = graph;
103
103
 
104
104
  /** @type {LogicalTraversal} */
105
- this.traverse = new LogicalTraversal(/** @type {*} */ (this)); // TODO(ts-cleanup): type observer cast
105
+ this.traverse = new LogicalTraversal(/** @type {import('../WarpGraph.js').default} */ (/** @type {unknown} */ (this)));
106
106
  }
107
107
 
108
108
  /**
@@ -124,11 +124,11 @@ export default class ObserverView {
124
124
  * Builds a filtered adjacency structure that only includes edges
125
125
  * where both endpoints pass the match filter.
126
126
  *
127
- * @returns {Promise<{state: *, stateHash: string, adjacency: {outgoing: Map<string, *[]>, incoming: Map<string, *[]>}}>}
127
+ * @returns {Promise<{state: unknown, stateHash: string, adjacency: {outgoing: Map<string, unknown[]>, incoming: Map<string, unknown[]>}}>}
128
128
  * @private
129
129
  */
130
130
  async _materializeGraph() {
131
- const materialized = await /** @type {*} */ (this._graph)._materializeGraph(); // TODO(ts-cleanup): narrow port type
131
+ const materialized = await /** @type {{ _materializeGraph: () => Promise<{state: import('./JoinReducer.js').WarpStateV5, stateHash: string, adjacency: {outgoing: Map<string, Array<{neighborId: string, label: string}>>, incoming: Map<string, Array<{neighborId: string, label: string}>>}}> }} */ (this._graph)._materializeGraph();
132
132
  const { state, stateHash } = materialized;
133
133
 
134
134
  // Build filtered adjacency: only edges where both endpoints match
@@ -212,7 +212,7 @@ export default class ObserverView {
212
212
  * the observer pattern.
213
213
  *
214
214
  * @param {string} nodeId - The node ID to get properties for
215
- * @returns {Promise<Map<string, *>|null>} Filtered properties Map, or null
215
+ * @returns {Promise<Map<string, unknown>|null>} Filtered properties Map, or null
216
216
  */
217
217
  async getNodeProps(nodeId) {
218
218
  if (!matchGlob(this._matchPattern, nodeId)) {
@@ -234,7 +234,7 @@ export default class ObserverView {
234
234
  *
235
235
  * An edge is visible only when both endpoints match the observer pattern.
236
236
  *
237
- * @returns {Promise<Array<{from: string, to: string, label: string, props: Record<string, *>}>>}
237
+ * @returns {Promise<Array<{from: string, to: string, label: string, props: Record<string, unknown>}>>}
238
238
  */
239
239
  async getEdges() {
240
240
  const allEdges = await this._graph.getEdges();
@@ -260,6 +260,6 @@ export default class ObserverView {
260
260
  * @returns {QueryBuilder} A query builder scoped to this observer
261
261
  */
262
262
  query() {
263
- return new QueryBuilder(/** @type {*} */ (this)); // TODO(ts-cleanup): type observer cast
263
+ return new QueryBuilder(/** @type {import('../WarpGraph.js').default} */ (/** @type {unknown} */ (this)));
264
264
  }
265
265
  }