@git-stunts/git-warp 12.3.0 → 12.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -6
- package/bin/cli/commands/info.js +1 -5
- package/bin/cli/infrastructure.js +6 -9
- package/bin/cli/shared.js +8 -0
- package/bin/warp-graph.js +6 -6
- package/package.json +1 -1
- package/src/domain/WarpGraph.js +5 -35
- package/src/domain/crdt/VersionVector.js +1 -1
- package/src/domain/entities/GraphNode.js +1 -6
- package/src/domain/errors/ForkError.js +1 -1
- package/src/domain/errors/IndexError.js +1 -1
- package/src/domain/errors/OperationAbortedError.js +1 -1
- package/src/domain/errors/PatchError.js +1 -1
- package/src/domain/errors/PersistenceError.js +45 -0
- package/src/domain/errors/QueryError.js +1 -1
- package/src/domain/errors/SchemaUnsupportedError.js +1 -1
- package/src/domain/errors/SyncError.js +1 -1
- package/src/domain/errors/TraversalError.js +1 -1
- package/src/domain/errors/TrustError.js +1 -1
- package/src/domain/errors/WormholeError.js +1 -1
- package/src/domain/errors/index.js +1 -0
- package/src/domain/services/AdjacencyNeighborProvider.js +1 -4
- package/src/domain/services/AnchorMessageCodec.js +1 -3
- package/src/domain/services/AuditMessageCodec.js +1 -5
- package/src/domain/services/AuditReceiptService.js +2 -17
- package/src/domain/services/AuditVerifierService.js +2 -7
- package/src/domain/services/BitmapIndexBuilder.js +6 -12
- package/src/domain/services/BitmapIndexReader.js +7 -20
- package/src/domain/services/BitmapNeighborProvider.js +1 -3
- package/src/domain/services/BoundaryTransitionRecord.js +6 -23
- package/src/domain/services/CheckpointMessageCodec.js +1 -6
- package/src/domain/services/CheckpointSerializerV5.js +8 -12
- package/src/domain/services/CheckpointService.js +9 -39
- package/src/domain/services/CommitDagTraversalService.js +1 -3
- package/src/domain/services/DagPathFinding.js +9 -59
- package/src/domain/services/DagTopology.js +4 -16
- package/src/domain/services/DagTraversal.js +7 -31
- package/src/domain/services/Frontier.js +4 -6
- package/src/domain/services/GitLogParser.js +1 -2
- package/src/domain/services/GraphTraversal.js +14 -114
- package/src/domain/services/HealthCheckService.js +3 -9
- package/src/domain/services/HookInstaller.js +2 -8
- package/src/domain/services/HttpSyncServer.js +24 -25
- package/src/domain/services/IncrementalIndexUpdater.js +4 -6
- package/src/domain/services/IndexRebuildService.js +6 -52
- package/src/domain/services/IndexStalenessChecker.js +2 -3
- package/src/domain/services/JoinReducer.js +39 -65
- package/src/domain/services/LogicalBitmapIndexBuilder.js +1 -2
- package/src/domain/services/LogicalIndexBuildService.js +2 -6
- package/src/domain/services/LogicalIndexReader.js +1 -2
- package/src/domain/services/LogicalTraversal.js +13 -64
- package/src/domain/services/MaterializedViewService.js +4 -18
- package/src/domain/services/MigrationService.js +1 -4
- package/src/domain/services/ObserverView.js +1 -7
- package/src/domain/services/PatchBuilderV2.js +6 -18
- package/src/domain/services/PatchMessageCodec.js +1 -6
- package/src/domain/services/PropertyIndexBuilder.js +1 -2
- package/src/domain/services/PropertyIndexReader.js +1 -4
- package/src/domain/services/ProvenanceIndex.js +5 -7
- package/src/domain/services/ProvenancePayload.js +1 -1
- package/src/domain/services/QueryBuilder.js +3 -16
- package/src/domain/services/StateDiff.js +3 -9
- package/src/domain/services/StateSerializerV5.js +10 -10
- package/src/domain/services/StreamingBitmapIndexBuilder.js +13 -41
- package/src/domain/services/SyncAuthService.js +5 -32
- package/src/domain/services/SyncController.js +5 -25
- package/src/domain/services/SyncProtocol.js +4 -8
- package/src/domain/services/SyncTrustGate.js +4 -9
- package/src/domain/services/TemporalQuery.js +9 -27
- package/src/domain/services/TranslationCost.js +2 -8
- package/src/domain/services/WarpStateIndexBuilder.js +2 -4
- package/src/domain/services/WormholeService.js +9 -25
- package/src/domain/trust/TrustCrypto.js +1 -5
- package/src/domain/trust/TrustEvaluator.js +1 -8
- package/src/domain/trust/TrustRecordService.js +5 -10
- package/src/domain/types/TickReceipt.js +3 -7
- package/src/domain/types/WarpTypes.js +1 -5
- package/src/domain/types/WarpTypesV2.js +1 -8
- package/src/domain/utils/CachedValue.js +1 -4
- package/src/domain/utils/MinHeap.js +3 -3
- package/src/domain/utils/RefLayout.js +26 -0
- package/src/domain/utils/WriterId.js +2 -7
- package/src/domain/utils/canonicalCbor.js +1 -1
- package/src/domain/utils/defaultCodec.js +1 -1
- package/src/domain/utils/parseCursorBlob.js +4 -4
- package/src/domain/warp/PatchSession.js +3 -8
- package/src/domain/warp/Writer.js +3 -12
- package/src/domain/warp/_wire.js +2 -2
- package/src/domain/warp/_wiredMethods.d.ts +5 -7
- package/src/domain/warp/checkpoint.methods.js +1 -1
- package/src/domain/warp/fork.methods.js +1 -5
- package/src/domain/warp/materializeAdvanced.methods.js +3 -3
- package/src/domain/warp/patch.methods.js +6 -8
- package/src/domain/warp/provenance.methods.js +5 -5
- package/src/domain/warp/query.methods.js +9 -18
- package/src/domain/warp/subscribe.methods.js +2 -8
- package/src/globals.d.ts +7 -0
- package/src/infrastructure/adapters/BunHttpAdapter.js +14 -18
- package/src/infrastructure/adapters/ConsoleLogger.js +2 -9
- package/src/infrastructure/adapters/DenoHttpAdapter.js +15 -15
- package/src/infrastructure/adapters/GitGraphAdapter.js +234 -58
- package/src/infrastructure/adapters/InMemoryGraphAdapter.js +9 -2
- package/src/infrastructure/adapters/NodeHttpAdapter.js +14 -14
- package/src/infrastructure/adapters/WebCryptoAdapter.js +1 -2
- package/src/ports/BlobPort.js +2 -2
- package/src/ports/HttpServerPort.js +24 -2
- package/src/ports/RefPort.js +2 -1
- package/src/visualization/renderers/ascii/box.js +1 -1
- package/src/visualization/renderers/ascii/check.js +1 -5
- package/src/visualization/renderers/ascii/history.js +1 -6
- package/src/visualization/renderers/ascii/path.js +4 -22
- package/src/visualization/renderers/ascii/progress.js +1 -4
- package/src/visualization/renderers/ascii/seek.js +1 -5
- package/src/visualization/renderers/ascii/table.js +1 -3
|
@@ -61,13 +61,8 @@ async function verifyShaExists(persistence, sha, paramName) {
|
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Processes a single commit in the wormhole chain.
|
|
64
|
-
* @param {
|
|
65
|
-
* @
|
|
66
|
-
* @param {string} opts.sha - The commit SHA
|
|
67
|
-
* @param {string} opts.graphName - Expected graph name
|
|
68
|
-
* @param {string|null} opts.expectedWriter - Expected writer ID (null for first commit)
|
|
69
|
-
* @param {import('../../ports/CodecPort.js').default} [opts.codec] - Codec for deserialization
|
|
70
|
-
* @returns {Promise<{patch: Object, sha: string, writerId: string, parentSha: string|null}>}
|
|
64
|
+
* @param {{ persistence: import('../../ports/GraphPersistencePort.js').default & import('../../ports/CommitPort.js').default & import('../../ports/BlobPort.js').default, sha: string, graphName: string, expectedWriter: string|null, codec?: import('../../ports/CodecPort.js').default }} opts - Options
|
|
65
|
+
* @returns {Promise<{patch: import('../types/WarpTypesV2.js').PatchV2, sha: string, writerId: string, parentSha: string|null}>}
|
|
71
66
|
* @throws {WormholeError} On validation errors
|
|
72
67
|
* @private
|
|
73
68
|
*/
|
|
@@ -101,7 +96,7 @@ async function processCommit({ persistence, sha, graphName, expectedWriter, code
|
|
|
101
96
|
}
|
|
102
97
|
|
|
103
98
|
const patchBuffer = await persistence.readBlob(patchMeta.patchOid);
|
|
104
|
-
const patch = /** @type {
|
|
99
|
+
const patch = /** @type {import('../types/WarpTypesV2.js').PatchV2} */ (codec.decode(patchBuffer));
|
|
105
100
|
|
|
106
101
|
return {
|
|
107
102
|
patch,
|
|
@@ -135,12 +130,7 @@ async function processCommit({ persistence, sha, graphName, expectedWriter, code
|
|
|
135
130
|
* must be an ancestor of `toSha` in the writer's patch chain. Both endpoints
|
|
136
131
|
* are inclusive in the wormhole.
|
|
137
132
|
*
|
|
138
|
-
* @param {
|
|
139
|
-
* @param {import('../../ports/GraphPersistencePort.js').default & import('../../ports/CommitPort.js').default & import('../../ports/BlobPort.js').default} options.persistence - Git persistence adapter
|
|
140
|
-
* @param {string} options.graphName - Name of the graph
|
|
141
|
-
* @param {string} options.fromSha - SHA of the first (oldest) patch commit
|
|
142
|
-
* @param {string} options.toSha - SHA of the last (newest) patch commit
|
|
143
|
-
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for deserialization
|
|
133
|
+
* @param {{ persistence: import('../../ports/GraphPersistencePort.js').default & import('../../ports/CommitPort.js').default & import('../../ports/BlobPort.js').default, graphName: string, fromSha: string, toSha: string, codec?: import('../../ports/CodecPort.js').default }} options - Wormhole creation options
|
|
144
134
|
* @returns {Promise<WormholeEdge>} The created wormhole
|
|
145
135
|
* @throws {WormholeError} If fromSha or toSha doesn't exist (E_WORMHOLE_SHA_NOT_FOUND)
|
|
146
136
|
* @throws {WormholeError} If fromSha is not an ancestor of toSha (E_WORMHOLE_INVALID_RANGE)
|
|
@@ -171,13 +161,8 @@ export async function createWormhole({ persistence, graphName, fromSha, toSha, c
|
|
|
171
161
|
* Walks the parent chain from toSha towards fromSha, collecting and
|
|
172
162
|
* validating each commit along the way.
|
|
173
163
|
*
|
|
174
|
-
* @param {
|
|
175
|
-
* @
|
|
176
|
-
* @param {string} options.graphName - Expected graph name
|
|
177
|
-
* @param {string} options.fromSha - SHA of the first (oldest) patch commit
|
|
178
|
-
* @param {string} options.toSha - SHA of the last (newest) patch commit
|
|
179
|
-
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for deserialization
|
|
180
|
-
* @returns {Promise<Array<{patch: Object, sha: string, writerId: string}>>} Patches in newest-first order
|
|
164
|
+
* @param {{ persistence: import('../../ports/GraphPersistencePort.js').default & import('../../ports/CommitPort.js').default & import('../../ports/BlobPort.js').default, graphName: string, fromSha: string, toSha: string, codec?: import('../../ports/CodecPort.js').default }} options
|
|
165
|
+
* @returns {Promise<Array<{patch: import('../types/WarpTypesV2.js').PatchV2, sha: string, writerId: string}>>} Patches in newest-first order
|
|
181
166
|
* @throws {WormholeError} If fromSha is not an ancestor of toSha or range is empty
|
|
182
167
|
* @private
|
|
183
168
|
*/
|
|
@@ -232,8 +217,7 @@ async function collectPatchRange({ persistence, graphName, fromSha, toSha, codec
|
|
|
232
217
|
*
|
|
233
218
|
* @param {WormholeEdge} first - The earlier (older) wormhole
|
|
234
219
|
* @param {WormholeEdge} second - The later (newer) wormhole
|
|
235
|
-
* @param {
|
|
236
|
-
* @param {import('../../ports/GraphPersistencePort.js').default & import('../../ports/CommitPort.js').default} [options.persistence] - Git persistence adapter (for validation)
|
|
220
|
+
* @param {{ persistence?: import('../../ports/GraphPersistencePort.js').default & import('../../ports/CommitPort.js').default }} [options] - Composition options
|
|
237
221
|
* @returns {Promise<WormholeEdge>} The composed wormhole
|
|
238
222
|
* @throws {WormholeError} If wormholes are from different writers (E_WORMHOLE_MULTI_WRITER)
|
|
239
223
|
* @throws {WormholeError} If wormholes are not consecutive (E_WORMHOLE_INVALID_RANGE)
|
|
@@ -294,7 +278,7 @@ export function replayWormhole(wormhole, initialState) {
|
|
|
294
278
|
* Serializes a wormhole to a JSON-serializable object.
|
|
295
279
|
*
|
|
296
280
|
* @param {WormholeEdge} wormhole - The wormhole to serialize
|
|
297
|
-
* @returns {
|
|
281
|
+
* @returns {Record<string, unknown>} JSON-serializable representation
|
|
298
282
|
*/
|
|
299
283
|
export function serializeWormhole(wormhole) {
|
|
300
284
|
return {
|
|
@@ -309,7 +293,7 @@ export function serializeWormhole(wormhole) {
|
|
|
309
293
|
/**
|
|
310
294
|
* Deserializes a wormhole from a JSON object.
|
|
311
295
|
*
|
|
312
|
-
* @param {
|
|
296
|
+
* @param {Record<string, unknown>} json - The JSON object to deserialize
|
|
313
297
|
* @returns {WormholeEdge} The deserialized wormhole
|
|
314
298
|
* @throws {WormholeError} If the JSON structure is invalid
|
|
315
299
|
*/
|
|
@@ -63,11 +63,7 @@ function decodePublicKey(base64) {
|
|
|
63
63
|
/**
|
|
64
64
|
* Verifies an Ed25519 signature against a payload.
|
|
65
65
|
*
|
|
66
|
-
* @param {
|
|
67
|
-
* @param {string} params.algorithm - Must be 'ed25519'
|
|
68
|
-
* @param {string} params.publicKeyBase64 - Base64-encoded 32-byte public key
|
|
69
|
-
* @param {string} params.signatureBase64 - Base64-encoded signature
|
|
70
|
-
* @param {Buffer} params.payload - Bytes to verify
|
|
66
|
+
* @param {{ algorithm: string, publicKeyBase64: string, signatureBase64: string, payload: Buffer }} params
|
|
71
67
|
* @returns {boolean} true if signature is valid
|
|
72
68
|
* @throws {TrustError} E_TRUST_UNSUPPORTED_ALGORITHM for non-ed25519
|
|
73
69
|
* @throws {TrustError} E_TRUST_INVALID_KEY for malformed public key
|
|
@@ -21,14 +21,7 @@ import { deriveTrustVerdict } from './verdict.js';
|
|
|
21
21
|
* @property {number} trustSchemaVersion
|
|
22
22
|
* @property {string} mode
|
|
23
23
|
* @property {string} trustVerdict
|
|
24
|
-
* @property {
|
|
25
|
-
* @property {'configured'|'pinned'|'error'|'not_configured'} trust.status
|
|
26
|
-
* @property {string} trust.source
|
|
27
|
-
* @property {string|null} trust.sourceDetail
|
|
28
|
-
* @property {string[]} trust.evaluatedWriters
|
|
29
|
-
* @property {string[]} trust.untrustedWriters
|
|
30
|
-
* @property {ReadonlyArray<{writerId: string, trusted: boolean, reasonCode: string, reason: string}>} trust.explanations
|
|
31
|
-
* @property {Record<string, number> & {recordsScanned: number, activeKeys: number, revokedKeys: number, activeBindings: number, revokedBindings: number}} trust.evidenceSummary
|
|
24
|
+
* @property {{ status: 'configured'|'pinned'|'error'|'not_configured', source: string, sourceDetail: string|null, evaluatedWriters: string[], untrustedWriters: string[], explanations: ReadonlyArray<{writerId: string, trusted: boolean, reasonCode: string, reason: string}>, evidenceSummary: Record<string, number> & {recordsScanned: number, activeKeys: number, revokedKeys: number, activeBindings: number, revokedBindings: number} }} trust
|
|
32
25
|
*/
|
|
33
26
|
|
|
34
27
|
/**
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { buildTrustRecordRef } from '../utils/RefLayout.js';
|
|
13
13
|
import { TrustRecordSchema } from './schemas.js';
|
|
14
14
|
import { verifyRecordId } from './TrustCanonical.js';
|
|
15
|
+
import PersistenceError from '../errors/PersistenceError.js';
|
|
15
16
|
import TrustError from '../errors/TrustError.js';
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -32,9 +33,7 @@ const MAX_CAS_ATTEMPTS = 3;
|
|
|
32
33
|
|
|
33
34
|
export class TrustRecordService {
|
|
34
35
|
/**
|
|
35
|
-
* @param {
|
|
36
|
-
* @param {import('../../ports/CommitPort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default & import('../../ports/RefPort.js').default} options.persistence - GraphPersistencePort adapter
|
|
37
|
-
* @param {import('../../ports/CodecPort.js').default} options.codec - CodecPort adapter (CBOR)
|
|
36
|
+
* @param {{ persistence: import('../../ports/CommitPort.js').default & import('../../ports/BlobPort.js').default & import('../../ports/TreePort.js').default & import('../../ports/RefPort.js').default, codec: import('../../ports/CodecPort.js').default }} options
|
|
38
37
|
*/
|
|
39
38
|
constructor({ persistence, codec }) {
|
|
40
39
|
this._persistence = persistence;
|
|
@@ -104,8 +103,7 @@ export class TrustRecordService {
|
|
|
104
103
|
* Reads all trust records from the chain, oldest first.
|
|
105
104
|
*
|
|
106
105
|
* @param {string} graphName
|
|
107
|
-
* @param {
|
|
108
|
-
* @param {string} [options.tip] - Override tip commit (for pinned reads)
|
|
106
|
+
* @param {{ tip?: string }} [options]
|
|
109
107
|
* @returns {Promise<ReadRecordsResult>}
|
|
110
108
|
*/
|
|
111
109
|
async readRecords(graphName, options = {}) {
|
|
@@ -118,7 +116,7 @@ export class TrustRecordService {
|
|
|
118
116
|
tip = await this._persistence.readRef(ref);
|
|
119
117
|
} catch (err) {
|
|
120
118
|
// Distinguish "ref not found" from operational error (J15)
|
|
121
|
-
if (err instanceof
|
|
119
|
+
if (err instanceof PersistenceError && err.code === PersistenceError.E_REF_NOT_FOUND) {
|
|
122
120
|
return { ok: true, records: [] };
|
|
123
121
|
}
|
|
124
122
|
return {
|
|
@@ -234,10 +232,7 @@ export class TrustRecordService {
|
|
|
234
232
|
*
|
|
235
233
|
* @param {string} graphName
|
|
236
234
|
* @param {Record<string, unknown>} record - Complete signed trust record
|
|
237
|
-
* @param {
|
|
238
|
-
* @param {number} [options.maxRetries=3] - Maximum rebuild-and-retry attempts
|
|
239
|
-
* @param {((record: Record<string, unknown>) => Promise<Record<string, unknown>>)|null} [options.resign] - Function to re-sign a rebuilt record (null for unsigned)
|
|
240
|
-
* @param {boolean} [options.skipSignatureVerify=false] - Skip signature verification
|
|
235
|
+
* @param {{ maxRetries?: number, resign?: ((record: Record<string, unknown>) => Promise<Record<string, unknown>>)|null, skipSignatureVerify?: boolean }} [options]
|
|
241
236
|
* @returns {Promise<{commitSha: string, ref: string, attempts: number}>}
|
|
242
237
|
* @throws {TrustError} E_TRUST_CAS_EXHAUSTED if all retries fail
|
|
243
238
|
*/
|
|
@@ -175,11 +175,7 @@ function validateOpResult(value, i) {
|
|
|
175
175
|
/**
|
|
176
176
|
* Creates an immutable TickReceipt.
|
|
177
177
|
*
|
|
178
|
-
* @param {
|
|
179
|
-
* @param {string} params.patchSha - SHA of the patch commit
|
|
180
|
-
* @param {string} params.writer - Writer ID
|
|
181
|
-
* @param {number} params.lamport - Lamport timestamp (non-negative integer)
|
|
182
|
-
* @param {OpOutcome[]} params.ops - Per-operation outcome records
|
|
178
|
+
* @param {{ patchSha: string, writer: string, lamport: number, ops: OpOutcome[] }} params
|
|
183
179
|
* @returns {Readonly<TickReceipt>} Frozen tick receipt
|
|
184
180
|
* @throws {Error} If any parameter is invalid
|
|
185
181
|
*/
|
|
@@ -279,9 +275,9 @@ export function canonicalJson(receipt) {
|
|
|
279
275
|
*/
|
|
280
276
|
function sortedReplacer(_key, value) {
|
|
281
277
|
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
282
|
-
/** @type {{ [x: string]:
|
|
278
|
+
/** @type {{ [x: string]: unknown }} */
|
|
283
279
|
const sorted = {};
|
|
284
|
-
const obj = /** @type {{ [x: string]:
|
|
280
|
+
const obj = /** @type {{ [x: string]: unknown }} */ (value);
|
|
285
281
|
for (const k of Object.keys(obj).sort()) {
|
|
286
282
|
sorted[k] = obj[k];
|
|
287
283
|
}
|
|
@@ -197,11 +197,7 @@ export function createPropSet(node, key, value) {
|
|
|
197
197
|
|
|
198
198
|
/**
|
|
199
199
|
* Creates an EventId
|
|
200
|
-
* @param {
|
|
201
|
-
* @param {number} options.lamport - Lamport timestamp
|
|
202
|
-
* @param {string} options.writerId - Writer ID
|
|
203
|
-
* @param {string} options.patchSha - Patch SHA
|
|
204
|
-
* @param {number} options.opIndex - Operation index within patch
|
|
200
|
+
* @param {{ lamport: number, writerId: string, patchSha: string, opIndex: number }} options - EventId options
|
|
205
201
|
* @returns {EventId} EventId object
|
|
206
202
|
*/
|
|
207
203
|
export function createEventId({ lamport, writerId, patchSha, opIndex }) {
|
|
@@ -241,14 +241,7 @@ export function createEdgePropSetV2(from, to, label, key, value) {
|
|
|
241
241
|
|
|
242
242
|
/**
|
|
243
243
|
* Creates a PatchV2
|
|
244
|
-
* @param {
|
|
245
|
-
* @param {2|3} [options.schema=2] - Schema version (2 for node-only, 3 for edge properties)
|
|
246
|
-
* @param {string} options.writer - Writer ID
|
|
247
|
-
* @param {number} options.lamport - Lamport timestamp
|
|
248
|
-
* @param {VersionVector} options.context - Writer's observed frontier
|
|
249
|
-
* @param {OpV2[]} options.ops - Array of operations
|
|
250
|
-
* @param {string[]} [options.reads] - Node/edge IDs read by this patch (for provenance tracking)
|
|
251
|
-
* @param {string[]} [options.writes] - Node/edge IDs written by this patch (for provenance tracking)
|
|
244
|
+
* @param {{ schema?: 2|3, writer: string, lamport: number, context: VersionVector, ops: OpV2[], reads?: string[], writes?: string[] }} options - Patch options
|
|
252
245
|
* @returns {PatchV2} PatchV2 object
|
|
253
246
|
*/
|
|
254
247
|
export function createPatchV2({ schema = 2, writer, lamport, context, ops, reads, writes }) {
|
|
@@ -28,10 +28,7 @@ class CachedValue {
|
|
|
28
28
|
/**
|
|
29
29
|
* Creates a CachedValue instance.
|
|
30
30
|
*
|
|
31
|
-
* @param {
|
|
32
|
-
* @param {import('../../ports/ClockPort.js').default} options.clock - Clock port for timing
|
|
33
|
-
* @param {number} options.ttlMs - Time-to-live in milliseconds
|
|
34
|
-
* @param {() => T | Promise<T>} options.compute - Function to compute the value when cache is stale
|
|
31
|
+
* @param {{ clock: import('../../ports/ClockPort.js').default, ttlMs: number, compute: () => T | Promise<T> }} options
|
|
35
32
|
* @throws {Error} If ttlMs is not a positive number
|
|
36
33
|
*/
|
|
37
34
|
constructor({ clock, ttlMs, compute }) {
|
|
@@ -9,9 +9,9 @@ class MinHeap {
|
|
|
9
9
|
/**
|
|
10
10
|
* Creates an empty MinHeap.
|
|
11
11
|
*
|
|
12
|
-
* @param {
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* @param {{ tieBreaker?: (a: T, b: T) => number }} [options] - Configuration options.
|
|
13
|
+
* `tieBreaker`: comparator invoked when two entries have equal priority.
|
|
14
|
+
* Negative return = a wins (comes out first).
|
|
15
15
|
* When omitted, equal-priority extraction order is unspecified (heap-natural).
|
|
16
16
|
*/
|
|
17
17
|
constructor(options) {
|
|
@@ -45,6 +45,23 @@ const WRITER_ID_PATTERN = /^[A-Za-z0-9._-]+$/;
|
|
|
45
45
|
*/
|
|
46
46
|
const PATH_TRAVERSAL_PATTERN = /\.\./;
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Ref-layout keywords that must not appear as any `/`-delimited segment
|
|
50
|
+
* of a graph name. Using one of these would create an ambiguous ref path
|
|
51
|
+
* (e.g. `refs/warp/writers/writers/alice`).
|
|
52
|
+
*
|
|
53
|
+
* @type {Set<string>}
|
|
54
|
+
*/
|
|
55
|
+
export const RESERVED_GRAPH_NAME_SEGMENTS = new Set([
|
|
56
|
+
'writers',
|
|
57
|
+
'checkpoints',
|
|
58
|
+
'coverage',
|
|
59
|
+
'cursor',
|
|
60
|
+
'audit',
|
|
61
|
+
'trust',
|
|
62
|
+
'seek-cache',
|
|
63
|
+
]);
|
|
64
|
+
|
|
48
65
|
// -----------------------------------------------------------------------------
|
|
49
66
|
// Validators
|
|
50
67
|
// -----------------------------------------------------------------------------
|
|
@@ -94,6 +111,15 @@ export function validateGraphName(name) {
|
|
|
94
111
|
if (name.includes('\0')) {
|
|
95
112
|
throw new Error(`Invalid graph name: contains null byte: ${name}`);
|
|
96
113
|
}
|
|
114
|
+
|
|
115
|
+
const segments = name.split('/');
|
|
116
|
+
for (const seg of segments) {
|
|
117
|
+
if (RESERVED_GRAPH_NAME_SEGMENTS.has(seg)) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Invalid graph name: segment '${seg}' is a reserved ref-layout keyword: ${name}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
97
123
|
}
|
|
98
124
|
|
|
99
125
|
/**
|
|
@@ -116,8 +116,7 @@ function crockfordBase32(bytes) {
|
|
|
116
116
|
* Uses 128 bits of entropy (16 bytes) encoded as Crockford Base32.
|
|
117
117
|
* The result is prefixed with `w_` for a total length of 28 characters.
|
|
118
118
|
*
|
|
119
|
-
* @param {
|
|
120
|
-
* @param {(n: number) => Uint8Array} [options.randomBytes] - Custom RNG for testing
|
|
119
|
+
* @param {{ randomBytes?: (n: number) => Uint8Array }} [options] - Options with optional custom RNG for testing
|
|
121
120
|
* @returns {string} A canonical writer ID (e.g., 'w_0123456789abcdefghjkmnpqrs')
|
|
122
121
|
* @throws {WriterIdError} If RNG is unavailable or returns wrong shape
|
|
123
122
|
*
|
|
@@ -148,11 +147,7 @@ export function generateWriterId({ randomBytes } = {}) {
|
|
|
148
147
|
* 2. Load from git config key `warp.writerId.<graphName>`
|
|
149
148
|
* 3. If missing or invalid, generate new canonical ID, persist, and return
|
|
150
149
|
*
|
|
151
|
-
* @param {
|
|
152
|
-
* @param {string} args.graphName - The graph name
|
|
153
|
-
* @param {string|undefined} args.explicitWriterId - Optional explicit writer ID
|
|
154
|
-
* @param {(key: string) => Promise<string|null>} args.configGet - Function to read git config
|
|
155
|
-
* @param {(key: string, value: string) => Promise<void>} args.configSet - Function to write git config
|
|
150
|
+
* @param {{ graphName: string, explicitWriterId: string|null|undefined, configGet: (key: string) => Promise<string|null>, configSet: (key: string, value: string) => Promise<void> }} args
|
|
156
151
|
* @returns {Promise<string>} The resolved writer ID
|
|
157
152
|
* @throws {WriterIdError} If config operations fail
|
|
158
153
|
*
|
|
@@ -28,7 +28,7 @@ export function encodeCanonicalCbor(value) {
|
|
|
28
28
|
/**
|
|
29
29
|
* Decodes CBOR bytes to a value.
|
|
30
30
|
*
|
|
31
|
-
* @param {
|
|
31
|
+
* @param {Uint8Array} buffer - CBOR bytes
|
|
32
32
|
* @returns {unknown} Decoded value
|
|
33
33
|
*/
|
|
34
34
|
export function decodeCanonicalCbor(buffer) {
|
|
@@ -34,7 +34,7 @@ function sortKeys(value) {
|
|
|
34
34
|
}
|
|
35
35
|
return sorted;
|
|
36
36
|
}
|
|
37
|
-
if (typeof value === 'object' && (/** @type {
|
|
37
|
+
if (typeof value === 'object' && (/** @type {Record<string, unknown>} */ (value).constructor === Object || /** @type {Record<string, unknown>} */ (value).constructor === undefined)) {
|
|
38
38
|
/** @type {Record<string, unknown>} */
|
|
39
39
|
const sorted = {};
|
|
40
40
|
for (const key of Object.keys(value).sort()) {
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Parses and validates a cursor blob (
|
|
8
|
+
* Parses and validates a cursor blob (Uint8Array) into a cursor object.
|
|
9
9
|
*
|
|
10
10
|
* The blob must contain UTF-8-encoded JSON representing a plain object with at
|
|
11
11
|
* minimum a finite numeric `tick` field. Any additional fields (e.g. `mode`,
|
|
12
12
|
* `name`) are preserved in the returned object.
|
|
13
13
|
*
|
|
14
|
-
* @param {
|
|
14
|
+
* @param {Uint8Array} buf - Raw blob contents (UTF-8 encoded JSON)
|
|
15
15
|
* @param {string} label - Human-readable label used in error messages
|
|
16
16
|
* (e.g. `"active cursor"`, `"saved cursor 'foo'"`)
|
|
17
17
|
* @returns {{ tick: number, mode?: string, [key: string]: unknown }}
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
* Infinity
|
|
24
24
|
*
|
|
25
25
|
* @example
|
|
26
|
-
* const buf =
|
|
26
|
+
* const buf = new TextEncoder().encode('{"tick":5,"mode":"lamport"}');
|
|
27
27
|
* const cursor = parseCursorBlob(buf, 'active cursor');
|
|
28
28
|
* // => { tick: 5, mode: 'lamport' }
|
|
29
29
|
*
|
|
30
30
|
* @example
|
|
31
31
|
* // Throws: "Corrupted active cursor: blob is not valid JSON"
|
|
32
|
-
* parseCursorBlob(
|
|
32
|
+
* parseCursorBlob(new TextEncoder().encode('not json'), 'active cursor');
|
|
33
33
|
*/
|
|
34
34
|
export function parseCursorBlob(buf, label) {
|
|
35
35
|
let obj;
|
|
@@ -19,12 +19,7 @@ export class PatchSession {
|
|
|
19
19
|
/**
|
|
20
20
|
* Creates a new PatchSession.
|
|
21
21
|
*
|
|
22
|
-
* @param {
|
|
23
|
-
* @param {import('../services/PatchBuilderV2.js').PatchBuilderV2} options.builder - Internal builder
|
|
24
|
-
* @param {import('../../ports/GraphPersistencePort.js').default & import('../../ports/RefPort.js').default} options.persistence - Git adapter
|
|
25
|
-
* @param {string} options.graphName - Graph namespace
|
|
26
|
-
* @param {string} options.writerId - Writer ID
|
|
27
|
-
* @param {string|null} options.expectedOldHead - Expected parent SHA for CAS
|
|
22
|
+
* @param {{ builder: import('../services/PatchBuilderV2.js').PatchBuilderV2, persistence: import('../../ports/GraphPersistencePort.js').default & import('../../ports/RefPort.js').default, graphName: string, writerId: string, expectedOldHead: string|null }} options
|
|
28
23
|
*/
|
|
29
24
|
constructor({ builder, persistence, graphName, writerId, expectedOldHead }) {
|
|
30
25
|
/** @type {import('../services/PatchBuilderV2.js').PatchBuilderV2} */
|
|
@@ -152,7 +147,7 @@ export class PatchSession {
|
|
|
152
147
|
* Attaches content to a node.
|
|
153
148
|
*
|
|
154
149
|
* @param {string} nodeId - The node ID to attach content to
|
|
155
|
-
* @param {
|
|
150
|
+
* @param {Uint8Array|string} content - The content to attach
|
|
156
151
|
* @returns {Promise<this>} This session for chaining
|
|
157
152
|
* @throws {WriterError} SESSION_COMMITTED if already committed
|
|
158
153
|
*/
|
|
@@ -168,7 +163,7 @@ export class PatchSession {
|
|
|
168
163
|
* @param {string} from - Source node ID
|
|
169
164
|
* @param {string} to - Target node ID
|
|
170
165
|
* @param {string} label - Edge label/type
|
|
171
|
-
* @param {
|
|
166
|
+
* @param {Uint8Array|string} content - The content to attach
|
|
172
167
|
* @returns {Promise<this>} This session for chaining
|
|
173
168
|
* @throws {WriterError} SESSION_COMMITTED if already committed
|
|
174
169
|
*/
|
|
@@ -36,16 +36,7 @@ export class Writer {
|
|
|
36
36
|
/**
|
|
37
37
|
* Creates a new Writer instance.
|
|
38
38
|
*
|
|
39
|
-
* @param {
|
|
40
|
-
* @param {import('../../ports/GraphPersistencePort.js').default & import('../../ports/RefPort.js').default & import('../../ports/CommitPort.js').default} options.persistence - Git adapter
|
|
41
|
-
* @param {string} options.graphName - Graph namespace
|
|
42
|
-
* @param {string} options.writerId - This writer's ID
|
|
43
|
-
* @param {import('../crdt/VersionVector.js').VersionVector} options.versionVector - Current version vector
|
|
44
|
-
* @param {() => Promise<import('../services/JoinReducer.js').WarpStateV5>} options.getCurrentState - Async function returning the current materialized V5 state
|
|
45
|
-
* @param {(result: {patch: Object, sha: string}) => void | Promise<void>} [options.onCommitSuccess] - Callback invoked after successful commit with { patch, sha }
|
|
46
|
-
* @param {'reject'|'cascade'|'warn'} [options.onDeleteWithData='warn'] - Policy when deleting a node with attached data
|
|
47
|
-
* @param {import('../../ports/CodecPort.js').default} [options.codec] - Codec for CBOR serialization (defaults to domain-local codec)
|
|
48
|
-
* @param {import('../../ports/LoggerPort.js').default} [options.logger] - Logger port
|
|
39
|
+
* @param {{ persistence: import('../../ports/GraphPersistencePort.js').default & import('../../ports/RefPort.js').default & import('../../ports/CommitPort.js').default, graphName: string, writerId: string, versionVector: import('../crdt/VersionVector.js').VersionVector, getCurrentState: () => import('../services/JoinReducer.js').WarpStateV5 | null, onCommitSuccess?: (result: {patch: import('../types/WarpTypesV2.js').PatchV2, sha: string}) => void | Promise<void>, onDeleteWithData?: 'reject'|'cascade'|'warn', codec?: import('../../ports/CodecPort.js').default, logger?: import('../../ports/LoggerPort.js').default }} options
|
|
49
40
|
*/
|
|
50
41
|
constructor({ persistence, graphName, writerId, versionVector, getCurrentState, onCommitSuccess, onDeleteWithData = 'warn', codec, logger }) {
|
|
51
42
|
validateWriterId(writerId);
|
|
@@ -62,10 +53,10 @@ export class Writer {
|
|
|
62
53
|
/** @type {import('../crdt/VersionVector.js').VersionVector} */
|
|
63
54
|
this._versionVector = versionVector;
|
|
64
55
|
|
|
65
|
-
/** @type {
|
|
56
|
+
/** @type {() => import('../services/JoinReducer.js').WarpStateV5 | null} */
|
|
66
57
|
this._getCurrentState = getCurrentState;
|
|
67
58
|
|
|
68
|
-
/** @type {
|
|
59
|
+
/** @type {((result: {patch: import('../types/WarpTypesV2.js').PatchV2, sha: string}) => void | Promise<void>)|undefined} */
|
|
69
60
|
this._onCommitSuccess = onCommitSuccess;
|
|
70
61
|
|
|
71
62
|
/** @type {'reject'|'cascade'|'warn'} */
|
package/src/domain/warp/_wire.js
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* become method names on the prototype. Duplicates across modules are
|
|
15
15
|
* detected eagerly and throw at import time (not at call time).
|
|
16
16
|
*
|
|
17
|
-
* @param {
|
|
18
|
-
* @param {Array<Record<string,
|
|
17
|
+
* @param {{ prototype: object, name: string }} Class - The class constructor whose prototype to extend
|
|
18
|
+
* @param {Array<Record<string, unknown>>} methodModules - Array of method module namespace objects
|
|
19
19
|
* @throws {Error} If a method name appears in more than one module
|
|
20
20
|
*/
|
|
21
21
|
export function wireWarpMethods(Class, methodModules) {
|
|
@@ -179,13 +179,11 @@ declare module '../WarpGraph.js' {
|
|
|
179
179
|
// ── provenance.methods.js ─────────────────────────────────────────────
|
|
180
180
|
patchesFor(entityId: string): Promise<string[]>;
|
|
181
181
|
materializeSlice(nodeId: string, options?: { receipts?: boolean }): Promise<{ state: WarpStateV5; patchCount: number; receipts?: TickReceipt[] }>;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
_loadPatchBySha(sha: string): Promise<{ patch: PatchV2; sha: string }>;
|
|
182
|
+
_computeBackwardCone(nodeId: string): Promise<Map<string, PatchV2>>;
|
|
183
|
+
loadPatchBySha(sha: string): Promise<PatchV2>;
|
|
184
|
+
_loadPatchBySha(sha: string): Promise<PatchV2>;
|
|
186
185
|
_loadPatchesBySha(shas: string[]): Promise<Array<{ patch: PatchV2; sha: string }>>;
|
|
187
|
-
|
|
188
|
-
_sortPatchesCausally(patches: Array<{ patch: any; sha: string }>): Array<{ patch: any; sha: string }>;
|
|
186
|
+
_sortPatchesCausally(patches: Array<{ patch: PatchV2; sha: string }>): Array<{ patch: PatchV2; sha: string }>;
|
|
189
187
|
|
|
190
188
|
// ── fork.methods.js ───────────────────────────────────────────────────
|
|
191
189
|
fork(options: { from: string; at: string; forkName?: string; forkWriterId?: string }): Promise<WarpGraph>;
|
|
@@ -251,7 +249,7 @@ declare module '../WarpGraph.js' {
|
|
|
251
249
|
_buildView(state: WarpStateV5, stateHash: string, diff?: import('../types/PatchDiff.js').PatchDiff): void;
|
|
252
250
|
_setMaterializedState(state: WarpStateV5, optionsOrDiff?: import('../types/PatchDiff.js').PatchDiff | { diff?: import('../types/PatchDiff.js').PatchDiff | null }): Promise<{ state: WarpStateV5; stateHash: string; adjacency: unknown }>;
|
|
253
251
|
_materializeWithCeiling(ceiling: number, collectReceipts: boolean, t0: number): Promise<WarpStateV5 | { state: WarpStateV5; receipts: TickReceipt[] }>;
|
|
254
|
-
_persistSeekCacheEntry(cacheKey: string, buf:
|
|
252
|
+
_persistSeekCacheEntry(cacheKey: string, buf: Uint8Array, state: WarpStateV5): Promise<void>;
|
|
255
253
|
_restoreIndexFromCache(indexTreeOid: string): Promise<void>;
|
|
256
254
|
materializeAt(checkpointSha: string): Promise<WarpStateV5>;
|
|
257
255
|
verifyIndex(options?: { seed?: number; sampleRate?: number }): { passed: number; failed: number; errors: Array<{ nodeId: string; direction: string; expected: string[]; actual: string[] }> };
|
|
@@ -375,7 +375,7 @@ export function _maybeRunGC(state) {
|
|
|
375
375
|
* **Requires a cached state.**
|
|
376
376
|
*
|
|
377
377
|
* @this {import('../WarpGraph.js').default}
|
|
378
|
-
* @returns {{ran: boolean, result:
|
|
378
|
+
* @returns {{ran: boolean, result: import('../services/GCPolicy.js').GCExecuteResult|null, reasons: string[]}} GC result
|
|
379
379
|
*
|
|
380
380
|
* @example
|
|
381
381
|
* await graph.materialize();
|
|
@@ -31,11 +31,7 @@ import { createWormhole as createWormholeImpl } from '../services/WormholeServic
|
|
|
31
31
|
* - History up to the fork point is shared (content-addressed dedup)
|
|
32
32
|
*
|
|
33
33
|
* @this {import('../WarpGraph.js').default}
|
|
34
|
-
* @param {
|
|
35
|
-
* @param {string} options.from - Writer ID whose chain to fork from
|
|
36
|
-
* @param {string} options.at - Patch SHA to fork at (must be in the writer's chain)
|
|
37
|
-
* @param {string} [options.forkName] - Name for the forked graph. Defaults to `<graphName>-fork-<timestamp>`
|
|
38
|
-
* @param {string} [options.forkWriterId] - Writer ID for the fork. Defaults to a new canonical ID.
|
|
34
|
+
* @param {{ from: string, at: string, forkName?: string, forkWriterId?: string }} options - Fork configuration
|
|
39
35
|
* @returns {Promise<import('../WarpGraph.js').default>} A new WarpGraph instance for the fork
|
|
40
36
|
* @throws {ForkError} If `from` writer does not exist (code: `E_FORK_WRITER_NOT_FOUND`)
|
|
41
37
|
* @throws {ForkError} If `at` SHA does not exist (code: `E_FORK_PATCH_NOT_FOUND`)
|
|
@@ -351,7 +351,7 @@ export async function _materializeWithCeiling(ceiling, collectReceipts, t0) {
|
|
|
351
351
|
cacheKey = buildSeekCacheKey(ceiling, frontier);
|
|
352
352
|
}
|
|
353
353
|
const buf = serializeFullStateV5(state, { codec: this._codec });
|
|
354
|
-
this._persistSeekCacheEntry(cacheKey,
|
|
354
|
+
this._persistSeekCacheEntry(cacheKey, buf, state)
|
|
355
355
|
.catch(() => {});
|
|
356
356
|
}
|
|
357
357
|
|
|
@@ -377,7 +377,7 @@ export async function _materializeWithCeiling(ceiling, collectReceipts, t0) {
|
|
|
377
377
|
*
|
|
378
378
|
* @this {import('../WarpGraph.js').default}
|
|
379
379
|
* @param {string} cacheKey - Seek cache key
|
|
380
|
-
* @param {
|
|
380
|
+
* @param {Uint8Array} buf - Serialized WarpStateV5 buffer
|
|
381
381
|
* @param {import('../services/JoinReducer.js').WarpStateV5} state
|
|
382
382
|
* @returns {Promise<void>}
|
|
383
383
|
* @private
|
|
@@ -473,7 +473,7 @@ export async function materializeAt(checkpointSha) {
|
|
|
473
473
|
|
|
474
474
|
const patchMeta = decodePatchMessage(message);
|
|
475
475
|
const patchBuffer = await this._persistence.readBlob(patchMeta.patchOid);
|
|
476
|
-
const patch = this._codec.decode(patchBuffer);
|
|
476
|
+
const patch = /** @type {import('../types/WarpTypesV2.js').PatchV2} */ (this._codec.decode(patchBuffer));
|
|
477
477
|
|
|
478
478
|
patches.push({ patch, sha: currentSha });
|
|
479
479
|
|
|
@@ -287,9 +287,9 @@ export async function writer(writerId) {
|
|
|
287
287
|
graphName: this._graphName,
|
|
288
288
|
writerId: resolvedWriterId,
|
|
289
289
|
versionVector: this._versionVector,
|
|
290
|
-
getCurrentState:
|
|
290
|
+
getCurrentState: () => this._cachedState,
|
|
291
291
|
onDeleteWithData: this._onDeleteWithData,
|
|
292
|
-
onCommitSuccess: /** @type {(result: {patch:
|
|
292
|
+
onCommitSuccess: /** @type {(result: {patch: import('../types/WarpTypesV2.js').PatchV2, sha: string}) => void} */ ((/** @type {{patch?: import('../types/WarpTypesV2.js').PatchV2, sha?: string}} */ opts) => this._onPatchCommitted(resolvedWriterId, opts)),
|
|
293
293
|
codec: this._codec,
|
|
294
294
|
logger: this._logger || undefined,
|
|
295
295
|
});
|
|
@@ -304,9 +304,7 @@ export async function writer(writerId) {
|
|
|
304
304
|
*
|
|
305
305
|
* @deprecated Use `writer()` to resolve a stable ID from git config, or `writer(id)` with an explicit ID.
|
|
306
306
|
* @this {import('../WarpGraph.js').default}
|
|
307
|
-
* @param {
|
|
308
|
-
* @param {'config'|'none'} [opts.persist='none'] - Whether to persist the new ID to git config
|
|
309
|
-
* @param {string} [opts.alias] - Optional alias for config key (used with persist:'config')
|
|
307
|
+
* @param {{ persist?: 'config'|'none', alias?: string }} [opts]
|
|
310
308
|
* @returns {Promise<Writer>} A Writer instance with new canonical ID
|
|
311
309
|
* @throws {Error} If config operations fail (when persist:'config')
|
|
312
310
|
*
|
|
@@ -346,9 +344,9 @@ export async function createWriter(opts = {}) {
|
|
|
346
344
|
graphName: this._graphName,
|
|
347
345
|
writerId: freshWriterId,
|
|
348
346
|
versionVector: this._versionVector,
|
|
349
|
-
getCurrentState:
|
|
347
|
+
getCurrentState: () => this._cachedState,
|
|
350
348
|
onDeleteWithData: this._onDeleteWithData,
|
|
351
|
-
onCommitSuccess: /** @type {(result: {patch:
|
|
349
|
+
onCommitSuccess: /** @type {(result: {patch: import('../types/WarpTypesV2.js').PatchV2, sha: string}) => void} */ ((/** @type {{patch?: import('../types/WarpTypesV2.js').PatchV2, sha?: string}} */ commitOpts) => this._onPatchCommitted(freshWriterId, commitOpts)),
|
|
352
350
|
codec: this._codec,
|
|
353
351
|
logger: this._logger || undefined,
|
|
354
352
|
});
|
|
@@ -484,7 +482,7 @@ export async function discoverTicks() {
|
|
|
484
482
|
*
|
|
485
483
|
* @this {import('../WarpGraph.js').default}
|
|
486
484
|
* @param {import('../services/JoinReducer.js').WarpStateV5} otherState - The state to merge in
|
|
487
|
-
* @returns {{state: import('../services/JoinReducer.js').WarpStateV5, receipt:
|
|
485
|
+
* @returns {{state: import('../services/JoinReducer.js').WarpStateV5, receipt: {nodesAdded: number, nodesRemoved: number, edgesAdded: number, edgesRemoved: number, propsChanged: number, frontierMerged: boolean}}} Merged state and receipt
|
|
488
486
|
* @throws {QueryError} If no cached state exists (code: `E_NO_STATE`)
|
|
489
487
|
* @throws {Error} If otherState is invalid
|
|
490
488
|
*/
|
|
@@ -152,7 +152,7 @@ export async function materializeSlice(nodeId, options) {
|
|
|
152
152
|
*
|
|
153
153
|
* @this {import('../WarpGraph.js').default}
|
|
154
154
|
* @param {string} nodeId - The target node ID
|
|
155
|
-
* @returns {Promise<Map<string,
|
|
155
|
+
* @returns {Promise<Map<string, import('../types/WarpTypesV2.js').PatchV2>>} Map of patch SHA to loaded patch object
|
|
156
156
|
*/
|
|
157
157
|
export async function _computeBackwardCone(nodeId) {
|
|
158
158
|
if (!this._provenanceIndex) {
|
|
@@ -209,7 +209,7 @@ export async function _computeBackwardCone(nodeId) {
|
|
|
209
209
|
*
|
|
210
210
|
* @this {import('../WarpGraph.js').default}
|
|
211
211
|
* @param {string} sha - The patch commit SHA
|
|
212
|
-
* @returns {Promise<
|
|
212
|
+
* @returns {Promise<import('../types/WarpTypesV2.js').PatchV2>} The decoded patch object
|
|
213
213
|
* @throws {Error} If the commit is not a patch or loading fails
|
|
214
214
|
*/
|
|
215
215
|
export async function loadPatchBySha(sha) {
|
|
@@ -221,7 +221,7 @@ export async function loadPatchBySha(sha) {
|
|
|
221
221
|
*
|
|
222
222
|
* @this {import('../WarpGraph.js').default}
|
|
223
223
|
* @param {string} sha - The patch commit SHA
|
|
224
|
-
* @returns {Promise<
|
|
224
|
+
* @returns {Promise<import('../types/WarpTypesV2.js').PatchV2>} The decoded patch object
|
|
225
225
|
* @throws {Error} If the commit is not a patch or loading fails
|
|
226
226
|
*/
|
|
227
227
|
export async function _loadPatchBySha(sha) {
|
|
@@ -234,7 +234,7 @@ export async function _loadPatchBySha(sha) {
|
|
|
234
234
|
|
|
235
235
|
const patchMeta = decodePatchMessage(nodeInfo.message);
|
|
236
236
|
const patchBuffer = await this._persistence.readBlob(patchMeta.patchOid);
|
|
237
|
-
return /** @type {
|
|
237
|
+
return /** @type {import('../types/WarpTypesV2.js').PatchV2} */ (this._codec.decode(patchBuffer));
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
/**
|
|
@@ -242,7 +242,7 @@ export async function _loadPatchBySha(sha) {
|
|
|
242
242
|
*
|
|
243
243
|
* @this {import('../WarpGraph.js').default}
|
|
244
244
|
* @param {string[]} shas - Array of patch commit SHAs
|
|
245
|
-
* @returns {Promise<Array<{patch:
|
|
245
|
+
* @returns {Promise<Array<{patch: import('../types/WarpTypesV2.js').PatchV2, sha: string}>>} Array of patch entries
|
|
246
246
|
* @throws {Error} If any SHA is not a patch or loading fails
|
|
247
247
|
*/
|
|
248
248
|
export async function _loadPatchesBySha(shas) {
|