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

restura-cli

v0.7.1

Published

Restura CLI — run API collections in CI with JUnit/HTML/JSON reporters

Readme

restura-cli

Run Restura API collections in CI — assert with scripts, get JUnit / HTML / JSON reports.

Live dashboard — restura run

Install

npm install -g restura-cli
# or, no install:
npx restura-cli run ./my-collection

Requires Node.js 24+.

Quick start

Export a collection from the Restura app (File → Export → OpenCollection directory), then:

restura run ./my-collection --reporter junit --reporter-output junit=results.xml

Exit code is 0 when every request passed, 1 if any failed, 2 on internal errors (missing collection, bad flags).

Interactive mode

Run restura (or restura run) with no collection in a terminal to launch a guided wizard — pick the collection, reporters, output paths, an optional env file, and whether to allow localhost, then it runs:

restura            # bare → wizard
restura run        # also → wizard when no <collection> is given

Interactive wizard

The wizard is terminal-only: piped output and CI never prompt. There, a missing collection is an error (exit 2) and bare restura prints help — so existing scripts and pipelines are unaffected. Cancelling (Ctrl-C / Esc) exits 130.

By default, an interactive run shows a live dashboard (the tui reporter); piped/CI runs fall back to plain line output (the live reporter). See Reporters.

Supported collection formats

The loader auto-detects three layouts:

| Layout | Detected when… | | ---------------------------------------- | --------------------------------------------------------------- | | OpenCollection directory (preferred) | the target directory contains opencollection.yml (or .yaml) | | OpenCollection bundled file | the target path ends in .yaml/.yml | | Legacy file-collection (deprecated) | the target directory contains _collection.yaml |

The legacy format prints a stderr deprecation warning the first time it's loaded.

Supported protocols

  • HTTP / REST — full support
  • GraphQL — runs as HTTP with body type graphql
  • gRPC — via Connect protocol (JSON-encoded, no proto compilation needed)
  • SSE — captures events for --sse-duration ms, or until --sse-events N
  • MCP — single JSON-RPC POST per request
  • WebSocket — not run in collection batches (matches the desktop collection runner, which skips streaming protocols). A standalone executor exists for future wiring (executors/websocket.ts) but no collection format routes to it yet.

Header-based auth (Bearer, Basic, API-key, OAuth2) is applied to HTTP/GraphQL, gRPC (as metadata), SSE, and MCP requests. For OAuth2, a pre-supplied access token is used as-is; if the auth instead carries a token endpoint + client id (and no token), the CLI fetches one via the client_credentials grant — the only non-interactive grant suited to CI — caching it per token-url/client/scope for the run. Wire-signed schemes (AWS SigV4, OAuth1, WSSE) are signed at the wire on the HTTP path. Auth configured at the collection or folder level is inherited by descendant requests (nearest-ancestor-wins), and collection/folder-level pre-request and test scripts run against every descendant. x-www-form-urlencoded bodies are sent for both inline (raw) and structured (OpenCollection field-array) forms. multipart/form-data is supported with text fields and file parts (file content must be inline base64 on the part; file parts that reference a path on disk are not read). protobuf bodies are not yet supported by the CLI fetcher.

CLI reference

restura run [collection] [options]

[collection] accepts a directory (any supported layout) or a bundled .yaml/.yml file. Omit it in a terminal to choose one via the interactive wizard; in CI it is required.

| Flag | Default | Description | | --------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------- | | --env <file> | | JSON or YAML env file. ${VAR} placeholders are expanded from process.env. | | --reporter <list> | auto | Comma-separated: tui, live, json, junit, html, stats. Defaults to tui in a terminal, live otherwise (piped / CI). | | --output <file> | | Shorthand for single file reporter. | | --reporter-output <kv...> | | Per-reporter output: --reporter-output junit=results.xml html=report.html. | | --bail | false | Stop on first failure. | | --timeout <ms> | 30000 | Per-request timeout. | | --allow-localhost | false | Permit requests to localhost / 127.0.0.1. Off by default (SSRF guard). | | --folder <path> | | Only run requests under this folder path (slash-joined). | | --include <pattern...> | | Substring or glob (e.g. users/*). Repeatable. | | --exclude <pattern...> | | Same syntax as --include. Applied after. | | --data <file> | | CSV (with header row) or JSON array. Runs the collection once per row; row keys are exposed as vars. | | --max-iterations <n> | | Cap iterations when a --data file is large. | | --retry <n> | 0 | Retry attempts per failing request. | | --retry-on <list> | network,5xx | Comma-separated triggers: network, 5xx, 4xx, or specific status codes (429,503). | | --sse-duration <ms> | 5000 | How long to keep SSE streams open. | | --sse-events <n> | | Stop SSE early after N events. | | --insecure | false | Skip TLS certificate verification (self-signed / staging). Insecure — use only when you trust the target. | | --ca <file> | | PEM CA bundle to trust (private CA) without disabling verification. | | --client-cert <file> | | PEM client certificate for mutual TLS (mTLS). | | --client-key <file> | | PEM client private key for mutual TLS. | | --cert-passphrase <value> | | Passphrase for an encrypted --client-key. | | --proxy <url> | | HTTP(S) proxy URL. Overrides HTTP_PROXY/HTTPS_PROXY and composes with the TLS options. |

TLS options apply to all HTTPS traffic for the run (HTTP/GraphQL/gRPC/SSE/MCP). They are global flags rather than per-request settings; per-domain client certificates (collection clientCertificates) are not yet honored — pass the cert that the run needs via --client-cert.

Proxies: the standard HTTP_PROXY / HTTPS_PROXY / NO_PROXY environment variables are honored automatically, or pass --proxy <url> to set one explicitly (this is the form that composes with the TLS flags above — the env var does not). SOCKS proxies and collection-scoped proxy config are not yet supported.

Scripts and assertions

Pre-request and test scripts run in a sandboxed QuickJS WASM VM (no DOM, no filesystem, no network escape; 64 MB memory cap, 5 s sync / 30 s async execution timeout).

# request.http.yaml
name: Get user
method: GET
url: '{{API_BASE}}/users/1'
testScript: |
  pm.test("status is 200", () => pm.response.to.have.status(200));
  pm.test("response has name", () => {
    pm.expect(pm.response.json()).to.have.property("name");
  });

When a test script runs and defines any pm.test(...) assertion, those drive pass/fail. Otherwise pass/fail falls back to the transport outcome (HTTP 2xx, gRPC OK, etc.).

Variables set inside a script (pm.environment.set('K', 'v')) propagate to subsequent requests in the same run.

Variables

Three layered sources, in order of precedence (later wins):

  1. --env file
  2. Collection variables (declared in opencollection.yml or _collection.yaml)
  3. Iteration row (when --data is set)

Substitutions are {{NAME}}. Unknown vars are left in place so the upstream sees them and you notice the gap.

Dynamic helpers

Postman-compatible {{$random*}} / {{$timestamp}} helpers are expanded after user var substitution:

| Helper | Example | | ---------------------- | --------------------------- | | {{$randomUUID}} | f4d2e3... | | {{$timestamp}} | 1700000000 (unix seconds) | | {{$isoTimestamp}} | 2026-05-22T13:42:00Z | | {{$randomEmail}} | [email protected] | | {{$randomFirstName}} | Olivia | | {{$randomIP}} | 192.0.2.4 |

Full list in src/lib/shared/dynamicVariables.ts.

Data-driven runs

restura run ./users-api --data ./users.csv --reporter junit --reporter-output junit=junit.xml
# users.csv
username,role
alice,admin
bob,viewer
charlie,editor

Each row exposes username and role as variables, overriding any same-named env or collection variable for that iteration only. JUnit testcase names carry an [iter N] suffix so each iteration is distinct in CI dashboards.

Reporters

  • tui — live, in-place dashboard with a progress bar and a spinner on the in-flight request. The default in an interactive terminal; on completion it collapses to a clean failure list + summary.
  • live — plain one-line-per-request progress. The default when output is piped or in CI (no ANSI cursor control). Force it with --reporter live if the dashboard misbehaves.
  • json — full RunResult dumped as JSON. Path required (--output or --reporter-output json=...).
  • junit — JUnit XML for CI dashboards. One <testcase> per request.
  • html — self-contained HTML page with embedded data + summary table.
  • stats — latency percentiles + throughput at the end of the run.

The default reporter is chosen automatically: tui when stdout is a TTY (and NO_COLOR is unset), live otherwise. Combine reporters with a comma: --reporter live,junit --reporter-output junit=results.xml.

The live reporter (also what CI logs get) prints one line per request:

Line reporter output

Exit codes

| Code | Meaning | | ---- | ------------------------------------------------------------------------------- | | 0 | Every request passed AND at least one request ran | | 1 | One or more requests failed or errored (or no requests matched after filtering) | | 2 | Internal error: missing collection, bad reporter name, IO failure, … |

Troubleshooting

  • No recognised collection layout — your target directory needs one of opencollection.yml, opencollection.yaml, or _collection.yaml. Re-export from the Restura app if unsure.
  • Invalid URL — the URL after {{var}} resolution isn't a valid absolute URL. Check that --env is loaded and your var names match.
  • Localhost URLs are not allowed — add --allow-localhost for local upstreams. Off by default to prevent SSRF in shared CI.
  • gRPC requests return UNKNOWN — the upstream likely doesn't speak Connect protocol. The CLI uses Connect-over-HTTP, not gRPC-over-HTTP/2 binary framing.
  • auth uses a desktop-only secret handle… — your auth references a secret handle that only the desktop app can decrypt. The request is errored (not sent unauthenticated); re-export the collection with inline secret values for CI use.

Development

# from cli/
npm install
npm test                   # vitest
npm run type-check         # tsc --noEmit
npm run build              # tsup → dist/

The CLI imports from the parent project at compile-time via path aliases (@/, @shared/); cli/tsconfig.json controls which parent modules participate in type-checking.

License

MIT.