@git-stunts/git-warp 10.8.0 → 11.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -32
- package/SECURITY.md +64 -0
- package/bin/cli/commands/check.js +168 -0
- package/bin/cli/commands/doctor/checks.js +422 -0
- package/bin/cli/commands/doctor/codes.js +46 -0
- package/bin/cli/commands/doctor/index.js +239 -0
- package/bin/cli/commands/doctor/types.js +89 -0
- package/bin/cli/commands/history.js +80 -0
- package/bin/cli/commands/info.js +139 -0
- package/bin/cli/commands/install-hooks.js +128 -0
- package/bin/cli/commands/materialize.js +99 -0
- package/bin/cli/commands/patch.js +142 -0
- package/bin/cli/commands/path.js +88 -0
- package/bin/cli/commands/query.js +235 -0
- package/bin/cli/commands/registry.js +32 -0
- package/bin/cli/commands/seek.js +598 -0
- package/bin/cli/commands/tree.js +230 -0
- package/bin/cli/commands/trust.js +154 -0
- package/bin/cli/commands/verify-audit.js +114 -0
- package/bin/cli/commands/view.js +46 -0
- package/bin/cli/infrastructure.js +350 -0
- package/bin/cli/schemas.js +177 -0
- package/bin/cli/shared.js +244 -0
- package/bin/cli/types.js +96 -0
- package/bin/presenters/index.js +41 -9
- package/bin/presenters/json.js +14 -12
- package/bin/presenters/text.js +286 -28
- package/bin/warp-graph.js +5 -2346
- package/index.d.ts +111 -21
- package/index.js +2 -0
- package/package.json +10 -8
- package/src/domain/WarpGraph.js +109 -3252
- package/src/domain/crdt/ORSet.js +8 -8
- package/src/domain/errors/EmptyMessageError.js +2 -2
- 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/QueryError.js +3 -3
- package/src/domain/errors/SchemaUnsupportedError.js +1 -1
- package/src/domain/errors/ShardCorruptionError.js +2 -2
- package/src/domain/errors/ShardLoadError.js +2 -2
- package/src/domain/errors/ShardValidationError.js +4 -4
- package/src/domain/errors/StorageError.js +2 -2
- package/src/domain/errors/SyncError.js +1 -1
- package/src/domain/errors/TraversalError.js +1 -1
- package/src/domain/errors/TrustError.js +29 -0
- package/src/domain/errors/WarpError.js +2 -2
- package/src/domain/errors/WormholeError.js +1 -1
- package/src/domain/errors/index.js +1 -0
- package/src/domain/services/AuditMessageCodec.js +137 -0
- package/src/domain/services/AuditReceiptService.js +471 -0
- package/src/domain/services/AuditVerifierService.js +707 -0
- package/src/domain/services/BitmapIndexBuilder.js +3 -3
- package/src/domain/services/BitmapIndexReader.js +28 -19
- package/src/domain/services/BoundaryTransitionRecord.js +18 -17
- package/src/domain/services/CheckpointSerializerV5.js +17 -16
- package/src/domain/services/CheckpointService.js +2 -2
- package/src/domain/services/CommitDagTraversalService.js +13 -13
- package/src/domain/services/DagPathFinding.js +7 -7
- package/src/domain/services/DagTopology.js +1 -1
- package/src/domain/services/DagTraversal.js +1 -1
- package/src/domain/services/HealthCheckService.js +1 -1
- package/src/domain/services/HookInstaller.js +1 -1
- package/src/domain/services/HttpSyncServer.js +120 -55
- package/src/domain/services/IndexRebuildService.js +7 -7
- package/src/domain/services/IndexStalenessChecker.js +4 -3
- package/src/domain/services/JoinReducer.js +11 -11
- package/src/domain/services/LogicalTraversal.js +1 -1
- package/src/domain/services/MessageCodecInternal.js +4 -1
- package/src/domain/services/MessageSchemaDetector.js +2 -2
- package/src/domain/services/MigrationService.js +1 -1
- package/src/domain/services/ObserverView.js +8 -8
- package/src/domain/services/PatchBuilderV2.js +42 -26
- package/src/domain/services/ProvenanceIndex.js +1 -1
- package/src/domain/services/ProvenancePayload.js +1 -1
- package/src/domain/services/QueryBuilder.js +3 -3
- package/src/domain/services/StateDiff.js +14 -11
- package/src/domain/services/StateSerializerV5.js +2 -2
- package/src/domain/services/StreamingBitmapIndexBuilder.js +26 -24
- package/src/domain/services/SyncAuthService.js +71 -4
- package/src/domain/services/SyncProtocol.js +25 -11
- package/src/domain/services/TemporalQuery.js +9 -6
- package/src/domain/services/TranslationCost.js +7 -5
- package/src/domain/services/WarpMessageCodec.js +4 -1
- package/src/domain/services/WormholeService.js +16 -7
- package/src/domain/trust/TrustCanonical.js +42 -0
- package/src/domain/trust/TrustCrypto.js +111 -0
- package/src/domain/trust/TrustEvaluator.js +195 -0
- package/src/domain/trust/TrustRecordService.js +281 -0
- package/src/domain/trust/TrustStateBuilder.js +222 -0
- package/src/domain/trust/canonical.js +68 -0
- package/src/domain/trust/reasonCodes.js +64 -0
- package/src/domain/trust/schemas.js +160 -0
- package/src/domain/trust/verdict.js +42 -0
- package/src/domain/types/TickReceipt.js +1 -1
- package/src/domain/types/WarpErrors.js +45 -0
- package/src/domain/types/WarpOptions.js +29 -0
- package/src/domain/types/WarpPersistence.js +41 -0
- package/src/domain/types/WarpTypes.js +2 -2
- package/src/domain/types/WarpTypesV2.js +2 -2
- package/src/domain/types/git-cas.d.ts +20 -0
- package/src/domain/utils/MinHeap.js +6 -5
- package/src/domain/utils/RefLayout.js +59 -0
- package/src/domain/utils/canonicalStringify.js +5 -4
- package/src/domain/utils/roaring.js +31 -5
- package/src/domain/warp/PatchSession.js +26 -17
- package/src/domain/warp/Writer.js +18 -3
- package/src/domain/warp/_internal.js +26 -0
- package/src/domain/warp/_wire.js +58 -0
- package/src/domain/warp/_wiredMethods.d.ts +254 -0
- package/src/domain/warp/checkpoint.methods.js +401 -0
- package/src/domain/warp/fork.methods.js +323 -0
- package/src/domain/warp/materialize.methods.js +238 -0
- package/src/domain/warp/materializeAdvanced.methods.js +350 -0
- package/src/domain/warp/patch.methods.js +554 -0
- package/src/domain/warp/provenance.methods.js +286 -0
- package/src/domain/warp/query.methods.js +280 -0
- package/src/domain/warp/subscribe.methods.js +272 -0
- package/src/domain/warp/sync.methods.js +554 -0
- package/src/globals.d.ts +64 -0
- package/src/infrastructure/adapters/BunHttpAdapter.js +14 -9
- package/src/infrastructure/adapters/CasSeekCacheAdapter.js +9 -4
- package/src/infrastructure/adapters/DenoHttpAdapter.js +5 -6
- package/src/infrastructure/adapters/GitGraphAdapter.js +79 -11
- package/src/infrastructure/adapters/InMemoryGraphAdapter.js +36 -0
- package/src/infrastructure/adapters/NodeHttpAdapter.js +2 -2
- package/src/infrastructure/adapters/WebCryptoAdapter.js +2 -2
- package/src/ports/CommitPort.js +10 -0
- package/src/ports/RefPort.js +17 -0
- package/src/visualization/layouts/converters.js +2 -2
- package/src/visualization/layouts/elkAdapter.js +1 -1
- package/src/visualization/layouts/elkLayout.js +10 -7
- package/src/visualization/layouts/index.js +1 -1
- package/src/visualization/renderers/ascii/seek.js +16 -6
- package/src/visualization/renderers/svg/index.js +1 -1
- package/src/hooks/post-merge.sh +0 -60
package/src/domain/crdt/ORSet.js
CHANGED
|
@@ -91,7 +91,7 @@ import { vvContains } from './VersionVector.js';
|
|
|
91
91
|
* An element is present if it has at least one non-tombstoned dot.
|
|
92
92
|
*
|
|
93
93
|
* @typedef {Object} ORSet
|
|
94
|
-
* @property {Map
|
|
94
|
+
* @property {Map<string, Set<string>>} entries - element -> dots that added it
|
|
95
95
|
* @property {Set<string>} tombstones - global tombstones
|
|
96
96
|
*/
|
|
97
97
|
|
|
@@ -112,7 +112,7 @@ export function createORSet() {
|
|
|
112
112
|
* Mutates the set.
|
|
113
113
|
*
|
|
114
114
|
* @param {ORSet} set - The ORSet to mutate
|
|
115
|
-
* @param {
|
|
115
|
+
* @param {string} element - The element to add
|
|
116
116
|
* @param {import('./Dot.js').Dot} dot - The dot representing this add operation
|
|
117
117
|
*/
|
|
118
118
|
export function orsetAdd(set, element, dot) {
|
|
@@ -145,7 +145,7 @@ export function orsetRemove(set, observedDots) {
|
|
|
145
145
|
* An element is present if it has at least one non-tombstoned dot.
|
|
146
146
|
*
|
|
147
147
|
* @param {ORSet} set - The ORSet to check
|
|
148
|
-
* @param {
|
|
148
|
+
* @param {string} element - The element to check
|
|
149
149
|
* @returns {boolean}
|
|
150
150
|
*/
|
|
151
151
|
export function orsetContains(set, element) {
|
|
@@ -168,7 +168,7 @@ export function orsetContains(set, element) {
|
|
|
168
168
|
* Only returns elements that have at least one non-tombstoned dot.
|
|
169
169
|
*
|
|
170
170
|
* @param {ORSet} set - The ORSet
|
|
171
|
-
* @returns {
|
|
171
|
+
* @returns {string[]} Array of present elements
|
|
172
172
|
*/
|
|
173
173
|
export function orsetElements(set) {
|
|
174
174
|
const result = [];
|
|
@@ -186,7 +186,7 @@ export function orsetElements(set) {
|
|
|
186
186
|
* Returns the non-tombstoned dots for an element.
|
|
187
187
|
*
|
|
188
188
|
* @param {ORSet} set - The ORSet
|
|
189
|
-
* @param {
|
|
189
|
+
* @param {string} element - The element
|
|
190
190
|
* @returns {Set<string>} Set of encoded dots that are not tombstoned
|
|
191
191
|
*/
|
|
192
192
|
export function orsetGetDots(set, element) {
|
|
@@ -311,11 +311,11 @@ export function orsetCompact(set, includedVV) {
|
|
|
311
311
|
* Tombstones are sorted.
|
|
312
312
|
*
|
|
313
313
|
* @param {ORSet} set
|
|
314
|
-
* @returns {{entries: Array<[
|
|
314
|
+
* @returns {{entries: Array<[string, string[]]>, tombstones: string[]}}
|
|
315
315
|
*/
|
|
316
316
|
export function orsetSerialize(set) {
|
|
317
317
|
// Serialize entries: convert Map to array of [element, sortedDots]
|
|
318
|
-
/** @type {Array<[
|
|
318
|
+
/** @type {Array<[string, string[]]>} */
|
|
319
319
|
const entriesArray = [];
|
|
320
320
|
for (const [element, dots] of set.entries) {
|
|
321
321
|
const sortedDots = [...dots].sort((a, b) => {
|
|
@@ -349,7 +349,7 @@ export function orsetSerialize(set) {
|
|
|
349
349
|
/**
|
|
350
350
|
* Deserializes a plain object back to an ORSet.
|
|
351
351
|
*
|
|
352
|
-
* @param {{entries?: Array<[
|
|
352
|
+
* @param {{entries?: Array<[string, string[]]>, tombstones?: string[]}} obj
|
|
353
353
|
* @returns {ORSet}
|
|
354
354
|
*/
|
|
355
355
|
export function orsetDeserialize(obj) {
|
|
@@ -12,7 +12,7 @@ import IndexError from './IndexError.js';
|
|
|
12
12
|
* @property {string} name - The error name ('EmptyMessageError')
|
|
13
13
|
* @property {string} code - Error code ('EMPTY_MESSAGE')
|
|
14
14
|
* @property {string} operation - The operation that failed due to empty message
|
|
15
|
-
* @property {Record<string,
|
|
15
|
+
* @property {Record<string, unknown>} context - Serializable context object for debugging
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
18
|
* if (!message || message.trim() === '') {
|
|
@@ -27,7 +27,7 @@ export default class EmptyMessageError extends IndexError {
|
|
|
27
27
|
* Creates a new EmptyMessageError.
|
|
28
28
|
*
|
|
29
29
|
* @param {string} message - Human-readable error message
|
|
30
|
-
* @param {{ operation?: string, context?: Record<string,
|
|
30
|
+
* @param {{ operation?: string, context?: Record<string, unknown> }} [options={}] - Error options
|
|
31
31
|
*/
|
|
32
32
|
constructor(message, options = {}) {
|
|
33
33
|
const context = {
|
|
@@ -26,7 +26,7 @@ import WarpError from './WarpError.js';
|
|
|
26
26
|
export default class ForkError extends WarpError {
|
|
27
27
|
/**
|
|
28
28
|
* @param {string} message
|
|
29
|
-
* @param {{ code?: string, context?:
|
|
29
|
+
* @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
|
|
30
30
|
*/
|
|
31
31
|
constructor(message, options = {}) {
|
|
32
32
|
super(message, 'FORK_ERROR', options);
|
|
@@ -19,7 +19,7 @@ import WarpError from './WarpError.js';
|
|
|
19
19
|
export default class IndexError extends WarpError {
|
|
20
20
|
/**
|
|
21
21
|
* @param {string} message
|
|
22
|
-
* @param {{ code?: string, context?:
|
|
22
|
+
* @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
|
|
23
23
|
*/
|
|
24
24
|
constructor(message, options = {}) {
|
|
25
25
|
super(message, 'INDEX_ERROR', options);
|
|
@@ -15,7 +15,7 @@ import WarpError from './WarpError.js';
|
|
|
15
15
|
export default class OperationAbortedError extends WarpError {
|
|
16
16
|
/**
|
|
17
17
|
* @param {string} operation
|
|
18
|
-
* @param {{ code?: string, context?:
|
|
18
|
+
* @param {{ code?: string, context?: Record<string, unknown>, reason?: string }} [options={}]
|
|
19
19
|
*/
|
|
20
20
|
constructor(operation, options = {}) {
|
|
21
21
|
const reason = options.reason || 'Operation was aborted';
|
|
@@ -11,8 +11,8 @@ import WarpError from './WarpError.js';
|
|
|
11
11
|
*
|
|
12
12
|
* | Code | Description |
|
|
13
13
|
* |------|-------------|
|
|
14
|
-
* | `E_NO_STATE` | No
|
|
15
|
-
* | `E_STALE_STATE` |
|
|
14
|
+
* | `E_NO_STATE` | No materialized state available; call `materialize()` or use `autoMaterialize: true` |
|
|
15
|
+
* | `E_STALE_STATE` | State is stale; call `materialize()` to refresh |
|
|
16
16
|
* | `E_QUERY_MATCH_TYPE` | Invalid type passed to `match()` (expected string) |
|
|
17
17
|
* | `E_QUERY_WHERE_TYPE` | Invalid type passed to `where()` (expected function or object) |
|
|
18
18
|
* | `E_QUERY_WHERE_VALUE` | Non-primitive value in where() object shorthand |
|
|
@@ -35,7 +35,7 @@ import WarpError from './WarpError.js';
|
|
|
35
35
|
export default class QueryError extends WarpError {
|
|
36
36
|
/**
|
|
37
37
|
* @param {string} message
|
|
38
|
-
* @param {{ code?: string, context?:
|
|
38
|
+
* @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
|
|
39
39
|
*/
|
|
40
40
|
constructor(message, options = {}) {
|
|
41
41
|
super(message, 'QUERY_ERROR', options);
|
|
@@ -13,7 +13,7 @@ import WarpError from './WarpError.js';
|
|
|
13
13
|
export default class SchemaUnsupportedError extends WarpError {
|
|
14
14
|
/**
|
|
15
15
|
* @param {string} message
|
|
16
|
-
* @param {{ code?: string, context?:
|
|
16
|
+
* @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
|
|
17
17
|
*/
|
|
18
18
|
constructor(message, options = {}) {
|
|
19
19
|
super(message, 'E_SCHEMA_UNSUPPORTED', options);
|
|
@@ -14,7 +14,7 @@ import IndexError from './IndexError.js';
|
|
|
14
14
|
* @property {string} shardPath - Path to the corrupted shard file
|
|
15
15
|
* @property {string} oid - Object ID associated with the shard
|
|
16
16
|
* @property {string} reason - Reason for corruption (e.g., 'invalid_checksum', 'invalid_version', 'parse_error')
|
|
17
|
-
* @property {Record<string,
|
|
17
|
+
* @property {Record<string, unknown>} context - Serializable context object for debugging
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* if (!validateChecksum(data)) {
|
|
@@ -30,7 +30,7 @@ export default class ShardCorruptionError extends IndexError {
|
|
|
30
30
|
* Creates a new ShardCorruptionError.
|
|
31
31
|
*
|
|
32
32
|
* @param {string} message - Human-readable error message
|
|
33
|
-
* @param {{ shardPath?: string, oid?: string, reason?: string, context?: Record<string,
|
|
33
|
+
* @param {{ shardPath?: string, oid?: string, reason?: string, context?: Record<string, unknown> }} [options={}] - Error options
|
|
34
34
|
*/
|
|
35
35
|
constructor(message, options = {}) {
|
|
36
36
|
const context = {
|
|
@@ -14,7 +14,7 @@ import IndexError from './IndexError.js';
|
|
|
14
14
|
* @property {string} shardPath - Path to the shard file that failed to load
|
|
15
15
|
* @property {string} oid - Object ID associated with the shard
|
|
16
16
|
* @property {Error} cause - The original error that caused the load failure
|
|
17
|
-
* @property {Record<string,
|
|
17
|
+
* @property {Record<string, unknown>} context - Serializable context object for debugging
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* try {
|
|
@@ -32,7 +32,7 @@ export default class ShardLoadError extends IndexError {
|
|
|
32
32
|
* Creates a new ShardLoadError.
|
|
33
33
|
*
|
|
34
34
|
* @param {string} message - Human-readable error message
|
|
35
|
-
* @param {{ shardPath?: string, oid?: string, cause?: Error, context?: Record<string,
|
|
35
|
+
* @param {{ shardPath?: string, oid?: string, cause?: Error, context?: Record<string, unknown> }} [options={}] - Error options
|
|
36
36
|
*/
|
|
37
37
|
constructor(message, options = {}) {
|
|
38
38
|
const context = {
|
|
@@ -12,10 +12,10 @@ import IndexError from './IndexError.js';
|
|
|
12
12
|
* @property {string} name - The error name ('ShardValidationError')
|
|
13
13
|
* @property {string} code - Error code ('SHARD_VALIDATION_ERROR')
|
|
14
14
|
* @property {string} shardPath - Path to the shard file that failed validation
|
|
15
|
-
* @property {
|
|
16
|
-
* @property {
|
|
15
|
+
* @property {unknown} expected - The expected value for the field
|
|
16
|
+
* @property {unknown} actual - The actual value found in the shard
|
|
17
17
|
* @property {string} field - The field that failed validation (e.g., 'checksum', 'version')
|
|
18
|
-
* @property {Record<string,
|
|
18
|
+
* @property {Record<string, unknown>} context - Serializable context object for debugging
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
21
|
* if (shard.version !== EXPECTED_VERSION) {
|
|
@@ -32,7 +32,7 @@ export default class ShardValidationError extends IndexError {
|
|
|
32
32
|
* Creates a new ShardValidationError.
|
|
33
33
|
*
|
|
34
34
|
* @param {string} message - Human-readable error message
|
|
35
|
-
* @param {{ shardPath?: string, expected?:
|
|
35
|
+
* @param {{ shardPath?: string, expected?: unknown, actual?: unknown, field?: string, context?: Record<string, unknown> }} [options={}] - Error options
|
|
36
36
|
*/
|
|
37
37
|
constructor(message, options = {}) {
|
|
38
38
|
const context = {
|
|
@@ -14,7 +14,7 @@ import IndexError from './IndexError.js';
|
|
|
14
14
|
* @property {string} operation - The operation that failed ('read' or 'write')
|
|
15
15
|
* @property {string} oid - Object ID associated with the operation
|
|
16
16
|
* @property {Error} cause - The original error that caused the failure
|
|
17
|
-
* @property {Record<string,
|
|
17
|
+
* @property {Record<string, unknown>} context - Serializable context object for debugging
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* try {
|
|
@@ -32,7 +32,7 @@ export default class StorageError extends IndexError {
|
|
|
32
32
|
* Creates a new StorageError.
|
|
33
33
|
*
|
|
34
34
|
* @param {string} message - Human-readable error message
|
|
35
|
-
* @param {{ operation?: string, oid?: string, cause?: Error, context?: Record<string,
|
|
35
|
+
* @param {{ operation?: string, oid?: string, cause?: Error, context?: Record<string, unknown> }} [options={}] - Error options
|
|
36
36
|
*/
|
|
37
37
|
constructor(message, options = {}) {
|
|
38
38
|
const context = {
|
|
@@ -26,7 +26,7 @@ import WarpError from './WarpError.js';
|
|
|
26
26
|
export default class SyncError extends WarpError {
|
|
27
27
|
/**
|
|
28
28
|
* @param {string} message
|
|
29
|
-
* @param {{ code?: string, context?:
|
|
29
|
+
* @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
|
|
30
30
|
*/
|
|
31
31
|
constructor(message, options = {}) {
|
|
32
32
|
super(message, 'SYNC_ERROR', options);
|
|
@@ -19,7 +19,7 @@ import WarpError from './WarpError.js';
|
|
|
19
19
|
export default class TraversalError extends WarpError {
|
|
20
20
|
/**
|
|
21
21
|
* @param {string} message
|
|
22
|
-
* @param {{ code?: string, context?:
|
|
22
|
+
* @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
|
|
23
23
|
*/
|
|
24
24
|
constructor(message, options = {}) {
|
|
25
25
|
super(message, 'TRAVERSAL_ERROR', options);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import WarpError from './WarpError.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error class for trust operations.
|
|
5
|
+
*
|
|
6
|
+
* ## Error Codes
|
|
7
|
+
*
|
|
8
|
+
* | Code | Description |
|
|
9
|
+
* |------|-------------|
|
|
10
|
+
* | `E_TRUST_UNSUPPORTED_ALGORITHM` | Algorithm is not `ed25519` |
|
|
11
|
+
* | `E_TRUST_INVALID_KEY` | Public key is malformed (wrong length or bad base64) |
|
|
12
|
+
* | `TRUST_ERROR` | Generic/default trust error |
|
|
13
|
+
*
|
|
14
|
+
* @class TrustError
|
|
15
|
+
* @extends WarpError
|
|
16
|
+
*
|
|
17
|
+
* @property {string} name - Always 'TrustError' for instanceof checks
|
|
18
|
+
* @property {string} code - Machine-readable error code for programmatic handling
|
|
19
|
+
* @property {Object} context - Serializable context object with error details
|
|
20
|
+
*/
|
|
21
|
+
export default class TrustError extends WarpError {
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} message
|
|
24
|
+
* @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
|
|
25
|
+
*/
|
|
26
|
+
constructor(message, options = {}) {
|
|
27
|
+
super(message, 'TRUST_ERROR', options);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @property {string} name - Error name (set from constructor.name)
|
|
12
12
|
* @property {string} code - Machine-readable error code
|
|
13
|
-
* @property {Record<string,
|
|
13
|
+
* @property {Record<string, unknown>} context - Serializable context for debugging
|
|
14
14
|
*/
|
|
15
15
|
export default class WarpError extends Error {
|
|
16
16
|
/**
|
|
17
17
|
* @param {string} message - Human-readable error message
|
|
18
18
|
* @param {string} defaultCode - Default error code if not overridden by options
|
|
19
|
-
* @param {{ code?: string, context?: Record<string,
|
|
19
|
+
* @param {{ code?: string, context?: Record<string, unknown> }} [options={}] - Error options
|
|
20
20
|
*/
|
|
21
21
|
constructor(message, defaultCode, options = {}) {
|
|
22
22
|
super(message);
|
|
@@ -24,7 +24,7 @@ import WarpError from './WarpError.js';
|
|
|
24
24
|
export default class WormholeError extends WarpError {
|
|
25
25
|
/**
|
|
26
26
|
* @param {string} message
|
|
27
|
-
* @param {{ code?: string, context?:
|
|
27
|
+
* @param {{ code?: string, context?: Record<string, unknown> }} [options={}]
|
|
28
28
|
*/
|
|
29
29
|
constructor(message, options = {}) {
|
|
30
30
|
super(message, 'WORMHOLE_ERROR', options);
|
|
@@ -17,5 +17,6 @@ export { default as ShardValidationError } from './ShardValidationError.js';
|
|
|
17
17
|
export { default as StorageError } from './StorageError.js';
|
|
18
18
|
export { default as SchemaUnsupportedError } from './SchemaUnsupportedError.js';
|
|
19
19
|
export { default as TraversalError } from './TraversalError.js';
|
|
20
|
+
export { default as TrustError } from './TrustError.js';
|
|
20
21
|
export { default as WriterError } from './WriterError.js';
|
|
21
22
|
export { default as WormholeError } from './WormholeError.js';
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit message encoding and decoding for WARP audit commit messages.
|
|
3
|
+
*
|
|
4
|
+
* Handles the 'audit' message type which records the outcome of materializing
|
|
5
|
+
* a data commit. See {@link module:domain/services/WarpMessageCodec} for the
|
|
6
|
+
* facade that re-exports all codec functions.
|
|
7
|
+
*
|
|
8
|
+
* @module domain/services/AuditMessageCodec
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { validateGraphName, validateWriterId } from '../utils/RefLayout.js';
|
|
12
|
+
import {
|
|
13
|
+
getCodec,
|
|
14
|
+
MESSAGE_TITLES,
|
|
15
|
+
TRAILER_KEYS,
|
|
16
|
+
validateOid,
|
|
17
|
+
validateSha256,
|
|
18
|
+
} from './MessageCodecInternal.js';
|
|
19
|
+
|
|
20
|
+
// -----------------------------------------------------------------------------
|
|
21
|
+
// Encoder
|
|
22
|
+
// -----------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Encodes an audit commit message with trailers.
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} options
|
|
28
|
+
* @param {string} options.graph - The graph name
|
|
29
|
+
* @param {string} options.writer - The writer ID
|
|
30
|
+
* @param {string} options.dataCommit - The OID of the data commit being audited
|
|
31
|
+
* @param {string} options.opsDigest - SHA-256 hex digest of the canonical ops JSON
|
|
32
|
+
* @returns {string} The encoded commit message
|
|
33
|
+
* @throws {Error} If any validation fails
|
|
34
|
+
*/
|
|
35
|
+
export function encodeAuditMessage({ graph, writer, dataCommit, opsDigest }) {
|
|
36
|
+
validateGraphName(graph);
|
|
37
|
+
validateWriterId(writer);
|
|
38
|
+
validateOid(dataCommit, 'dataCommit');
|
|
39
|
+
validateSha256(opsDigest, 'opsDigest');
|
|
40
|
+
|
|
41
|
+
const codec = getCodec();
|
|
42
|
+
return codec.encode({
|
|
43
|
+
title: MESSAGE_TITLES.audit,
|
|
44
|
+
trailers: {
|
|
45
|
+
[TRAILER_KEYS.dataCommit]: dataCommit,
|
|
46
|
+
[TRAILER_KEYS.graph]: graph,
|
|
47
|
+
[TRAILER_KEYS.kind]: 'audit',
|
|
48
|
+
[TRAILER_KEYS.opsDigest]: opsDigest,
|
|
49
|
+
[TRAILER_KEYS.schema]: '1',
|
|
50
|
+
[TRAILER_KEYS.writer]: writer,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// -----------------------------------------------------------------------------
|
|
56
|
+
// Decoder
|
|
57
|
+
// -----------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Decodes an audit commit message.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} message - The raw commit message
|
|
63
|
+
* @returns {{ kind: 'audit', graph: string, writer: string, dataCommit: string, opsDigest: string, schema: number }}
|
|
64
|
+
* @throws {Error} If the message is not a valid audit message
|
|
65
|
+
*/
|
|
66
|
+
export function decodeAuditMessage(message) {
|
|
67
|
+
const codec = getCodec();
|
|
68
|
+
const decoded = codec.decode(message);
|
|
69
|
+
const { trailers } = decoded;
|
|
70
|
+
|
|
71
|
+
// Check for duplicate trailers (strict decode)
|
|
72
|
+
const keys = Object.keys(trailers);
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
for (const key of keys) {
|
|
75
|
+
if (seen.has(key)) {
|
|
76
|
+
throw new Error(`Duplicate trailer rejected: ${key}`);
|
|
77
|
+
}
|
|
78
|
+
seen.add(key);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Validate kind discriminator
|
|
82
|
+
const kind = trailers[TRAILER_KEYS.kind];
|
|
83
|
+
if (kind !== 'audit') {
|
|
84
|
+
throw new Error(`Invalid audit message: eg-kind must be 'audit', got '${kind}'`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Extract and validate required fields
|
|
88
|
+
const graph = trailers[TRAILER_KEYS.graph];
|
|
89
|
+
if (!graph) {
|
|
90
|
+
throw new Error('Invalid audit message: missing required trailer eg-graph');
|
|
91
|
+
}
|
|
92
|
+
validateGraphName(graph);
|
|
93
|
+
|
|
94
|
+
const writer = trailers[TRAILER_KEYS.writer];
|
|
95
|
+
if (!writer) {
|
|
96
|
+
throw new Error('Invalid audit message: missing required trailer eg-writer');
|
|
97
|
+
}
|
|
98
|
+
validateWriterId(writer);
|
|
99
|
+
|
|
100
|
+
const dataCommit = trailers[TRAILER_KEYS.dataCommit];
|
|
101
|
+
if (!dataCommit) {
|
|
102
|
+
throw new Error('Invalid audit message: missing required trailer eg-data-commit');
|
|
103
|
+
}
|
|
104
|
+
validateOid(dataCommit, 'dataCommit');
|
|
105
|
+
|
|
106
|
+
const opsDigest = trailers[TRAILER_KEYS.opsDigest];
|
|
107
|
+
if (!opsDigest) {
|
|
108
|
+
throw new Error('Invalid audit message: missing required trailer eg-ops-digest');
|
|
109
|
+
}
|
|
110
|
+
validateSha256(opsDigest, 'opsDigest');
|
|
111
|
+
|
|
112
|
+
const schemaStr = trailers[TRAILER_KEYS.schema];
|
|
113
|
+
if (!schemaStr) {
|
|
114
|
+
throw new Error('Invalid audit message: missing required trailer eg-schema');
|
|
115
|
+
}
|
|
116
|
+
if (!/^\d+$/.test(schemaStr)) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Invalid audit message: eg-schema must be a positive integer, got '${schemaStr}'`,
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const schema = Number(schemaStr);
|
|
122
|
+
if (!Number.isInteger(schema) || schema < 1) {
|
|
123
|
+
throw new Error(`Invalid audit message: eg-schema must be a positive integer, got '${schemaStr}'`);
|
|
124
|
+
}
|
|
125
|
+
if (schema > 1) {
|
|
126
|
+
throw new Error(`Unsupported audit schema version: ${schema}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
kind: 'audit',
|
|
131
|
+
graph,
|
|
132
|
+
writer,
|
|
133
|
+
dataCommit,
|
|
134
|
+
opsDigest,
|
|
135
|
+
schema,
|
|
136
|
+
};
|
|
137
|
+
}
|