@trylimbo/sdk-verifier-wasm 0.2.25-canary.37 → 0.2.25

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.
@@ -16,31 +16,37 @@ export interface RangeSource {
16
16
 
17
17
 
18
18
  /**
19
- * A `soft-binding-block-map`. No scope is the whole content.
19
+ * A C2PA soft binding: an algorithm id (from the C2PA soft-binding algorithm
20
+ * list, e.g. `io.iscc.v0`) plus its algorithm-specific value (the `ISCC:…` code,
21
+ * a watermark token, …). The signer embeds it as a `c2pa.soft-binding` assertion
22
+ * and indexes it, so a transcoded copy whose exact content hash no longer
23
+ * matches still recovers the manifest from the repository.
20
24
  */
21
- export interface Block {
22
- value: Uint8Array;
23
- scope?: Scope;
24
- }
25
-
26
- /**
27
- * A `soft-binding-scope-map`.
28
- */
29
- export interface Scope {
30
- timespan?: Timespan;
25
+ export interface SoftBinding {
26
+ /**
27
+ * C2PA soft-binding algorithm id, e.g. `io.iscc.v0`.
28
+ */
29
+ alg: string;
30
+ /**
31
+ * Algorithm-specific binding value: the canonical string the algorithm
32
+ * produces (an `ISCC:…` code, a watermark token). Its UTF-8 bytes are what
33
+ * the repository lookup base64-encodes.
34
+ */
35
+ value: string;
31
36
  }
32
37
 
33
38
  /**
34
- * A `soft-binding-timespan-map`: where the range starts in the media and how long it lasts, in
35
- * milliseconds.
39
+ * A binder spelled as data, so it crosses into a worker as well as the direct import: the
40
+ * SDK\'s own two. A browser has no host binder: a detector runs repository-side.
36
41
  */
37
- export interface Timespan {
38
- start: number;
39
- duration: number;
40
- }
42
+ export type BinderSpec = { kind: "iscc" } | { kind: "held"; binding: SoftBinding };
41
43
 
42
44
  /**
43
45
  * A canonical gRPC/Connect status code: the coarse, closed failure class.
46
+ *
47
+ * The wasm lane projects this as a camelCase string like every other tagged value
48
+ * there, so a consumer narrows on `err.code === \"resourceExhausted\"`; the native lane
49
+ * projects an enum.
44
50
  */
45
51
  export type Code = "canceled" | "unknown" | "invalidArgument" | "deadlineExceeded" | "notFound" | "alreadyExists" | "permissionDenied" | "resourceExhausted" | "failedPrecondition" | "aborted" | "outOfRange" | "unimplemented" | "internal" | "unavailable" | "dataLoss" | "unauthenticated";
46
52
 
@@ -71,11 +77,11 @@ export interface ReasonError {
71
77
  /**
72
78
  * A session signing key from the init manifest\'s roster (spec §19.4.4).
73
79
  */
74
- export interface SessionKey {
80
+ export interface SessionKeySummary {
75
81
  /**
76
82
  * Identifier of the session signing key.
77
83
  */
78
- kid: Uint8Array;
84
+ keyId: Uint8Array;
79
85
  /**
80
86
  * The session key\'s public half (SEC1-encoded bytes).
81
87
  */
@@ -91,33 +97,103 @@ export interface StatusError {
91
97
  }
92
98
 
93
99
  /**
94
- * An asset a repository downloads, as the `byReference` request body names it.
100
+ * C2PA validation state of a manifest (spec §14.3).
95
101
  */
96
- export interface Reference {
102
+ export type ValidationState = "Invalid" | "Valid" | "Trusted";
103
+
104
+ /**
105
+ * Construction options for [`AssetVerifier::new`] (and the `AssetVerifier.create` JS
106
+ * binding). Every field is stated: nothing here is chosen on the caller\'s behalf.
107
+ *
108
+ * One definition, all lanes: `#[binding]` derives the shapes directly here:
109
+ * tsify (camelCase) on wasm, a `uniffi::Record` on the native `ffi` build, so there is no
110
+ * per-lane DTO copy. Off both lanes it is a plain struct.
111
+ */
112
+ export interface AssetVerifierOptions {
113
+ /**
114
+ * The C2PA manifest repositories recovery asks, each a Soft Binding Resolution API declared
115
+ * for exactly the algorithms it may be asked for. Results merge by manifest, and a match\'s
116
+ * `endpoint` is fetched from only when it names one of these. Empty: no recovery can be
117
+ * asked of this verifier.
118
+ */
119
+ repositories: Repository[];
97
120
  /**
98
- * A short-lived https URL without credentials.
121
+ * PEM trust anchors for the manifest signers the caller trusts.
99
122
  */
100
- url: string;
123
+ trustAnchors: string[];
101
124
  /**
102
- * The asset\'s size in bytes.
125
+ * PEM trust anchors for the time-stamping authorities the caller trusts.
103
126
  */
104
- length: number;
127
+ tsaTrustAnchors: string[];
105
128
  /**
106
- * The asset\'s media type.
129
+ * Also trust the bundled official C2PA anchors, manifest and TSA lists, beside the
130
+ * caller\'s. `false` trusts the caller\'s lists alone.
107
131
  */
108
- format?: string;
109
- ranges?: import('@contentauth/c2pa-types').Range[];
132
+ trustC2paAnchors: boolean;
133
+ /**
134
+ * Issuer DIDs whose CAWG identity (ICA) credentials count as validated, matched
135
+ * exactly against the credential issuer. Empty trusts no issuer: every identity assertion
136
+ * then reports `cawg.ica.untrusted_issuer` and withholds `cawg.ica.credential_valid`,
137
+ * which leaves the manifest\'s own validity untouched.
138
+ */
139
+ trustedIcaIssuers: string[];
110
140
  }
111
141
 
112
142
  /**
113
- * C2PA validation state of a manifest (spec §14.3).
143
+ * Construction options for [`StreamVerifier::new`] (and the `StreamVerifier.create`
144
+ * JS binding). Every field is stated: nothing here is chosen on the caller\'s behalf.
145
+ *
146
+ * `#[binding]` derives the wasm shape (`trustC2paAnchors` camelCase) and,
147
+ * with `ffi`, a `uniffi::Record` for the native `StreamVerifier.create` binding, so there
148
+ * is no per-lane DTO copy. Off both lanes it is a plain struct.
114
149
  */
115
- export type ValidationState = "Invalid" | "Valid" | "Trusted";
150
+ export interface StreamVerifierOptions {
151
+ /**
152
+ * PEM trust anchors for the manifest signers the caller trusts.
153
+ */
154
+ trustAnchors: string[];
155
+ /**
156
+ * PEM trust anchors for the time-stamping authorities the caller trusts.
157
+ */
158
+ tsaTrustAnchors: string[];
159
+ /**
160
+ * Also trust the bundled official C2PA anchors, manifest and TSA lists, beside the
161
+ * caller\'s. `false` trusts the caller\'s lists alone.
162
+ */
163
+ trustC2paAnchors: boolean;
164
+ /**
165
+ * Issuer DIDs whose CAWG identity (ICA) credentials count as validated, matched
166
+ * exactly against the credential issuer. Empty trusts no issuer: an identity assertion
167
+ * on the init segment\'s manifest then reports `cawg.ica.untrusted_issuer` and withholds
168
+ * `cawg.ica.credential_valid`.
169
+ */
170
+ trustedIcaIssuers: string[];
171
+ /**
172
+ * How far a segment\'s timestamp may sit from wall-clock before it is rejected as
173
+ * skewed, in seconds: the deployment\'s own encoder-clock allowance, stated rather than
174
+ * assumed.
175
+ */
176
+ segmentSkewToleranceSecs: number;
177
+ }
178
+
179
+ /**
180
+ * Everything one `derive` needs beyond the asset: how its format is known. The same record
181
+ * the native lane\'s `DeriveOptions` is, spelled as data.
182
+ */
183
+ export interface DeriveOptions {
184
+ format: AssetFormat;
185
+ }
186
+
187
+ /**
188
+ * How a call knows the asset\'s format: stated by the caller, or read from the leading bytes.
189
+ * Stated, never defaulted: sniffing is a choice made by name.
190
+ */
191
+ export type AssetFormat = { kind: "sniff" } | { kind: "declared"; mediaType: string };
116
192
 
117
193
  /**
118
194
  * One C2PA manifest repository, as the Soft Binding Resolution API spec lets a client find it.
119
195
  */
120
- export type Repository = { kind: "named"; url: string; algorithms: string[] } | { kind: "registered"; alg: string };
196
+ export type Repository = { kind: "named"; url: string; algorithms: string[] } | { kind: "listed"; algorithm: string };
121
197
 
122
198
  /**
123
199
  * One C2PA validation status entry (spec §15.3): the registered code, its kind, and the
@@ -151,7 +227,13 @@ export interface FieldViolation {
151
227
  */
152
228
  export interface Credential {
153
229
  /**
154
- * Where this credential came from.
230
+ * The bytes behind every thumbnail the manifests reference, by that reference\'s
231
+ * `identifier`: each manifest\'s claim thumbnail and each ingredient\'s. The manifests state
232
+ * identifiers and no images, so this is what a chain draws from.
233
+ */
234
+ thumbnails: Record<string, Uint8Array>;
235
+ /**
236
+ * Where this credential came from. See [`CredentialOrigin`].
155
237
  */
156
238
  origin: CredentialOrigin;
157
239
  manifest: import('@contentauth/c2pa-types').ManifestStore;
@@ -160,40 +242,18 @@ export interface Credential {
160
242
  */
161
243
  hardBinding: HardBinding;
162
244
  /**
163
- * Where this credential sits among the others returned.
245
+ * Where this credential sits among the others returned. See [`crate::asset::Lineage`].
164
246
  */
165
247
  lineage: Lineage;
166
248
  }
167
249
 
168
- /**
169
- * One query that located a recovered credential: how it was asked, under which algorithm, and
170
- * where the manifest came from.
171
- */
172
- export interface Discovery {
173
- via: DiscoveryVia;
174
- alg: string;
175
- type: SoftBindingType;
176
- /**
177
- * 0-100, the repository\'s `similarityScore`.
178
- */
179
- score?: number;
180
- repository: string;
181
- /**
182
- * The resolution API the manifest was fetched from, when not `repository`.
183
- */
184
- endpoint?: string;
185
- }
186
-
187
250
  /**
188
251
  * Outcome of validating a media segment against its stream\'s init.
189
252
  */
190
253
  export interface MediaValidation {
191
- /**
192
- * `invalid` on any failure, else the state of the init manifest the segment\'s key came from.
193
- */
194
- state: ValidationState;
254
+ valid: boolean;
195
255
  codes: ValidationCode[];
196
- kid: Uint8Array;
256
+ keyId: Uint8Array;
197
257
  timing: SegmentTiming;
198
258
  manifestId: string;
199
259
  }
@@ -205,7 +265,7 @@ export interface InitValidation {
205
265
  state: ValidationState;
206
266
  codes: ValidationCode[];
207
267
  manifest: import('@contentauth/c2pa-types').ManifestStore;
208
- sessionKeys: SessionKey[];
268
+ sessionKeys: SessionKeySummary[];
209
269
  }
210
270
 
211
271
  /**
@@ -213,202 +273,125 @@ export interface InitValidation {
213
273
  */
214
274
  export type SegmentValidation = ({ kind: "init" } & InitValidation) | ({ kind: "media" } & MediaValidation) | { kind: "unknown" };
215
275
 
216
- /**
217
- * The C2PA 2.4 golden-flow comparison of the embedded manifest against what the repository holds.
218
- */
219
- export type Golden = { kind: "matches"; index: number } | { kind: "differs"; index: number } | { kind: "noneMatches"; candidates: number[] } | { kind: "unreadable"; index: number };
220
-
221
- /**
222
- * The C2PA list\'s `type` of a soft binding algorithm.
223
- */
224
- export type SoftBindingType = "fingerprint" | "watermark";
225
-
226
- /**
227
- * The Soft Binding Resolution API route a discovery came through.
228
- */
229
- export type DiscoveryVia = { kind: "byBinding"; value: Uint8Array } | { kind: "byContent"; hint?: Hint } | { kind: "byReference"; hint?: Hint };
230
-
231
276
  /**
232
277
  * The error every SDK call throws: a decoded `google.rpc.Status`, discriminated
233
278
  * by `kind`. A consumer switches on `err.kind` (`\"reason\" | \"invalid\" | \"status\"`)
234
279
  * and reads the shape-specific fields; `code` and `message` are common to every
235
- * shape.
280
+ * shape. Thrown as a plain object across the wasm boundary (tsify).
236
281
  */
237
282
  export type SdkError = ({ kind: "status" } & StatusError) | ({ kind: "reason" } & ReasonError) | ({ kind: "invalid" } & InvalidError);
238
283
 
239
284
  /**
240
- * The evidence that singled a recovered verdict out.
285
+ * Timing facts carried by a media segment\'s container.
241
286
  */
242
- export type VerdictRule = "onlyCandidate" | "notSuperseded" | "hardBinding";
243
-
244
- /**
245
- * The query a repository answers from the content: `matches/byReference` when `reference` is
246
- * stated, so nothing is uploaded, else `matches/byContent` with the asset in the request.
247
- */
248
- export interface Content {
249
- when: ContentWhen;
287
+ export interface SegmentTiming {
250
288
  /**
251
- * Where each repository downloads the asset from.
289
+ * Media segment sequence number (exact below 2^53).
252
290
  */
253
- reference?: Reference;
291
+ sequenceNumber: number;
254
292
  /**
255
- * The largest asset an upload sends, in bytes; a larger one is reported `tooLarge`. Absent,
256
- * 64 MiB.
293
+ * MP4 timescale (ticks per second) for this segment\'s timing, if present.
257
294
  */
258
- maxUploadBytes?: number;
259
- }
260
-
261
- /**
262
- * The re-sign chain between the returned credentials, by manifest label.
263
- */
264
- export interface Lineage {
265
- supersedes: string[];
266
- supersededBy: string[];
267
- }
268
-
269
- /**
270
- * The value a content query was hinted with, under its own algorithm.
271
- */
272
- export interface Hint {
273
- alg: string;
274
- value: Uint8Array;
275
- }
276
-
277
- /**
278
- * Timing a media segment\'s container carries.
279
- */
280
- export interface SegmentTiming {
281
- /**
282
- * The segment\'s `sequenceNumber` (exact below 2^53).
283
- */
284
- sequence: number;
295
+ timescale?: number;
285
296
  /**
286
- * The span its C2PA `emsg` covers, in milliseconds.
297
+ * Segment duration in seconds, if the container reports it.
287
298
  */
288
- duration?: number;
299
+ eventDurationSecs?: number;
289
300
  }
290
301
 
291
302
  /**
292
- * What a stream verifier trusts, and how far a segment\'s clock may drift.
303
+ * What one verify may do to recover a manifest, as data: the binders this client derives for
304
+ * itself, decided into `matches/byBinding`, and one field per content operation, absent when
305
+ * not to be called. It needs a configured repository and at least one query.
293
306
  */
294
- export interface StreamVerifierOptions {
295
- trust: Trust;
296
- /**
297
- * How far a segment\'s presentation time may sit outside its session key\'s validity period,
298
- * in milliseconds. Absent, 5 minutes.
299
- */
300
- skewTolerance?: number;
307
+ export interface Recovery {
308
+ when: RecoveryTrigger;
309
+ binders: BinderSpec[];
310
+ byContent?: ByContent;
311
+ byReference?: ByReference;
301
312
  }
302
313
 
303
314
  /**
304
- * What a verifier trusts. An omitted list trusts nothing.
315
+ * When [`AssetVerifier::verify_asset`] queries the repository.
305
316
  */
306
- export interface Trust {
307
- /**
308
- * PEM anchors for the manifest signers the caller trusts.
309
- */
310
- anchors?: string[];
311
- /**
312
- * PEM anchors for the time-stamping authorities the caller trusts.
313
- */
314
- tsaAnchors?: string[];
315
- /**
316
- * Also trust the bundled official C2PA manifest and TSA lists, beside the caller\'s.
317
- */
318
- c2pa: boolean;
319
- /**
320
- * Issuer DIDs whose CAWG identity (ICA) credentials count as validated, matched exactly
321
- * against the credential issuer. Empty trusts no issuer: every identity assertion then
322
- * reports `cawg.ica.untrusted_issuer` and withholds `cawg.ica.credential_valid`, which leaves
323
- * the manifest\'s own validity untouched.
324
- */
325
- icaIssuers?: string[];
326
- }
317
+ export type RecoveryTrigger = "manifestMissing" | "always";
327
318
 
328
319
  /**
329
- * What an asset verifier trusts and which repositories it may ask. An omitted list trusts or
330
- * asks nothing.
320
+ * Whether a code is a success, an informational note, or a failure.
331
321
  */
332
- export interface AssetVerifierOptions {
333
- /**
334
- * The C2PA manifest repositories recovery asks, each a Soft Binding Resolution API declared
335
- * for exactly the algorithms it may be asked for. Results merge by manifest, and a match\'s
336
- * `endpoint` is fetched from only when it names one of these. Empty: no recovery can be
337
- * asked of this verifier.
338
- */
339
- repositories?: Repository[];
340
- trust: Trust;
341
- }
322
+ export type ValidationCodeKind = "success" | "informational" | "failure";
342
323
 
343
324
  /**
344
- * What one verify may do to recover a manifest, as data: the soft bindings this client looks up
345
- * itself through `matches/byBinding`, and the content query, absent when not to be asked. It
346
- * needs a configured repository and at least one query.
325
+ * Whether a content form runs on this verify. Judged against the byBinding results alone.
347
326
  */
348
- export interface Recovery {
349
- when: RecoveryTrigger;
350
- softBindings?: SoftBindingSource[];
351
- content?: Content;
352
- /**
353
- * The whole recovery\'s budget in milliseconds, every repository together, each request
354
- * bounded by what remains. Absent, 10 minutes; at most 2147483647.
355
- */
356
- timeout?: number;
357
- }
327
+ export type ContentTrigger = "byBindingMisses" | "always";
358
328
 
359
329
  /**
360
- * What this verify concludes about the asset, from signed evidence alone.
330
+ * [`crate::asset::ByReference`] as JS states it: the region is the `Range` of
331
+ * `@contentauth/c2pa-types`, the shape a credential\'s actions carry.
361
332
  */
362
- export type Verdict = { kind: "unsigned" } | { kind: "inconclusive" } | { kind: "embedded" } | { kind: "recovered"; index: number; decidedBy: VerdictRule } | { kind: "recoveredDerivative"; index: number; decidedBy: VerdictRule } | { kind: "ambiguous"; candidates: number[] };
333
+ export interface ByReference {
334
+ after: ContentTrigger;
335
+ url: string;
336
+ length: number;
337
+ mediaType?: string;
338
+ region: import('@contentauth/c2pa-types').Range[];
339
+ }
363
340
 
364
341
  /**
365
- * When a verify asks the repositories.
342
+ * [`crate::asset::CredentialOrigin`] as JS sees it: a tagged union, since each way of finding a
343
+ * credential carries different evidence. Lane-local for the same reason [`FingerprintCheck`] is: a
344
+ * tag layout is what `#[binding(wasm)]` declines to express.
366
345
  */
367
- export type RecoveryTrigger = "manifestMissing" | "always";
346
+ export type CredentialOrigin = { kind: "embedded" } | { kind: "recovered"; discoveries: RecoveryDiscovery[]; fingerprintCheck: FingerprintCheck };
368
347
 
369
348
  /**
370
- * Where a credential came from: embedded in the asset, or recovered from a repository.
349
+ * [`crate::asset::FingerprintCheck`] as JS sees it: a tagged union, since `compared` carries a
350
+ * measurement the other two do not. Lane-local rather than `#[binding(wasm)]` on the core,
351
+ * because a tag layout is exactly what that macro declines to express.
371
352
  */
372
- export type CredentialOrigin = { kind: "embedded" } | { kind: "recovered"; discoveries: Discovery[]; fingerprintCheck: FingerprintCheck };
353
+ export type FingerprintCheck = { kind: "notNeeded" } | { kind: "nothingToCompare" } | { kind: "unsupported"; algorithm: string } | { kind: "indeterminate" } | { kind: "compared"; score: number };
373
354
 
374
355
  /**
375
- * Where one byBinding query\'s value comes from. A browser has no host engine: a vendor\'s
376
- * detector runs repository-side, through `byContent`.
356
+ * [`crate::asset::HardBinding`] as JS sees it.
377
357
  */
378
- export type SoftBindingSource = { kind: "builtin"; alg: string } | { kind: "held"; alg: string; value: Uint8Array };
358
+ export type HardBinding = "match" | "mismatch";
379
359
 
380
360
  /**
381
- * Whether a code is a success, an informational note, or a failure.
361
+ * [`crate::asset::Lineage`] as JS sees it.
382
362
  */
383
- export type ValidationCodeKind = "success" | "informational" | "failure";
363
+ export interface Lineage {
364
+ supersedes: string[];
365
+ supersededBy: string[];
366
+ }
384
367
 
385
368
  /**
386
- * Whether a content form runs on this verify. Judged against the byBinding results alone.
369
+ * [`crate::asset::RecoveryIssue`] as JS sees it: a tagged union, each kind with its own data.
387
370
  */
388
- export type ContentWhen = "bindingMisses" | "always";
371
+ export type RecoveryIssue = { kind: "binderFailed"; binderIndex: number; message: string } | { kind: "algorithmDeprecated"; algorithm: string } | { kind: "bindingUndeclared"; binderIndex: number; algorithm: string } | { kind: "bindingQueryFailed"; repository: string; binderIndex: number; algorithm: string; message: string } | { kind: "queryRefused"; repository: string; algorithm: string; message: string } | { kind: "contentFormUnsupported"; repository: string; message: string } | { kind: "contentQueryFailed"; repository: string; algorithm: string; message: string } | { kind: "capabilitiesUnavailable"; repository: string; message: string } | { kind: "contentTooLarge"; capBytes: number } | { kind: "candidateFetchFailed"; repository: string; manifestId: string; message: string } | { kind: "candidateInvalid"; manifestId: string; reason: string } | { kind: "endpointRefused"; repository: string; manifestId: string; endpoint: string } | { kind: "resourceLimitReached"; message: string };
389
372
 
390
373
  /**
391
- * Whether the asset\'s own fingerprint backs up a manifest that a watermark led to.
374
+ * [`crate::asset::VerdictRule`] as JS sees it.
392
375
  */
393
- export type FingerprintCheck = { kind: "notNeeded" } | { kind: "missing" } | { kind: "unsupported"; alg: string } | { kind: "indeterminate" } | { kind: "compared"; score: number };
376
+ export type VerdictRule = "onlyCandidate" | "notSuperseded" | "hardBinding";
394
377
 
395
378
  /**
396
- * Whether the manifest\'s hard binding holds over the bytes this verify read.
379
+ * [`crate::asset::Verdict`] as JS sees it.
397
380
  */
398
- export type HardBinding = "match" | "mismatch";
381
+ export type Verdict = { kind: "unsigned" } | { kind: "inconclusive" } | { kind: "embedded" } | { kind: "recovered"; index: number; decidedBy: VerdictRule } | { kind: "recoveredDerivative"; index: number; decidedBy: VerdictRule } | { kind: "ambiguous"; candidates: number[] };
399
382
 
400
383
  /**
401
- * Why repository recovery did not complete cleanly, or why one candidate was omitted.
384
+ * `matches/byContent`: the asset is uploaded to each repository, one request per algorithm that
385
+ * repository is declared for.
402
386
  */
403
- export type RecoveryIssue = { kind: "computeFailed"; alg: string; message: string } | { kind: "bindingFailed"; repository: string; alg: string; message: string } | { kind: "queryRefused"; repository: string; alg: string; message: string } | { kind: "contentFailed"; repository: string; alg: string; message: string } | { kind: "capabilitiesUnavailable"; repository: string; message: string } | { kind: "tooLarge"; maxUploadBytes: number } | { kind: "fetchFailed"; repository: string; manifestId: string; message: string } | { kind: "candidateInvalid"; manifestId: string; reason: string } | { kind: "endpointRefused"; repository: string; manifestId: string; endpoint: string } | { kind: "limitReached"; message: string };
387
+ export interface ByContent {
388
+ after: ContentTrigger;
389
+ }
404
390
 
405
391
  export interface AssetVerification {
406
392
  credentials: Credential[];
407
393
  recovery: RecoverySummary;
408
- /**
409
- * Absent when there was nothing to compare.
410
- */
411
- golden?: Golden;
394
+ goldenComparison: GoldenComparison;
412
395
  verdict: Verdict;
413
396
  }
414
397
 
@@ -417,6 +400,12 @@ export interface RecoverySummary {
417
400
  issues: RecoveryIssue[];
418
401
  }
419
402
 
403
+ export type ContentBindingClass = "fingerprint" | "watermark";
404
+
405
+ export type GoldenComparison = { kind: "notRequested" } | { kind: "noEmbeddedManifest" } | { kind: "noRecoveredManifest" } | { kind: "recoveryIncomplete" } | { kind: "matches"; recoveredIndex: number } | { kind: "differs"; recoveredIndex: number } | { kind: "noneMatches"; candidates: number[] } | { kind: "unreadable"; recoveredIndex: number };
406
+
407
+ export type RecoveryDiscovery = { kind: "byBinding"; class: ContentBindingClass; binding: SoftBinding; binderIndex: number; repositoryScore: number | undefined; repository: string; fetchedFrom: string } | { kind: "byContent"; hint: SoftBinding | undefined; class: ContentBindingClass; algorithm: string; repositoryScore: number | undefined; repository: string; fetchedFrom: string } | { kind: "byReference"; hint: SoftBinding | undefined; class: ContentBindingClass; algorithm: string; repositoryScore: number | undefined; repository: string; fetchedFrom: string };
408
+
420
409
  export type RecoveryStatus = "notRequested" | "notFound" | "recovered" | "incomplete";
421
410
 
422
411
 
@@ -438,18 +427,19 @@ export class AssetVerifier {
438
427
  *
439
428
  * # Errors
440
429
  *
441
- * Throws on a malformed `source`, a repository (or engine) failure, or a validation
430
+ * Throws on a malformed `input`, a repository (or binder) failure, or a validation
442
431
  * failure.
443
432
  */
444
- verify(source: RangeSource, recovery?: Recovery | null): Promise<Verification>;
433
+ verify(input: RangeSource, recovery?: Recovery | null): Promise<AssetVerification>;
445
434
  }
446
435
 
447
436
  /**
448
- * A `RangeSource` over a `Blob`: a `File` off an `<input>`, a
437
+ * A [`RangeSource`](crate::wasm::RangeInput) over a `Blob`: a `File` off an `<input>`, a
449
438
  * `Response.blob()`, a handle from the file system access API.
450
439
  *
451
- * It holds no bytes at all. The SDK reads one slice at a time, so an asset larger than the tab's
452
- * memory verifies at the disk's speed rather than the heap's.
440
+ * The only source here that holds nothing. The SDK reads one slice at a time, so an asset larger
441
+ * than the tab's memory verifies at the disk's speed rather than the heap's, and neither ceiling
442
+ * the other two carry applies.
453
443
  *
454
444
  * # Worker only
455
445
  *
@@ -483,6 +473,51 @@ export class BlobSource {
483
473
  readonly length: number;
484
474
  }
485
475
 
476
+ /**
477
+ * A [`RangeSource`](crate::wasm::RangeInput) over bytes the caller already holds, read in place.
478
+ *
479
+ * [`MemorySource`] without the copy: the array stays on the JS side and only the window the SDK
480
+ * asks for crosses, so nothing is resident here and linear memory's 4 GiB ceiling never applies to
481
+ * the asset.
482
+ */
483
+ export class BytesSource {
484
+ free(): void;
485
+ [Symbol.dispose](): void;
486
+ constructor(data: Uint8Array);
487
+ readAt(offset: number, length: number): Uint8Array;
488
+ readonly length: number;
489
+ }
490
+
491
+ export function C2PA_TRUST_LIST(): string;
492
+
493
+ export function C2PA_TSA_TRUST_LIST(): string;
494
+
495
+ export function DEV_CA(): string;
496
+
497
+ /**
498
+ * A binder contributing a binding you already hold (e.g. an out-of-band video ISCC):
499
+ * `new HeldBinder(binding)`, the spelling the native lane uses. A verify takes it as data,
500
+ * `{ kind: "held", binding }`, in `recovery.binders`.
501
+ */
502
+ export class HeldBinder {
503
+ free(): void;
504
+ [Symbol.dispose](): void;
505
+ /**
506
+ * Hand back the held binding; reads nothing.
507
+ *
508
+ * # Errors
509
+ *
510
+ * Throws when the source cannot be opened.
511
+ */
512
+ derive(content: RangeSource, options: DeriveOptions): Promise<SoftBinding | undefined>;
513
+ /**
514
+ * # Errors
515
+ *
516
+ * Throws `SdkError.invalid` on a binding with an empty algorithm or value.
517
+ */
518
+ constructor(binding: SoftBinding);
519
+ }
520
+
486
521
  export class IntoUnderlyingByteSource {
487
522
  private constructor();
488
523
  free(): void;
@@ -512,9 +547,37 @@ export class IntoUnderlyingSource {
512
547
  }
513
548
 
514
549
  /**
515
- * A `RangeSource` over bytes the caller already holds, read in place: the array stays on the JS
516
- * side and only the window the SDK asks for crosses, so nothing is resident here and linear
517
- * memory's 4 GiB ceiling never applies to the asset.
550
+ * The SDK's local ISCC Image-Code binder, for a standalone `derive`: `new IsccBinder()`, the
551
+ * spelling the native lane uses. A verify takes it as data, `{ kind: "iscc" }`, in
552
+ * `recovery.binders`, because a class cannot cross into a worker.
553
+ *
554
+ * Vendor watermark detection is repository-side in this SDK: configured detectors participate in
555
+ * `verify` through `byContent`, while a held binder covers values already available to the caller.
556
+ */
557
+ export class IsccBinder {
558
+ free(): void;
559
+ [Symbol.dispose](): void;
560
+ /**
561
+ * Derive the asset's ISCC standalone; `undefined` when the format yields none.
562
+ *
563
+ * # Errors
564
+ *
565
+ * Throws on malformed or unreadable input.
566
+ */
567
+ derive(content: RangeSource, options: DeriveOptions): Promise<SoftBinding | undefined>;
568
+ constructor();
569
+ }
570
+
571
+ /**
572
+ * An in-memory [`RangeSource`](crate::wasm::RangeInput), for a caller that already holds the whole
573
+ * asset as bytes.
574
+ *
575
+ * # Size ceiling
576
+ *
577
+ * The constructor copies the bytes into wasm linear memory, which is 32-bit addressed, so the
578
+ * asset and everything else the module allocates share a 4 GiB ceiling (a browser tab reaches its
579
+ * own memory limit well before that). [`BytesSource`] takes the same bytes without the copy, and
580
+ * [`BlobSource`] holds nothing at all.
518
581
  */
519
582
  export class MemorySource {
520
583
  free(): void;
@@ -533,8 +596,8 @@ export class StreamSession {
533
596
  free(): void;
534
597
  [Symbol.dispose](): void;
535
598
  /**
536
- * This stream's id and everything its init segments have registered, as CBOR for another
537
- * node to `StreamVerifier.resume` from.
599
+ * Everything this stream's init segments have registered, as CBOR for another node to
600
+ * `StreamVerifier.resume` from.
538
601
  *
539
602
  * The one piece of stream state that leaves the SDK, and only because a clustered
540
603
  * verifier needs it: the init URL is overwritten on rotation, so a node joining during
@@ -555,7 +618,7 @@ export class StreamSession {
555
618
  * Throws an `SdkError` on parse or signature failure, or when a media segment arrives
556
619
  * before any init was processed for the stream.
557
620
  */
558
- validate(source: RangeSource): Promise<SegmentValidation>;
621
+ validate(data: RangeSource): Promise<SegmentValidation>;
559
622
  }
560
623
 
561
624
  export class StreamVerifier {
@@ -571,82 +634,26 @@ export class StreamVerifier {
571
634
  */
572
635
  static create(options: StreamVerifierOptions): StreamVerifier;
573
636
  /**
574
- * Open the stream `id` for validation, handing back a `StreamSession` to feed segments to.
637
+ * Open `stream_id` for validation, handing back a `StreamSession` to feed segments to.
575
638
  *
576
639
  * No I/O: the handle carries the id so it cannot be mistyped or confused with another
577
640
  * stream's, and classification still happens per segment. Opening one id twice hands
578
641
  * back the same live session, so a component that remounts keeps the state its earlier
579
642
  * handle accumulated.
580
643
  */
581
- open(id: string): StreamSession;
644
+ open(stream_id: string): StreamSession;
582
645
  /**
583
- * Open the stream another node exported, its state merged into whatever this one holds
584
- * for that stream already.
646
+ * Open `stream_id` on the state another node exported, merged into whatever this one
647
+ * holds for that id already.
585
648
  *
586
649
  * # Errors
587
650
  *
588
- * Throws an `SdkError` with a field violation at `state` when it is not a value
589
- * `StreamSession.export` produced (`state.malformed`), or one of another export version
590
- * (`state.version`).
651
+ * Throws an `SdkError` (`STREAM_INVALID`) when `state` is not a value
652
+ * `StreamSession.export` produced, or carries a version this SDK no longer reads.
591
653
  */
592
- resume(state: Uint8Array): StreamSession;
654
+ resume(stream_id: string, state: Uint8Array): StreamSession;
593
655
  }
594
656
 
595
- /**
596
- * One `verify` result held with the stores it read: `report` is the data, and `resource` reads a
597
- * thumbnail from credential `credential` (its position in `report.credentials`) by the
598
- * `identifier` of a resource reference in its manifest. A class rather than a field of the
599
- * report because a store cannot be serialized, and one handle per verify is what a worker can
600
- * proxy (a class nested in the report cannot cross a thread).
601
- */
602
- export class Verification {
603
- private constructor();
604
- free(): void;
605
- [Symbol.dispose](): void;
606
- /**
607
- * The bytes of one resource credential `credential` holds, or `undefined`.
608
- *
609
- * # Errors
610
- *
611
- * Throws `READER_INVALID` when the store holds the resource but cannot produce it, and
612
- * `undefined` for a `credential` out of range.
613
- */
614
- resource(credential: number, uri: string): Uint8Array | undefined;
615
- /**
616
- * The report: credentials, recovery, golden flow and verdict.
617
- */
618
- readonly report: AssetVerification;
619
- }
620
-
621
- /**
622
- * The bundled C2PA Conformance Program signing-CA trust list (a release snapshot). Trusted by
623
- * default with `trust.c2pa`; read it to pin or extend your own list.
624
- */
625
- export function c2paTrustList(): string;
626
-
627
- /**
628
- * The bundled C2PA time-stamping-authority trust list (a release snapshot).
629
- */
630
- export function c2paTsaTrustList(): string;
631
-
632
- /**
633
- * The values this SDK computes for `alg` over `source`, `[]` when it finds none. `format` is
634
- * the asset's media type; omitted, the bytes name it.
635
- *
636
- * # Errors
637
- *
638
- * Throws on an algorithm this SDK computes no value of, a `format` that is no media type or that
639
- * the bytes contradict, an unreadable source, or no trustworthy answer.
640
- */
641
- export function computeSoftBinding(alg: string, source: RangeSource, format?: string | null): Promise<Block[]>;
642
-
643
- /**
644
- * PEM trust anchor for the Limbo Integrity development signing environment, **development
645
- * only**, no security guarantees: put it in `trust.anchors` for a development build, never in a
646
- * release.
647
- */
648
- export function devCa(): string;
649
-
650
657
  export function init_panic_hook(): void;
651
658
 
652
659
  /**
@@ -662,51 +669,78 @@ export function init_panic_hook(): void;
662
669
  *
663
670
  * Throws `READER_INVALID` when the bytes are not a manifest store c2pa can parse.
664
671
  */
665
- export function parse(manifest: Uint8Array): Promise<import('@contentauth/c2pa-types').ManifestStore>;
672
+ export function parse(manifest: Uint8Array): import('@contentauth/c2pa-types').ManifestStore;
666
673
 
667
674
  /**
668
675
  * The bytes of one resource in a detached manifest store, or `undefined` when it holds none
669
- * under `uri`: the `identifier` on a resource reference the parsed store carries.
676
+ * under `uri`.
677
+ *
678
+ * `uri` is the `identifier` on a resource reference the store carries, so walking the chain in
679
+ * the parsed store is what produces it: any manifest's claim thumbnail, including a non-active
680
+ * one, and any ingredient's. Render it with the `format` beside that identifier. A `uri` naming a
681
+ * manifest rather than a resource answers that manifest's own JUMBF, so pass what a reference
682
+ * states, never a bare label.
670
683
  *
671
684
  * # Errors
672
685
  *
673
686
  * Throws `READER_INVALID` when the bytes are not a manifest store c2pa can parse, or the store
674
687
  * holds the resource but cannot produce it.
675
688
  */
676
- export function resource(manifest: Uint8Array, uri: string): Promise<Uint8Array | undefined>;
689
+ export function resource(manifest: Uint8Array, uri: string): Uint8Array | undefined;
690
+
691
+ /**
692
+ * Every thumbnail the store references, by the `identifier` it references them under: each
693
+ * manifest's claim thumbnail and each ingredient's, whichever manifest carries them.
694
+ *
695
+ * One parse for the whole set, where `resource` pays one per call, so a chain view asks once
696
+ * instead of once per tile. Render each one as the `format` beside its identifier. A reference
697
+ * the store cannot produce is left out rather than failing the set.
698
+ *
699
+ * # Errors
700
+ *
701
+ * Throws `READER_INVALID` when the bytes are not a manifest store c2pa can parse.
702
+ */
703
+ export function thumbnails(manifest: Uint8Array): Record<string, Uint8Array>;
677
704
 
678
705
  export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
679
706
 
680
707
  export interface InitOutput {
681
708
  readonly memory: WebAssembly.Memory;
682
- readonly computeSoftBinding: (a: number, b: number, c: any, d: number, e: number) => any;
683
709
  readonly __wbg_assetverifier_free: (a: number, b: number) => void;
684
710
  readonly __wbg_blobsource_free: (a: number, b: number) => void;
711
+ readonly __wbg_bytessource_free: (a: number, b: number) => void;
685
712
  readonly __wbg_memorysource_free: (a: number, b: number) => void;
686
713
  readonly __wbg_streamsession_free: (a: number, b: number) => void;
687
714
  readonly __wbg_streamverifier_free: (a: number, b: number) => void;
688
- readonly __wbg_verification_free: (a: number, b: number) => void;
689
715
  readonly assetverifier_create: (a: any) => [number, number, number];
690
716
  readonly assetverifier_verify: (a: number, b: any, c: number) => any;
691
717
  readonly blobsource_length: (a: number) => number;
692
718
  readonly blobsource_new: (a: any) => [number, number, number];
693
719
  readonly blobsource_readAt: (a: number, b: number, c: number) => [number, number, number];
720
+ readonly bytessource_length: (a: number) => number;
721
+ readonly bytessource_new: (a: any) => number;
722
+ readonly bytessource_readAt: (a: number, b: number, c: number) => any;
694
723
  readonly memorysource_length: (a: number) => number;
695
- readonly memorysource_new: (a: any) => number;
724
+ readonly memorysource_new: (a: number, b: number) => number;
696
725
  readonly memorysource_readAt: (a: number, b: number, c: number) => any;
697
- readonly parse: (a: number, b: number) => any;
698
- readonly resource: (a: number, b: number, c: number, d: number) => any;
726
+ readonly parse: (a: number, b: number) => [number, number, number];
727
+ readonly resource: (a: number, b: number, c: number, d: number) => [number, number, number, number];
699
728
  readonly streamsession_export: (a: number) => [number, number, number, number];
700
729
  readonly streamsession_validate: (a: number, b: any) => any;
701
730
  readonly streamverifier_create: (a: any) => [number, number, number];
702
731
  readonly streamverifier_open: (a: number, b: number, c: number) => number;
703
- readonly streamverifier_resume: (a: number, b: number, c: number) => [number, number, number];
704
- readonly verification_report: (a: number) => any;
705
- readonly verification_resource: (a: number, b: number, c: number, d: number) => [number, number, number, number];
706
- readonly c2paTrustList: () => [number, number];
707
- readonly c2paTsaTrustList: () => [number, number];
708
- readonly devCa: () => [number, number];
732
+ readonly streamverifier_resume: (a: number, b: number, c: number, d: number, e: number) => [number, number, number];
733
+ readonly thumbnails: (a: number, b: number) => [number, number, number];
734
+ readonly C2PA_TRUST_LIST: () => [number, number];
735
+ readonly C2PA_TSA_TRUST_LIST: () => [number, number];
736
+ readonly DEV_CA: () => [number, number];
709
737
  readonly init_panic_hook: () => void;
738
+ readonly __wbg_heldbinder_free: (a: number, b: number) => void;
739
+ readonly __wbg_isccbinder_free: (a: number, b: number) => void;
740
+ readonly heldbinder_derive: (a: number, b: any, c: any) => any;
741
+ readonly heldbinder_new: (a: any) => [number, number, number];
742
+ readonly isccbinder_derive: (a: number, b: any, c: any) => any;
743
+ readonly isccbinder_new: () => number;
710
744
  readonly __wbg_intounderlyingbytesource_free: (a: number, b: number) => void;
711
745
  readonly intounderlyingbytesource_autoAllocateChunkSize: (a: number) => number;
712
746
  readonly intounderlyingbytesource_cancel: (a: number) => void;
@@ -723,7 +757,7 @@ export interface InitOutput {
723
757
  readonly wasm_bindgen__convert__closures_____invoke__hfa954cb356c7e7e1: (a: number, b: number, c: any) => [number, number];
724
758
  readonly wasm_bindgen__convert__closures_____invoke__h32a4f2e7671466cf: (a: number, b: number, c: any, d: any) => void;
725
759
  readonly wasm_bindgen__convert__closures_____invoke__hedf60f9cb8ab20c3: (a: number, b: number, c: any) => void;
726
- readonly wasm_bindgen__convert__closures_____invoke__hbf782ef36cea6846: (a: number, b: number) => void;
760
+ readonly wasm_bindgen__convert__closures_____invoke__hcc9f2329e90526d5: (a: number, b: number) => void;
727
761
  readonly __wbindgen_malloc: (a: number, b: number) => number;
728
762
  readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
729
763
  readonly __wbindgen_exn_store: (a: number) => void;
@@ -731,7 +765,6 @@ export interface InitOutput {
731
765
  readonly __wbindgen_externrefs: WebAssembly.Table;
732
766
  readonly __wbindgen_free: (a: number, b: number, c: number) => void;
733
767
  readonly __wbindgen_destroy_closure: (a: number, b: number) => void;
734
- readonly __externref_drop_slice: (a: number, b: number) => void;
735
768
  readonly __externref_table_dealloc: (a: number) => void;
736
769
  readonly __wbindgen_start: () => void;
737
770
  }