@totemsdk/proofgraph 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +202 -21
  2. package/NOTICE +60 -0
  3. package/README.md +1 -1
  4. package/dist/canonical.js +11 -19
  5. package/dist/cjs/canonical.d.ts +22 -0
  6. package/dist/cjs/canonical.js +51 -0
  7. package/dist/cjs/durable-store.d.ts +50 -0
  8. package/dist/cjs/durable-store.js +178 -0
  9. package/dist/cjs/evidence.d.ts +89 -0
  10. package/dist/cjs/evidence.js +130 -0
  11. package/dist/cjs/graph.d.ts +103 -0
  12. package/dist/cjs/graph.js +298 -0
  13. package/dist/cjs/index.d.ts +26 -0
  14. package/dist/cjs/index.js +84 -0
  15. package/dist/cjs/io.d.ts +26 -0
  16. package/dist/cjs/io.js +173 -0
  17. package/dist/cjs/package.json +1 -0
  18. package/dist/cjs/query.d.ts +85 -0
  19. package/dist/cjs/query.js +189 -0
  20. package/dist/cjs/replicated-evidence.d.ts +42 -0
  21. package/dist/cjs/replicated-evidence.js +98 -0
  22. package/dist/cjs/types.d.ts +62 -0
  23. package/dist/cjs/types.js +7 -0
  24. package/dist/cjs/verify.d.ts +23 -0
  25. package/dist/cjs/verify.js +77 -0
  26. package/dist/durable-store.js +9 -12
  27. package/dist/evidence.js +14 -19
  28. package/dist/graph.d.ts +11 -0
  29. package/dist/graph.js +47 -34
  30. package/dist/index.d.ts +3 -2
  31. package/dist/index.js +8 -52
  32. package/dist/io.js +4 -8
  33. package/dist/query.d.ts +4 -0
  34. package/dist/query.js +28 -36
  35. package/dist/replicated-evidence.d.ts +42 -0
  36. package/dist/replicated-evidence.js +95 -0
  37. package/dist/types.d.ts +1 -1
  38. package/dist/types.js +1 -2
  39. package/dist/verify.js +3 -40
  40. package/package.json +21 -14
  41. package/rust/pkg/package.json +2 -2
  42. package/rust/pkg/proofgraph_wasm_bg.wasm +0 -0
  43. package/rust/pkg-node/package.json +2 -2
  44. package/rust/pkg-node/proofgraph_wasm_bg.wasm +0 -0
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * RFC-057 Phase 4 — replicated proofgraph evidence adapter.
4
+ *
5
+ * Keeps the authoritative proofgraph evidence store local while allowing a
6
+ * replicated index to locate the same digest-verified artifacts on other
7
+ * peers. The replicated index is never trusted for bytes: every read
8
+ * re-verifies the artifact digest.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.createReplicatedProofGraphEvidenceStore = createReplicatedProofGraphEvidenceStore;
12
+ const core_1 = require("@totemsdk/core");
13
+ const errors_1 = require("@totemsdk/storage/errors");
14
+ const KEY_PREFIX = 'proofgraph:evidence:';
15
+ const DEFAULT_NAMESPACE = 'totem-proofgraph-evidence';
16
+ function normalizeHash(value) {
17
+ return value.replace(/^0x/i, '').toLowerCase();
18
+ }
19
+ function evidenceNodes(graph) {
20
+ return graph.nodes.filter((node) => node.type === 'evidence');
21
+ }
22
+ function contentHashOf(node) {
23
+ const value = node.data?.contentHash;
24
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
25
+ }
26
+ function createReplicatedProofGraphEvidenceStore(options) {
27
+ if (!options.artifacts.capabilities.writable) {
28
+ throw new Error('replicated evidence store requires a writable artifact store');
29
+ }
30
+ const namespace = options.namespace ?? DEFAULT_NAMESPACE;
31
+ const key = (nodeId) => `${KEY_PREFIX}${nodeId}`;
32
+ return {
33
+ async putEvidence(graph, bytesFor) {
34
+ const refs = [];
35
+ for (const node of evidenceNodes(graph)) {
36
+ const bytes = bytesFor(node.id);
37
+ if (!bytes)
38
+ continue;
39
+ const digest = (0, core_1.toHex)((0, core_1.sha3_256)(bytes));
40
+ const contentHash = contentHashOf(node);
41
+ if (contentHash && normalizeHash(contentHash) !== digest) {
42
+ throw new errors_1.StorageError(`evidence commitment mismatch for node "${node.id}"`, 'corrupt', {
43
+ key: key(node.id),
44
+ });
45
+ }
46
+ const receipt = await options.artifacts.put(namespace, bytes);
47
+ if (contentHash && normalizeHash(contentHash) !== receipt.ref.digest) {
48
+ throw new errors_1.StorageError(`artifact digest mismatch for node "${node.id}"`, 'corrupt', {
49
+ key: key(node.id),
50
+ });
51
+ }
52
+ await options.index.put(key(node.id), {
53
+ nodeId: node.id,
54
+ ref: receipt.ref,
55
+ contentHash: contentHash ?? receipt.ref.digest,
56
+ storedAt: Date.now(),
57
+ });
58
+ refs.push(receipt.ref);
59
+ }
60
+ return refs;
61
+ },
62
+ async getEvidence(nodeId) {
63
+ const raw = await options.index.get(key(nodeId));
64
+ if (!raw)
65
+ return { nodeId, status: 'not-found' };
66
+ const entry = raw;
67
+ const read = await options.artifacts.get(entry.ref);
68
+ if (read.status !== 'ok' || !read.bytes) {
69
+ return {
70
+ nodeId,
71
+ status: read.status,
72
+ ref: entry.ref,
73
+ ...(read.message ? { message: read.message } : {}),
74
+ };
75
+ }
76
+ const digest = (0, core_1.toHex)((0, core_1.sha3_256)(read.bytes));
77
+ if (normalizeHash(entry.contentHash) !== digest) {
78
+ return {
79
+ nodeId,
80
+ status: 'corrupt',
81
+ ref: entry.ref,
82
+ message: `evidence digest mismatch: ${digest} !== ${entry.contentHash}`,
83
+ };
84
+ }
85
+ return { nodeId, status: 'ok', ref: entry.ref, bytes: read.bytes };
86
+ },
87
+ async verifyEvidence(nodeId) {
88
+ return (await this.getEvidence(nodeId)).status === 'ok';
89
+ },
90
+ async *listEvidence() {
91
+ if (!options.index.list)
92
+ return;
93
+ for await (const entry of options.index.list(KEY_PREFIX)) {
94
+ yield entry.value;
95
+ }
96
+ },
97
+ };
98
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @totemsdk/proofgraph — Type definitions
3
+ *
4
+ * Pure schema — no network, no DHT, no blockchain submission, no crypto.
5
+ */
6
+ export type ProofGraphNodeType = 'proof' | 'identity' | 'identity-claim' | 'manifest' | 'address' | 'subject' | 'evidence' | 'anchor' | 'receipt' | 'payment' | 'device' | 'service' | 'policy' | 'custom';
7
+ export type ProofGraphEdgeType = 'proves' | 'issued_by' | 'signed_by' | 'about' | 'references' | 'derived_from' | 'supports' | 'contradicts' | 'supersedes' | 'revokes' | 'anchored_to' | 'delegates_to' | 'controls' | 'depends_on' | 'manifests_as' | 'revision_of' | 'conflicts_with';
8
+ export interface ProofGraphNode {
9
+ id: string;
10
+ type: ProofGraphNodeType;
11
+ refId: string;
12
+ data?: Record<string, unknown>;
13
+ createdAt: number;
14
+ }
15
+ export interface ProofGraphEdge {
16
+ id: string;
17
+ type: ProofGraphEdgeType;
18
+ from: string;
19
+ to: string;
20
+ proofId?: string;
21
+ data?: Record<string, unknown>;
22
+ }
23
+ export interface ProofGraph {
24
+ graphId: string;
25
+ nodes: ProofGraphNode[];
26
+ edges: ProofGraphEdge[];
27
+ createdAt: number;
28
+ metadata?: Record<string, unknown>;
29
+ }
30
+ export interface ProofGraphVerifyResult {
31
+ valid: boolean;
32
+ invalidProofs: string[];
33
+ reason?: string;
34
+ }
35
+ /**
36
+ * Input object for addReceiptLike.
37
+ */
38
+ export interface ReceiptLikeInput {
39
+ id: string;
40
+ data?: Record<string, unknown>;
41
+ proofId?: string;
42
+ }
43
+ /**
44
+ * Input object for addAnchor.
45
+ */
46
+ export interface AnchorInput {
47
+ hash: string;
48
+ provider?: string;
49
+ txId?: string;
50
+ confirmedAt?: number;
51
+ metadata?: Record<string, unknown>;
52
+ proofId?: string;
53
+ }
54
+ /**
55
+ * Storage port — interface only, no concrete implementation in this package.
56
+ * Adapters (SQLite, LevelDB, in-memory) live in consumer packages.
57
+ */
58
+ export interface ProofGraphStoragePort {
59
+ save(graph: ProofGraph): Promise<void>;
60
+ load(graphId: string): Promise<ProofGraph | null>;
61
+ findByNodeId(id: string): Promise<ProofGraph | null>;
62
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * @totemsdk/proofgraph — Type definitions
4
+ *
5
+ * Pure schema — no network, no DHT, no blockchain submission, no crypto.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Graph-level verification.
3
+ *
4
+ * verifyProofGraph: iterates proof nodes, recovers SignedProof from node.data,
5
+ * and delegates to @totemsdk/proof's verifyProof for each one.
6
+ * Never reimplements cryptography.
7
+ *
8
+ * verifyGraphProofs: same logic, returns the list of invalid proof IDs (string[]).
9
+ */
10
+ import type { ProofGraph, ProofGraphVerifyResult } from './types.js';
11
+ /**
12
+ * Verify every proof node stored in the graph.
13
+ *
14
+ * Iterates nodes of type 'proof', casts node.data back to SignedProof,
15
+ * and calls proofModule.verifyProof() from @totemsdk/proof.
16
+ * Returns { valid: true } if ALL proofs pass; otherwise lists the failing proofIds.
17
+ */
18
+ export declare function verifyProofGraph(graph: ProofGraph, _options?: Record<string, unknown>): ProofGraphVerifyResult;
19
+ /**
20
+ * Returns the list of invalid proof IDs in the graph.
21
+ * Equivalent to verifyProofGraph(graph).invalidProofs.
22
+ */
23
+ export declare function verifyGraphProofs(graph: ProofGraph): string[];
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * Graph-level verification.
4
+ *
5
+ * verifyProofGraph: iterates proof nodes, recovers SignedProof from node.data,
6
+ * and delegates to @totemsdk/proof's verifyProof for each one.
7
+ * Never reimplements cryptography.
8
+ *
9
+ * verifyGraphProofs: same logic, returns the list of invalid proof IDs (string[]).
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.verifyProofGraph = verifyProofGraph;
46
+ exports.verifyGraphProofs = verifyGraphProofs;
47
+ const proofModule = __importStar(require("@totemsdk/proof"));
48
+ /**
49
+ * Verify every proof node stored in the graph.
50
+ *
51
+ * Iterates nodes of type 'proof', casts node.data back to SignedProof,
52
+ * and calls proofModule.verifyProof() from @totemsdk/proof.
53
+ * Returns { valid: true } if ALL proofs pass; otherwise lists the failing proofIds.
54
+ */
55
+ function verifyProofGraph(graph, _options) {
56
+ const invalidProofs = [];
57
+ for (const node of graph.nodes) {
58
+ if (node.type !== 'proof' || !node.data)
59
+ continue;
60
+ const signedProof = node.data;
61
+ const result = proofModule.verifyProof(signedProof);
62
+ if (!result.valid) {
63
+ invalidProofs.push(node.refId);
64
+ }
65
+ }
66
+ return {
67
+ valid: invalidProofs.length === 0,
68
+ invalidProofs,
69
+ };
70
+ }
71
+ /**
72
+ * Returns the list of invalid proof IDs in the graph.
73
+ * Equivalent to verifyProofGraph(graph).invalidProofs.
74
+ */
75
+ function verifyGraphProofs(graph) {
76
+ return verifyProofGraph(graph).invalidProofs;
77
+ }
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Durable `ProofGraphStoragePort` adapter for @totemsdk/proofgraph.
4
3
  *
@@ -16,11 +15,9 @@
16
15
  * recomputes the graphId — a tampered or truncated record surfaces as
17
16
  * `StorageError` `corrupt`, never as `not-found` (RFC-007 §4.2 strict).
18
17
  */
19
- Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.createDurableProofGraphStore = createDurableProofGraphStore;
21
- const types_1 = require("@totemsdk/storage/types");
22
- const errors_1 = require("@totemsdk/storage/errors");
23
- const io_js_1 = require("./io.js");
18
+ import { assertCapabilities } from '@totemsdk/storage/types';
19
+ import { StorageError } from '@totemsdk/storage/errors';
20
+ import { exportProofGraph, importProofGraph } from './io.js';
24
21
  const DEFAULT_NAMESPACE = 'totem_proofgraph:v1:';
25
22
  const GRAPH_PREFIX = 'graph:';
26
23
  const NODE_PREFIX = 'node:';
@@ -45,10 +42,10 @@ function isCasStore(adapter) {
45
42
  * so concurrent saves never clobber a newer graph. A non-CAS or low-durability
46
43
  * adapter is rejected at construction (RFC-007 §4.2 no-silent-downgrade).
47
44
  */
48
- function createDurableProofGraphStore(adapter, options = {}) {
45
+ export function createDurableProofGraphStore(adapter, options = {}) {
49
46
  const namespace = options.namespace ?? DEFAULT_NAMESPACE;
50
47
  if (typeof adapter.capabilities === 'object') {
51
- (0, types_1.assertCapabilities)(adapter, {
48
+ assertCapabilities(adapter, {
52
49
  acknowledge: options.requireAckMode ?? 'durably-acknowledged',
53
50
  atomic: true,
54
51
  conditional: true,
@@ -70,14 +67,14 @@ function createDurableProofGraphStore(adapter, options = {}) {
70
67
  };
71
68
  function parseGraph(graphId, raw) {
72
69
  if (typeof raw !== 'string' && (typeof raw !== 'object' || raw === null || typeof raw.json !== 'string')) {
73
- throw new errors_1.StorageError(`proofgraph record "${graphId}" is malformed`, 'corrupt', { key: graphKey(graphId) });
70
+ throw new StorageError(`proofgraph record "${graphId}" is malformed`, 'corrupt', { key: graphKey(graphId) });
74
71
  }
75
72
  const json = typeof raw === 'string' ? raw : raw.json;
76
73
  try {
77
- return (0, io_js_1.importProofGraph)(json);
74
+ return importProofGraph(json);
78
75
  }
79
76
  catch (err) {
80
- throw new errors_1.StorageError(`proofgraph record "${graphId}" failed validation: ${err.message}`, 'corrupt', { key: graphKey(graphId), cause: err });
77
+ throw new StorageError(`proofgraph record "${graphId}" failed validation: ${err.message}`, 'corrupt', { key: graphKey(graphId), cause: err });
81
78
  }
82
79
  }
83
80
  async function loadUnchecked(graphId) {
@@ -104,7 +101,7 @@ function createDurableProofGraphStore(adapter, options = {}) {
104
101
  const savedAt = nextSavedAt();
105
102
  return withStorageLock(adapter, async () => {
106
103
  // Immutable content-addressed record first (idempotent, safe on retry).
107
- const record = { json: (0, io_js_1.exportProofGraph)(graph), savedAt };
104
+ const record = { json: exportProofGraph(graph), savedAt };
108
105
  await adapter.set(graphKey(graph.graphId), record);
109
106
  // Reverse index: most-recent snapshot wins (CAS, never clobbers newer).
110
107
  for (const node of graph.nodes) {
package/dist/evidence.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Durable evidence-chain owner for @totemsdk/proofgraph (RFC-007 G8 / §4.3).
4
3
  *
@@ -12,21 +11,17 @@
12
11
  * `not-found` (bytes absent); `unavailable` (backend unreachable, or the
13
12
  * backend deleted a blob the local index still references) is also surfaced.
14
13
  */
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.normalizeEvidenceHash = normalizeEvidenceHash;
17
- exports.assertEvidenceBinding = assertEvidenceBinding;
18
- exports.createProofGraphEvidenceStore = createProofGraphEvidenceStore;
19
- const errors_1 = require("@totemsdk/storage/errors");
20
- const core_1 = require("@totemsdk/core");
14
+ import { StorageError } from '@totemsdk/storage/errors';
15
+ import { sha3_256, toHex } from '@totemsdk/core';
21
16
  const DEFAULT_NS = 'totem-proofgraph-evidence';
22
17
  const INDEX_PREFIX = 'totem_proofgraph_evidence:v1:';
23
- function normalizeEvidenceHash(hash) {
18
+ export function normalizeEvidenceHash(hash) {
24
19
  return hash.replace(/^0x/i, '').toLowerCase();
25
20
  }
26
21
  /** Throws `StorageError('corrupt')` unless `contentHash === artifact.digest`. */
27
- function assertEvidenceBinding(binding) {
22
+ export function assertEvidenceBinding(binding) {
28
23
  if (normalizeEvidenceHash(binding.contentHash) !== normalizeEvidenceHash(binding.artifact.digest)) {
29
- throw new errors_1.StorageError(`evidence binding mismatch for node "${binding.nodeId}": contentHash ${binding.contentHash} !== artifact.digest ${binding.artifact.digest}`, 'corrupt', { key: binding.nodeId });
24
+ throw new StorageError(`evidence binding mismatch for node "${binding.nodeId}": contentHash ${binding.contentHash} !== artifact.digest ${binding.artifact.digest}`, 'corrupt', { key: binding.nodeId });
30
25
  }
31
26
  }
32
27
  function evidenceNodeIds(graph) {
@@ -37,7 +32,7 @@ function nodeContentHash(graph, nodeId) {
37
32
  const value = graph.nodes.find((node) => node.id === nodeId)?.data?.contentHash;
38
33
  return typeof value === 'string' && value.length > 0 ? value : undefined;
39
34
  }
40
- function createProofGraphEvidenceStore(artifacts, index, options = {}) {
35
+ export function createProofGraphEvidenceStore(artifacts, index, options = {}) {
41
36
  if (!artifacts.capabilities.writable) {
42
37
  throw new Error('createProofGraphEvidenceStore requires a writable artifact store');
43
38
  }
@@ -53,15 +48,15 @@ function createProofGraphEvidenceStore(artifacts, index, options = {}) {
53
48
  continue;
54
49
  const contentHash = options.contentHashFor?.(nodeId) ?? nodeContentHash(graph, nodeId);
55
50
  if (!contentHash && options.requireContentHash) {
56
- throw new errors_1.StorageError(`evidence commitment missing for node "${nodeId}"`, 'corrupt', { key: indexKey(nodeId) });
51
+ throw new StorageError(`evidence commitment missing for node "${nodeId}"`, 'corrupt', { key: indexKey(nodeId) });
57
52
  }
58
53
  // Byte-identity invariant: the stored bytes must hash to the commitment.
59
- const digest = (0, core_1.toHex)((0, core_1.sha3_256)(bytes));
54
+ const digest = toHex(sha3_256(bytes));
60
55
  if (contentHash && normalizeEvidenceHash(contentHash) !== digest) {
61
- throw new errors_1.StorageError(`evidence commitment mismatch for node "${nodeId}": sha3(bytes) ${digest} !== contentHash ${contentHash}`, 'corrupt', { key: indexKey(nodeId) });
56
+ throw new StorageError(`evidence commitment mismatch for node "${nodeId}": sha3(bytes) ${digest} !== contentHash ${contentHash}`, 'corrupt', { key: indexKey(nodeId) });
62
57
  }
63
58
  const receipt = await artifacts.put(namespace, bytes).catch((err) => {
64
- throw new errors_1.StorageError(`evidence put failed for node "${nodeId}": ${err.message}`, 'write-failed', { key: indexKey(nodeId), cause: err });
59
+ throw new StorageError(`evidence put failed for node "${nodeId}": ${err.message}`, 'write-failed', { key: indexKey(nodeId), cause: err });
65
60
  });
66
61
  if (contentHash) {
67
62
  // The artifact must address exactly the committed hash.
@@ -79,9 +74,9 @@ function createProofGraphEvidenceStore(artifacts, index, options = {}) {
79
74
  async restoreEvidence(graph) {
80
75
  const results = [];
81
76
  const fail = (err) => {
82
- if (err instanceof errors_1.StorageError)
77
+ if (err instanceof StorageError)
83
78
  throw err;
84
- throw new errors_1.StorageError(`evidence read failed: ${err.message}`, 'unavailable', { cause: err });
79
+ throw new StorageError(`evidence read failed: ${err.message}`, 'unavailable', { cause: err });
85
80
  };
86
81
  for (const nodeId of evidenceNodeIds(graph)) {
87
82
  const entry = await index.get(indexKey(nodeId));
@@ -101,13 +96,13 @@ function createProofGraphEvidenceStore(artifacts, index, options = {}) {
101
96
  break;
102
97
  case 'corrupt':
103
98
  if (strict) {
104
- throw new errors_1.StorageError(`evidence artifact corrupt for node "${nodeId}": ${read.message ?? 'digest mismatch'}`, 'corrupt', { key: indexKey(nodeId) });
99
+ throw new StorageError(`evidence artifact corrupt for node "${nodeId}": ${read.message ?? 'digest mismatch'}`, 'corrupt', { key: indexKey(nodeId) });
105
100
  }
106
101
  results.push({ nodeId, status: 'corrupt', ref, message: read.message ?? 'digest mismatch' });
107
102
  break;
108
103
  case 'unavailable':
109
104
  if (strict) {
110
- throw new errors_1.StorageError(`evidence artifact unavailable for node "${nodeId}": ${read.message ?? 'backend unavailable'}`, 'unavailable', { key: indexKey(nodeId) });
105
+ throw new StorageError(`evidence artifact unavailable for node "${nodeId}": ${read.message ?? 'backend unavailable'}`, 'unavailable', { key: indexKey(nodeId) });
111
106
  }
112
107
  results.push({ nodeId, status: 'unavailable', ref, message: read.message ?? 'backend unavailable' });
113
108
  break;
package/dist/graph.d.ts CHANGED
@@ -80,6 +80,17 @@ export declare function addIdentityClaim(graph: ProofGraph, signedClaim: SignedI
80
80
  * manifests_as manifest → address
81
81
  */
82
82
  export declare function addManifest(graph: ProofGraph, signedManifest: SignedManifest): ProofGraph;
83
+ /**
84
+ * Add a signed manifest **revision** without collapsing other revisions.
85
+ *
86
+ * Creates:
87
+ * manifest (logical) refId = manifestId
88
+ * manifest (revision) refId = manifestEnvelopeId, data = { manifestId, manifestEnvelopeId, signedManifest }
89
+ * address resolved author/operator address
90
+ * manifests_as manifestId → address
91
+ * revision_of manifestEnvelopeId → manifestId
92
+ */
93
+ export declare function addManifestRevision(graph: ProofGraph, signedManifest: SignedManifest): ProofGraph;
83
94
  /**
84
95
  * Add a receipt-like node (payment, subscription, claim receipt) to the graph.
85
96
  * If receipt.proofId is set, adds a 'supports' edge from the receipt to that proof.
package/dist/graph.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Proof graph mutation functions — all pure, all returning NEW graphs.
4
3
  *
@@ -6,24 +5,12 @@
6
5
  * recomputed graphId. Nodes and edges are deduplicated by ID so adding the
7
6
  * same proof twice is idempotent.
8
7
  */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.createProofGraph = createProofGraph;
11
- exports.setGraphMetadata = setGraphMetadata;
12
- exports.buildEdge = buildEdge;
13
- exports.addNode = addNode;
14
- exports.addEdge = addEdge;
15
- exports.addIdentityDocument = addIdentityDocument;
16
- exports.addProof = addProof;
17
- exports.addIdentityClaim = addIdentityClaim;
18
- exports.addManifest = addManifest;
19
- exports.addReceiptLike = addReceiptLike;
20
- exports.addAnchor = addAnchor;
21
- const manifest_1 = require("@totemsdk/manifest");
22
- const canonical_js_1 = require("./canonical.js");
23
- const evidence_js_1 = require("./evidence.js");
8
+ import { computeManifestId, computeManifestEnvelopeId } from '@totemsdk/manifest';
9
+ import { computeNodeId, computeEdgeId, computeProofGraphId } from './canonical.js';
10
+ import { normalizeEvidenceHash } from './evidence.js';
24
11
  function makeNode(type, refId, data) {
25
12
  return {
26
- id: (0, canonical_js_1.computeNodeId)(type, refId),
13
+ id: computeNodeId(type, refId),
27
14
  type,
28
15
  refId,
29
16
  ...(data !== undefined ? { data } : {}),
@@ -32,7 +19,7 @@ function makeNode(type, refId, data) {
32
19
  }
33
20
  function makeEdge(type, from, to, proofId, data) {
34
21
  return {
35
- id: (0, canonical_js_1.computeEdgeId)(type, from, to, proofId, data),
22
+ id: computeEdgeId(type, from, to, proofId, data),
36
23
  type,
37
24
  from,
38
25
  to,
@@ -65,17 +52,17 @@ function rebuild(graph, newNodes, newEdges) {
65
52
  ...graph,
66
53
  nodes,
67
54
  edges,
68
- graphId: (0, canonical_js_1.computeProofGraphId)(nodes, edges),
55
+ graphId: computeProofGraphId(nodes, edges),
69
56
  };
70
57
  }
71
58
  /**
72
59
  * Create an empty ProofGraph.
73
60
  */
74
- function createProofGraph(metadata) {
61
+ export function createProofGraph(metadata) {
75
62
  const nodes = [];
76
63
  const edges = [];
77
64
  return {
78
- graphId: (0, canonical_js_1.computeProofGraphId)(nodes, edges),
65
+ graphId: computeProofGraphId(nodes, edges),
79
66
  nodes,
80
67
  edges,
81
68
  createdAt: Date.now(),
@@ -85,39 +72,39 @@ function createProofGraph(metadata) {
85
72
  /**
86
73
  * Attach or replace mutable metadata. Does NOT affect graphId.
87
74
  */
88
- function setGraphMetadata(graph, metadata) {
75
+ export function setGraphMetadata(graph, metadata) {
89
76
  return { ...graph, metadata };
90
77
  }
91
78
  /**
92
79
  * Build a ProofGraphEdge with a deterministic ID from its fields.
93
80
  * Convenience helper so callers don't need to import computeEdgeId.
94
81
  */
95
- function buildEdge(type, from, to, proofId, data) {
82
+ export function buildEdge(type, from, to, proofId, data) {
96
83
  return makeEdge(type, from, to, proofId, data);
97
84
  }
98
85
  /**
99
86
  * Add a node directly (type + refId pair). Idempotent — skipped if the node already exists.
100
87
  */
101
- function addNode(graph, type, refId, data) {
88
+ export function addNode(graph, type, refId, data) {
102
89
  return rebuild(graph, [makeNode(type, refId, data)], []);
103
90
  }
104
91
  /**
105
92
  * Append a ProofGraphEdge and recompute graphId. Idempotent by edge ID.
106
93
  * Spec API: addEdge(graph, edge). Use buildEdge() to construct the edge object.
107
94
  */
108
- function addEdge(graph, edge) {
95
+ export function addEdge(graph, edge) {
109
96
  const edges = mergeEdges(graph.edges, [edge]);
110
97
  return {
111
98
  ...graph,
112
99
  edges,
113
- graphId: (0, canonical_js_1.computeProofGraphId)(graph.nodes, edges),
100
+ graphId: computeProofGraphId(graph.nodes, edges),
114
101
  };
115
102
  }
116
103
  /**
117
104
  * Index a TotemIdentityDocument into the graph.
118
105
  * Creates an 'identity' node with refId = doc.id.
119
106
  */
120
- function addIdentityDocument(graph, doc) {
107
+ export function addIdentityDocument(graph, doc) {
121
108
  return rebuild(graph, [makeNode('identity', doc.id, { ...doc })], []);
122
109
  }
123
110
  /**
@@ -137,7 +124,7 @@ function addIdentityDocument(graph, doc) {
137
124
  * references proof → evidence (one per evidence ref, in array order)
138
125
  * anchored_to proof → anchor (if present)
139
126
  */
140
- function addProof(graph, signedProof) {
127
+ export function addProof(graph, signedProof) {
141
128
  const proofNode = makeNode('proof', signedProof.proofId, {
142
129
  ...signedProof,
143
130
  });
@@ -153,7 +140,7 @@ function addProof(graph, signedProof) {
153
140
  for (const ev of signedProof.evidence) {
154
141
  // RFC-007 Amendment A (A3): carry the claim commitment on the evidence
155
142
  // node so the evidence store can enforce claim→contentHash→artifact.
156
- newNodes.push(makeNode('evidence', ev.id, ev.hash ? { contentHash: (0, evidence_js_1.normalizeEvidenceHash)(ev.hash) } : undefined));
143
+ newNodes.push(makeNode('evidence', ev.id, ev.hash ? { contentHash: normalizeEvidenceHash(ev.hash) } : undefined));
157
144
  newEdges.push(makeEdge('references', signedProof.proofId, ev.id, signedProof.proofId));
158
145
  }
159
146
  }
@@ -177,7 +164,7 @@ function addProof(graph, signedProof) {
177
164
  * revokes → revokes edge (claim-node → subject identity)
178
165
  * rotates_to → controls edge (claim-node → new address)
179
166
  */
180
- function addIdentityClaim(graph, signedClaim) {
167
+ export function addIdentityClaim(graph, signedClaim) {
181
168
  const { claim } = signedClaim;
182
169
  const claimNode = makeNode('identity-claim', claim.id, {
183
170
  ...signedClaim,
@@ -231,8 +218,8 @@ function resolveManifestAddress(signedManifest) {
231
218
  * Edge created:
232
219
  * manifests_as manifest → address
233
220
  */
234
- function addManifest(graph, signedManifest) {
235
- const manifestId = (0, manifest_1.computeManifestId)(signedManifest.manifest);
221
+ export function addManifest(graph, signedManifest) {
222
+ const manifestId = computeManifestId(signedManifest.manifest);
236
223
  const address = resolveManifestAddress(signedManifest);
237
224
  const manifestNode = makeNode('manifest', manifestId, {
238
225
  ...signedManifest,
@@ -242,11 +229,37 @@ function addManifest(graph, signedManifest) {
242
229
  makeEdge('manifests_as', manifestId, address),
243
230
  ]);
244
231
  }
232
+ /**
233
+ * Add a signed manifest **revision** without collapsing other revisions.
234
+ *
235
+ * Creates:
236
+ * manifest (logical) refId = manifestId
237
+ * manifest (revision) refId = manifestEnvelopeId, data = { manifestId, manifestEnvelopeId, signedManifest }
238
+ * address resolved author/operator address
239
+ * manifests_as manifestId → address
240
+ * revision_of manifestEnvelopeId → manifestId
241
+ */
242
+ export function addManifestRevision(graph, signedManifest) {
243
+ const manifestId = computeManifestId(signedManifest.manifest);
244
+ const manifestEnvelopeId = computeManifestEnvelopeId(signedManifest);
245
+ const address = resolveManifestAddress(signedManifest);
246
+ const logicalNode = makeNode('manifest', manifestId, { manifestId });
247
+ const revisionNode = makeNode('manifest', manifestEnvelopeId, {
248
+ manifestId,
249
+ manifestEnvelopeId,
250
+ signedManifest,
251
+ });
252
+ const addressNode = makeNode('address', address);
253
+ return rebuild(graph, [logicalNode, revisionNode, addressNode], [
254
+ makeEdge('manifests_as', manifestId, address),
255
+ makeEdge('revision_of', manifestEnvelopeId, manifestId),
256
+ ]);
257
+ }
245
258
  /**
246
259
  * Add a receipt-like node (payment, subscription, claim receipt) to the graph.
247
260
  * If receipt.proofId is set, adds a 'supports' edge from the receipt to that proof.
248
261
  */
249
- function addReceiptLike(graph, receipt) {
262
+ export function addReceiptLike(graph, receipt) {
250
263
  const { id, data, proofId } = receipt;
251
264
  const receiptNode = makeNode('receipt', id, data);
252
265
  const newEdges = [];
@@ -259,7 +272,7 @@ function addReceiptLike(graph, receipt) {
259
272
  * Add a standalone anchor node. If anchor.proofId is set, adds an 'anchored_to'
260
273
  * edge from the proof to this anchor.
261
274
  */
262
- function addAnchor(graph, anchor) {
275
+ export function addAnchor(graph, anchor) {
263
276
  const { hash, proofId, ...rest } = anchor;
264
277
  const nodeData = { ...rest };
265
278
  const anchorNode = makeNode('anchor', hash, Object.keys(nodeData).length > 0 ? nodeData : undefined);
package/dist/index.d.ts CHANGED
@@ -19,7 +19,8 @@ export type { DurableProofGraphStore, DurableProofGraphStoreOptions, ProofGraphR
19
19
  export { createProofGraphEvidenceStore, assertEvidenceBinding, normalizeEvidenceHash, } from './evidence.js';
20
20
  export type { ProofGraphEvidenceStore, ProofGraphEvidenceStoreOptions, ProofGraphEvidenceResult, EvidenceArtifactBinding, PutEvidenceOptions, } from './evidence.js';
21
21
  export { toHex, canonicalJson, computeNodeId, computeEdgeId, computeProofGraphId, recomputeGraphId, } from './canonical.js';
22
- export { createProofGraph, setGraphMetadata, buildEdge, addNode, addEdge, addIdentityDocument, addProof, addIdentityClaim, addManifest, addReceiptLike, addAnchor, } from './graph.js';
23
- export { findNode, getEdgesFrom, getEdgesTo, getEdgesByType, getProofNodes, findProofsBySubject, findProofsByIssuer, findAnchorsForProof, findRevocations, findSupersessions, findConflicts, getEvidenceTrail, getProofLineage, resolveCurrentProofSet, getManifestsForAddress, getEdgesBetween, reachableFrom, } from './query.js';
22
+ export { createProofGraph, setGraphMetadata, buildEdge, addNode, addEdge, addIdentityDocument, addProof, addIdentityClaim, addManifest, addManifestRevision, addReceiptLike, addAnchor, } from './graph.js';
23
+ export { findNode, getEdgesFrom, getEdgesTo, getEdgesByType, getProofNodes, findProofsBySubject, findProofsByIssuer, findAnchorsForProof, findRevocations, findSupersessions, findConflicts, getEvidenceTrail, getProofLineage, resolveCurrentProofSet, getManifestRevisions, getManifestsForAddress, getEdgesBetween, reachableFrom, } from './query.js';
24
24
  export { verifyProofGraph, verifyGraphProofs, } from './verify.js';
25
25
  export { exportProofGraph, importProofGraph, } from './io.js';
26
+ export * from './replicated-evidence.js';