@git-stunts/git-warp 10.3.2 → 10.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/SECURITY.md +89 -1
- package/bin/warp-graph.js +574 -208
- package/index.d.ts +55 -0
- package/index.js +4 -0
- package/package.json +8 -4
- package/src/domain/WarpGraph.js +334 -161
- package/src/domain/crdt/LWW.js +1 -1
- package/src/domain/crdt/ORSet.js +10 -6
- package/src/domain/crdt/VersionVector.js +5 -1
- package/src/domain/errors/EmptyMessageError.js +2 -4
- package/src/domain/errors/ForkError.js +4 -0
- package/src/domain/errors/IndexError.js +4 -0
- package/src/domain/errors/OperationAbortedError.js +4 -0
- package/src/domain/errors/QueryError.js +4 -0
- package/src/domain/errors/SchemaUnsupportedError.js +4 -0
- package/src/domain/errors/ShardCorruptionError.js +2 -6
- package/src/domain/errors/ShardLoadError.js +2 -6
- package/src/domain/errors/ShardValidationError.js +2 -7
- package/src/domain/errors/StorageError.js +2 -6
- package/src/domain/errors/SyncError.js +4 -0
- package/src/domain/errors/TraversalError.js +4 -0
- package/src/domain/errors/WarpError.js +2 -4
- package/src/domain/errors/WormholeError.js +4 -0
- package/src/domain/services/AnchorMessageCodec.js +1 -4
- package/src/domain/services/BitmapIndexBuilder.js +10 -6
- package/src/domain/services/BitmapIndexReader.js +27 -21
- package/src/domain/services/BoundaryTransitionRecord.js +22 -15
- package/src/domain/services/CheckpointMessageCodec.js +1 -7
- package/src/domain/services/CheckpointSerializerV5.js +20 -19
- package/src/domain/services/CheckpointService.js +18 -18
- package/src/domain/services/CommitDagTraversalService.js +13 -1
- package/src/domain/services/DagPathFinding.js +40 -18
- package/src/domain/services/DagTopology.js +7 -6
- package/src/domain/services/DagTraversal.js +5 -3
- package/src/domain/services/Frontier.js +7 -6
- package/src/domain/services/HealthCheckService.js +15 -14
- package/src/domain/services/HookInstaller.js +64 -13
- package/src/domain/services/HttpSyncServer.js +88 -19
- package/src/domain/services/IndexRebuildService.js +12 -12
- package/src/domain/services/IndexStalenessChecker.js +13 -6
- package/src/domain/services/JoinReducer.js +28 -27
- package/src/domain/services/LogicalTraversal.js +7 -6
- package/src/domain/services/MessageCodecInternal.js +2 -0
- package/src/domain/services/ObserverView.js +6 -6
- package/src/domain/services/PatchBuilderV2.js +9 -9
- package/src/domain/services/PatchMessageCodec.js +1 -7
- package/src/domain/services/ProvenanceIndex.js +6 -8
- package/src/domain/services/ProvenancePayload.js +1 -2
- package/src/domain/services/QueryBuilder.js +29 -23
- package/src/domain/services/StateDiff.js +7 -7
- package/src/domain/services/StateSerializerV5.js +8 -6
- package/src/domain/services/StreamingBitmapIndexBuilder.js +29 -23
- package/src/domain/services/SyncAuthService.js +396 -0
- package/src/domain/services/SyncProtocol.js +23 -26
- package/src/domain/services/TemporalQuery.js +4 -3
- package/src/domain/services/TranslationCost.js +4 -4
- package/src/domain/services/WormholeService.js +19 -15
- package/src/domain/types/TickReceipt.js +10 -6
- package/src/domain/types/WarpTypesV2.js +2 -3
- package/src/domain/utils/CachedValue.js +1 -1
- package/src/domain/utils/LRUCache.js +3 -3
- package/src/domain/utils/MinHeap.js +2 -2
- package/src/domain/utils/RefLayout.js +19 -0
- package/src/domain/utils/WriterId.js +2 -2
- package/src/domain/utils/defaultCodec.js +9 -2
- package/src/domain/utils/defaultCrypto.js +36 -0
- package/src/domain/utils/roaring.js +5 -5
- package/src/domain/utils/seekCacheKey.js +32 -0
- package/src/domain/warp/PatchSession.js +3 -3
- package/src/domain/warp/Writer.js +2 -2
- package/src/infrastructure/adapters/BunHttpAdapter.js +21 -8
- package/src/infrastructure/adapters/CasSeekCacheAdapter.js +311 -0
- package/src/infrastructure/adapters/ClockAdapter.js +2 -2
- package/src/infrastructure/adapters/DenoHttpAdapter.js +22 -9
- package/src/infrastructure/adapters/GitGraphAdapter.js +25 -83
- package/src/infrastructure/adapters/InMemoryGraphAdapter.js +488 -0
- package/src/infrastructure/adapters/NodeCryptoAdapter.js +16 -3
- package/src/infrastructure/adapters/NodeHttpAdapter.js +33 -11
- package/src/infrastructure/adapters/WebCryptoAdapter.js +21 -11
- package/src/infrastructure/adapters/adapterValidation.js +90 -0
- package/src/infrastructure/codecs/CborCodec.js +16 -8
- package/src/ports/BlobPort.js +2 -2
- package/src/ports/CodecPort.js +2 -2
- package/src/ports/CommitPort.js +8 -21
- package/src/ports/ConfigPort.js +3 -3
- package/src/ports/CryptoPort.js +7 -7
- package/src/ports/GraphPersistencePort.js +12 -14
- package/src/ports/HttpServerPort.js +1 -5
- package/src/ports/IndexStoragePort.js +1 -0
- package/src/ports/LoggerPort.js +9 -9
- package/src/ports/RefPort.js +5 -5
- package/src/ports/SeekCachePort.js +73 -0
- package/src/ports/TreePort.js +3 -3
- package/src/visualization/layouts/converters.js +14 -7
- package/src/visualization/layouts/elkAdapter.js +17 -4
- package/src/visualization/layouts/elkLayout.js +23 -7
- package/src/visualization/layouts/index.js +3 -3
- package/src/visualization/renderers/ascii/check.js +30 -17
- package/src/visualization/renderers/ascii/graph.js +92 -1
- package/src/visualization/renderers/ascii/history.js +28 -26
- package/src/visualization/renderers/ascii/info.js +9 -7
- package/src/visualization/renderers/ascii/materialize.js +20 -16
- package/src/visualization/renderers/ascii/opSummary.js +15 -7
- package/src/visualization/renderers/ascii/path.js +1 -1
- package/src/visualization/renderers/ascii/seek.js +187 -23
- package/src/visualization/renderers/ascii/table.js +1 -1
- package/src/visualization/renderers/svg/index.js +5 -1
|
@@ -82,10 +82,10 @@ const BTR_VERSION = 1;
|
|
|
82
82
|
* @param {string} fields.h_in - Hash of input state
|
|
83
83
|
* @param {string} fields.h_out - Hash of output state
|
|
84
84
|
* @param {Uint8Array} fields.U_0 - Serialized initial state
|
|
85
|
-
* @param {Array} fields.P - Serialized provenance payload
|
|
85
|
+
* @param {Array<*>} fields.P - Serialized provenance payload
|
|
86
86
|
* @param {string} fields.t - ISO timestamp
|
|
87
87
|
* @param {string|Uint8Array} key - HMAC key
|
|
88
|
-
* @param {import('../../ports/CryptoPort.js').default}
|
|
88
|
+
* @param {{ crypto: import('../../ports/CryptoPort.js').default, codec?: import('../../ports/CodecPort.js').default }} deps - Dependencies
|
|
89
89
|
* @returns {Promise<string>} Hex-encoded HMAC tag
|
|
90
90
|
* @private
|
|
91
91
|
*/
|
|
@@ -111,7 +111,7 @@ async function computeHmac(fields, key, { crypto, codec }) {
|
|
|
111
111
|
* @property {string} h_in - Hash of input state (hex SHA-256)
|
|
112
112
|
* @property {string} h_out - Hash of output state (hex SHA-256)
|
|
113
113
|
* @property {Uint8Array} U_0 - Serialized initial state (CBOR)
|
|
114
|
-
* @property {Array} P - Serialized provenance payload
|
|
114
|
+
* @property {Array<*>} P - Serialized provenance payload
|
|
115
115
|
* @property {string} t - ISO 8601 timestamp
|
|
116
116
|
* @property {string} kappa - Authentication tag (hex HMAC-SHA256)
|
|
117
117
|
*/
|
|
@@ -155,6 +155,7 @@ async function computeHmac(fields, key, { crypto, codec }) {
|
|
|
155
155
|
* @param {string|Uint8Array} options.key - HMAC key for authentication
|
|
156
156
|
* @param {string} [options.timestamp] - ISO timestamp (defaults to now)
|
|
157
157
|
* @param {import('../../ports/CryptoPort.js').default} options.crypto - CryptoPort instance
|
|
158
|
+
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for serialization
|
|
158
159
|
* @returns {Promise<BTR>} The created BTR
|
|
159
160
|
* @throws {TypeError} If payload is not a ProvenancePayload
|
|
160
161
|
*/
|
|
@@ -212,7 +213,7 @@ function validateBTRStructure(btr) {
|
|
|
212
213
|
*
|
|
213
214
|
* @param {BTR} btr - The BTR to verify
|
|
214
215
|
* @param {string|Uint8Array} key - HMAC key
|
|
215
|
-
* @param {import('../../ports/CryptoPort.js').default}
|
|
216
|
+
* @param {{ crypto: import('../../ports/CryptoPort.js').default, codec?: import('../../ports/CodecPort.js').default }} deps - Dependencies
|
|
216
217
|
* @returns {Promise<boolean>} True if the HMAC tag matches
|
|
217
218
|
* @private
|
|
218
219
|
*/
|
|
@@ -243,10 +244,13 @@ async function verifyHmac(btr, key, { crypto, codec }) {
|
|
|
243
244
|
* Verifies replay produces expected h_out.
|
|
244
245
|
*
|
|
245
246
|
* @param {BTR} btr - The BTR to verify
|
|
247
|
+
* @param {Object} [deps] - Dependencies
|
|
248
|
+
* @param {import('../../ports/CryptoPort.js').default} [deps.crypto] - CryptoPort instance
|
|
249
|
+
* @param {import('../../ports/CodecPort.js').default} [deps.codec] - Codec
|
|
246
250
|
* @returns {Promise<string|null>} Error message if replay mismatch, null if valid
|
|
247
251
|
* @private
|
|
248
252
|
*/
|
|
249
|
-
async function verifyReplayHash(btr, { crypto, codec } = {}) {
|
|
253
|
+
async function verifyReplayHash(btr, { crypto, codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
250
254
|
try {
|
|
251
255
|
const result = await replayBTR(btr, { crypto, codec });
|
|
252
256
|
if (result.h_out !== btr.h_out) {
|
|
@@ -254,7 +258,7 @@ async function verifyReplayHash(btr, { crypto, codec } = {}) {
|
|
|
254
258
|
}
|
|
255
259
|
return null;
|
|
256
260
|
} catch (err) {
|
|
257
|
-
return `Replay failed: ${err.message}`;
|
|
261
|
+
return `Replay failed: ${/** @type {any} */ (err).message}`; // TODO(ts-cleanup): type error
|
|
258
262
|
}
|
|
259
263
|
}
|
|
260
264
|
|
|
@@ -272,10 +276,11 @@ async function verifyReplayHash(btr, { crypto, codec } = {}) {
|
|
|
272
276
|
* @param {string|Uint8Array} key - HMAC key
|
|
273
277
|
* @param {Object} [options] - Verification options
|
|
274
278
|
* @param {boolean} [options.verifyReplay=false] - Also verify replay produces h_out
|
|
275
|
-
* @param {import('../../ports/CryptoPort.js').default} options.crypto - CryptoPort instance
|
|
279
|
+
* @param {import('../../ports/CryptoPort.js').default} [options.crypto] - CryptoPort instance
|
|
280
|
+
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for serialization
|
|
276
281
|
* @returns {Promise<VerificationResult>} Verification result with valid flag and optional reason
|
|
277
282
|
*/
|
|
278
|
-
export async function verifyBTR(btr, key, options = {}) {
|
|
283
|
+
export async function verifyBTR(btr, key, options = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
279
284
|
const { crypto, codec } = options;
|
|
280
285
|
|
|
281
286
|
const structureError = validateBTRStructure(btr);
|
|
@@ -285,7 +290,7 @@ export async function verifyBTR(btr, key, options = {}) {
|
|
|
285
290
|
|
|
286
291
|
let hmacValid;
|
|
287
292
|
try {
|
|
288
|
-
hmacValid = await verifyHmac(btr, key, { crypto, codec });
|
|
293
|
+
hmacValid = await verifyHmac(btr, key, { crypto: /** @type {import('../../ports/CryptoPort.js').default} */ (crypto), codec });
|
|
289
294
|
} catch (err) {
|
|
290
295
|
if (err instanceof RangeError) {
|
|
291
296
|
return { valid: false, reason: `Invalid hex in authentication tag: ${err.message}` };
|
|
@@ -313,11 +318,12 @@ export async function verifyBTR(btr, key, options = {}) {
|
|
|
313
318
|
* encoding (U_0, P), replay uniquely determines the interior worldline.
|
|
314
319
|
*
|
|
315
320
|
* @param {BTR} btr - The BTR to replay
|
|
321
|
+
* @param {{ crypto?: import('../../ports/CryptoPort.js').default, codec?: import('../../ports/CodecPort.js').default }} deps - Dependencies
|
|
316
322
|
* @returns {Promise<{ state: import('./JoinReducer.js').WarpStateV5, h_out: string }>}
|
|
317
323
|
* The final state and its hash
|
|
318
324
|
* @throws {Error} If replay fails
|
|
319
325
|
*/
|
|
320
|
-
export async function replayBTR(btr, { crypto, codec } = {}) {
|
|
326
|
+
export async function replayBTR(btr, { crypto, codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
321
327
|
// Deserialize initial state from U_0
|
|
322
328
|
// Note: U_0 is the full serialized state (via serializeFullStateV5)
|
|
323
329
|
const initialState = deserializeInitialState(btr.U_0, { codec });
|
|
@@ -329,7 +335,7 @@ export async function replayBTR(btr, { crypto, codec } = {}) {
|
|
|
329
335
|
const finalState = payload.replay(initialState);
|
|
330
336
|
|
|
331
337
|
// Compute h_out
|
|
332
|
-
const h_out = await computeStateHashV5(finalState, { crypto, codec });
|
|
338
|
+
const h_out = await computeStateHashV5(finalState, { crypto: /** @type {import('../../ports/CryptoPort.js').default} */ (crypto), codec });
|
|
333
339
|
|
|
334
340
|
return { state: finalState, h_out };
|
|
335
341
|
}
|
|
@@ -345,10 +351,11 @@ export async function replayBTR(btr, { crypto, codec } = {}) {
|
|
|
345
351
|
* the correct h_out hash.
|
|
346
352
|
*
|
|
347
353
|
* @param {Uint8Array} U_0 - Serialized full state
|
|
354
|
+
* @param {{ codec?: import('../../ports/CodecPort.js').default }} options
|
|
348
355
|
* @returns {import('./JoinReducer.js').WarpStateV5} The deserialized state
|
|
349
356
|
* @private
|
|
350
357
|
*/
|
|
351
|
-
function deserializeInitialState(U_0, { codec } = {}) {
|
|
358
|
+
function deserializeInitialState(U_0, { codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
352
359
|
return deserializeFullStateV5(U_0, { codec });
|
|
353
360
|
}
|
|
354
361
|
|
|
@@ -363,7 +370,7 @@ function deserializeInitialState(U_0, { codec } = {}) {
|
|
|
363
370
|
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for serialization
|
|
364
371
|
* @returns {Uint8Array} CBOR-encoded BTR
|
|
365
372
|
*/
|
|
366
|
-
export function serializeBTR(btr, { codec } = {}) {
|
|
373
|
+
export function serializeBTR(btr, { codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
367
374
|
const c = codec || defaultCodec;
|
|
368
375
|
return c.encode({
|
|
369
376
|
version: btr.version,
|
|
@@ -385,9 +392,9 @@ export function serializeBTR(btr, { codec } = {}) {
|
|
|
385
392
|
* @returns {BTR} The deserialized BTR
|
|
386
393
|
* @throws {Error} If the bytes are not valid CBOR or missing required fields
|
|
387
394
|
*/
|
|
388
|
-
export function deserializeBTR(bytes, { codec } = {}) {
|
|
395
|
+
export function deserializeBTR(bytes, { codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
389
396
|
const c = codec || defaultCodec;
|
|
390
|
-
const obj = c.decode(bytes);
|
|
397
|
+
const obj = /** @type {Record<string, *>} */ (c.decode(bytes));
|
|
391
398
|
|
|
392
399
|
// Validate structure (reuse module-level constant for consistency with validateBTRStructure)
|
|
393
400
|
for (const field of REQUIRED_FIELDS) {
|
|
@@ -79,13 +79,7 @@ export function encodeCheckpointMessage({ graph, stateHash, frontierOid, indexOi
|
|
|
79
79
|
* Decodes a checkpoint commit message.
|
|
80
80
|
*
|
|
81
81
|
* @param {string} message - The raw commit message
|
|
82
|
-
* @returns {
|
|
83
|
-
* @returns {string} return.kind - Always 'checkpoint'
|
|
84
|
-
* @returns {string} return.graph - The graph name
|
|
85
|
-
* @returns {string} return.stateHash - The SHA-256 state hash
|
|
86
|
-
* @returns {string} return.frontierOid - The frontier blob OID
|
|
87
|
-
* @returns {string} return.indexOid - The index tree OID
|
|
88
|
-
* @returns {number} return.schema - The schema version
|
|
82
|
+
* @returns {{ kind: 'checkpoint', graph: string, stateHash: string, frontierOid: string, indexOid: string, schema: number, checkpointVersion: string|null }} The decoded checkpoint message
|
|
89
83
|
* @throws {Error} If the message is not a valid checkpoint message
|
|
90
84
|
*
|
|
91
85
|
* @example
|
|
@@ -37,9 +37,9 @@ import { createEmptyStateV5 } from './JoinReducer.js';
|
|
|
37
37
|
* @param {import('./JoinReducer.js').WarpStateV5} state
|
|
38
38
|
* @param {Object} [options]
|
|
39
39
|
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for serialization
|
|
40
|
-
* @returns {Buffer} CBOR-encoded full state
|
|
40
|
+
* @returns {Buffer|Uint8Array} CBOR-encoded full state
|
|
41
41
|
*/
|
|
42
|
-
export function serializeFullStateV5(state, { codec } = {}) {
|
|
42
|
+
export function serializeFullStateV5(state, { codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
43
43
|
const c = codec || defaultCodec;
|
|
44
44
|
// Serialize ORSets using existing serialization
|
|
45
45
|
const nodeAliveObj = orsetSerialize(state.nodeAlive);
|
|
@@ -84,20 +84,20 @@ export function serializeFullStateV5(state, { codec } = {}) {
|
|
|
84
84
|
/**
|
|
85
85
|
* Deserializes full V5 state. Used for resume.
|
|
86
86
|
*
|
|
87
|
-
* @param {Buffer} buffer - CBOR-encoded full state
|
|
87
|
+
* @param {Buffer|Uint8Array} buffer - CBOR-encoded full state
|
|
88
88
|
* @param {Object} [options]
|
|
89
89
|
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for deserialization
|
|
90
90
|
* @returns {import('./JoinReducer.js').WarpStateV5}
|
|
91
91
|
*/
|
|
92
92
|
// eslint-disable-next-line complexity
|
|
93
|
-
export function deserializeFullStateV5(buffer, { codec: codecOpt } = {}) {
|
|
93
|
+
export function deserializeFullStateV5(buffer, { codec: codecOpt } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
94
94
|
const codec = codecOpt || defaultCodec;
|
|
95
95
|
// Handle null/undefined buffer before attempting decode
|
|
96
96
|
if (buffer === null || buffer === undefined) {
|
|
97
97
|
return createEmptyStateV5();
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
const obj = codec.decode(buffer);
|
|
100
|
+
const obj = /** @type {Record<string, *>} */ (codec.decode(buffer));
|
|
101
101
|
|
|
102
102
|
// Handle null/undefined decoded result: return empty state
|
|
103
103
|
if (obj === null || obj === undefined) {
|
|
@@ -117,7 +117,7 @@ export function deserializeFullStateV5(buffer, { codec: codecOpt } = {}) {
|
|
|
117
117
|
edgeAlive: orsetDeserialize(obj.edgeAlive || {}),
|
|
118
118
|
prop: deserializeProps(obj.prop),
|
|
119
119
|
observedFrontier: vvDeserialize(obj.observedFrontier || {}),
|
|
120
|
-
edgeBirthEvent: deserializeEdgeBirthEvent(obj),
|
|
120
|
+
edgeBirthEvent: /** @type {Map<string, import('../utils/EventId.js').EventId>} */ (deserializeEdgeBirthEvent(obj)),
|
|
121
121
|
};
|
|
122
122
|
}
|
|
123
123
|
|
|
@@ -170,9 +170,9 @@ export function computeAppliedVV(state) {
|
|
|
170
170
|
* @param {Map<string, number>} vv - Version vector (Map<writerId, counter>)
|
|
171
171
|
* @param {Object} [options]
|
|
172
172
|
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for serialization
|
|
173
|
-
* @returns {Buffer} CBOR-encoded version vector
|
|
173
|
+
* @returns {Buffer|Uint8Array} CBOR-encoded version vector
|
|
174
174
|
*/
|
|
175
|
-
export function serializeAppliedVV(vv, { codec } = {}) {
|
|
175
|
+
export function serializeAppliedVV(vv, { codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
176
176
|
const c = codec || defaultCodec;
|
|
177
177
|
const obj = vvSerialize(vv);
|
|
178
178
|
return c.encode(obj);
|
|
@@ -181,14 +181,14 @@ export function serializeAppliedVV(vv, { codec } = {}) {
|
|
|
181
181
|
/**
|
|
182
182
|
* Deserializes appliedVV from CBOR format.
|
|
183
183
|
*
|
|
184
|
-
* @param {Buffer} buffer - CBOR-encoded version vector
|
|
184
|
+
* @param {Buffer|Uint8Array} buffer - CBOR-encoded version vector
|
|
185
185
|
* @param {Object} [options]
|
|
186
186
|
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for deserialization
|
|
187
187
|
* @returns {Map<string, number>} Version vector
|
|
188
188
|
*/
|
|
189
|
-
export function deserializeAppliedVV(buffer, { codec } = {}) {
|
|
189
|
+
export function deserializeAppliedVV(buffer, { codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
190
190
|
const c = codec || defaultCodec;
|
|
191
|
-
const obj = c.decode(buffer);
|
|
191
|
+
const obj = /** @type {{ [x: string]: number }} */ (c.decode(buffer));
|
|
192
192
|
return vvDeserialize(obj);
|
|
193
193
|
}
|
|
194
194
|
|
|
@@ -198,8 +198,8 @@ export function deserializeAppliedVV(buffer, { codec } = {}) {
|
|
|
198
198
|
|
|
199
199
|
/**
|
|
200
200
|
* Deserializes the props array from checkpoint format.
|
|
201
|
-
* @param {Array} propArray - Array of [key, registerObj] pairs
|
|
202
|
-
* @returns {Map<string, import('../crdt/LWW.js').LWWRegister
|
|
201
|
+
* @param {Array<*>} propArray - Array of [key, registerObj] pairs
|
|
202
|
+
* @returns {Map<string, import('../crdt/LWW.js').LWWRegister<*>>}
|
|
203
203
|
*/
|
|
204
204
|
function deserializeProps(propArray) {
|
|
205
205
|
const prop = new Map();
|
|
@@ -213,10 +213,11 @@ function deserializeProps(propArray) {
|
|
|
213
213
|
|
|
214
214
|
/**
|
|
215
215
|
* Deserializes edge birth event data, supporting both legacy and current formats.
|
|
216
|
-
* @param {
|
|
217
|
-
* @returns {Map<string,
|
|
216
|
+
* @param {Record<string, *>} obj - The decoded checkpoint object
|
|
217
|
+
* @returns {Map<string, import('../utils/EventId.js').EventId>}
|
|
218
218
|
*/
|
|
219
219
|
function deserializeEdgeBirthEvent(obj) {
|
|
220
|
+
/** @type {Map<string, import('../utils/EventId.js').EventId>} */
|
|
220
221
|
const edgeBirthEvent = new Map();
|
|
221
222
|
const birthData = obj.edgeBirthEvent || obj.edgeBirthLamport;
|
|
222
223
|
if (birthData && Array.isArray(birthData)) {
|
|
@@ -239,8 +240,8 @@ function deserializeEdgeBirthEvent(obj) {
|
|
|
239
240
|
* Serializes an LWW register for CBOR encoding.
|
|
240
241
|
* EventId is serialized as a plain object with sorted keys.
|
|
241
242
|
*
|
|
242
|
-
* @param {import('../crdt/LWW.js').LWWRegister} register
|
|
243
|
-
* @returns {
|
|
243
|
+
* @param {import('../crdt/LWW.js').LWWRegister<*>} register
|
|
244
|
+
* @returns {{ eventId: { lamport: number, opIndex: number, patchSha: string, writerId: string }, value: * } | null}
|
|
244
245
|
*/
|
|
245
246
|
function serializeLWWRegister(register) {
|
|
246
247
|
if (!register) {
|
|
@@ -261,8 +262,8 @@ function serializeLWWRegister(register) {
|
|
|
261
262
|
/**
|
|
262
263
|
* Deserializes an LWW register from CBOR.
|
|
263
264
|
*
|
|
264
|
-
* @param {
|
|
265
|
-
* @returns {import('../crdt/LWW.js').LWWRegister}
|
|
265
|
+
* @param {{ eventId: { lamport: number, writerId: string, patchSha: string, opIndex: number }, value: * } | null} obj
|
|
266
|
+
* @returns {import('../crdt/LWW.js').LWWRegister<*> | null}
|
|
266
267
|
*/
|
|
267
268
|
function deserializeLWWRegister(obj) {
|
|
268
269
|
if (!obj) {
|
|
@@ -46,7 +46,7 @@ import { ProvenanceIndex } from './ProvenanceIndex.js';
|
|
|
46
46
|
* ```
|
|
47
47
|
*
|
|
48
48
|
* @param {Object} options - Checkpoint creation options
|
|
49
|
-
* @param {import('../../ports/GraphPersistencePort.js').default} options.persistence - Git persistence adapter
|
|
49
|
+
* @param {import('../../ports/GraphPersistencePort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default & import('../../ports/CommitPort.js').default} options.persistence - Git persistence adapter
|
|
50
50
|
* @param {string} options.graphName - Name of the graph
|
|
51
51
|
* @param {import('./JoinReducer.js').WarpStateV5} options.state - The V5 state to checkpoint
|
|
52
52
|
* @param {import('./Frontier.js').Frontier} options.frontier - Writer frontier map
|
|
@@ -75,7 +75,7 @@ export async function create({ persistence, graphName, state, frontier, parents
|
|
|
75
75
|
* ```
|
|
76
76
|
*
|
|
77
77
|
* @param {Object} options - Checkpoint creation options
|
|
78
|
-
* @param {import('../../ports/GraphPersistencePort.js').default} options.persistence - Git persistence adapter
|
|
78
|
+
* @param {import('../../ports/GraphPersistencePort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default & import('../../ports/CommitPort.js').default} options.persistence - Git persistence adapter
|
|
79
79
|
* @param {string} options.graphName - Name of the graph
|
|
80
80
|
* @param {import('./JoinReducer.js').WarpStateV5} options.state - The V5 state to checkpoint
|
|
81
81
|
* @param {import('./Frontier.js').Frontier} options.frontier - Writer frontier map
|
|
@@ -113,23 +113,23 @@ export async function createV5({
|
|
|
113
113
|
|
|
114
114
|
// 4. Serialize visible projection (CACHE)
|
|
115
115
|
const visibleBuffer = serializeStateV5(checkpointState, { codec });
|
|
116
|
-
const stateHash = await computeStateHashV5(checkpointState, { codec, crypto });
|
|
116
|
+
const stateHash = await computeStateHashV5(checkpointState, { codec, crypto: /** @type {import('../../ports/CryptoPort.js').default} */ (crypto) });
|
|
117
117
|
|
|
118
118
|
// 5. Serialize frontier and appliedVV
|
|
119
|
-
const frontierBuffer = serializeFrontier(frontier, { codec });
|
|
120
|
-
const appliedVVBuffer = serializeAppliedVV(appliedVV, { codec });
|
|
119
|
+
const frontierBuffer = serializeFrontier(frontier, { codec: /** @type {import('../../ports/CodecPort.js').default} */ (codec) });
|
|
120
|
+
const appliedVVBuffer = serializeAppliedVV(appliedVV, { codec: /** @type {import('../../ports/CodecPort.js').default} */ (codec) });
|
|
121
121
|
|
|
122
122
|
// 6. Write blobs to git
|
|
123
|
-
const stateBlobOid = await persistence.writeBlob(stateBuffer);
|
|
124
|
-
const visibleBlobOid = await persistence.writeBlob(visibleBuffer);
|
|
125
|
-
const frontierBlobOid = await persistence.writeBlob(frontierBuffer);
|
|
126
|
-
const appliedVVBlobOid = await persistence.writeBlob(appliedVVBuffer);
|
|
123
|
+
const stateBlobOid = await persistence.writeBlob(/** @type {Buffer} */ (stateBuffer));
|
|
124
|
+
const visibleBlobOid = await persistence.writeBlob(/** @type {Buffer} */ (visibleBuffer));
|
|
125
|
+
const frontierBlobOid = await persistence.writeBlob(/** @type {Buffer} */ (frontierBuffer));
|
|
126
|
+
const appliedVVBlobOid = await persistence.writeBlob(/** @type {Buffer} */ (appliedVVBuffer));
|
|
127
127
|
|
|
128
128
|
// 6b. Optionally serialize and write provenance index
|
|
129
129
|
let provenanceIndexBlobOid = null;
|
|
130
130
|
if (provenanceIndex) {
|
|
131
131
|
const provenanceIndexBuffer = provenanceIndex.serialize({ codec });
|
|
132
|
-
provenanceIndexBlobOid = await persistence.writeBlob(provenanceIndexBuffer);
|
|
132
|
+
provenanceIndexBlobOid = await persistence.writeBlob(/** @type {Buffer} */ (provenanceIndexBuffer));
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
// 7. Create tree with sorted entries
|
|
@@ -189,17 +189,17 @@ export async function createV5({
|
|
|
189
189
|
* Schema:1 checkpoints are not supported and will throw an error.
|
|
190
190
|
* Use MigrationService to upgrade schema:1 checkpoints first.
|
|
191
191
|
*
|
|
192
|
-
* @param {import('../../ports/GraphPersistencePort.js').default} persistence - Git persistence adapter
|
|
192
|
+
* @param {import('../../ports/GraphPersistencePort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default & import('../../ports/CommitPort.js').default} persistence - Git persistence adapter
|
|
193
193
|
* @param {string} checkpointSha - The checkpoint commit SHA to load
|
|
194
194
|
* @param {Object} [options] - Load options
|
|
195
195
|
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for CBOR deserialization
|
|
196
|
-
* @returns {Promise<{state: import('./JoinReducer.js').WarpStateV5, frontier: import('./Frontier.js').Frontier, stateHash: string, schema: number, appliedVV
|
|
196
|
+
* @returns {Promise<{state: import('./JoinReducer.js').WarpStateV5, frontier: import('./Frontier.js').Frontier, stateHash: string, schema: number, appliedVV: Map<string, number>|null, provenanceIndex?: import('./ProvenanceIndex.js').ProvenanceIndex}>} The loaded checkpoint data
|
|
197
197
|
* @throws {Error} If checkpoint is schema:1 (migration required)
|
|
198
198
|
*/
|
|
199
|
-
export async function loadCheckpoint(persistence, checkpointSha, { codec } = {}) {
|
|
199
|
+
export async function loadCheckpoint(persistence, checkpointSha, { codec } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
200
200
|
// 1. Read commit message and decode
|
|
201
201
|
const message = await persistence.showNode(checkpointSha);
|
|
202
|
-
const decoded = decodeCheckpointMessage(message);
|
|
202
|
+
const decoded = /** @type {{ schema: number, stateHash: string, indexOid: string }} */ (decodeCheckpointMessage(message));
|
|
203
203
|
|
|
204
204
|
// 2. Reject schema:1 checkpoints - migration required
|
|
205
205
|
if (decoded.schema !== 2 && decoded.schema !== 3) {
|
|
@@ -218,7 +218,7 @@ export async function loadCheckpoint(persistence, checkpointSha, { codec } = {})
|
|
|
218
218
|
throw new Error(`Checkpoint ${checkpointSha} missing frontier.cbor in tree`);
|
|
219
219
|
}
|
|
220
220
|
const frontierBuffer = await persistence.readBlob(frontierOid);
|
|
221
|
-
const frontier = deserializeFrontier(frontierBuffer, { codec });
|
|
221
|
+
const frontier = deserializeFrontier(frontierBuffer, { codec: /** @type {import('../../ports/CodecPort.js').default} */ (codec) });
|
|
222
222
|
|
|
223
223
|
// 5. Read state.cbor blob and deserialize as V5 full state
|
|
224
224
|
const stateOid = treeOids['state.cbor'];
|
|
@@ -252,7 +252,7 @@ export async function loadCheckpoint(persistence, checkpointSha, { codec } = {})
|
|
|
252
252
|
stateHash: decoded.stateHash,
|
|
253
253
|
schema: decoded.schema,
|
|
254
254
|
appliedVV,
|
|
255
|
-
provenanceIndex,
|
|
255
|
+
provenanceIndex: provenanceIndex || undefined,
|
|
256
256
|
};
|
|
257
257
|
}
|
|
258
258
|
|
|
@@ -270,7 +270,7 @@ export async function loadCheckpoint(persistence, checkpointSha, { codec } = {})
|
|
|
270
270
|
* loadCheckpoint to throw an error.
|
|
271
271
|
*
|
|
272
272
|
* @param {Object} options - Materialization options
|
|
273
|
-
* @param {import('../../ports/GraphPersistencePort.js').default} options.persistence - Git persistence adapter
|
|
273
|
+
* @param {import('../../ports/GraphPersistencePort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default & import('../../ports/CommitPort.js').default} options.persistence - Git persistence adapter
|
|
274
274
|
* @param {string} options.graphName - Name of the graph
|
|
275
275
|
* @param {string} options.checkpointSha - The schema:2 checkpoint commit SHA to start from
|
|
276
276
|
* @param {import('./Frontier.js').Frontier} options.targetFrontier - The target frontier to materialize to
|
|
@@ -313,7 +313,7 @@ export async function materializeIncremental({
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
// 5. Apply new patches using V5 reducer with checkpoint state as initial
|
|
316
|
-
const finalState = reduceV5(allPatches, initialState);
|
|
316
|
+
const finalState = /** @type {import('./JoinReducer.js').WarpStateV5} */ (reduceV5(allPatches, initialState));
|
|
317
317
|
|
|
318
318
|
return finalState;
|
|
319
319
|
}
|
|
@@ -39,7 +39,7 @@ export default class CommitDagTraversalService {
|
|
|
39
39
|
* @param {import('./BitmapIndexReader.js').default} options.indexReader - Index reader for O(1) lookups
|
|
40
40
|
* @param {import('../../ports/LoggerPort.js').default} [options.logger] - Logger instance
|
|
41
41
|
*/
|
|
42
|
-
constructor({ indexReader, logger = nullLogger } = {}) {
|
|
42
|
+
constructor({ indexReader, logger = nullLogger } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
43
43
|
if (!indexReader) {
|
|
44
44
|
throw new Error('CommitDagTraversalService requires an indexReader');
|
|
45
45
|
}
|
|
@@ -56,6 +56,7 @@ export default class CommitDagTraversalService {
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Breadth-first traversal from a starting node.
|
|
59
|
+
* @param {*} options
|
|
59
60
|
* @see DagTraversal#bfs
|
|
60
61
|
*/
|
|
61
62
|
bfs(options) {
|
|
@@ -64,6 +65,7 @@ export default class CommitDagTraversalService {
|
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
67
|
* Depth-first pre-order traversal from a starting node.
|
|
68
|
+
* @param {*} options
|
|
67
69
|
* @see DagTraversal#dfs
|
|
68
70
|
*/
|
|
69
71
|
dfs(options) {
|
|
@@ -72,6 +74,7 @@ export default class CommitDagTraversalService {
|
|
|
72
74
|
|
|
73
75
|
/**
|
|
74
76
|
* Yields all ancestors of a node.
|
|
77
|
+
* @param {*} options
|
|
75
78
|
* @see DagTraversal#ancestors
|
|
76
79
|
*/
|
|
77
80
|
ancestors(options) {
|
|
@@ -80,6 +83,7 @@ export default class CommitDagTraversalService {
|
|
|
80
83
|
|
|
81
84
|
/**
|
|
82
85
|
* Yields all descendants of a node.
|
|
86
|
+
* @param {*} options
|
|
83
87
|
* @see DagTraversal#descendants
|
|
84
88
|
*/
|
|
85
89
|
descendants(options) {
|
|
@@ -88,6 +92,7 @@ export default class CommitDagTraversalService {
|
|
|
88
92
|
|
|
89
93
|
/**
|
|
90
94
|
* Checks if there is any path from one node to another.
|
|
95
|
+
* @param {*} options
|
|
91
96
|
* @see DagTraversal#isReachable
|
|
92
97
|
*/
|
|
93
98
|
isReachable(options) {
|
|
@@ -98,6 +103,7 @@ export default class CommitDagTraversalService {
|
|
|
98
103
|
|
|
99
104
|
/**
|
|
100
105
|
* Finds ANY path between two nodes using BFS.
|
|
106
|
+
* @param {*} options
|
|
101
107
|
* @see DagPathFinding#findPath
|
|
102
108
|
*/
|
|
103
109
|
findPath(options) {
|
|
@@ -106,6 +112,7 @@ export default class CommitDagTraversalService {
|
|
|
106
112
|
|
|
107
113
|
/**
|
|
108
114
|
* Finds the shortest path using bidirectional BFS.
|
|
115
|
+
* @param {*} options
|
|
109
116
|
* @see DagPathFinding#shortestPath
|
|
110
117
|
*/
|
|
111
118
|
shortestPath(options) {
|
|
@@ -114,6 +121,7 @@ export default class CommitDagTraversalService {
|
|
|
114
121
|
|
|
115
122
|
/**
|
|
116
123
|
* Finds shortest path using Dijkstra's algorithm.
|
|
124
|
+
* @param {*} options
|
|
117
125
|
* @see DagPathFinding#weightedShortestPath
|
|
118
126
|
*/
|
|
119
127
|
weightedShortestPath(options) {
|
|
@@ -122,6 +130,7 @@ export default class CommitDagTraversalService {
|
|
|
122
130
|
|
|
123
131
|
/**
|
|
124
132
|
* Finds shortest path using A* with heuristic guidance.
|
|
133
|
+
* @param {*} options
|
|
125
134
|
* @see DagPathFinding#aStarSearch
|
|
126
135
|
*/
|
|
127
136
|
aStarSearch(options) {
|
|
@@ -130,6 +139,7 @@ export default class CommitDagTraversalService {
|
|
|
130
139
|
|
|
131
140
|
/**
|
|
132
141
|
* Bi-directional A* search.
|
|
142
|
+
* @param {*} options
|
|
133
143
|
* @see DagPathFinding#bidirectionalAStar
|
|
134
144
|
*/
|
|
135
145
|
bidirectionalAStar(options) {
|
|
@@ -140,6 +150,7 @@ export default class CommitDagTraversalService {
|
|
|
140
150
|
|
|
141
151
|
/**
|
|
142
152
|
* Finds common ancestors of multiple nodes.
|
|
153
|
+
* @param {*} options
|
|
143
154
|
* @see DagTopology#commonAncestors
|
|
144
155
|
*/
|
|
145
156
|
commonAncestors(options) {
|
|
@@ -148,6 +159,7 @@ export default class CommitDagTraversalService {
|
|
|
148
159
|
|
|
149
160
|
/**
|
|
150
161
|
* Yields nodes in topological order using Kahn's algorithm.
|
|
162
|
+
* @param {*} options
|
|
151
163
|
* @see DagTopology#topologicalSort
|
|
152
164
|
*/
|
|
153
165
|
topologicalSort(options) {
|
|
@@ -41,7 +41,7 @@ export default class DagPathFinding {
|
|
|
41
41
|
* @param {import('./BitmapIndexReader.js').default} options.indexReader - Index reader for O(1) lookups
|
|
42
42
|
* @param {import('../../ports/LoggerPort.js').default} [options.logger] - Logger instance
|
|
43
43
|
*/
|
|
44
|
-
constructor({ indexReader, logger = nullLogger } = {}) {
|
|
44
|
+
constructor(/** @type {{ indexReader: import('./BitmapIndexReader.js').default, logger?: import('../../ports/LoggerPort.js').default }} */ { indexReader, logger = nullLogger } = /** @type {*} */ ({})) { // TODO(ts-cleanup): needs options type
|
|
45
45
|
if (!indexReader) {
|
|
46
46
|
throw new Error('DagPathFinding requires an indexReader');
|
|
47
47
|
}
|
|
@@ -85,7 +85,7 @@ export default class DagPathFinding {
|
|
|
85
85
|
checkAborted(signal, 'findPath');
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const current = queue.shift();
|
|
88
|
+
const current = /** @type {{sha: string, depth: number}} */ (queue.shift());
|
|
89
89
|
|
|
90
90
|
if (current.depth > maxDepth) { continue; }
|
|
91
91
|
if (visited.has(current.sha)) { continue; }
|
|
@@ -200,7 +200,7 @@ export default class DagPathFinding {
|
|
|
200
200
|
* @param {Object} options - Path finding options
|
|
201
201
|
* @param {string} options.from - Starting SHA
|
|
202
202
|
* @param {string} options.to - Target SHA
|
|
203
|
-
* @param {
|
|
203
|
+
* @param {(from: string, to: string) => number|Promise<number>} [options.weightProvider] - Async callback `(fromSha, toSha) => number`
|
|
204
204
|
* @param {string} [options.direction='children'] - Edge direction: 'children' or 'parents'
|
|
205
205
|
* @param {AbortSignal} [options.signal] - Optional AbortSignal for cancellation
|
|
206
206
|
* @returns {Promise<{path: string[], totalCost: number}>} Path and cost
|
|
@@ -277,8 +277,8 @@ export default class DagPathFinding {
|
|
|
277
277
|
* @param {Object} options - Path finding options
|
|
278
278
|
* @param {string} options.from - Starting SHA
|
|
279
279
|
* @param {string} options.to - Target SHA
|
|
280
|
-
* @param {
|
|
281
|
-
* @param {
|
|
280
|
+
* @param {(from: string, to: string) => number|Promise<number>} [options.weightProvider] - Async callback `(fromSha, toSha) => number`
|
|
281
|
+
* @param {(sha: string, target: string) => number} [options.heuristicProvider] - Callback `(sha, targetSha) => number`
|
|
282
282
|
* @param {string} [options.direction='children'] - Edge direction: 'children' or 'parents'
|
|
283
283
|
* @param {AbortSignal} [options.signal] - Optional AbortSignal for cancellation
|
|
284
284
|
* @returns {Promise<{path: string[], totalCost: number, nodesExplored: number}>} Path result
|
|
@@ -367,9 +367,9 @@ export default class DagPathFinding {
|
|
|
367
367
|
* @param {Object} options - Path finding options
|
|
368
368
|
* @param {string} options.from - Starting SHA
|
|
369
369
|
* @param {string} options.to - Target SHA
|
|
370
|
-
* @param {
|
|
371
|
-
* @param {
|
|
372
|
-
* @param {
|
|
370
|
+
* @param {(from: string, to: string) => number|Promise<number>} [options.weightProvider] - Async callback `(fromSha, toSha) => number`
|
|
371
|
+
* @param {(sha: string, target: string) => number} [options.forwardHeuristic] - Callback for forward search
|
|
372
|
+
* @param {(sha: string, target: string) => number} [options.backwardHeuristic] - Callback for backward search
|
|
373
373
|
* @param {AbortSignal} [options.signal] - Optional AbortSignal for cancellation
|
|
374
374
|
* @returns {Promise<{path: string[], totalCost: number, nodesExplored: number}>} Path result
|
|
375
375
|
* @throws {TraversalError} With code 'NO_PATH' if no path exists
|
|
@@ -463,6 +463,17 @@ export default class DagPathFinding {
|
|
|
463
463
|
* Expands the forward frontier by one node in bidirectional A*.
|
|
464
464
|
*
|
|
465
465
|
* @param {Object} state - Forward expansion state
|
|
466
|
+
* @param {import('../utils/MinHeap.js').default} state.fwdHeap
|
|
467
|
+
* @param {Set<string>} state.fwdVisited
|
|
468
|
+
* @param {Map<string, number>} state.fwdGScore
|
|
469
|
+
* @param {Map<string, string>} state.fwdPrevious
|
|
470
|
+
* @param {Set<string>} state.bwdVisited
|
|
471
|
+
* @param {Map<string, number>} state.bwdGScore
|
|
472
|
+
* @param {(from: string, to: string) => number|Promise<number>} state.weightProvider
|
|
473
|
+
* @param {(sha: string, target: string) => number} state.forwardHeuristic
|
|
474
|
+
* @param {string} state.to
|
|
475
|
+
* @param {number} state.mu
|
|
476
|
+
* @param {string|null} state.meetingPoint
|
|
466
477
|
* @returns {Promise<{explored: number, mu: number, meetingPoint: string|null}>}
|
|
467
478
|
* @private
|
|
468
479
|
*/
|
|
@@ -484,7 +495,7 @@ export default class DagPathFinding {
|
|
|
484
495
|
explored = 1;
|
|
485
496
|
|
|
486
497
|
if (bwdVisited.has(current)) {
|
|
487
|
-
const totalCost = fwdGScore.get(current) + bwdGScore.get(current);
|
|
498
|
+
const totalCost = /** @type {number} */ (fwdGScore.get(current)) + /** @type {number} */ (bwdGScore.get(current));
|
|
488
499
|
if (totalCost < bestMu) {
|
|
489
500
|
bestMu = totalCost;
|
|
490
501
|
bestMeeting = current;
|
|
@@ -498,8 +509,8 @@ export default class DagPathFinding {
|
|
|
498
509
|
}
|
|
499
510
|
|
|
500
511
|
const edgeWeight = await weightProvider(current, child);
|
|
501
|
-
const tentativeG = fwdGScore.get(current) + edgeWeight;
|
|
502
|
-
const currentG = fwdGScore.has(child) ? fwdGScore.get(child) : Infinity;
|
|
512
|
+
const tentativeG = /** @type {number} */ (fwdGScore.get(current)) + edgeWeight;
|
|
513
|
+
const currentG = fwdGScore.has(child) ? /** @type {number} */ (fwdGScore.get(child)) : Infinity;
|
|
503
514
|
|
|
504
515
|
if (tentativeG < currentG) {
|
|
505
516
|
fwdPrevious.set(child, current);
|
|
@@ -509,7 +520,7 @@ export default class DagPathFinding {
|
|
|
509
520
|
fwdHeap.insert(child, f);
|
|
510
521
|
|
|
511
522
|
if (bwdGScore.has(child)) {
|
|
512
|
-
const totalCost = tentativeG + bwdGScore.get(child);
|
|
523
|
+
const totalCost = tentativeG + /** @type {number} */ (bwdGScore.get(child));
|
|
513
524
|
if (totalCost < bestMu) {
|
|
514
525
|
bestMu = totalCost;
|
|
515
526
|
bestMeeting = child;
|
|
@@ -525,6 +536,17 @@ export default class DagPathFinding {
|
|
|
525
536
|
* Expands the backward frontier by one node in bidirectional A*.
|
|
526
537
|
*
|
|
527
538
|
* @param {Object} state - Backward expansion state
|
|
539
|
+
* @param {import('../utils/MinHeap.js').default} state.bwdHeap
|
|
540
|
+
* @param {Set<string>} state.bwdVisited
|
|
541
|
+
* @param {Map<string, number>} state.bwdGScore
|
|
542
|
+
* @param {Map<string, string>} state.bwdNext
|
|
543
|
+
* @param {Set<string>} state.fwdVisited
|
|
544
|
+
* @param {Map<string, number>} state.fwdGScore
|
|
545
|
+
* @param {(from: string, to: string) => number|Promise<number>} state.weightProvider
|
|
546
|
+
* @param {(sha: string, target: string) => number} state.backwardHeuristic
|
|
547
|
+
* @param {string} state.from
|
|
548
|
+
* @param {number} state.mu
|
|
549
|
+
* @param {string|null} state.meetingPoint
|
|
528
550
|
* @returns {Promise<{explored: number, mu: number, meetingPoint: string|null}>}
|
|
529
551
|
* @private
|
|
530
552
|
*/
|
|
@@ -546,7 +568,7 @@ export default class DagPathFinding {
|
|
|
546
568
|
explored = 1;
|
|
547
569
|
|
|
548
570
|
if (fwdVisited.has(current)) {
|
|
549
|
-
const totalCost = fwdGScore.get(current) + bwdGScore.get(current);
|
|
571
|
+
const totalCost = /** @type {number} */ (fwdGScore.get(current)) + /** @type {number} */ (bwdGScore.get(current));
|
|
550
572
|
if (totalCost < bestMu) {
|
|
551
573
|
bestMu = totalCost;
|
|
552
574
|
bestMeeting = current;
|
|
@@ -560,8 +582,8 @@ export default class DagPathFinding {
|
|
|
560
582
|
}
|
|
561
583
|
|
|
562
584
|
const edgeWeight = await weightProvider(parent, current);
|
|
563
|
-
const tentativeG = bwdGScore.get(current) + edgeWeight;
|
|
564
|
-
const currentG = bwdGScore.has(parent) ? bwdGScore.get(parent) : Infinity;
|
|
585
|
+
const tentativeG = /** @type {number} */ (bwdGScore.get(current)) + edgeWeight;
|
|
586
|
+
const currentG = bwdGScore.has(parent) ? /** @type {number} */ (bwdGScore.get(parent)) : Infinity;
|
|
565
587
|
|
|
566
588
|
if (tentativeG < currentG) {
|
|
567
589
|
bwdNext.set(parent, current);
|
|
@@ -571,7 +593,7 @@ export default class DagPathFinding {
|
|
|
571
593
|
bwdHeap.insert(parent, f);
|
|
572
594
|
|
|
573
595
|
if (fwdGScore.has(parent)) {
|
|
574
|
-
const totalCost = fwdGScore.get(parent) + tentativeG;
|
|
596
|
+
const totalCost = /** @type {number} */ (fwdGScore.get(parent)) + tentativeG;
|
|
575
597
|
if (totalCost < bestMu) {
|
|
576
598
|
bestMu = totalCost;
|
|
577
599
|
bestMeeting = parent;
|
|
@@ -691,7 +713,7 @@ export default class DagPathFinding {
|
|
|
691
713
|
const forwardPath = [meeting];
|
|
692
714
|
let current = meeting;
|
|
693
715
|
while (fwdParent.has(current) && fwdParent.get(current) !== undefined) {
|
|
694
|
-
current = fwdParent.get(current);
|
|
716
|
+
current = /** @type {string} */ (fwdParent.get(current));
|
|
695
717
|
forwardPath.unshift(current);
|
|
696
718
|
}
|
|
697
719
|
if (forwardPath[0] !== from) {
|
|
@@ -700,7 +722,7 @@ export default class DagPathFinding {
|
|
|
700
722
|
|
|
701
723
|
current = meeting;
|
|
702
724
|
while (bwdParent.has(current) && bwdParent.get(current) !== undefined) {
|
|
703
|
-
current = bwdParent.get(current);
|
|
725
|
+
current = /** @type {string} */ (bwdParent.get(current));
|
|
704
726
|
forwardPath.push(current);
|
|
705
727
|
}
|
|
706
728
|
if (forwardPath[forwardPath.length - 1] !== to) {
|