-
Notifications
You must be signed in to change notification settings - Fork 1
Add c2pa-types + typed activeManifest and manifestStore APIs #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
'@contentauth/c2pa-types': minor | ||
'@contentauth/c2pa-wasm': minor | ||
'@contentauth/c2pa-web': minor | ||
--- | ||
|
||
Added reader.manifestStore() and reader.activeManifest() APIs |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
resolver = '2' | ||
members = [ | ||
'packages/c2pa-wasm', | ||
'packages/c2pa-types', | ||
] | ||
|
||
[profile.release] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
schemas | ||
types |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[package] | ||
name = "c2pa-types" | ||
version = "0.1.0" | ||
edition = "2024" | ||
|
||
[dependencies] | ||
c2pa = { version = "0.62.0", features = ["pdf", "rust_native_crypto", "json_schema"], default-features = false } | ||
schemars = "0.8.21" | ||
serde_json = "1.0.143" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/** | ||
* Copyright 2025 Adobe | ||
* All Rights Reserved. | ||
* | ||
* NOTICE: Adobe permits you to use, modify, and distribute this file in | ||
* accordance with the terms of the Adobe license agreement accompanying | ||
* it. | ||
*/ | ||
|
||
import type { Reader } from './types/ManifestStore.js'; | ||
|
||
// Renames the auto-generated "Reader" type to the more appropriate "ManifestStore" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ManifestStore because you only deal with the "extracted" JSON afterwards? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This type really is just a ManifestStore despite being called a "Reader," and if I don't rename it I think it will be confusing to consumers. I.e. "why does |
||
// eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-empty-object-type | ||
export interface ManifestStore extends Reader {} | ||
|
||
export type { Manifest } from './types/ManifestStore.js'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"name": "@contentauth/c2pa-types", | ||
"description": "Typescript types generated from c2pa-rs", | ||
"type": "module", | ||
"version": "0.1.1", | ||
"types": "index.d.ts", | ||
"scripts": { | ||
"test": "echo \"No tests to run\" && exit 0", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why keep it then? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is kind of an annoying hangup with the monorepo system I'm using right now (NX). It expects a "test" command to be available for each published package and will error out if there's no command to run, so I've put this in place to get around that. Frankly I'll be looking to get off of NX quite soon following this and would happily revisit this when I migrate. |
||
"build": "pnpm clean && json2ts -i schemas/ -o types/", | ||
"clean": "rimraf types" | ||
}, | ||
"files": ["index.d.ts", "types/**/*"], | ||
"dependencies": { | ||
"json-schema-to-typescript": "^15.0.4", | ||
"rimraf": "^6.0.1" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"name": "c2pa-types", | ||
"$schema": "../../node_modules/nx/schemas/project-schema.json", | ||
"tags": ["lib"], | ||
"projectType": "library", | ||
"sourceRoot": "packages/c2pa-types/src", | ||
"targets": { | ||
"build": { | ||
"cache": true, | ||
"inputs": [ | ||
"{projectRoot}/**/*", | ||
"!{projectRoot}/schemas/**/*", | ||
"!{projectRoot}/types/**/*" | ||
], | ||
"executor": "nx:run-commands", | ||
"options": { | ||
"commands": [ | ||
"cargo run", | ||
"pnpm build" | ||
], | ||
"parallel": false, | ||
"cwd": "{projectRoot}" | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright 2025 Adobe | ||
// All Rights Reserved. | ||
// | ||
// NOTICE: Adobe permits you to use, modify, and distribute this file in | ||
// accordance with the terms of the Adobe license agreement accompanying | ||
// it. | ||
|
||
use std::{fs, path::Path}; | ||
|
||
use c2pa::Reader; | ||
use schemars::{schema::RootSchema, schema_for}; | ||
|
||
fn main() { | ||
let output_dir = Path::new("./schemas"); | ||
|
||
if fs::exists(output_dir).unwrap() { | ||
fs::remove_dir_all(output_dir).expect("Could not clear existing schema directory"); | ||
} | ||
|
||
fs::create_dir_all(output_dir).expect("Could not create schema directory"); | ||
|
||
write_schema(&schema_for!(Reader), &"ManifestStore", output_dir); | ||
} | ||
|
||
fn write_schema(schema: &RootSchema, name: &str, output_dir: &Path) { | ||
println!("Exporting JSON schema for {name}"); | ||
let output_path = output_dir.join(format!("{name}.json")); | ||
let output = serde_json::to_string_pretty(schema).expect("Failed to serialize schema"); | ||
fs::write(&output_path, output).expect("Unable to write schema"); | ||
println!("Wrote schema to {}", output_path.display()); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,8 @@ use std::io::{Cursor, Read, Seek}; | |
|
||
use c2pa::{identity::validator::CawgValidator, Reader}; | ||
use js_sys::{ArrayBuffer, Error as JsError, Uint8Array}; | ||
use serde::Serialize; | ||
use serde_wasm_bindgen::Serializer; | ||
use wasm_bindgen::prelude::*; | ||
use web_sys::Blob; | ||
|
||
|
@@ -18,6 +20,7 @@ use crate::{error::WasmError, stream::BlobStream}; | |
#[wasm_bindgen] | ||
pub struct WasmReader { | ||
reader: Reader, | ||
serializer: Serializer, | ||
} | ||
|
||
#[wasm_bindgen] | ||
|
@@ -33,17 +36,11 @@ impl WasmReader { | |
format: &str, | ||
stream: impl Read + Seek + Send, | ||
) -> Result<WasmReader, JsError> { | ||
let mut reader = Reader::from_stream_async(format, stream) | ||
let reader = Reader::from_stream_async(format, stream) | ||
.await | ||
.map_err(WasmError::from)?; | ||
|
||
// This will be removed once CawgValidation is rolled into the reader | ||
reader | ||
.post_validate_async(&CawgValidator {}) | ||
.await | ||
.map_err(WasmError::other)?; | ||
|
||
Ok(WasmReader { reader }) | ||
Ok(WasmReader::from_reader(reader).await?) | ||
} | ||
|
||
/// Attempts to create a new `WasmReader` from an asset format, a `Blob` of the bytes of the initial segment, and a fragment `Blob`. | ||
|
@@ -64,23 +61,23 @@ impl WasmReader { | |
init: impl Read + Seek + Send, | ||
fragment: impl Read + Seek + Send, | ||
) -> Result<WasmReader, JsError> { | ||
let mut reader = Reader::from_fragment_async(format, init, fragment) | ||
let reader = Reader::from_fragment_async(format, init, fragment) | ||
.await | ||
.map_err(WasmError::other)?; | ||
|
||
Ok(WasmReader::from_reader(reader).await?) | ||
} | ||
|
||
async fn from_reader(mut reader: Reader) -> Result<WasmReader, JsError> { | ||
let serializer = Serializer::new().serialize_maps_as_objects(true); | ||
|
||
// This will be removed once CawgValidation is rolled into the reader | ||
reader | ||
.post_validate_async(&CawgValidator {}) | ||
.await | ||
.map_err(WasmError::other)?; | ||
|
||
Ok(WasmReader { reader }) | ||
} | ||
|
||
/// Returns a JSON representation of the asset's manifest store. | ||
#[wasm_bindgen] | ||
pub fn json(&self) -> String { | ||
self.reader.json() | ||
Ok(WasmReader { reader, serializer }) | ||
} | ||
|
||
/// Returns the label of the asset's active manifest. | ||
|
@@ -89,6 +86,37 @@ impl WasmReader { | |
self.reader.active_label().map(|val| val.to_owned()) | ||
} | ||
|
||
/// Returns the asset's manifest store. | ||
/// NOTE: at the moment, CAWG data is not decoded via this function. Use WasmReader::json() if CAWG is a requirement. | ||
#[wasm_bindgen(js_name = manifestStore)] | ||
pub fn manifest_store(&self) -> Result<JsValue, JsError> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see what it's doing, but what is the intend? Why is the manifest store by itself needed somewhere? (Especially because I see the js below: const manifestStore = await reader.json();, so it puzzles me a bit). Why is Reader.json() not usable all the time? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like to get rid of
I'm hopeful that once @scouten-adobe is able to land contentauth/c2pa-rs#1370 and these methods return CAWG correctly, I can just get rid of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it, sounds good! |
||
let manifest_store = self | ||
.reader | ||
.serialize(&self.serializer) | ||
.map_err(WasmError::from)?; | ||
|
||
Ok(manifest_store) | ||
} | ||
|
||
/// Returns the asset's active manifest. | ||
/// NOTE: at the moment, CAWG data is not decoded via this function. Use WasmReader::json() if CAWG is a requirement. | ||
#[wasm_bindgen(js_name = activeManifest)] | ||
pub fn active_manifest(&self) -> Result<JsValue, JsError> { | ||
let active_manifest = self | ||
.reader | ||
.active_manifest() | ||
.serialize(&self.serializer) | ||
.map_err(WasmError::from)?; | ||
|
||
Ok(active_manifest) | ||
} | ||
|
||
/// Returns a JSON representation of the asset's manifest store. | ||
#[wasm_bindgen] | ||
pub fn json(&self) -> String { | ||
self.reader.json() | ||
} | ||
|
||
/// Accepts a URI reference to a binary object in the resource store and returns a `js_sys::ArrayBuffer` containing the resource's bytes. | ||
#[wasm_bindgen(js_name = resourceToBuffer)] | ||
pub fn resource_to_buffer(&self, uri: &str) -> Result<ArrayBuffer, JsError> { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need the pdf feature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just matching the features of the V1 SDK. I don't know if clients actively need this but we do support PDFs on Verify right now and the plan is to migrate that site to use this SDK.