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

@openvtc/pnm-core

v0.9.1

Published

Browser-side bridge between WebAuthn passkeys and VTA-managed DIDs. Wire types, WebAuthn ceremony helpers, COSE→Multikey conversion, DID verificationMethod builder, REST + DIDComm transports, mediator client, SIOP / RP-login / provision-integration flows.

Readme

@openvtc/pnm-core

Browser-side bridge between WebAuthn passkeys and VTA-managed DIDs. Lets a relying party prove the user controls a DID hosted in a remote Verifiable Trust Agent (VTA) by performing a passkey ceremony in the browser — no DID private keys ever leave the VTA, and no long-lived bearer token sits in browser storage. Speaks both REST and full DIDComm v2 to the VTA, including when the VTA is private-network and only reachable via a mediator.

This package is the shared TypeScript library that backs the Personal Network Manager browser plugin: both the PWA and the Manifest v3 extension are thin shells over it. External consumers can use it directly to build mobile companions, desktop wallets, or RP-side integrations that need the same flows without the bundled UI.

Install

npm install @openvtc/pnm-core

What it gives you

| Sub-module | Surface | |---|---| | @openvtc/pnm-core/webauthn | Passkey enrol / login ceremonies, COSE-key extraction, DID verificationMethod builder, PRF-derived secret-wrap helpers. | | @openvtc/pnm-core/did | Multikey ↔ JWK conversion, DID-URL parsing, did:webvh log resolution. | | @openvtc/pnm-core/vta | The VTA protocol: Trust-Task envelopes, REST/DIDComm/TSP channels, the REST auth bootstrap, passkey login as a Trust Task, and trust-task-discovery for asking an agent what it supports. Mirrors the vta-sdk Rust client's surface. | | @openvtc/pnm-core/did-hosting | The did-management/* control plane — registering, publishing, disabling and rolling back hosted DIDs, plus domains and server instances. A hosting service, not an agent. | | @openvtc/pnm-core/vtc | Verifiable Trust Community membership, from the member's side: apply, track, hold the credential, leave. | | @openvtc/pnm-core/credentials | OID4VCI issuance and OID4VP presentation, plus the deferred presentations a verifier asked for while you were away. Holder-side. | | @openvtc/pnm-core/vault | Vault Trust Tasks — list, upsert, delete, release, proxy-login, sign. | | @openvtc/pnm-core/app-state | Agent-held key/value state scoped to a VTA context — the state a wallet needs true on every device, as distinct from /store, which is this browser profile's own. | | @openvtc/pnm-core/admin | Agent administration: acl/*, keys/*, policy/*, consent/*, device/* (list, disable, wipe), vta/did-templates/*, vta/memory/*, vta/services/* (including drains), vta/credentials/{issue,revoke}, audit/list, config/{show,patch}, messaging/ping, session introspection, and context deletion. Operator surface — not in the root barrel, import it explicitly. | | @openvtc/pnm-core/siop | SIOPv2 / OpenID4VP RP-side helpers. | | @openvtc/pnm-core/provision | Sealed-bootstrap provisioning (provision/integration). | | @openvtc/pnm-core/didcomm | DIDComm v2 packing, mediator routing, forward envelopes. | | @openvtc/pnm-core/store | Key/value persistence (IndexedDB in a browser, in-memory elsewhere). | | Plus | /device, /inbound, /onboarding, /rp-login, /trust-tasks, /http, /util. |

Import the module you need, not the package. Every module directory is a published entry point, the package is marked sideEffects: false, and the modules are layered so that lower ones never import higher ones — so import "@openvtc/pnm-core/vta" gets you the VTA protocol without the wallet's WebAuthn ceremonies or its IndexedDB store coming with it. Two tests enforce this rather than trusting it (tests/package.module-boundaries.mjs, tests/package.entry-points.mjs): one fails the build on a sideways or upward import or a cycle, the other imports every advertised entry point in plain Node so a stray browser global cannot reach npm.

The root src/index.ts still re-exports everything, for callers who want it all in one import.

Minimal example — passkey enrolment

import {
  beginEnrolment,
  finishEnrolment,
  type WebauthnEnrolmentChallenge,
} from "@openvtc/pnm-core";

// 1. Ask the VTA for an enrolment challenge for the named DID.
const challenge: WebauthnEnrolmentChallenge = await vtaClient.enrolBegin({
  did: "did:webvh:example.com:alice",
});

// 2. Run the WebAuthn create() ceremony in the browser.
const credential = await beginEnrolment(challenge);

// 3. Submit the assertion. The VTA verifies it, appends the COSE
//    public key as a `verificationMethod` on the WebVH log, and
//    publishes the new DID-document revision.
const result = await finishEnrolment(credential, challenge.session_id);

Wire compatibility

Types come from the specification, not from a copy of it

The admin/* calls take their payload types, response types and task URIs from @openvtc/trust-tasks — generated from the same JSON Schemas the agent's own implementation is generated from. This package supplies the call layer: envelope, dispatch, unwrap.

Checked against the agent, not assumed

Every VTA call this library makes names a canonical Trust-Task URI, and task-surface.json is a committed snapshot of the surface the agent actually publishes (from vta-sdk). tests/task-surface.mjs holds the two of them together:

  • a URI this library names that the agent has never heard of — a typo, a rename, a task that moved — fails the build here rather than at a user;
  • a task version the SDK has deprecated fails too, during the window where the agent still accepts it and everything appears to work;
  • coverage is a recorded number (152 of 177 task families today), so a gap that grows or shrinks shows up in a diff someone reviews — and it moves when the agent grows a family just as much as when this library adds one.

Refresh the snapshot against a local checkout:

npm run tasks:sync -- /path/to/vta-sdk

A second snapshot, acl-capabilities.json, covers the one part of the ACL surface that has no binding to generate from. AclEntry.role is specified as "an opaque role identifier interpreted by the ACL maintainer", so roles — and the capabilities they imply — are ecosystem-local and live in ext under org.openvtc.capabilities. src/admin/acl-capabilities.ts therefore keeps a copy of the agent's tables, and the snapshot is what stops the copy drifting:

npm run acl:sync -- /path/to/vti-common

The failure it guards is asymmetric and worth naming. A role whose derived set grows at the agent and not here makes the console under-report what an entry can do — an operator reading a narrowing believes it holds less than it holds, which is the misreading the agent's capability enforcement was added to end.

This package is byte-compatible with:

A change to the wire surface is made in dtgwg-trust-tasks-tf first, regenerates the Rust + TS bindings, and only then lands in this package — see the project's spec-first development discipline.

Architecture

┌──────────────┐  WebAuthn        ┌────────────────┐
│   Browser    │ ───────────────▶ │  Authenticator │ (Touch ID,
│ (PWA / ext)  │ ◀─────────────── │   / Passkey    │  Windows Hello,
└──────┬───────┘   pubkey + sig   └────────────────┘  YubiKey, …)
       │
       │ enrol(passkey_pubkey)         verify(assertion)
       ▼                                       ▲
┌──────────────┐                       ┌───────┴────────┐
│      VTA     │ ── WebVH update ─────▶│ Public DID doc │
│   (remote)   │                       │ (resolvable by │
└──────────────┘                       │  any verifier) │
                                       └────────────────┘

A passkey is enrolled as a verificationMethod (purpose: authentication) in the DID document the VTA publishes via WebVH. Any verifier that resolves the DID can then validate a WebAuthn assertion against the embedded public key without ever talking to the VTA — the DID document is the trust anchor.

Browser / runtime support

  • Modern browsers with WebAuthn level 2 + WebCrypto (Chrome 108+, Safari 17+, Firefox 122+).
  • Node 20+ for server-side use (the WebAuthn-specific entry points are no-ops in non-browser contexts; the DID / VTA / DIDComm transports work everywhere).

ESM-only — no CommonJS build.

Versioning

Pre-1.0 (0.x) — breaking changes may land in minor bumps. The internal contract this package depends on (@openvtc/vti-didcomm-js, @openvtc/trust-tasks) follows the same cadence. Once the underlying SPEC.md reaches 1.0 this package will follow.

License

Apache-2.0. See LICENSE at the repo root.

Contributing

Source lives in OpenVTC/vta-browser-plugin under packages/core/. See the root README for the workspace layout, development setup, and the smoke-test harness.