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

@riddledc/riddle-proof-runner-playwright

v0.6.1

Published

Local Playwright runner for Riddle Proof profiles.

Readme

@riddledc/riddle-proof-runner-playwright

Local, self-hosted Playwright runtime for Riddle Proof profiles.

This package is the minimal trusted reference implementation for running profile scripts in your own process.

Install

pnpm add -D @riddledc/riddle-proof-runner-playwright
pnpm add -D playwright

playwright is a peer dependency and must be installed in your environment. Install its bundled browser with npx playwright install chromium. If that executable is absent and PLAYWRIGHT_BROWSERS_PATH was not explicitly set, the Chromium runner can use an installed system Chrome instead.

CLI

Run one profile with a local browser session:

riddle-proof-playwright run-profile \
  --profile ./mobile-layout-smoke.json \
  --url https://example.com \
  --output ./artifacts/riddle-proof \
  --viewport-name desktop

Use --help for full flag details.

When the URL is a Riddle Preview, attach its immutable receipt so the local executor preserves the Preview target and source binding instead of recording an unbound generic URL:

riddle-proof-playwright run-profile \
  --profile ./mobile-layout-smoke.json \
  --url https://preview.riddledc.com/s/pv_example/ \
  --preview-receipt ./artifacts/preview/preview-receipt.json \
  --source-revision "$PR_HEAD_SHA" \
  --output ./artifacts/riddle-proof-preview

--source-revision, --source-repository, and --source-dirty override individual source fields; unspecified fields continue to come from the Preview receipt.

The CLI exits according to the profile's failure_policy; a regression, blocked environment, or insufficient required evidence therefore produces a nonzero process exit when the policy says it should. Use --always-zero only for an explicit collector workflow that must persist evidence without gating the calling process.

Node API

import { runProfileLocal } from "@riddledc/riddle-proof-runner-playwright";

const result = await runProfileLocal({
  profile: {
    version: "riddle-proof.profile.v1",
    name: "mobile-layout-smoke",
    target: {
      route: "/",
      viewports: [{ name: "desktop", width: 1280, height: 800 }],
      wait_for_selector: "body",
      setup_actions: [{ type: "wait", ms: 200 }],
    },
    checks: [
      { type: "text_visible", text: "Example" },
      { type: "no_fatal_console_errors" },
    ],
  },
  outputDir: "./artifacts/riddle-proof",
  url: "https://example.com",
  // previewReceipt: parsedPreviewReceipt,
});

console.log(result.result.status);

For a trusted target that requires a runtime credential, the Node API can add headers directly to the Playwright browser context:

const result = await runProfileLocal({
  profile,
  outputDir: "./artifacts/riddle-proof",
  url: "http://127.0.0.1:4173",
  extraHTTPHeaders: {
    "x-local-run-capability": process.env.LOCAL_RUN_CAPABILITY!,
  },
});

extraHTTPHeaders is runtime-only. It is not a profile field or CLI option, and the runner does not write the header map into results, receipts, grounded capture bundles, manifests, summaries, or other artifacts. Playwright applies these headers across the browser context, including redirects and subresource requests, so use the option only with an isolated target whose entire request graph is trusted. A target can still expose a received secret in its own DOM or responses; callers must not capture such reflected content as evidence.

To bind the browser observation to an independent challenge, semantic scope, collector/verifier identities, and an Ed25519 signer, pass groundedCapture to runProfileLocal:

const result = await runProfileLocal({
  profile,
  outputDir: "./artifacts/riddle-proof",
  url: "https://example.com",
  groundedCapture: {
    scope,
    nonce, // canonical base64url encoding of an independently issued 32-byte challenge
    collector,
    verifier,
    signingKey: {
      key_id: "local-playwright-key",
      private_key_pkcs8_base64: privateKeyDer.toString("base64"),
    },
  },
});

console.log(result.groundedCapturePath);

This mode also writes normalized-profile.json, profile-evidence.json, and grounded-capture-bundle.json. The signed bundle contains the exact persisted artifact bytes and declares the browser name/version, user agent, observed URL, and capture policy. The legacy manifest, observation receipt, and bundle itself are deliberately excluded from the signed artifact set to avoid self-reference cycles. Verification still requires an independently supplied policy, trusted public key, and deterministic verifier via verifyRiddleProofSignedCaptureBundle from @riddledc/riddle-proof-core.

Sealed profile composition

An exploratory browser run may remain unsealed. When a browser result is going to be reused as a proof premise, the package can turn one signed profile-result.json into an exact seven-node checked closure:

capture bound to scope + route matched       -> target confirmed
declared profile passed + captured run clean -> behavior confirmed
target confirmed + behavior confirmed        -> sealed profile satisfied

Every node carries the same repository, revision, environment, target, proof-attempt, profile-name, and exact normalized-profile digest. The three rules require all seven to match, so a fact from another run or a weaker profile with the same name cannot silently enter the pyramid. The root means only that the exact declared profile was satisfied for that sealed scope; it does not mean that the page is generally correct or release-ready.

Independently compute the digest of the exact normalized profile bytes, construct the expected protocol before capture, use its verifier reference for the signed capture, and then issue the checked closure:

import {
  createRiddleProofBrowserSealedProof,
  createRiddleProofBrowserSealedProtocol,
  replayRiddleProofBrowserSealedProof,
} from "@riddledc/riddle-proof-runner-playwright";

const expected = createRiddleProofBrowserSealedProtocol({
  expected_scope: scope,
  expected_profile_name: profile.name,
  expected_profile_digest: expectedProfileDigest,
});
if (!expected.ok) throw new Error(expected.error.message);

// Pass expected.protocol.verifier.verifier_ref to
// runProfileLocal({ groundedCapture: ... }).

const proof = createRiddleProofBrowserSealedProof({
  bundle: groundedCaptureBundle,
  expected_scope: scope,
  expected_profile_name: profile.name,
  expected_profile_digest: expectedProfileDigest,
  authority: { policy, trusted_signers },
  protocol: expected.protocol,
  leaf_issued_at: policy.verification_time,
  target_issued_at: targetIssuedAt,
  behavior_issued_at: behaviorIssuedAt,
  root_issued_at: rootIssuedAt,
});
if (!proof.ok) throw new Error(proof.error.message);

const replay = replayRiddleProofBrowserSealedProof({
  checked_closure: JSON.parse(JSON.stringify(proof.checked_closure)),
  // Independently supplied by the consumer; never copied from the packet.
  authority: { policy, trusted_signers },
  protocol: expected.protocol,
  expected_root_certificate_id: proof.root_certificate.certificate_id,
  expected_scope: scope,
  expected_profile_name: profile.name,
  expected_profile_digest: expectedProfileDigest,
});
if (!replay.ok) throw new Error(replay.error.message);

Replay, exact-root matching, missing-premise rejection, mutation rejection, and branch reuse are the acceptance criteria. A fresh agent can invoke replay as a portability check, but whether that agent happens to feel like rechecking is not a proof property. This is semantic compaction rather than byte compression: callers can rely on the root while the complete signed evidence and derivation graph remain available for expansion and audit.

The installed package's external sealed-observation verifier is part of the trust boundary. Replay replaces serialized verifier callbacks with that pinned registration; the core checks its declared identity and invokes it, but does not derive an implementation digest from JavaScript function source. The verifier parses the exact digest-pinned normalized profile, binds result and evidence timestamps to the signed capture, deterministically reassesses the signed evidence against the profile, and requires the reported status, route, and exact ordered check-identity vector to match that reassessment. It can therefore authenticate passed, product_regression, proof_insufficient, and environment_blocked observations without treating those outcomes as interchangeable. The sealed-profile contracts—not the observation verifier—separately require passed evidence before issuing a successful sealed root. The same signed capture can consequently support an honest negative or unresolved report without weakening the successful proof.

Sealed-observation protocol v3 intentionally does not replay archived v2 protocol objects. Version 3 tightens canonical-profile and result binding, so callers with v2 captures must recapture and recompose instead of silently receiving the newer verification semantics.

Replay also reconstructs every exact contract registration and expected contract from the protocol. The consumer must supply the capture policy and trusted signer set independently. proof.replay_contexts is useful for same-process composition, but it is convenience output—not a portable trust root and not an input to sealed replay.

Durable browser-transition composition

The transition protocol composes four separately signed, exact-profile checkpoints into a reusable fan-out graph:

before + action/after -> transition observed (T)
T + reload readback  -> transition survived reload (PR)
T + fresh readback   -> transition visible in fresh context (PF)
PR + PF              -> durable state transition observed (D)

createRiddleProofBrowserTransitionProtocol pins the scope, binds the transition ID to scope.proof_attempt, four profile names, four distinct normalized-profile digests, and all seven composition rules. createRiddleProofBrowserTransition independently replays the four sealed checkpoints using one caller-supplied evidence-authority entry per role, requires four distinct signed capture bundles, and enforces the signed capture partial order before <= action, action <= reload, and action <= fresh without imposing an order between reload and fresh. It then creates D. replayRiddleProofBrowserTransition independently reconstructs all 16 leaf contexts from those authorities and exact protocol contracts, re-verifies every signed leaf, checks the expected root, and repeats the bundle and signed- capture chronology checks. The shared T branch remains one content- addressed node, so replacing only the fresh-context capture preserves the before/action and reload certificate IDs while producing replacement PF and D certificates. The immutable historical certificates remain auditable.

Returned transition replay contexts are likewise same-process convenience data. Consumers hand off the checked closure and separately pinned protocol, profiles, scope, root ID, and four evidence authorities; packet-supplied policies, signers, verifiers, or contracts never authorize replay.

The root is intentionally narrow: the declared before, action/after, reload, and fresh-context profiles were observed under the exact protocol. It does not prove that the action caused the state, identify the persistence mechanism, or establish general application correctness.

Artifacts are written to the output directory:

  • profile-result.json
  • proof.json
  • console.json
  • dom-summary.json
  • summary.md
  • artifact-manifest.json
  • observation-receipt.json
  • optional screenshots/*.png
  • optional grounded-capture files listed above

The Observation receipt records the local executor and source Git identity, uses the final viewport frame as its canonical screenshot, distinguishes setup screenshots from final evidence, and points at the actual artifact paths in the manifest.

Outputs

  • result: normalized RiddleProofProfileResult
  • outputDir: resolved output directory used for artifact writes
  • manifestPath: absolute path to artifact-manifest.json
  • observation: parsed riddle-proof.observation-receipt.v1
  • observationPath: absolute path to observation-receipt.json
  • groundedCaptureBundle: parsed signed bundle when groundedCapture is enabled
  • groundedCapturePath: absolute path to grounded-capture-bundle.json when enabled
  • groundedCaptureError: explicit omission reason when grounded capture was requested but no truthful signed browser capture could be created