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/trust-tasks

v0.19.21

Published

Generated TypeScript bindings for the Trust Tasks framework registry.

Readme

@openvtc/trust-tasks

TypeScript bindings and the consumer pipeline for the Trust Tasks framework registry.

Two halves: generated types for every specification in the registry, and a hand-written implementation of the SPEC.md §7.2 checks that decide whether an inbound document may be acted on. See Consuming a document — types alone will not make a conforming consumer.

Every spec under dtgwg-trust-tasks-tf/specs/ that defines a payload.schema.json is compiled — via scripts/build-ts-bindings.mjs (json-schema-to-typescript) — to a TypeScript module under src/<slug>/<version>/payload.ts, giving you a typed Payload and (where the spec defines one) Response interface for each Trust Task. The package's root index.ts re-exports every module under a stable name keyed by the spec slug.

The Rust counterpart is trust-tasks-rs; both crates are regenerated together so the Rust and TypeScript wire shapes stay byte-identical.

Install

npm install @openvtc/trust-tasks

Usage

import { AclGrant_v0_1, DidManagementDidRegister_v0_1 } from "@openvtc/trust-tasks";

// Compose a request payload, type-checked against the spec's
// payload.schema.json. `Payload` is a stable alias every module
// exports, so you never have to look up the title-derived interface
// name (here, `ACLGrantPayload`).
const grant: AclGrant_v0_1.Payload = {
  entry: {
    subject: "did:key:z6MkAlice",
    role: "admin",
  },
  reason: "onboarding",
};

// Each module exports the Response sub-schema too when the spec
// defines one — the framework's #response fragment convention.
// Fire-and-forget specs export neither `Response` nor
// `RESPONSE_TYPE_URI`, because SPEC.md §4.4.1 forbids emitting a
// `#response` document for them.
const reply: AclGrant_v0_1.Response = {
  entry: { /* … */ },
};

// did-management example.
const register: DidManagementDidRegister_v0_1.Payload = {
  path: "alice",
  method: "webvh",
  didData: "{\"versionId\":\"1-…\",…}",
};

For the full list of generated modules, see src/index.ts or the website index.

Module layout

Each spec lands at a stable path:

src/
├── acl/grant/0.1/payload.ts           // AclGrant_v0_1
├── auth/authenticate/0.1/payload.ts   // AuthAuthenticate_v0_1
├── did-management/did/register/0.1/
│   └── payload.ts                     // DidManagementDidRegister_v0_1
├── vault/proxy-login/0.1/payload.ts   // VaultProxyLogin_v0_1
└── …

Slug / separators in the URI map to directory boundaries; the exported name is generated by Pascal-casing the slug segments and appending _v<MAJOR>_<MINOR>. Multiple versions of the same spec land in sibling directories (0.1/, 1.0/, …) and export distinct names — there is no "latest" alias by design.

Shared definitions

A definition several specs $refExt (the SPEC §4.5.1 extension object), AclEntry, VaultEntry, DigestMultibase — is declared once, in src/_shared/components.ts, and re-exported from every spec module that uses it under the name that module has always used. So AclGrant_v0_1.AclEntry and AclShow_v0_1.AclEntry are the same type, not two copies of one shape:

import { SharedComponents, type AclGrant_v0_1 } from "@openvtc/trust-tasks";

// Write a helper once, over the shared definition, and it takes any spec's.
const namespaces = (ext: SharedComponents.Ext) => Object.keys(ext);

Where one definition name covers more than one shape — VaultEntry differs between vault/_shared/0.1, 0.2 and 0.3components.ts qualifies each (VaultEntry_VaultV0_1, …) rather than pretending they are interchangeable. The spec modules still export the bare VaultEntry, bound to the version they were generated against.

Before 0.15.0 these definitions were copied into every module that referenced them, and repeated copies inside one module were numbered Ext1, Ext2, Vid1 and so on. Those numbered names are gone; see CHANGELOG.md for the one-line migration.

Consuming a document

A conforming consumer applies all eight checks in SPEC.md §7.2 before acting on an inbound document. Three of them — recipient-REQUIRED, proof-REQUIRED and audience binding — are declared per specification and cannot be derived from the document itself, so every generated module exports the declarations as SPEC (and RESPONSE_SPEC, where the spec defines a response).

consumeInbound runs item 2 and items 4–8, the freshness bound, and item 11's duplicate-execution record, then calls your handler. Items 1 and 3 (framework schema, unknown type) belong to your parse and dispatch, and have already succeeded by the time you hold a typed document.

import {
  consequentialChecks,
  consumeInbound,
  InMemoryReplayGuard,
  respondWith,
  StaticTransport,
  AclGrant_v0_1,
} from "@openvtc/trust-tasks";

// The guard *is* the duplicate-execution record — one per consumer, held for
// the process's lifetime. Back it with a shared store if you run replicas.
const guard = new InMemoryReplayGuard();

const outcome = await consumeInbound<AclGrant_v0_1.Payload, AclGrant_v0_1.Response>({
  transport: new StaticTransport({ issuer: peerVid }), // what the transport authenticated
  spec: AclGrant_v0_1.SPEC,
  proofPolicy: { kind: "verify", verify: myVerifier },
  payloadPolicy: { kind: "validate", validate: myValidator }, // or acceptUnvalidated
  // acl/grant is consequential: a replayed envelope must not grant twice.
  checks: consequentialChecks(guard), // or notConsequentialChecks()
  doc,
  myVid: "did:web:maintainer.example",
  now: Date.now(),
  newErrorId: () => crypto.randomUUID(),
  handler: async (accepted, parties) =>
    respondWith(accepted, crypto.randomUUID(), await applyGrant(accepted.payload, parties)),
});

switch (outcome.kind) {
  case "handled":
    return send(outcome.response);
  case "rejected":
    return send(outcome.error); // already addressed per §8.1
  case "suppressed":
    // §8.1: an `identityMismatch` the transport cannot safely answer. Emitting
    // anything here would be an oracle. Log it — silent is the rule, invisible
    // is a footgun.
    return log(outcome.reason);
  case "duplicate":
    // §7.2 item 11: this document already executed. Not an error — return the
    // prior result where there is one, otherwise emit nothing.
    return outcome.priorResponse === undefined ? undefined : send(outcome.priorResponse);
  case "accepted":
    return undefined; // fire-and-forget: nothing to emit
}

Choose the checks deliberately. consequentialChecks(guard) is correct for any task whose execution grants access, moves value, discloses a secret, or is otherwise irreversible — SPEC §7.2 item 11 makes duplicate-execution protection normative for those, and every transport binding delegates it to the consumer. notConsequentialChecks() keeps no record and is conformant only where the task is not consequential, or where the specification declares repeated execution safe and intended.

Choose a proof policy deliberately. { kind: "verify" } honours in-band proofs. { kind: "rejectIfPresent" } is for consumers with integrity from another layer — it refuses a proof-bearing document rather than silently dropping the proof, which would mislead the producer about the guarantees of the exchange. { kind: "acceptUnverified" } is the explicit opt-out and only safe where the transport already provides equivalent end-to-end integrity. A specification that declares proof REQUIRED rejects a proofless document under all three.

The pipeline mirrors consume_inbound in trust-tasks-rs check for check, so a TypeScript consumer and a Rust one reach the same verdict on the same document.

Validating payloads at runtime

This package does not bundle a JSON-Schema validator, so §7.2 items 1–2 (framework and payload schema validation) are yours to wire up. Fetch the payload.schema.json from https://trusttasks.org/spec/<slug>/<version> and feed it to ajv or any other Draft 2020-12 validator.

Versioning

The package version follows Semantic Versioning over this package's own API — the exported types, the runtime, and the generated module surface. A breaking change to any of those bumps the leading non-zero component (0.2.x0.3.0 while below 1.0); anything additive is a patch. Behavioural changes count: when a specification starts declaring proof REQUIRED, consumeInbound rejects documents it previously accepted, and the version has to reflect that even though the wire format is unchanged.

The version is not tied to the SPEC.md framework revision, which it once claimed to track. The two move for different reasons — a framework revision can change the spec-authoring contract without altering a single generated type. Read a document's framework version from the specification's targetFrameworkVersion declaration instead.

A bump in an individual spec's own MAJOR.MINOR ships as a new exported module name (AclGrant_v1_0 alongside AclGrant_v0_1) and so is additive here.

trust-tasks-rs and @openvtc/trust-tasks are usually released together and carry matching version numbers, so a given pair is known to be generated from the same registry revision. They diverge when a change is breaking on one side only — 0.15.0 is such a release, hoisting the shared definitions in a way that is safe here (TypeScript is structurally typed) and a coherence break in Rust.

One divergence is standing and worth knowing before you write a switch: StandardCode is a closed union here and #[non_exhaustive] in trust-tasks-rs, so a new SPEC §8.3 error code is a minor bump on this package and a patch on the crate. Narrow with isStandardCode and keep a default arm to be immune to it; the reasoning is on the type itself and in CHANGELOG.md.

License

Apache-2.0. See LICENSE.md at the repo root.

Contributing

This package is generated, not authored by hand. To change the exported surface, add or modify a spec under specs/ in the dtgwg-trust-tasks-tf repo and run npm run build-ts-bindings from the repo root. The generator updates this package's src/ tree atomically. See CONTRIBUTING-SPECS.md for the spec authoring guide.