npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

c2pa-structured-text

v0.3.0

Published

C2PA manifest embedding, hard binding, and validation for structured text formats using ASCII armour delimiters

Readme

Overview

Implements the Embedding Manifests into Structured Text section of the C2PA Technical Specification, which associates a C2PA Manifest Store with source code, configuration files, markup, and other text formats that support comment syntax or front matter conventions.

The manifest block uses fixed ASCII armour-style delimiters modelled on RFC 4880:

-----BEGIN C2PA MANIFEST----- <reference> -----END C2PA MANIFEST-----

This crate owns three things:

  1. Embed / Extract — place a reference or an inline manifest as a comment or front matter block, and locate and resolve it again.
  2. Hard binding — define and compute the exact c2pa.hash.data coverage for structured text, and verify it.
  3. A validation bridge to c2pa-rs for signature, trust, and assertion validation — which this crate does not reimplement.

This crate is not certified or conformance-tested by the C2PA. It implements the structured-text embedding and hard binding as specified, and delegates cryptographic validation to c2pa-rs.

Quick Start

[dependencies]
c2pa-structured-text = "0.1"

Embed a manifest reference

use c2pa_structured_text::{embed_manifest, ManifestRef};

let signed = embed_manifest(
    "print('hello')\n",
    ManifestRef::Url("https://example.com/manifests/abc.c2pa"),
    "#",   // comment prefix
    None,  // no comment suffix
);
// # -----BEGIN C2PA MANIFEST----- https://example.com/manifests/abc.c2pa -----END C2PA MANIFEST-----
// print('hello')

embed_manifest_at_end places the block on the last line (for files whose first line is reserved, e.g. a shebang or XML declaration), and embed_front_matter writes the multi-line form inside YAML/TOML front matter.

Extract a manifest reference

use c2pa_structured_text::{extract_manifest, classify_reference, Reference};

let text = "# -----BEGIN C2PA MANIFEST----- https://example.com/m.c2pa -----END C2PA MANIFEST-----
print('hello')
";
let result = extract_manifest(text).unwrap();
assert_eq!(result.reference, "https://example.com/m.c2pa");

// A `data:application/c2pa;base64,` reference decodes to the manifest bytes;
// anything else is treated as an external URI.
match classify_reference(&result.reference).unwrap() {
    Reference::Url(url) => { /* fetch it */ }
    Reference::Embedded(bytes) => { /* raw JUMBF manifest store */ }
}

The Hard Binding

A structured-text manifest is bound with a c2pa.hash.data assertion carrying a single exclusion range covering the entire manifest block. The hash is computed over the raw bytes of the file with that range removed.

Unlike the Unicode Variation Selector method for unstructured text, this binding applies no Unicode normalization: structured text files are byte-stable on disk, and normalizing to NFC would create false mismatches for files that legitimately contain NFD content. Files must be read in binary mode, preserving exact line terminators; bare CR line endings are unsupported.

# #[cfg(feature = "hard-binding")] {
use c2pa_structured_text::hardbinding::{compute_data_hash, verify_data_hash, Algorithm};

let signed = c2pa_structured_text::embed_manifest(
    "print('hello')\n",
    c2pa_structured_text::ManifestRef::Url("https://example.com/m.c2pa"),
    "#",
    None,
);
let data_hash = compute_data_hash(&signed, Algorithm::Sha256).unwrap();
verify_data_hash(&signed, &data_hash).unwrap();
# }

The exclusion-range and covered-byte primitives (manifest_exclusion, hashed_bytes) are always available and dependency-free; compute_data_hash / verify_data_hash require the hard-binding feature (which pulls sha2).

Fragility — and the soft-binding recovery path

This is a byte-exact binding, and it is meant to be. Any change to the covered bytes — reformatting, re-indentation, transcoding, or an LF↔CRLF conversion outside the block — breaks it. Where durability across such transformations matters, pair it with the perceptual soft binding in c2pa-text-binding, which re-associates transformed content with its provenance after the hard binding is lost. Do not treat the structured-text hard binding as robust to editing.

Validating with c2pa-rs

Enable the c2pa feature to validate the signature, trust chain, and hard binding via c2pa-rs. This crate extracts and resolves the reference; c2pa-rs does the cryptography.

use c2pa_structured_text::bridge;

// Inline (data:) references are decoded automatically; URL references are
// fetched with the `remote` feature (or resolve them yourself and call
// `bridge::validate_with_manifest`).
let reader = bridge::validate(&signed, bridge::DEFAULT_FORMAT)?;
println!("{:?}", reader.validation_state());

Features

| Feature | Adds | Pulls | |---|---|---| | (none) | embed, extract, exclusion-range and covered-byte primitives | — | | hard-binding | compute_data_hash / verify_data_hash (SHA2-256/384/512) | sha2 | | c2pa | the bridge to c2pa-rs for signature/trust/assertion validation | c2pa | | remote | HTTP(S) resolution of URL references in the bridge | c2pa, ureq |

No feature is enabled by default; the core API has no dependencies.

Supported Formats

Any text format with a comment syntax or front matter convention:

| Comment Style | Formats | Example | |---|---|---| | # | Python, Ruby, Shell, YAML, TOML | # -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- | | // | JavaScript, TypeScript, Go, Rust, C++ | // -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- | | -- | SQL, Lua, Haskell | -- -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- | | /* */ | CSS, C, Java | /* -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- */ | | <!-- --> | Markdown, XML (non-HTML) | <!-- -----BEGIN C2PA MANIFEST----- ... -----END C2PA MANIFEST----- --> | | Front matter | Markdown (YAML), TOML | Multi-line form between front matter delimiters |

The crate is format-agnostic: it does not hard-code a fixed list of languages. Any text/* asset with a comment introducer or a front matter convention works — you supply the comment prefix/suffix (or front matter fence). The table above is illustrative, not exhaustive.

Applicability and exclusions

Per the specification, the structured-text method applies to any text/* (or plain-text) asset not already covered by a format-specific embedding method, provided it has a comment syntax or front matter. The following are out of scope and will not round-trip through this crate:

| Not supported | Why | Use instead | |---|---|---| | JSON, CSV | No comment or front matter syntax — nothing to carry the block | none (embed in a container) | | HTML | Has its own C2PA embedding method | the HTML embedding method | | SVG, TTML | Have their own C2PA embedding methods | the SVG / TTML methods | | WebVTT | Structured text, but streaming placement is specialised | c2pa-vtt | | Unstructured/plain prose | No stable comment location; use invisible codepoints | c2pa-text |

Line endings must be LF or CRLF (bare CR is rejected). When structured text is carried inside a container (MP4, PDF, ZIP), prefer embedding in the container.

Related Crates

Part of a family of single-purpose crates, one per C2PA embedding method. Each is standalone and independently versioned.

| Crate | Description | |---|---| | c2pa-unstructured-text | Unstructured text: invisible Unicode variation-selector run | | c2pa-html | HTML: script and link elements in the document head | | c2pa-http | HTTP: the c2pa-manifest Link header, with a Tower middleware | | c2pa-text-binding | Soft binding and content fingerprinting for text assets | | c2pa-vtt | WebVTT caption and subtitle embedding | | c2pa-zip | ZIP-based documents: EPUB, DOCX, ODT, OXPS | | c2pa-warc | WARC web archive embedding (ISO 28500) | | c2pa-fonts | OpenType/TrueType (SFNT) font embedding | | c2pa-ml | ML model containers: GGUF, SafeTensors, ONNX | | c2pa | Official C2PA SDK |

Security

Found a vulnerability? Please report it privately — see SECURITY.md.

License

Licensed under either of Apache License, Version 2.0 or MIT License at your option.

Built by WritersLogic