@totemsdk/raster-proof 0.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.
- package/LICENSE +21 -0
- package/README.md +383 -0
- package/dist/canonical.d.ts +40 -0
- package/dist/canonical.js +76 -0
- package/dist/hash.d.ts +19 -0
- package/dist/hash.js +32 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +72 -0
- package/dist/manifest.d.ts +24 -0
- package/dist/manifest.js +146 -0
- package/dist/merkle.d.ts +49 -0
- package/dist/merkle.js +171 -0
- package/dist/proof.d.ts +54 -0
- package/dist/proof.js +247 -0
- package/dist/proofgraph.d.ts +51 -0
- package/dist/proofgraph.js +120 -0
- package/dist/provenance.d.ts +29 -0
- package/dist/provenance.js +95 -0
- package/dist/spatial.d.ts +23 -0
- package/dist/spatial.js +77 -0
- package/dist/types.d.ts +189 -0
- package/dist/types.js +14 -0
- package/dist/window.d.ts +19 -0
- package/dist/window.js +59 -0
- package/package.json +69 -0
package/dist/proof.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Proof envelope integration for @totemsdk/raster-proof.
|
|
4
|
+
*
|
|
5
|
+
* Bridges raster manifests, window proofs and Merkle proofs into
|
|
6
|
+
* @totemsdk/proof evidence refs and signed proof envelopes. Signing and
|
|
7
|
+
* verification delegate to @totemsdk/proof. Anchoring is deliberately NOT
|
|
8
|
+
* required for verification.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.rasterEvidenceRefs = rasterEvidenceRefs;
|
|
12
|
+
exports.createUnsignedRasterProof = createUnsignedRasterProof;
|
|
13
|
+
exports.signRasterProof = signRasterProof;
|
|
14
|
+
exports.verifyRasterProof = verifyRasterProof;
|
|
15
|
+
const proof_1 = require("@totemsdk/proof");
|
|
16
|
+
const canonical_js_1 = require("./canonical.js");
|
|
17
|
+
const manifest_js_1 = require("./manifest.js");
|
|
18
|
+
const window_js_1 = require("./window.js");
|
|
19
|
+
const provenance_js_1 = require("./provenance.js");
|
|
20
|
+
const merkle_js_1 = require("./merkle.js");
|
|
21
|
+
/**
|
|
22
|
+
* Build the evidence ref list for a raster proof:
|
|
23
|
+
* - raster manifest hash
|
|
24
|
+
* - content hash
|
|
25
|
+
* - Merkle root when present
|
|
26
|
+
* - window proof hash when present
|
|
27
|
+
* - source raster IDs when derived
|
|
28
|
+
* - spatial object ID when present
|
|
29
|
+
*/
|
|
30
|
+
function rasterEvidenceRefs(manifest, windowProof, spatialObjectId) {
|
|
31
|
+
const refs = [
|
|
32
|
+
(0, manifest_js_1.rasterManifestToEvidenceRef)(manifest),
|
|
33
|
+
{ id: manifest.asset.contentHash, kind: 'raster-content', hash: manifest.asset.contentHash },
|
|
34
|
+
];
|
|
35
|
+
if (manifest.asset.merkleRoot) {
|
|
36
|
+
refs.push({ id: manifest.rasterId + ':merkle', kind: 'raster-merkle-root', hash: manifest.asset.merkleRoot });
|
|
37
|
+
}
|
|
38
|
+
if (windowProof) {
|
|
39
|
+
refs.push((0, window_js_1.rasterWindowProofToEvidenceRef)(windowProof));
|
|
40
|
+
}
|
|
41
|
+
if (manifest.provenance?.derivedFrom) {
|
|
42
|
+
for (const src of manifest.provenance.derivedFrom) {
|
|
43
|
+
refs.push({ id: src, kind: 'raster-source', hash: src });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (spatialObjectId) {
|
|
47
|
+
refs.push({ id: spatialObjectId, kind: 'spatial-object', hash: spatialObjectId });
|
|
48
|
+
}
|
|
49
|
+
return refs;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create an unsigned attestation proof for a raster manifest.
|
|
53
|
+
*
|
|
54
|
+
* The proof claims: "this manifest describes this asset, produced by this
|
|
55
|
+
* source, at this time, with this content hash / Merkle root". It does NOT
|
|
56
|
+
* claim the visual interpretation is correct — interpretation is an
|
|
57
|
+
* operator / model / reviewer claim made elsewhere.
|
|
58
|
+
*/
|
|
59
|
+
function createUnsignedRasterProof(params) {
|
|
60
|
+
const { manifest, windowProof, merkleProofs, spatialObjectId } = params;
|
|
61
|
+
return (0, proof_1.createProof)({
|
|
62
|
+
kind: 'attestation',
|
|
63
|
+
subject: {
|
|
64
|
+
id: manifest.rasterId,
|
|
65
|
+
kind: 'raster-manifest',
|
|
66
|
+
metadata: {
|
|
67
|
+
sourceType: manifest.sourceType,
|
|
68
|
+
layerType: manifest.layerType,
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
issuer: params.issuer ?? manifest.deviceId ?? manifest.operatorId ?? manifest.rasterId,
|
|
72
|
+
issuedAt: params.issuedAt,
|
|
73
|
+
expiresAt: params.expiresAt,
|
|
74
|
+
evidence: rasterEvidenceRefs(manifest, windowProof, spatialObjectId),
|
|
75
|
+
payload: {
|
|
76
|
+
rasterManifest: manifest,
|
|
77
|
+
...(windowProof ? { windowProof } : {}),
|
|
78
|
+
...(merkleProofs && merkleProofs.length > 0 ? { merkleProofs } : {}),
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Sign an unsigned raster proof with a WOTS key.
|
|
84
|
+
*
|
|
85
|
+
* The caller is responsible for reserving the WOTS key index (see
|
|
86
|
+
* @totemsdk/wots-lease) before calling — one-time key warning applies.
|
|
87
|
+
*/
|
|
88
|
+
function signRasterProof(unsigned, seed, keyIndex) {
|
|
89
|
+
return (0, proof_1.signProof)(unsigned, seed, keyIndex);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Verify a window proof payload against the manifest and any supplied Merkle
|
|
93
|
+
* proofs. Returns a failure reason string, or null when valid.
|
|
94
|
+
*/
|
|
95
|
+
function checkWindowProof(windowProof, manifest, merkleProofs) {
|
|
96
|
+
const { windowProofId: _wid, ...rest } = windowProof;
|
|
97
|
+
if ((0, canonical_js_1.computeRasterWindowProofId)(rest) !== windowProof.windowProofId) {
|
|
98
|
+
return 'windowProofId does not match recomputed value';
|
|
99
|
+
}
|
|
100
|
+
if (manifest.asset.merkleRoot && windowProof.merkleRoot !== manifest.asset.merkleRoot) {
|
|
101
|
+
return 'window proof merkleRoot does not match manifest asset.merkleRoot';
|
|
102
|
+
}
|
|
103
|
+
if (windowProof.rasterId !== manifest.rasterId) {
|
|
104
|
+
return 'window proof rasterId does not match manifest';
|
|
105
|
+
}
|
|
106
|
+
if (windowProof.chunkIndices.length === 0 || windowProof.chunkIndices.length !== windowProof.chunkHashes.length) {
|
|
107
|
+
return 'window proof chunkIndices must be non-empty and match chunkHashes length';
|
|
108
|
+
}
|
|
109
|
+
for (const proof of merkleProofs ?? []) {
|
|
110
|
+
if (!(0, merkle_js_1.verifyMerkleProof)(proof)) {
|
|
111
|
+
return 'a supplied merkle proof failed verification';
|
|
112
|
+
}
|
|
113
|
+
if (windowProof.merkleRoot && proof.root !== windowProof.merkleRoot) {
|
|
114
|
+
return 'a supplied merkle proof root does not match the window proof root';
|
|
115
|
+
}
|
|
116
|
+
if (!windowProof.chunkIndices.includes(proof.leafIndex)) {
|
|
117
|
+
return 'a supplied merkle proof leafIndex is not referenced by the window proof';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Verify a signed raster proof end to end.
|
|
124
|
+
*
|
|
125
|
+
* Checks:
|
|
126
|
+
* 1. the underlying @totemsdk/proof verification (signature, proofId, expiry)
|
|
127
|
+
* 2. payload contains a structurally valid RasterManifest
|
|
128
|
+
* 3. the manifest rasterId matches a recomputation from its fields
|
|
129
|
+
* 4. the manifest evidence hash matches the payload manifest
|
|
130
|
+
* 5. content hash and Merkle root evidence refs are present when declared
|
|
131
|
+
* 6. window proof (when supplied) has a recomputable ID, matches the
|
|
132
|
+
* manifest's Merkle root, and any supplied Merkle proofs verify
|
|
133
|
+
* 7. provenance structure is valid for derived rasters
|
|
134
|
+
*
|
|
135
|
+
* Anchoring is not required. Source raster manifests are not supplied inside
|
|
136
|
+
* the proof, so derivation checks are structural only (full cross-source
|
|
137
|
+
* verification is @totemsdk/raster-proof's verifyRasterDerivation).
|
|
138
|
+
*/
|
|
139
|
+
function verifyRasterProof(signed) {
|
|
140
|
+
const base = (0, proof_1.verifyProof)(signed);
|
|
141
|
+
if (!base.valid) {
|
|
142
|
+
return {
|
|
143
|
+
valid: false,
|
|
144
|
+
reason: base.reason,
|
|
145
|
+
signerAddress: base.signerAddress,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const signerAddress = signed.signature.address;
|
|
149
|
+
const manifest = signed.payload?.['rasterManifest'];
|
|
150
|
+
if (!manifest || typeof manifest !== 'object') {
|
|
151
|
+
return { valid: false, reason: 'payload missing rasterManifest', signerAddress };
|
|
152
|
+
}
|
|
153
|
+
const validation = (0, manifest_js_1.validateRasterManifest)(manifest);
|
|
154
|
+
if (!validation.valid) {
|
|
155
|
+
return {
|
|
156
|
+
valid: false,
|
|
157
|
+
reason: 'payload rasterManifest invalid: ' + validation.errors.join('; '),
|
|
158
|
+
payloadValid: false,
|
|
159
|
+
rasterId: manifest.rasterId,
|
|
160
|
+
signerAddress,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const { rasterId: _rasterId, ...rest } = manifest;
|
|
164
|
+
if ((0, canonical_js_1.computeRasterManifestId)(rest) !== manifest.rasterId) {
|
|
165
|
+
return {
|
|
166
|
+
valid: false,
|
|
167
|
+
reason: 'rasterId does not match recomputed value',
|
|
168
|
+
rasterIdValid: false,
|
|
169
|
+
rasterId: manifest.rasterId,
|
|
170
|
+
signerAddress,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const manifestEvidence = signed.evidence?.find((e) => e.id === manifest.rasterId && e.kind === 'raster-manifest');
|
|
174
|
+
if (!manifestEvidence) {
|
|
175
|
+
return {
|
|
176
|
+
valid: false,
|
|
177
|
+
reason: 'evidence missing raster-manifest ref',
|
|
178
|
+
rasterId: manifest.rasterId,
|
|
179
|
+
signerAddress,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (manifestEvidence.hash !== (0, canonical_js_1.hashRasterManifest)(manifest)) {
|
|
183
|
+
return {
|
|
184
|
+
valid: false,
|
|
185
|
+
reason: 'evidence hash does not match payload manifest',
|
|
186
|
+
manifestHashValid: false,
|
|
187
|
+
rasterId: manifest.rasterId,
|
|
188
|
+
signerAddress,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const contentEvidence = signed.evidence?.find((e) => e.kind === 'raster-content');
|
|
192
|
+
if (!contentEvidence || contentEvidence.hash !== manifest.asset.contentHash) {
|
|
193
|
+
return {
|
|
194
|
+
valid: false,
|
|
195
|
+
reason: 'evidence missing or mismatched raster-content hash',
|
|
196
|
+
rasterId: manifest.rasterId,
|
|
197
|
+
signerAddress,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (manifest.asset.merkleRoot) {
|
|
201
|
+
const merkleEvidence = signed.evidence?.find((e) => e.kind === 'raster-merkle-root');
|
|
202
|
+
if (!merkleEvidence || merkleEvidence.hash !== manifest.asset.merkleRoot) {
|
|
203
|
+
return {
|
|
204
|
+
valid: false,
|
|
205
|
+
reason: 'evidence missing or mismatched raster-merkle-root',
|
|
206
|
+
rasterId: manifest.rasterId,
|
|
207
|
+
signerAddress,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const windowProof = signed.payload?.['windowProof'];
|
|
212
|
+
if (windowProof) {
|
|
213
|
+
const merkleProofs = signed.payload?.['merkleProofs'];
|
|
214
|
+
const err = checkWindowProof(windowProof, manifest, merkleProofs);
|
|
215
|
+
if (err) {
|
|
216
|
+
return {
|
|
217
|
+
valid: false,
|
|
218
|
+
reason: err,
|
|
219
|
+
windowProofValid: false,
|
|
220
|
+
rasterId: manifest.rasterId,
|
|
221
|
+
signerAddress,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (manifest.sourceType === 'derived') {
|
|
226
|
+
const derivation = (0, provenance_js_1.structuralDerivationCheck)(manifest);
|
|
227
|
+
if (!derivation.valid) {
|
|
228
|
+
return {
|
|
229
|
+
valid: false,
|
|
230
|
+
reason: 'derivation structure invalid: ' + derivation.reasons?.join('; '),
|
|
231
|
+
derivationValid: false,
|
|
232
|
+
rasterId: manifest.rasterId,
|
|
233
|
+
signerAddress,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
valid: true,
|
|
239
|
+
signerAddress,
|
|
240
|
+
rasterId: manifest.rasterId,
|
|
241
|
+
payloadValid: true,
|
|
242
|
+
rasterIdValid: true,
|
|
243
|
+
manifestHashValid: true,
|
|
244
|
+
...(windowProof ? { windowProofValid: true } : {}),
|
|
245
|
+
...(manifest.sourceType === 'derived' ? { derivationValid: true } : {}),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proofgraph integration helpers for @totemsdk/raster-proof.
|
|
3
|
+
*
|
|
4
|
+
* Produces nodes and edges for @totemsdk/proofgraph without storage
|
|
5
|
+
* assumptions. Helpers never mutate a graph directly — callers combine the
|
|
6
|
+
* returned nodes/edges with addNode/addEdge.
|
|
7
|
+
*
|
|
8
|
+
* Note: @totemsdk/proofgraph has no native 'raster' node type, so raster
|
|
9
|
+
* manifests and window proofs map to the generic 'custom' node type (the
|
|
10
|
+
* same approach @totemsdk/location-proof and @totemsdk/spatial-proof use).
|
|
11
|
+
* If a dedicated 'raster' node type is ever wanted, propose it in
|
|
12
|
+
* @totemsdk/proofgraph (do not silently fork the vocabulary).
|
|
13
|
+
*/
|
|
14
|
+
import type { ProofGraph, ProofGraphNode, ProofGraphEdge } from '@totemsdk/proofgraph';
|
|
15
|
+
import type { RasterManifest, RasterWindowProof } from './types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Build a ProofGraphNode for a raster manifest ('custom' type).
|
|
18
|
+
* Node ID is deterministic: "custom:<rasterId>".
|
|
19
|
+
*/
|
|
20
|
+
export declare function rasterManifestToProofGraphNode(manifest: RasterManifest): ProofGraphNode;
|
|
21
|
+
/**
|
|
22
|
+
* Build a ProofGraphNode for a raster window proof ('custom' type).
|
|
23
|
+
* Node ID is deterministic: "custom:<windowProofId>".
|
|
24
|
+
*/
|
|
25
|
+
export declare function rasterWindowProofToProofGraphNode(windowProof: RasterWindowProof): ProofGraphNode;
|
|
26
|
+
/**
|
|
27
|
+
* Build ProofGraphEdges for a raster manifest:
|
|
28
|
+
* derived_from raster → each source raster (when provenance.derivedFrom)
|
|
29
|
+
* references raster → spatial object (when spatial.spatialObjectId)
|
|
30
|
+
* about raster → device (when deviceId)
|
|
31
|
+
* about raster → subject(operator) (when operatorId)
|
|
32
|
+
* about raster → subject(mission) (when missionId)
|
|
33
|
+
* references window proof → raster (see rasterWindowProofToGraphEdges)
|
|
34
|
+
*
|
|
35
|
+
* The "raster supports proof" edge is created by @totemsdk/proofgraph's
|
|
36
|
+
* addProof when the signed proof is added to the graph — this helper has no
|
|
37
|
+
* proof to link at construction time.
|
|
38
|
+
*
|
|
39
|
+
* Edge IDs are deterministic (content-derived in @totemsdk/proofgraph).
|
|
40
|
+
*/
|
|
41
|
+
export declare function rasterManifestToGraphEdges(manifest: RasterManifest): ProofGraphEdge[];
|
|
42
|
+
/**
|
|
43
|
+
* Build ProofGraphEdges for a raster window proof:
|
|
44
|
+
* derived_from window proof → raster
|
|
45
|
+
*/
|
|
46
|
+
export declare function rasterWindowProofToGraphEdges(windowProof: RasterWindowProof): ProofGraphEdge[];
|
|
47
|
+
/**
|
|
48
|
+
* Add a raster manifest as a 'custom' node to a proof graph (immutable —
|
|
49
|
+
* returns a new graph).
|
|
50
|
+
*/
|
|
51
|
+
export declare function addRasterManifestToGraph(graph: ProofGraph, manifest: RasterManifest): ProofGraph;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Proofgraph integration helpers for @totemsdk/raster-proof.
|
|
4
|
+
*
|
|
5
|
+
* Produces nodes and edges for @totemsdk/proofgraph without storage
|
|
6
|
+
* assumptions. Helpers never mutate a graph directly — callers combine the
|
|
7
|
+
* returned nodes/edges with addNode/addEdge.
|
|
8
|
+
*
|
|
9
|
+
* Note: @totemsdk/proofgraph has no native 'raster' node type, so raster
|
|
10
|
+
* manifests and window proofs map to the generic 'custom' node type (the
|
|
11
|
+
* same approach @totemsdk/location-proof and @totemsdk/spatial-proof use).
|
|
12
|
+
* If a dedicated 'raster' node type is ever wanted, propose it in
|
|
13
|
+
* @totemsdk/proofgraph (do not silently fork the vocabulary).
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.rasterManifestToProofGraphNode = rasterManifestToProofGraphNode;
|
|
17
|
+
exports.rasterWindowProofToProofGraphNode = rasterWindowProofToProofGraphNode;
|
|
18
|
+
exports.rasterManifestToGraphEdges = rasterManifestToGraphEdges;
|
|
19
|
+
exports.rasterWindowProofToGraphEdges = rasterWindowProofToGraphEdges;
|
|
20
|
+
exports.addRasterManifestToGraph = addRasterManifestToGraph;
|
|
21
|
+
const proofgraph_1 = require("@totemsdk/proofgraph");
|
|
22
|
+
/**
|
|
23
|
+
* Build a ProofGraphNode for a raster manifest ('custom' type).
|
|
24
|
+
* Node ID is deterministic: "custom:<rasterId>".
|
|
25
|
+
*/
|
|
26
|
+
function rasterManifestToProofGraphNode(manifest) {
|
|
27
|
+
return {
|
|
28
|
+
id: (0, proofgraph_1.computeNodeId)('custom', manifest.rasterId),
|
|
29
|
+
type: 'custom',
|
|
30
|
+
refId: manifest.rasterId,
|
|
31
|
+
data: {
|
|
32
|
+
kind: 'raster-manifest',
|
|
33
|
+
sourceType: manifest.sourceType,
|
|
34
|
+
layerType: manifest.layerType,
|
|
35
|
+
contentHash: manifest.asset.contentHash,
|
|
36
|
+
...(manifest.asset.merkleRoot ? { merkleRoot: manifest.asset.merkleRoot } : {}),
|
|
37
|
+
...(manifest.spatial?.spatialObjectId ? { spatialObjectId: manifest.spatial.spatialObjectId } : {}),
|
|
38
|
+
...(manifest.deviceId ? { deviceId: manifest.deviceId } : {}),
|
|
39
|
+
},
|
|
40
|
+
createdAt: manifest.createdAt,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build a ProofGraphNode for a raster window proof ('custom' type).
|
|
45
|
+
* Node ID is deterministic: "custom:<windowProofId>".
|
|
46
|
+
*/
|
|
47
|
+
function rasterWindowProofToProofGraphNode(windowProof) {
|
|
48
|
+
return {
|
|
49
|
+
id: (0, proofgraph_1.computeNodeId)('custom', windowProof.windowProofId),
|
|
50
|
+
type: 'custom',
|
|
51
|
+
refId: windowProof.windowProofId,
|
|
52
|
+
data: {
|
|
53
|
+
kind: 'raster-window-proof',
|
|
54
|
+
rasterId: windowProof.rasterId,
|
|
55
|
+
merkleRoot: windowProof.merkleRoot,
|
|
56
|
+
chunkIndices: windowProof.chunkIndices,
|
|
57
|
+
hashes: windowProof.chunkHashes,
|
|
58
|
+
},
|
|
59
|
+
createdAt: windowProof.createdAt,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build ProofGraphEdges for a raster manifest:
|
|
64
|
+
* derived_from raster → each source raster (when provenance.derivedFrom)
|
|
65
|
+
* references raster → spatial object (when spatial.spatialObjectId)
|
|
66
|
+
* about raster → device (when deviceId)
|
|
67
|
+
* about raster → subject(operator) (when operatorId)
|
|
68
|
+
* about raster → subject(mission) (when missionId)
|
|
69
|
+
* references window proof → raster (see rasterWindowProofToGraphEdges)
|
|
70
|
+
*
|
|
71
|
+
* The "raster supports proof" edge is created by @totemsdk/proofgraph's
|
|
72
|
+
* addProof when the signed proof is added to the graph — this helper has no
|
|
73
|
+
* proof to link at construction time.
|
|
74
|
+
*
|
|
75
|
+
* Edge IDs are deterministic (content-derived in @totemsdk/proofgraph).
|
|
76
|
+
*/
|
|
77
|
+
function rasterManifestToGraphEdges(manifest) {
|
|
78
|
+
const edges = [];
|
|
79
|
+
for (const src of manifest.provenance?.derivedFrom ?? []) {
|
|
80
|
+
edges.push((0, proofgraph_1.buildEdge)('derived_from', manifest.rasterId, src, manifest.rasterId, {
|
|
81
|
+
kind: 'raster-source',
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
if (manifest.spatial?.spatialObjectId) {
|
|
85
|
+
edges.push((0, proofgraph_1.buildEdge)('references', manifest.rasterId, manifest.spatial.spatialObjectId, manifest.rasterId, {
|
|
86
|
+
kind: 'spatial-object',
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
if (manifest.deviceId) {
|
|
90
|
+
edges.push((0, proofgraph_1.buildEdge)('about', manifest.rasterId, manifest.deviceId, manifest.rasterId, { kind: 'device' }));
|
|
91
|
+
}
|
|
92
|
+
if (manifest.operatorId) {
|
|
93
|
+
edges.push((0, proofgraph_1.buildEdge)('about', manifest.rasterId, manifest.operatorId, manifest.rasterId, { kind: 'operator' }));
|
|
94
|
+
}
|
|
95
|
+
if (manifest.missionId) {
|
|
96
|
+
edges.push((0, proofgraph_1.buildEdge)('about', manifest.rasterId, manifest.missionId, manifest.rasterId, { kind: 'mission' }));
|
|
97
|
+
}
|
|
98
|
+
return edges;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Build ProofGraphEdges for a raster window proof:
|
|
102
|
+
* derived_from window proof → raster
|
|
103
|
+
*/
|
|
104
|
+
function rasterWindowProofToGraphEdges(windowProof) {
|
|
105
|
+
return [
|
|
106
|
+
(0, proofgraph_1.buildEdge)('derived_from', windowProof.windowProofId, windowProof.rasterId, windowProof.windowProofId, {
|
|
107
|
+
kind: 'raster-window-proof',
|
|
108
|
+
}),
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Add a raster manifest as a 'custom' node to a proof graph (immutable —
|
|
113
|
+
* returns a new graph).
|
|
114
|
+
*/
|
|
115
|
+
function addRasterManifestToGraph(graph, manifest) {
|
|
116
|
+
return (0, proofgraph_1.addNode)(graph, 'custom', manifest.rasterId, {
|
|
117
|
+
kind: 'raster-manifest',
|
|
118
|
+
...manifest,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derived raster provenance for @totemsdk/raster-proof.
|
|
3
|
+
*
|
|
4
|
+
* createDerivedRasterManifest records a raster produced from other rasters
|
|
5
|
+
* (satellite scene → water mask, image set → orthomosaic, before/after →
|
|
6
|
+
* change mask, …). verifyRasterDerivation checks the DECLARED provenance
|
|
7
|
+
* structure — that every derivedFrom ID is supplied, parameters are present
|
|
8
|
+
* when a pipeline is named, and the manifest is honestly marked as derived.
|
|
9
|
+
*
|
|
10
|
+
* It does NOT verify that image processing was performed correctly. That is
|
|
11
|
+
* outside this package's scope.
|
|
12
|
+
*/
|
|
13
|
+
import type { CreateDerivedRasterManifestParams, RasterDerivationVerifyResult, RasterManifest } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* Create a derived raster manifest from source rasters. sourceType is forced
|
|
16
|
+
* to 'derived'; provenance.derivedFrom lists the source raster IDs.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createDerivedRasterManifest(params: CreateDerivedRasterManifestParams): RasterManifest;
|
|
19
|
+
/**
|
|
20
|
+
* Structural derivation check (no source manifests required). Used both by
|
|
21
|
+
* verifyRasterDerivation (with sources) and by proof verification (where the
|
|
22
|
+
* signer's source rasters are not inside the proof).
|
|
23
|
+
*/
|
|
24
|
+
export declare function structuralDerivationCheck(manifest: RasterManifest): Omit<RasterDerivationVerifyResult, 'sourceRasterIds' | 'missingSources'>;
|
|
25
|
+
/**
|
|
26
|
+
* Verify the declared provenance structure of a derived raster manifest
|
|
27
|
+
* against the supplied source manifests.
|
|
28
|
+
*/
|
|
29
|
+
export declare function verifyRasterDerivation(manifest: RasterManifest, sourceManifests: RasterManifest[]): RasterDerivationVerifyResult;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Derived raster provenance for @totemsdk/raster-proof.
|
|
4
|
+
*
|
|
5
|
+
* createDerivedRasterManifest records a raster produced from other rasters
|
|
6
|
+
* (satellite scene → water mask, image set → orthomosaic, before/after →
|
|
7
|
+
* change mask, …). verifyRasterDerivation checks the DECLARED provenance
|
|
8
|
+
* structure — that every derivedFrom ID is supplied, parameters are present
|
|
9
|
+
* when a pipeline is named, and the manifest is honestly marked as derived.
|
|
10
|
+
*
|
|
11
|
+
* It does NOT verify that image processing was performed correctly. That is
|
|
12
|
+
* outside this package's scope.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.createDerivedRasterManifest = createDerivedRasterManifest;
|
|
16
|
+
exports.structuralDerivationCheck = structuralDerivationCheck;
|
|
17
|
+
exports.verifyRasterDerivation = verifyRasterDerivation;
|
|
18
|
+
const manifest_js_1 = require("./manifest.js");
|
|
19
|
+
/**
|
|
20
|
+
* Create a derived raster manifest from source rasters. sourceType is forced
|
|
21
|
+
* to 'derived'; provenance.derivedFrom lists the source raster IDs.
|
|
22
|
+
*/
|
|
23
|
+
function createDerivedRasterManifest(params) {
|
|
24
|
+
const { sourceManifests, layerType, asset, pipelineId, pipelineVersion, parametersHash, modelId, uncertainty, operatorId, ...rest } = params;
|
|
25
|
+
if (sourceManifests.length === 0) {
|
|
26
|
+
throw new Error('a derived raster requires at least one source manifest');
|
|
27
|
+
}
|
|
28
|
+
if (pipelineId !== undefined && parametersHash === undefined) {
|
|
29
|
+
throw new Error('parametersHash is required when pipelineId is set');
|
|
30
|
+
}
|
|
31
|
+
return (0, manifest_js_1.createRasterManifest)({
|
|
32
|
+
sourceType: 'derived',
|
|
33
|
+
layerType,
|
|
34
|
+
asset,
|
|
35
|
+
provenance: {
|
|
36
|
+
derivedFrom: sourceManifests.map((m) => m.rasterId),
|
|
37
|
+
...(pipelineId !== undefined ? { pipelineId } : {}),
|
|
38
|
+
...(pipelineVersion !== undefined ? { pipelineVersion } : {}),
|
|
39
|
+
...(parametersHash !== undefined ? { parametersHash } : {}),
|
|
40
|
+
...(modelId !== undefined ? { modelId } : {}),
|
|
41
|
+
...(uncertainty !== undefined && uncertainty.length > 0 ? { uncertainty } : {}),
|
|
42
|
+
...(operatorId !== undefined ? { operatorId } : {}),
|
|
43
|
+
},
|
|
44
|
+
...rest,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Structural derivation check (no source manifests required). Used both by
|
|
49
|
+
* verifyRasterDerivation (with sources) and by proof verification (where the
|
|
50
|
+
* signer's source rasters are not inside the proof).
|
|
51
|
+
*/
|
|
52
|
+
function structuralDerivationCheck(manifest) {
|
|
53
|
+
const reasons = [];
|
|
54
|
+
if (manifest.sourceType !== 'derived') {
|
|
55
|
+
reasons.push('manifest.sourceType must be "derived"');
|
|
56
|
+
}
|
|
57
|
+
if (!manifest.asset || typeof manifest.asset.contentHash !== 'string' || manifest.asset.contentHash.length === 0) {
|
|
58
|
+
reasons.push('derived raster must declare asset.contentHash');
|
|
59
|
+
}
|
|
60
|
+
const derivedFrom = manifest.provenance?.derivedFrom ?? [];
|
|
61
|
+
if (derivedFrom.length === 0) {
|
|
62
|
+
reasons.push('derived raster must declare provenance.derivedFrom');
|
|
63
|
+
}
|
|
64
|
+
if (manifest.provenance?.pipelineId !== undefined && manifest.provenance.parametersHash === undefined) {
|
|
65
|
+
reasons.push('parametersHash is required when pipelineId is present');
|
|
66
|
+
}
|
|
67
|
+
if (manifest.provenance?.uncertainty !== undefined) {
|
|
68
|
+
const bad = manifest.provenance.uncertainty.some((u) => typeof u !== 'string' || u.length === 0);
|
|
69
|
+
if (bad) {
|
|
70
|
+
reasons.push('provenance.uncertainty must be an array of non-empty strings');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { valid: reasons.length === 0, ...(reasons.length > 0 ? { reasons } : {}) };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Verify the declared provenance structure of a derived raster manifest
|
|
77
|
+
* against the supplied source manifests.
|
|
78
|
+
*/
|
|
79
|
+
function verifyRasterDerivation(manifest, sourceManifests) {
|
|
80
|
+
const structural = structuralDerivationCheck(manifest);
|
|
81
|
+
const reasons = structural.reasons ?? [];
|
|
82
|
+
const derivedFrom = manifest.provenance?.derivedFrom ?? [];
|
|
83
|
+
const supplied = new Set(sourceManifests.map((m) => m.rasterId));
|
|
84
|
+
const missing = derivedFrom.filter((id) => !supplied.has(id));
|
|
85
|
+
if (missing.length > 0) {
|
|
86
|
+
reasons.push(`derivedFrom references missing source rasters: ${missing.join(', ')}`);
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
valid: reasons.length === 0,
|
|
90
|
+
...(reasons.length > 0 ? { reasons } : {}),
|
|
91
|
+
sourceRasterIds: derivedFrom,
|
|
92
|
+
...(missing.length > 0 ? { missingSources: missing } : {}),
|
|
93
|
+
...(manifest.provenance?.uncertainty !== undefined ? { uncertainty: manifest.provenance.uncertainty } : {}),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @totemsdk/spatial-proof integration for @totemsdk/raster-proof.
|
|
3
|
+
*
|
|
4
|
+
* Bridges a raster manifest's bounds into a @totemsdk/spatial-proof
|
|
5
|
+
* SpatialObject and evaluates spatial relations (covers, intersects,
|
|
6
|
+
* overlaps, covered_by, …) against site boundaries, zones, routes, scene
|
|
7
|
+
* footprints and inspection areas. All geometry math is delegated to
|
|
8
|
+
* @totemsdk/spatial-proof — nothing here is reimplemented.
|
|
9
|
+
*/
|
|
10
|
+
import type { SpatialObject, SpatialRelationClaim, SpatialRelationType } from '@totemsdk/spatial-proof';
|
|
11
|
+
import type { CreateRasterSpatialRelationParams, RasterManifest } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Convert a raster manifest into a spatial object footprint, or null when the
|
|
14
|
+
* manifest has no bounds (nothing to georeference).
|
|
15
|
+
*/
|
|
16
|
+
export declare function rasterFootprintToSpatialObject(manifest: RasterManifest): SpatialObject | null;
|
|
17
|
+
/**
|
|
18
|
+
* Evaluate a spatial relation between a raster footprint and a spatial
|
|
19
|
+
* object, producing a deterministic SpatialRelationClaim via
|
|
20
|
+
* @totemsdk/spatial-proof. Requires the manifest to have bounds.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createRasterSpatialRelation(params: CreateRasterSpatialRelationParams): SpatialRelationClaim;
|
|
23
|
+
export type { SpatialRelationType };
|
package/dist/spatial.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @totemsdk/spatial-proof integration for @totemsdk/raster-proof.
|
|
4
|
+
*
|
|
5
|
+
* Bridges a raster manifest's bounds into a @totemsdk/spatial-proof
|
|
6
|
+
* SpatialObject and evaluates spatial relations (covers, intersects,
|
|
7
|
+
* overlaps, covered_by, …) against site boundaries, zones, routes, scene
|
|
8
|
+
* footprints and inspection areas. All geometry math is delegated to
|
|
9
|
+
* @totemsdk/spatial-proof — nothing here is reimplemented.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.rasterFootprintToSpatialObject = rasterFootprintToSpatialObject;
|
|
13
|
+
exports.createRasterSpatialRelation = createRasterSpatialRelation;
|
|
14
|
+
const spatial_proof_1 = require("@totemsdk/spatial-proof");
|
|
15
|
+
/**
|
|
16
|
+
* Build a bbox Polygon (GeoJSON [lon, lat], closed ring) from manifest bounds.
|
|
17
|
+
*/
|
|
18
|
+
function footprintPolygon(bounds) {
|
|
19
|
+
const [minLon, minLat, maxLon, maxLat] = bounds;
|
|
20
|
+
return {
|
|
21
|
+
type: 'Polygon',
|
|
22
|
+
coordinates: [[
|
|
23
|
+
[minLon, minLat],
|
|
24
|
+
[maxLon, minLat],
|
|
25
|
+
[maxLon, maxLat],
|
|
26
|
+
[minLon, maxLat],
|
|
27
|
+
[minLon, minLat],
|
|
28
|
+
]],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Convert a raster manifest into a spatial object footprint, or null when the
|
|
33
|
+
* manifest has no bounds (nothing to georeference).
|
|
34
|
+
*/
|
|
35
|
+
function rasterFootprintToSpatialObject(manifest) {
|
|
36
|
+
const bounds = manifest.spatial?.bounds;
|
|
37
|
+
if (!bounds || bounds.length !== 4) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const geometry = footprintPolygon(bounds);
|
|
41
|
+
const body = {
|
|
42
|
+
kind: 'scene-footprint',
|
|
43
|
+
geometry,
|
|
44
|
+
...(manifest.spatial?.crs !== undefined ? { crs: manifest.spatial.crs } : {}),
|
|
45
|
+
...(manifest.spatial?.spatialObjectId !== undefined ? { spatialId: manifest.spatial.spatialObjectId } : {}),
|
|
46
|
+
...(manifest.rasterId !== undefined ? { name: `raster ${manifest.rasterId}` } : {}),
|
|
47
|
+
};
|
|
48
|
+
const spatialObject = {
|
|
49
|
+
...body,
|
|
50
|
+
spatialId: body.spatialId ?? (0, spatial_proof_1.computeSpatialObjectId)(body),
|
|
51
|
+
};
|
|
52
|
+
return spatialObject;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Evaluate a spatial relation between a raster footprint and a spatial
|
|
56
|
+
* object, producing a deterministic SpatialRelationClaim via
|
|
57
|
+
* @totemsdk/spatial-proof. Requires the manifest to have bounds.
|
|
58
|
+
*/
|
|
59
|
+
function createRasterSpatialRelation(params) {
|
|
60
|
+
const { manifest, spatialObject, relation, computedAt, maxDistanceM, subjectProofId, metadata } = params;
|
|
61
|
+
const bounds = manifest.spatial?.bounds;
|
|
62
|
+
if (!bounds || bounds.length !== 4) {
|
|
63
|
+
throw new Error('createRasterSpatialRelation requires manifest.spatial.bounds');
|
|
64
|
+
}
|
|
65
|
+
return (0, spatial_proof_1.evaluateSpatialRelation)({
|
|
66
|
+
subjectId: manifest.rasterId,
|
|
67
|
+
subjectKind: 'raster-manifest',
|
|
68
|
+
spatialObject,
|
|
69
|
+
relation,
|
|
70
|
+
subjectGeometry: footprintPolygon(bounds),
|
|
71
|
+
rasterManifestId: manifest.rasterId,
|
|
72
|
+
...(computedAt !== undefined ? { computedAt } : {}),
|
|
73
|
+
...(maxDistanceM !== undefined ? { maxDistanceM } : {}),
|
|
74
|
+
...(subjectProofId !== undefined ? { subjectProofId } : {}),
|
|
75
|
+
...(metadata !== undefined ? { metadata } : {}),
|
|
76
|
+
});
|
|
77
|
+
}
|