@git-stunts/git-warp 10.3.2 → 10.4.2
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/bin/warp-graph.js +371 -141
- package/index.d.ts +31 -0
- package/index.js +4 -0
- package/package.json +8 -3
- package/src/domain/WarpGraph.js +263 -147
- 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 +15 -14
- 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/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 +16 -27
- 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/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 +19 -5
- package/src/visualization/renderers/ascii/table.js +1 -1
- package/src/visualization/renderers/svg/index.js +5 -1
|
@@ -2,9 +2,9 @@ import CryptoPort from '../../ports/CryptoPort.js';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Map of common algorithm names to Web Crypto API algorithm identifiers.
|
|
5
|
-
* @const {
|
|
5
|
+
* @const {Record<string, string>}
|
|
6
6
|
*/
|
|
7
|
-
const ALGO_MAP = {
|
|
7
|
+
const ALGO_MAP = /** @type {Record<string, string>} */ ({
|
|
8
8
|
'sha-1': 'SHA-1',
|
|
9
9
|
'sha1': 'SHA-1',
|
|
10
10
|
'sha-256': 'SHA-256',
|
|
@@ -13,7 +13,7 @@ const ALGO_MAP = {
|
|
|
13
13
|
'sha384': 'SHA-384',
|
|
14
14
|
'sha-512': 'SHA-512',
|
|
15
15
|
'sha512': 'SHA-512',
|
|
16
|
-
};
|
|
16
|
+
});
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Converts a common algorithm name to the Web Crypto API identifier.
|
|
@@ -38,8 +38,9 @@ function toWebCryptoAlgo(algorithm) {
|
|
|
38
38
|
function toUint8Array(data) {
|
|
39
39
|
if (data instanceof Uint8Array) { return data; }
|
|
40
40
|
if (typeof data === 'string') { return new TextEncoder().encode(data); }
|
|
41
|
-
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(data)) {
|
|
42
|
-
|
|
41
|
+
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(/** @type {*} */ (data))) { // TODO(ts-cleanup): narrow port type
|
|
42
|
+
const buf = /** @type {Buffer} */ (/** @type {*} */ (data)); // TODO(ts-cleanup): narrow port type
|
|
43
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
43
44
|
}
|
|
44
45
|
throw new Error('WebCryptoAdapter: data must be string, Buffer, or Uint8Array');
|
|
45
46
|
}
|
|
@@ -59,7 +60,7 @@ function bufToHex(buf) {
|
|
|
59
60
|
* Web Crypto API adapter implementing CryptoPort.
|
|
60
61
|
*
|
|
61
62
|
* Uses the standard Web Crypto API (globalThis.crypto.subtle) which is
|
|
62
|
-
* available in browsers, Deno, Bun, and Node.js
|
|
63
|
+
* available in browsers, Deno, Bun, and Node.js 22+.
|
|
63
64
|
*
|
|
64
65
|
* All hash and HMAC operations are async because the Web Crypto API
|
|
65
66
|
* is inherently promise-based.
|
|
@@ -77,26 +78,35 @@ export default class WebCryptoAdapter extends CryptoPort {
|
|
|
77
78
|
this._subtle = subtle || globalThis.crypto.subtle;
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* @param {string} algorithm
|
|
83
|
+
* @param {string|Buffer|Uint8Array} data
|
|
84
|
+
* @returns {Promise<string>}
|
|
85
|
+
*/
|
|
81
86
|
async hash(algorithm, data) {
|
|
82
87
|
const digest = await this._subtle.digest(
|
|
83
88
|
toWebCryptoAlgo(algorithm),
|
|
84
|
-
toUint8Array(data),
|
|
89
|
+
/** @type {BufferSource} */ (toUint8Array(data)),
|
|
85
90
|
);
|
|
86
91
|
return bufToHex(digest);
|
|
87
92
|
}
|
|
88
93
|
|
|
89
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* @param {string} algorithm
|
|
96
|
+
* @param {string|Buffer|Uint8Array} key
|
|
97
|
+
* @param {string|Buffer|Uint8Array} data
|
|
98
|
+
* @returns {Promise<Uint8Array>}
|
|
99
|
+
*/
|
|
90
100
|
async hmac(algorithm, key, data) {
|
|
91
101
|
const keyBytes = toUint8Array(key);
|
|
92
102
|
const cryptoKey = await this._subtle.importKey(
|
|
93
103
|
'raw',
|
|
94
|
-
keyBytes,
|
|
104
|
+
/** @type {BufferSource} */ (keyBytes),
|
|
95
105
|
{ name: 'HMAC', hash: toWebCryptoAlgo(algorithm) },
|
|
96
106
|
false,
|
|
97
107
|
['sign'],
|
|
98
108
|
);
|
|
99
|
-
const signature = await this._subtle.sign('HMAC', cryptoKey, toUint8Array(data));
|
|
109
|
+
const signature = await this._subtle.sign('HMAC', cryptoKey, /** @type {BufferSource} */ (toUint8Array(data)));
|
|
100
110
|
return new Uint8Array(signature);
|
|
101
111
|
}
|
|
102
112
|
|
|
@@ -83,17 +83,18 @@ const encoder = new Encoder({
|
|
|
83
83
|
* @private
|
|
84
84
|
*/
|
|
85
85
|
function isPlainObject(value) {
|
|
86
|
-
return typeof value === 'object' && (value.constructor === Object || value.constructor === undefined);
|
|
86
|
+
return typeof value === 'object' && value !== null && (value.constructor === Object || value.constructor === undefined);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
90
|
* Sorts the keys of a plain object and recursively processes values.
|
|
91
91
|
*
|
|
92
|
-
* @param {
|
|
93
|
-
* @returns {
|
|
92
|
+
* @param {Record<string, unknown>} obj - The plain object to process
|
|
93
|
+
* @returns {Record<string, unknown>} A new object with sorted keys
|
|
94
94
|
* @private
|
|
95
95
|
*/
|
|
96
96
|
function sortPlainObject(obj) {
|
|
97
|
+
/** @type {Record<string, unknown>} */
|
|
97
98
|
const sorted = {};
|
|
98
99
|
const keys = Object.keys(obj).sort();
|
|
99
100
|
for (const key of keys) {
|
|
@@ -106,8 +107,8 @@ function sortPlainObject(obj) {
|
|
|
106
107
|
* Converts a Map to a sorted plain object with recursive value processing.
|
|
107
108
|
* Validates that all Map keys are strings (required for CBOR encoding).
|
|
108
109
|
*
|
|
109
|
-
* @param {Map} map - The Map instance to convert
|
|
110
|
-
* @returns {
|
|
110
|
+
* @param {Map<string, unknown>} map - The Map instance to convert
|
|
111
|
+
* @returns {Record<string, unknown>} A plain object with sorted keys
|
|
111
112
|
* @throws {TypeError} If any Map key is not a string
|
|
112
113
|
* @private
|
|
113
114
|
*/
|
|
@@ -118,6 +119,7 @@ function sortMapToObject(map) {
|
|
|
118
119
|
throw new TypeError(`Map keys must be strings for CBOR encoding, got ${typeof key}`);
|
|
119
120
|
}
|
|
120
121
|
}
|
|
122
|
+
/** @type {Record<string, unknown>} */
|
|
121
123
|
const sorted = {};
|
|
122
124
|
keys.sort();
|
|
123
125
|
for (const key of keys) {
|
|
@@ -198,7 +200,7 @@ function sortKeys(value) {
|
|
|
198
200
|
|
|
199
201
|
// Plain objects: sort keys and recursively process values
|
|
200
202
|
if (isPlainObject(value)) {
|
|
201
|
-
return sortPlainObject(value);
|
|
203
|
+
return sortPlainObject(/** @type {Record<string, unknown>} */ (value));
|
|
202
204
|
}
|
|
203
205
|
|
|
204
206
|
// Map instances: convert to sorted object
|
|
@@ -370,12 +372,18 @@ export function decode(buffer) {
|
|
|
370
372
|
* @extends CodecPort
|
|
371
373
|
*/
|
|
372
374
|
export class CborCodec extends CodecPort {
|
|
373
|
-
/**
|
|
375
|
+
/**
|
|
376
|
+
* @param {unknown} data
|
|
377
|
+
* @returns {Buffer|Uint8Array}
|
|
378
|
+
*/
|
|
374
379
|
encode(data) {
|
|
375
380
|
return encode(data);
|
|
376
381
|
}
|
|
377
382
|
|
|
378
|
-
/**
|
|
383
|
+
/**
|
|
384
|
+
* @param {Buffer|Uint8Array} buffer
|
|
385
|
+
* @returns {unknown}
|
|
386
|
+
*/
|
|
379
387
|
decode(buffer) {
|
|
380
388
|
return decode(buffer);
|
|
381
389
|
}
|
package/src/ports/BlobPort.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
export default class BlobPort {
|
|
11
11
|
/**
|
|
12
12
|
* Writes content as a Git blob and returns its OID.
|
|
13
|
-
* @param {Buffer|string}
|
|
13
|
+
* @param {Buffer|string} _content - The blob content to write
|
|
14
14
|
* @returns {Promise<string>} The Git OID of the created blob
|
|
15
15
|
* @throws {Error} If not implemented by a concrete adapter
|
|
16
16
|
*/
|
|
@@ -20,7 +20,7 @@ export default class BlobPort {
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Reads the content of a Git blob.
|
|
23
|
-
* @param {string}
|
|
23
|
+
* @param {string} _oid - The blob OID to read
|
|
24
24
|
* @returns {Promise<Buffer>} The blob content
|
|
25
25
|
* @throws {Error} If not implemented by a concrete adapter
|
|
26
26
|
*/
|
package/src/ports/CodecPort.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export default class CodecPort {
|
|
8
8
|
/**
|
|
9
9
|
* Encodes data to binary format.
|
|
10
|
-
* @param {unknown}
|
|
10
|
+
* @param {unknown} _data - Data to encode
|
|
11
11
|
* @returns {Buffer|Uint8Array} Encoded bytes
|
|
12
12
|
*/
|
|
13
13
|
encode(_data) {
|
|
@@ -16,7 +16,7 @@ export default class CodecPort {
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Decodes binary data back to a JavaScript value.
|
|
19
|
-
* @param {Buffer|Uint8Array}
|
|
19
|
+
* @param {Buffer|Uint8Array} _bytes - Encoded bytes to decode
|
|
20
20
|
* @returns {unknown} Decoded value
|
|
21
21
|
*/
|
|
22
22
|
decode(_bytes) {
|
package/src/ports/CommitPort.js
CHANGED
|
@@ -10,10 +10,7 @@
|
|
|
10
10
|
export default class CommitPort {
|
|
11
11
|
/**
|
|
12
12
|
* Creates a commit pointing to the empty tree.
|
|
13
|
-
* @param {
|
|
14
|
-
* @param {string} options.message - The commit message (typically CBOR-encoded patch data)
|
|
15
|
-
* @param {string[]} [options.parents=[]] - Parent commit SHAs for the commit graph
|
|
16
|
-
* @param {boolean} [options.sign=false] - Whether to GPG-sign the commit
|
|
13
|
+
* @param {{ message: string, parents?: string[], sign?: boolean }} _options
|
|
17
14
|
* @returns {Promise<string>} The SHA of the created commit
|
|
18
15
|
* @throws {Error} If not implemented by a concrete adapter
|
|
19
16
|
*/
|
|
@@ -23,7 +20,7 @@ export default class CommitPort {
|
|
|
23
20
|
|
|
24
21
|
/**
|
|
25
22
|
* Retrieves the raw commit message for a given SHA.
|
|
26
|
-
* @param {string}
|
|
23
|
+
* @param {string} _sha - The commit SHA to read
|
|
27
24
|
* @returns {Promise<string>} The raw commit message content
|
|
28
25
|
* @throws {Error} If not implemented by a concrete adapter
|
|
29
26
|
*/
|
|
@@ -33,7 +30,7 @@ export default class CommitPort {
|
|
|
33
30
|
|
|
34
31
|
/**
|
|
35
32
|
* Gets full commit metadata for a node.
|
|
36
|
-
* @param {string}
|
|
33
|
+
* @param {string} _sha - The commit SHA to retrieve
|
|
37
34
|
* @returns {Promise<{sha: string, message: string, author: string, date: string, parents: string[]}>}
|
|
38
35
|
* Full commit metadata including SHA, message, author, date, and parent SHAs
|
|
39
36
|
* @throws {Error} If not implemented by a concrete adapter
|
|
@@ -44,10 +41,7 @@ export default class CommitPort {
|
|
|
44
41
|
|
|
45
42
|
/**
|
|
46
43
|
* Returns raw git log output for a ref.
|
|
47
|
-
* @param {
|
|
48
|
-
* @param {string} options.ref - The Git ref to log from
|
|
49
|
-
* @param {number} [options.limit=50] - Maximum number of commits to return
|
|
50
|
-
* @param {string} [options.format] - Custom format string for git log
|
|
44
|
+
* @param {{ ref: string, limit?: number, format?: string }} _options
|
|
51
45
|
* @returns {Promise<string>} The raw log output
|
|
52
46
|
* @throws {Error} If not implemented by a concrete adapter
|
|
53
47
|
*/
|
|
@@ -57,10 +51,7 @@ export default class CommitPort {
|
|
|
57
51
|
|
|
58
52
|
/**
|
|
59
53
|
* Streams git log output for a ref.
|
|
60
|
-
* @param {
|
|
61
|
-
* @param {string} options.ref - The Git ref to log from
|
|
62
|
-
* @param {number} [options.limit=1000000] - Maximum number of commits to return
|
|
63
|
-
* @param {string} [options.format] - Custom format string for git log
|
|
54
|
+
* @param {{ ref: string, limit?: number, format?: string }} _options
|
|
64
55
|
* @returns {Promise<import('node:stream').Readable>} A readable stream of log output
|
|
65
56
|
* @throws {Error} If not implemented by a concrete adapter
|
|
66
57
|
*/
|
|
@@ -70,7 +61,7 @@ export default class CommitPort {
|
|
|
70
61
|
|
|
71
62
|
/**
|
|
72
63
|
* Counts nodes reachable from a ref without loading them into memory.
|
|
73
|
-
* @param {string}
|
|
64
|
+
* @param {string} _ref - Git ref to count from (e.g., 'HEAD', 'main', or a SHA)
|
|
74
65
|
* @returns {Promise<number>} The count of reachable nodes
|
|
75
66
|
* @throws {Error} If not implemented by a concrete adapter
|
|
76
67
|
*/
|
|
@@ -81,11 +72,7 @@ export default class CommitPort {
|
|
|
81
72
|
/**
|
|
82
73
|
* Creates a commit pointing to a specified tree (not the empty tree).
|
|
83
74
|
* Used by CheckpointService and PatchBuilderV2 for tree-backed commits.
|
|
84
|
-
* @param {
|
|
85
|
-
* @param {string} options.treeOid - The tree OID to commit
|
|
86
|
-
* @param {string[]} [options.parents=[]] - Parent commit SHAs
|
|
87
|
-
* @param {string} options.message - The commit message
|
|
88
|
-
* @param {boolean} [options.sign=false] - Whether to GPG-sign the commit
|
|
75
|
+
* @param {{ treeOid: string, parents?: string[], message: string, sign?: boolean }} _options
|
|
89
76
|
* @returns {Promise<string>} The SHA of the created commit
|
|
90
77
|
* @throws {Error} If not implemented by a concrete adapter
|
|
91
78
|
*/
|
|
@@ -95,7 +82,7 @@ export default class CommitPort {
|
|
|
95
82
|
|
|
96
83
|
/**
|
|
97
84
|
* Checks whether a commit exists in the repository.
|
|
98
|
-
* @param {string}
|
|
85
|
+
* @param {string} _sha - The commit SHA to check
|
|
99
86
|
* @returns {Promise<boolean>} True if the commit exists
|
|
100
87
|
* @throws {Error} If not implemented by a concrete adapter
|
|
101
88
|
*/
|
package/src/ports/ConfigPort.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
export default class ConfigPort {
|
|
11
11
|
/**
|
|
12
12
|
* Reads a git config value.
|
|
13
|
-
* @param {string}
|
|
13
|
+
* @param {string} _key - The config key to read (e.g., 'warp.writerId.events')
|
|
14
14
|
* @returns {Promise<string|null>} The config value, or null if not set
|
|
15
15
|
* @throws {Error} If not implemented by a concrete adapter
|
|
16
16
|
*/
|
|
@@ -20,8 +20,8 @@ export default class ConfigPort {
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Sets a git config value.
|
|
23
|
-
* @param {string}
|
|
24
|
-
* @param {string}
|
|
23
|
+
* @param {string} _key - The config key to set (e.g., 'warp.writerId.events')
|
|
24
|
+
* @param {string} _value - The value to set
|
|
25
25
|
* @returns {Promise<void>}
|
|
26
26
|
* @throws {Error} If not implemented by a concrete adapter
|
|
27
27
|
*/
|
package/src/ports/CryptoPort.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
export default class CryptoPort {
|
|
8
8
|
/**
|
|
9
9
|
* Computes a hash digest of the given data.
|
|
10
|
-
* @param {string}
|
|
11
|
-
* @param {string|Buffer|Uint8Array}
|
|
10
|
+
* @param {string} _algorithm - Hash algorithm (e.g. 'sha1', 'sha256')
|
|
11
|
+
* @param {string|Buffer|Uint8Array} _data - Data to hash
|
|
12
12
|
* @returns {Promise<string>} Hex-encoded digest
|
|
13
13
|
*/
|
|
14
14
|
async hash(_algorithm, _data) {
|
|
@@ -17,9 +17,9 @@ export default class CryptoPort {
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Computes an HMAC of the given data.
|
|
20
|
-
* @param {string}
|
|
21
|
-
* @param {string|Buffer|Uint8Array}
|
|
22
|
-
* @param {string|Buffer|Uint8Array}
|
|
20
|
+
* @param {string} _algorithm - Hash algorithm (e.g. 'sha256')
|
|
21
|
+
* @param {string|Buffer|Uint8Array} _key - HMAC key
|
|
22
|
+
* @param {string|Buffer|Uint8Array} _data - Data to authenticate
|
|
23
23
|
* @returns {Promise<Buffer|Uint8Array>} Raw HMAC digest
|
|
24
24
|
*/
|
|
25
25
|
async hmac(_algorithm, _key, _data) {
|
|
@@ -28,8 +28,8 @@ export default class CryptoPort {
|
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Constant-time comparison of two buffers.
|
|
31
|
-
* @param {Buffer|Uint8Array}
|
|
32
|
-
* @param {Buffer|Uint8Array}
|
|
31
|
+
* @param {Buffer|Uint8Array} _a - First buffer
|
|
32
|
+
* @param {Buffer|Uint8Array} _b - Second buffer
|
|
33
33
|
* @returns {boolean} True if buffers are equal
|
|
34
34
|
*/
|
|
35
35
|
timingSafeEqual(_a, _b) {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import CommitPort from './CommitPort.js';
|
|
2
|
+
import BlobPort from './BlobPort.js';
|
|
3
|
+
import TreePort from './TreePort.js';
|
|
4
|
+
import RefPort from './RefPort.js';
|
|
5
|
+
import ConfigPort from './ConfigPort.js';
|
|
6
|
+
|
|
1
7
|
/**
|
|
2
8
|
* Abstract port for graph persistence operations.
|
|
3
9
|
*
|
|
@@ -20,27 +26,19 @@
|
|
|
20
26
|
* All methods throw by default and must be overridden by implementations.
|
|
21
27
|
*
|
|
22
28
|
* @abstract
|
|
23
|
-
* @implements {CommitPort}
|
|
24
|
-
* @implements {BlobPort}
|
|
25
|
-
* @implements {TreePort}
|
|
26
|
-
* @implements {RefPort}
|
|
27
|
-
* @implements {ConfigPort}
|
|
28
29
|
*/
|
|
29
|
-
|
|
30
|
-
import CommitPort from './CommitPort.js';
|
|
31
|
-
import BlobPort from './BlobPort.js';
|
|
32
|
-
import TreePort from './TreePort.js';
|
|
33
|
-
import RefPort from './RefPort.js';
|
|
34
|
-
import ConfigPort from './ConfigPort.js';
|
|
35
|
-
|
|
36
30
|
class GraphPersistencePort {}
|
|
37
31
|
|
|
32
|
+
/** @type {Array<typeof CommitPort | typeof BlobPort | typeof TreePort | typeof RefPort | typeof ConfigPort>} */
|
|
38
33
|
const focusedPorts = [CommitPort, BlobPort, TreePort, RefPort, ConfigPort];
|
|
39
34
|
const seen = new Map();
|
|
40
35
|
|
|
41
36
|
for (const Port of focusedPorts) {
|
|
42
|
-
const
|
|
43
|
-
|
|
37
|
+
const allDescriptors = Object.getOwnPropertyDescriptors(Port.prototype);
|
|
38
|
+
/** @type {Record<string, PropertyDescriptor>} */
|
|
39
|
+
const descriptors = Object.fromEntries(
|
|
40
|
+
Object.entries(allDescriptors).filter(([k]) => k !== 'constructor'),
|
|
41
|
+
);
|
|
44
42
|
|
|
45
43
|
for (const [name, descriptor] of Object.entries(descriptors)) {
|
|
46
44
|
if (seen.has(name)) {
|
|
@@ -12,11 +12,7 @@ export default class HttpServerPort {
|
|
|
12
12
|
* and must return `{ status, headers, body }`. No raw req/res objects
|
|
13
13
|
* are exposed to the domain.
|
|
14
14
|
*
|
|
15
|
-
* @param {
|
|
16
|
-
* @param {string} requestHandler.method - HTTP method
|
|
17
|
-
* @param {string} requestHandler.url - Request URL
|
|
18
|
-
* @param {Object} requestHandler.headers - Request headers (lowercased keys)
|
|
19
|
-
* @param {Buffer|undefined} requestHandler.body - Request body (undefined if none)
|
|
15
|
+
* @param {(request: { method: string, url: string, headers: Object, body: Buffer|undefined }) => Promise<{ status: number, headers: Object, body: string|Buffer }>} _requestHandler - Async function (request) => response
|
|
20
16
|
* @returns {{ listen: Function, close: Function, address: Function }} Server with listen(port, [host], cb(err)), close(cb), and address()
|
|
21
17
|
*/
|
|
22
18
|
createServer(_requestHandler) {
|
package/src/ports/LoggerPort.js
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
export default class LoggerPort {
|
|
14
14
|
/**
|
|
15
15
|
* Log a debug-level message.
|
|
16
|
-
* @param {string}
|
|
17
|
-
* @param {Record<string, unknown>} [
|
|
16
|
+
* @param {string} _message - The log message
|
|
17
|
+
* @param {Record<string, unknown>} [_context] - Structured metadata
|
|
18
18
|
* @returns {void}
|
|
19
19
|
* @abstract
|
|
20
20
|
*/
|
|
@@ -24,8 +24,8 @@ export default class LoggerPort {
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Log an info-level message.
|
|
27
|
-
* @param {string}
|
|
28
|
-
* @param {Record<string, unknown>} [
|
|
27
|
+
* @param {string} _message - The log message
|
|
28
|
+
* @param {Record<string, unknown>} [_context] - Structured metadata
|
|
29
29
|
* @returns {void}
|
|
30
30
|
* @abstract
|
|
31
31
|
*/
|
|
@@ -35,8 +35,8 @@ export default class LoggerPort {
|
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Log a warning-level message.
|
|
38
|
-
* @param {string}
|
|
39
|
-
* @param {Record<string, unknown>} [
|
|
38
|
+
* @param {string} _message - The log message
|
|
39
|
+
* @param {Record<string, unknown>} [_context] - Structured metadata
|
|
40
40
|
* @returns {void}
|
|
41
41
|
* @abstract
|
|
42
42
|
*/
|
|
@@ -46,8 +46,8 @@ export default class LoggerPort {
|
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Log an error-level message.
|
|
49
|
-
* @param {string}
|
|
50
|
-
* @param {Record<string, unknown>} [
|
|
49
|
+
* @param {string} _message - The log message
|
|
50
|
+
* @param {Record<string, unknown>} [_context] - Structured metadata
|
|
51
51
|
* @returns {void}
|
|
52
52
|
* @abstract
|
|
53
53
|
*/
|
|
@@ -58,7 +58,7 @@ export default class LoggerPort {
|
|
|
58
58
|
/**
|
|
59
59
|
* Create a child logger with additional base context.
|
|
60
60
|
* Child loggers inherit parent context and merge with their own.
|
|
61
|
-
* @param {Record<string, unknown>}
|
|
61
|
+
* @param {Record<string, unknown>} _context - Base context for the child logger
|
|
62
62
|
* @returns {LoggerPort} A new logger instance with merged context
|
|
63
63
|
* @abstract
|
|
64
64
|
*/
|
package/src/ports/RefPort.js
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
export default class RefPort {
|
|
11
11
|
/**
|
|
12
12
|
* Updates a ref to point to an OID.
|
|
13
|
-
* @param {string}
|
|
14
|
-
* @param {string}
|
|
13
|
+
* @param {string} _ref - The ref name (e.g., 'refs/warp/events/writers/alice')
|
|
14
|
+
* @param {string} _oid - The OID to point to
|
|
15
15
|
* @returns {Promise<void>}
|
|
16
16
|
* @throws {Error} If not implemented by a concrete adapter
|
|
17
17
|
*/
|
|
@@ -21,7 +21,7 @@ export default class RefPort {
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Reads the OID a ref points to.
|
|
24
|
-
* @param {string}
|
|
24
|
+
* @param {string} _ref - The ref name
|
|
25
25
|
* @returns {Promise<string|null>} The OID, or null if the ref does not exist
|
|
26
26
|
* @throws {Error} If not implemented by a concrete adapter
|
|
27
27
|
*/
|
|
@@ -31,7 +31,7 @@ export default class RefPort {
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Deletes a ref.
|
|
34
|
-
* @param {string}
|
|
34
|
+
* @param {string} _ref - The ref name to delete
|
|
35
35
|
* @returns {Promise<void>}
|
|
36
36
|
* @throws {Error} If not implemented by a concrete adapter
|
|
37
37
|
*/
|
|
@@ -41,7 +41,7 @@ export default class RefPort {
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Lists refs matching a prefix.
|
|
44
|
-
* @param {string}
|
|
44
|
+
* @param {string} _prefix - The ref prefix to match (e.g., 'refs/warp/events/writers/')
|
|
45
45
|
* @returns {Promise<string[]>} Array of matching ref names
|
|
46
46
|
* @throws {Error} If not implemented by a concrete adapter
|
|
47
47
|
*/
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Port interface for seek materialization cache operations.
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for caching and retrieving serialized WarpStateV5
|
|
5
|
+
* snapshots keyed by (ceiling, frontier) tuples. Used by the seek time-travel
|
|
6
|
+
* feature to avoid full re-materialization for previously-visited ticks.
|
|
7
|
+
*
|
|
8
|
+
* Concrete adapters (e.g., CasSeekCacheAdapter) implement this interface
|
|
9
|
+
* to store cached states in different backends (git-cas, filesystem, etc.).
|
|
10
|
+
*
|
|
11
|
+
* @abstract
|
|
12
|
+
*/
|
|
13
|
+
export default class SeekCachePort {
|
|
14
|
+
/**
|
|
15
|
+
* Retrieves a cached state buffer by key.
|
|
16
|
+
* @param {string} _key - Cache key (e.g., 'v1:t42-<frontierHash>')
|
|
17
|
+
* @returns {Promise<Buffer|null>} The cached buffer, or null on miss
|
|
18
|
+
* @throws {Error} If not implemented by a concrete adapter
|
|
19
|
+
*/
|
|
20
|
+
async get(_key) {
|
|
21
|
+
throw new Error('SeekCachePort.get() not implemented');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Stores a state buffer under the given key.
|
|
26
|
+
* @param {string} _key - Cache key
|
|
27
|
+
* @param {Buffer} _buffer - Serialized state to cache
|
|
28
|
+
* @returns {Promise<void>}
|
|
29
|
+
* @throws {Error} If not implemented by a concrete adapter
|
|
30
|
+
*/
|
|
31
|
+
async set(_key, _buffer) {
|
|
32
|
+
throw new Error('SeekCachePort.set() not implemented');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Checks whether a key exists in the cache.
|
|
37
|
+
* @param {string} _key - Cache key
|
|
38
|
+
* @returns {Promise<boolean>}
|
|
39
|
+
* @throws {Error} If not implemented by a concrete adapter
|
|
40
|
+
*/
|
|
41
|
+
async has(_key) {
|
|
42
|
+
throw new Error('SeekCachePort.has() not implemented');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Lists all keys currently in the cache index.
|
|
47
|
+
* Note: keys may reference GC'd blobs; callers should handle miss on get().
|
|
48
|
+
* @returns {Promise<string[]>}
|
|
49
|
+
* @throws {Error} If not implemented by a concrete adapter
|
|
50
|
+
*/
|
|
51
|
+
async keys() {
|
|
52
|
+
throw new Error('SeekCachePort.keys() not implemented');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Removes a single entry from the cache.
|
|
57
|
+
* @param {string} _key - Cache key to remove
|
|
58
|
+
* @returns {Promise<boolean>} True if the entry existed and was removed
|
|
59
|
+
* @throws {Error} If not implemented by a concrete adapter
|
|
60
|
+
*/
|
|
61
|
+
async delete(_key) {
|
|
62
|
+
throw new Error('SeekCachePort.delete() not implemented');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Removes all entries from the cache.
|
|
67
|
+
* @returns {Promise<void>}
|
|
68
|
+
* @throws {Error} If not implemented by a concrete adapter
|
|
69
|
+
*/
|
|
70
|
+
async clear() {
|
|
71
|
+
throw new Error('SeekCachePort.clear() not implemented');
|
|
72
|
+
}
|
|
73
|
+
}
|
package/src/ports/TreePort.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
export default class TreePort {
|
|
11
11
|
/**
|
|
12
12
|
* Creates a Git tree from mktree-formatted entries.
|
|
13
|
-
* @param {string[]}
|
|
13
|
+
* @param {string[]} _entries - Lines in git mktree format (e.g., "100644 blob <oid>\t<path>")
|
|
14
14
|
* @returns {Promise<string>} The Git OID of the created tree
|
|
15
15
|
* @throws {Error} If not implemented by a concrete adapter
|
|
16
16
|
*/
|
|
@@ -20,7 +20,7 @@ export default class TreePort {
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Reads a tree and returns a map of path to content.
|
|
23
|
-
* @param {string}
|
|
23
|
+
* @param {string} _treeOid - The tree OID to read
|
|
24
24
|
* @returns {Promise<Record<string, Buffer>>} Map of file path to blob content
|
|
25
25
|
* @throws {Error} If not implemented by a concrete adapter
|
|
26
26
|
*/
|
|
@@ -31,7 +31,7 @@ export default class TreePort {
|
|
|
31
31
|
/**
|
|
32
32
|
* Reads a tree and returns a map of path to blob OID.
|
|
33
33
|
* Useful for lazy-loading shards without reading all blob contents.
|
|
34
|
-
* @param {string}
|
|
34
|
+
* @param {string} _treeOid - The tree OID to read
|
|
35
35
|
* @returns {Promise<Record<string, string>>} Map of file path to blob OID
|
|
36
36
|
* @throws {Error} If not implemented by a concrete adapter
|
|
37
37
|
*/
|
|
@@ -6,13 +6,19 @@
|
|
|
6
6
|
* { nodes: [{ id, label, props? }], edges: [{ from, to, label? }] }
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {{ id: string, label: string, props?: Record<string, any> }} GraphDataNode
|
|
11
|
+
* @typedef {{ from: string, to: string, label?: string }} GraphDataEdge
|
|
12
|
+
* @typedef {{ nodes: GraphDataNode[], edges: GraphDataEdge[] }} GraphData
|
|
13
|
+
*/
|
|
14
|
+
|
|
9
15
|
/**
|
|
10
16
|
* Converts a query result payload + edge array into graph data.
|
|
11
17
|
* Edges are filtered to only those connecting matched nodes.
|
|
12
18
|
*
|
|
13
|
-
* @param {
|
|
14
|
-
* @param {Array} edges - Edge array from graph.getEdges()
|
|
15
|
-
* @returns {
|
|
19
|
+
* @param {{ nodes?: Array<{ id: string, props?: Record<string, any> }> } | null} payload - Query result
|
|
20
|
+
* @param {Array<{ from: string, to: string, label?: string }>} edges - Edge array from graph.getEdges()
|
|
21
|
+
* @returns {GraphData}
|
|
16
22
|
*/
|
|
17
23
|
export function queryResultToGraphData(payload, edges) {
|
|
18
24
|
const nodes = (payload?.nodes ?? []).map((n) => ({
|
|
@@ -34,8 +40,8 @@ export function queryResultToGraphData(payload, edges) {
|
|
|
34
40
|
* Converts a path result payload into graph data.
|
|
35
41
|
* Builds a linear chain of nodes with labelled edges.
|
|
36
42
|
*
|
|
37
|
-
* @param {
|
|
38
|
-
* @returns {
|
|
43
|
+
* @param {{ path?: string[], edges?: string[] } | null} payload - Path result
|
|
44
|
+
* @returns {GraphData}
|
|
39
45
|
*/
|
|
40
46
|
export function pathResultToGraphData(payload) {
|
|
41
47
|
const pathArr = payload?.path ?? [];
|
|
@@ -43,6 +49,7 @@ export function pathResultToGraphData(payload) {
|
|
|
43
49
|
|
|
44
50
|
const nodes = pathArr.map((id) => ({ id, label: id }));
|
|
45
51
|
|
|
52
|
+
/** @type {GraphDataEdge[]} */
|
|
46
53
|
const edges = [];
|
|
47
54
|
for (let i = 0; i < pathArr.length - 1; i++) {
|
|
48
55
|
edges.push({
|
|
@@ -59,8 +66,8 @@ export function pathResultToGraphData(payload) {
|
|
|
59
66
|
* Converts raw getNodes() + getEdges() output into graph data.
|
|
60
67
|
*
|
|
61
68
|
* @param {string[]} nodeIds - Array of node IDs
|
|
62
|
-
* @param {Array} edges - Edge array from graph.getEdges()
|
|
63
|
-
* @returns {
|
|
69
|
+
* @param {Array<{ from: string, to: string, label?: string }>} edges - Edge array from graph.getEdges()
|
|
70
|
+
* @returns {GraphData}
|
|
64
71
|
*/
|
|
65
72
|
export function rawGraphToGraphData(nodeIds, edges) {
|
|
66
73
|
const nodes = (nodeIds ?? []).map((id) => ({ id, label: id }));
|