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

open-news-protocol

v0.3.0

Published

Open News Protocol (ONP) reference implementation: sign, verify, retrieve, and aggregate cryptographically provenanced News Objects. Envelope, identifiers, JCS (RFC 8785) canonicalization, Ed25519 + ECDSA-P256 signatures, multi-level validation, domain Tr

Readme

ONP Reference Implementation

A working TypeScript implementation of ONP-1000 through ONP-1004, plus Trust Anchor resolution (ONP-0004) and Retrieval (ONP-1006): envelope construction, identifier computation (VID, content-addressed per ONP-1001), canonicalization (JCS/RFC 8785, per ONP-1002), Ed25519 signing/verification (per ONP-1003), the full multi-level validation pipeline (ONP-1004), domain-anchored Trust Anchor resolution (ONP-0004), and the Retrieval Convention (ONP-1006). This goes beyond the minimum scope specs/9000-reference-implementation.md Section 4.1 requires; the sections below state exactly what is and is not covered.

This is real, tested code — not pseudocode. It computes actual VID and signature values; nothing here uses the placeholder AbC123-example-digest-bytes-style values the specification text itself uses for illustration.

What this covers

  • src/preimage.ts — Pre-Image construction (ONP-1002 Section 4.2), using the canonicalize package (an RFC 8785 reference implementation, written by one of the RFC's own authors — reuse over reinvention, per Principle P3).
  • src/identifiers.ts — OID construction and VID computation (ONP-1001), hashing with @noble/hashes and base64url via @scure/base.
  • src/algorithms.ts (+ src/algorithms/) — a signature-algorithm provider registry keyed by the algorithm-id in onp:sig:<id>:.... Ed25519 (via @noble/curves) is the required-baseline provider; adding ECDSA-P256 (ONP-0005 Appendix A lists it recommended) or a post-quantum algorithm is one provider file plus a registerSignatureAlgorithm call — no change to signing, verification, or validation.
  • src/signatures.ts — Ed25519 signing and verification (ONP-1003) over the provider registry. Keys are raw bytes and the crypto is pure-JS (no node:crypto), so the whole SDK runs unchanged on Node, browsers, Deno, edge runtimes, and EUDI-style wallet contexts.
  • src/validate.ts — the full Core validation pipeline (ONP-1003 Section 6.1): structural check → VID integrity → algorithm check → signature verification, each step terminal on failure.
  • src/export-schemaorg.ts and src/export-rss.ts — deterministic export mappings to schema.org/NewsArticle and RSS 2.0, per specs/9005-external-standards-interoperability.md. Run npm run bridges to see both applied to the running fusie-onderzoek example.

What this deliberately does NOT cover

  • Some Companions and most Extensions: reference validators ship for the Article (ONP-2100), Media (ONP-2200), Rights (ONP-2400), Payments (ONP-2500) and Corrections (ONP-2700) Companions, plus the ai-metadata Extension (ONP-3100). The Sources, Comments and Identity Companions and every other Extension correctly report unknown via the pluggable registry — itself conformant behavior (ONP-1004 Section 6.3), not a gap.

Multi-level validation (ONP-1004) — implemented

src/multilevel.ts implements the full four-level pipeline of ONP-1004 Section 6.1. validateFull() runs Level 1 (Core, reusing validateCoreWithTrust() unchanged), then Levels 2a/2b on a pluggable ValidatorRegistry, and returns the Section 5.1 Validation Result — as a discriminated union, so Section 4.5 rule 2 ("no other field is meaningful when core_authenticated is false") is a type-level fact rather than a convention. The contract's edge rules are all enforced and tested: unknown vs false are never conflated (Section 4.3 rule 3), Companion invalidity never touches core_authenticated (Section 4.3 rule 2), Extension Conflicts are reported explicitly and never silently resolved (Section 4.4 rule 2), silence between two Extensions is not a conflict (Section 6.2), and an empty registry still yields a complete well-formed Result (Section 6.3). referenceValidatorRegistry bundles reference validators for the Article (ONP-2100), Media (ONP-2200), Rights (ONP-2400), Payments (ONP-2500) and Corrections (ONP-2700) Companions and the org.onp.ai-metadata Extension (ONP-3100).

Retrieval (ONP-1006) — implemented

src/retrieval.ts implements the Retrieval Convention: objectUrlFromOid() derives the canonical Object URL mechanically from the OID (the publisher's domain is inside the OID — no lookup, registry, or resolver), etagForVid() gives the VID-as-entity-tag convention, and retrieveNewsObject() runs the full Section 5.1 algorithm: conditional GET (If-None-Match with a held VID), 304 / 404 semantics, then MANDATORY full Core validation including Trust Anchor resolution on the retrieved bytes, then the requested-OID match check. There is deliberately no code path that returns retrieved bytes without validating them (Section 8.1). The RSS export bridge now carries <onp:object> per item (Section 4.4, namespace https://opennewsprotocol.org/ns/feed), so existing feeds point at the signed Object.

Aggregation — a consumer Node (ONP-0001 Section 6.3)

src/aggregator.ts is the Node role that closes the network model's Publisher Node -> Signed Object -> Other Nodes -> Applications loop. aggregate(feedUrls, resolver) follows the <onp:object> pointers in ordinary RSS/Atom feeds, retrieves every referenced Object, runs full Core validation (Trust Anchor resolution included) on each, and returns a newest-first, per-OID-deduplicated timeline of only the authentic ones, with a separate list of what was rejected and why. This is "trust the Object, not the Messenger" made concrete: discovery is untrusted, so a hostile or broken feed can only waste a fetch — it cannot inject an unauthentic Object into the timeline (there is a test for exactly that). Feed and Object fetching are injectable, so it is a pure, offline-testable function; the onp aggregate <feed-url>... CLI command runs it over live HTTPS.

Trust Anchor resolution (ONP-0004) — implemented

src/trust.ts implements the domain-anchored Trust Anchor baseline:

  • the Publisher Key Record structure (ONP-0004 Section 5.1) with structural validation;
  • the full Resolution Algorithm (Section 6.1): current-key match, previous-key validity-window check against the Object's signed_at, and revoked_at handling (Section 4.4, rule 4: "at or after revoked_at" is untrusted);
  • caching with the mandatory re-fetch-on-failure rule (Section 6.3, rule 2), so a legitimate key rotation the cache has not yet observed never causes a false rejection;
  • OPTIONAL DNS corroboration (Section 4.3) as a warning-only fingerprint comparison via an injectable lookup — absence never fails resolution, exactly as rule 3 requires.
  • OPTIONAL, PROVISIONAL EUDI corroboration (Section 4.6): an injectable EudiAttestationVerifier can bind the resolved key/domain to a wallet-verified legal identity (SD-JWT VC by default, with the organization's LEI as the recommended identifier). It is additive and elevation/warning-only — absence, a failed credential, or a binding mismatch never rejects an Object whose domain resolution already succeeded (rule 3: authenticity stays domain-verifiable). The SDK delegates all SD-JWT / mdoc / EU-Trust-List work to the injected verifier and does no credential crypto itself; the eudi_attestation shape is an implementation proposal, not yet ratified.

validateCoreWithTrust() in src/validate.ts runs the complete six-step verification procedure of ONP-1003 Section 4.5 in the mandatory Section 4.6 order, including the algorithm cross-check (step 4) between the signature's algorithm-id and the resolved Publisher Key Record entry, and verifies the signature against the resolved key — never a caller-supplied one. The original synchronous validateCore(envelope, publicKey) remains available for offline / key-in-hand verification.

Fetching is pluggable (KeyRecordFetcher); the default fetcher uses fetch() over HTTPS at /.well-known/onp/publisher.json, with WebPKI/TLS validation performed by the platform TLS stack (Section 4.2, rule 3). Tests inject in-memory records and cover every example in ONP-0004 Section 7.

keyRecordFingerprint() implements the Record Fingerprint exactly as ONP-0004 v0.2.0 Section 4.3 rule 4 now normatively specifies it: sha-256 over the JCS (RFC 8785) canonicalization of the parsed Publisher Key Record, base64url unpadded, labeled sha-256: per the Algorithm Registry identifier form. (This rule was added to the specification after this implementation surfaced that the pre-image was previously undefined — the gap-to-spec feedback loop working as ONP-9000 intends.)

Usage

npm install
npm run build
npm test                 # runs the test suite (88 tests)
npm run example          # signs and verifies the running fusie-onderzoek Article
npm run bridges           # exports the same Article to schema.org JSON-LD and RSS XML
npm run capstone         # the whole loop: sign -> RSS feed -> aggregate -> verified timeline (with a rejected forgery)
node dist/examples/generate-test-vectors.js   # regenerates examples/test-vectors.json

CLI

After npm run build, the onp command (also exposed as the package's bin) drives the SDK from the shell — no TypeScript required. verify exits 0 when the Object is Core-authenticated and 1 when it is rejected, so it drops straight into CI and pipelines.

onp keygen [--algorithm ed25519|ecdsa-p256]
onp sign <unsigned.json> --key <b64url-private> [--algorithm <id>] [--out <file>]
onp verify <file|url> [--key <b64url-public>] [--anchor <publisher.json>]
onp aggregate <feed-url> [<feed-url> ...]
onp publisher-json --domain <d> --key-id <id> --public-key <b64url> [--algorithm <name>]

verify runs the full pipeline — Trust Anchor resolution over HTTPS against the Object's own domain — by default; --key does offline crypto-only verification against a supplied public key, and --anchor resolves against a local Publisher Key Record instead of fetching one. Run the built entry directly during development with node dist/src/cli.js <command>.

Test Vectors

examples/test-vectors.json contains real, computed Test Vectors per specs/9000-reference-implementation.md Section 4.3: a Minimal Viable Object, a superseding Version, and a structurally invalid rejection case — each with a genuine VID and signature, generated against a fixed, published test keypair (never a production key). Any independent implementation can verify its own output against these values without running this code at all, which is the entire point of publishing them.

License

Apache License 2.0 — see LICENSE in this directory. This is separate from the CC BY 4.0 license covering specification text elsewhere in this repository, per ONP-9000 Section 4.5.