Skip to content
Preview (Alpha), release 0.1. No independent cryptographic review of the protocol or its reference verifiers has been done.

Your first verification, in TypeScript

In this tutorial you build @loquitur/verify, the TypeScript verifier, and run it over the test vectors that ship in its repository. It is a library for Node.js, with no command line. Only the first steps use the network; the verifications themselves run offline.

You need Git and Node.js 22 or later.

Get the material

Clone the repository at the release tag.

Terminal window
git clone --branch v0.1.0 https://github.com/loquitur-dev/loquitur-verify-ts.git

The directory you are in now is the one that contains the clone. The last section of this page starts from it again.

Run the verifier over the test vectors

Move into the clone:

Terminal window
cd loquitur-verify-ts

npm ci installs the three runtime dependencies and the build tools; it is the last step of this section that uses the network.

examples/verify-test-vectors.mjs verifies the bundles in test-vectors/ through the package’s public entry point and compares each report with the outcome test-vectors/verify.json records for it. From a clone:

Terminal window
npm ci
npm run build
node examples/verify-test-vectors.mjs

It prints one line per case and exits 0 when every report matches, 1 otherwise:

valid PASS exit 0 local_integrity_checks_passed
tampered FAIL exit 1 p1_integrity_failed
link PASS exit 0 local_integrity_and_registry_link_checks_passed
authorization_valid REVIEW exit 2 trust_registry_root_not_pinned AUTHORIZED_ACTIVE_KEY VALID_SIGNATURE NO_PINNED_TRUST_ROOT
authorization_revoked FAIL exit 1 trust_registry_verification_failed ISSUER_KEY_REVOKED null ROOT_SIGNATURE_NOT_EVALUATED
all 5 reports match test-vectors/verify.json

The example passes the evaluation time test-vectors/verify.json records for the two authorization cases, 2026-05-20T00:00:00Z. authorization_valid is REVIEW because no trust-root document is supplied: the trust registry is authorized at that time and the signature holds, but nothing authenticates the registry itself. The case names and outcomes are those test-vectors/verify.json records. test-vectors/ holds local fixtures, not the corpus: the pinned conformance corpus is the reference (see Conformance below).

Included from loquitur-verify-ts/README.md, “Try it”. MIT OR Apache-2.0.

The five cases cover most of what the Python tutorial shows on the command line: a PASS on the two checks every run makes, a FAIL on tampered bytes, a PASS with the link check, and the authorization check twice. authorization_valid stops at REVIEW with the reason trust_registry_root_not_pinned, because no trust root is given. The test vectors of this repository carry no trust-root document, so the PASS with a pinned trust root is shown in the Python tutorial.

Call it from your own code

Go back to the directory that contains the clone, and create the project that will use the package. npm init -y writes a package.json; the example below is saved as check.mjs, so it is an ES module whatever the project says.

Terminal window
cd ..
mkdir your-project
cd your-project
npm init -y
cd ..

You are again in the directory that contains the clone and your-project. Install the package into your project from the tarball:

Build a tarball from a clone of loquitur-verify-ts and install it in your project. The commands are the same in PowerShell and in a POSIX shell:

Terminal window
cd loquitur-verify-ts
npm ci
npm pack # builds dist/ and writes loquitur-verify-0.1.0.tgz
cd ../your-project
npm install ../loquitur-verify-ts/loquitur-verify-0.1.0.tgz

Included from loquitur-verify-ts/README.md, “Installation”. MIT OR Apache-2.0.

The commands above end in your-project. Save this there as check.mjs. It verifies a bundle that ships in the clone, with no registry entry, trust registry or trust root, which are all optional:

import { verifyBundle } from "@loquitur/verify";
const report = verifyBundle("../loquitur-verify-ts/test-vectors/bundles/valid_bundle", {});
console.log(report.status, report.verdict, report.exit_code);
Terminal window
node check.mjs

It prints OFFLINE_OK PASS 0. This is the same PASS on the two checks every run makes that the first case of the previous section shows.

The next block is the full form of the call. In it, registryEntry, trustRegistry and trustRoots are documents the host has read, and each is optional: leave them out, as above, for your first run. Replace ./my_bundle with the path of a bundle you have.

import { verifyBundle } from "@loquitur/verify";
// registryEntry, trustRegistry and trustRoots are documents the host has read,
// for instance with readDocumentPath, which the package exports.
const report = verifyBundle("./my_bundle", {
registryEntry, // optional: requests the link check
trustRegistry, // optional: requests the authorization check; FAIL without registryEntry
trustRoots, // optional: without it, an authorization that holds is REVIEW
// The operator's time; without it, authorization is not established (REVIEW).
evaluationTime: "2026-05-20T00:00:00Z",
});
console.log(report.status, report.verdict, report.exit_code);
console.log(report.checks_requested, report.checks_established, report.review_reasons);
console.log(report.outcome.reason, report.errors.map((e) => e.code)); // the reason surface
console.log(report.trust_registry); // the three authorization statuses, or null
console.log(report.checks); // per-check results, same keys as loquitur-verify

The documents are values, not paths: the host reads them and passes what it found. That is the parsed document, or one of four markers this package exports: DOCUMENT_PATH_NAMES_NOTHING when nothing is found at the path, DOCUMENT_PATH_NAMES_NO_REGULAR_FILE when what is found is a directory or anything else that is not a regular file, DOCUMENT_READ_FAILED when reading the file failed, and DOCUMENT_NOT_STRICT_JSON when the bytes are not strict JSON. report-contract.md section 5.3 gives the first three conditions errors of their own for a registry entry, different from a document that is not strict JSON, so a host that passed a document for them would report what loquitur-verify, which reads the path itself, does not. A file the host failed to read is a host failure for the trust registry and the trust roots too: trust_registry_read_failed and trust_root_read_failed, HOST_FAILURE, exit 5.

Included from loquitur-verify-ts/README.md, “Quick start”. MIT OR Apache-2.0.

Next

Project site: loquitur.dev

Written for this site; text licensed CC BY 4.0. Included sections keep the licence of their source, named under each.