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

@reopt-ai/data-cli

v0.1.0

Published

reopt-data command line: provision organizations and projects, run analytics queries, and upload source maps — built for CI and AI agents

Readme

@reopt-ai/data-cli

reopt-data — the command line for a reopt-data deployment. Provision organizations and projects, run analytics queries, manage the event catalogue, and upload source maps from CI. Built to be driven by scripts and AI agents as much as by people.

npm install -g @reopt-ai/data-cli     # or: npx @reopt-ai/data-cli --help
reopt-data --help

Node 22 or newer. Runtime dependencies: @reopt-ai/data-contract, zod, and @modelcontextprotocol/server (loaded only by reopt-data mcp).

Commands

| Group | Command | Needs | Effect | | ----------- | -------------------------------------------------------------------------- | -------------------------- | ------------------- | | org | create, update | platform key | writes | | org | rotate-key | platform key | destructive --yes | | project | list, get | org key | read-only | | project | create, update | org key | writes | | project | delete, rotate-secret | org key | destructive --yes | | event | set-meta | org key | writes | | query | timeseries, funnel, retention, traffic-overview, traffic-sources | client credential | read-only | | sourcemap | inject, upload | key by target | writes, --dry-run | | event | init, pull, diff, verify, push, types, history | org key (init/types: none) | see below | | config | link (also reopt-data link), show | none | local writes |

reopt-data <group> <command> --help prints every flag with its type, default and whether it is required — generated from the same schema the parser validates against.

Credentials

Set them in the environment. Flags (--platform-key, --org-key, --client-id, --client-secret) exist for one-off use; they land in shell history.

| Variable | Issued by | Used by | | --------------------------------------------------- | ------------------------------------------------- | ---------------------------------------------- | | REOPT_DATA_API_URL | you; default https://data.reopt.ai | everything | | REOPT_DATA_PLATFORM_KEY | the deployment operator | org *, platform uploads | | REOPT_DATA_ORG_KEY | org create (once) / org rotate-key | project *, event *, project & host uploads | | REOPT_DATA_CLIENT_ID + REOPT_DATA_CLIENT_SECRET | project create (once) / project rotate-secret | query * |

A command that lacks its credential exits 2 before making any request and names the variable to set.

Output contract

  • stdout carries the result and nothing else. Default --format json prints the server's response verbatim — the shape documented in @reopt-ai/data-contract. --format text gives a one-line human summary where one exists.

  • stderr carries progress (--quiet silences it) and, on failure, one envelope:

    { "error": "auth_error", "message": "…", "exitCode": 2, "status": 401, "apiCode": "invalid_key", "requestId": "…" }
  • Exit codes name the caller's next move:

    | Code | Name | Do | | ---- | ----------------------- | ----------------------------------------------------------- | | 0 | success | | | 1 | api_error | server or network failed; retryAfterMs if the server said | | 2 | auth_error | set or rotate the credential named in message | | 3 | validation_error | fix the input; details.issues lists each field | | 4 | config_error | environment incomplete (URL, directory, peer dependency) | | 5 | internal_error | CLI bug — please report with requestId if present | | 6 | partial_failure | some items failed; the result on stdout lists them | | 7 | confirmation_required | destructive command; re-run with --yes | | 8 | drift_detected | event verify: file and server disagree; pull or push |

Giving input

Three equivalent ways, merged (later wins):

# flags, kebab-case, one per field
reopt-data query funnel --project-id prj_1 --start-date 2026-08-01 --end-date 2026-08-31 \
  --steps view_item --steps add_to_cart --steps purchase

# one JSON object — inline, from a file, or from stdin
reopt-data query funnel --input '{"projectId":"prj_1","steps":["view_item","purchase"],…}'
reopt-data query funnel --input @funnel.json
echo '{…}' | reopt-data query funnel --input @-

# positionals for ids
reopt-data project get prj_1

Arrays of scalars repeat the flag; nested objects take JSON (--property-filters '[{"key":"plan","value":"pro"}]'). null clears a nullable field (--symbol-host-app null). Booleans stand alone (--conversion, --no-conversion).

For agents

reopt-data tools --json

returns every command with its inputSchema (JSON Schema 2020-12), flags, which credential it needs, whether it mutates, whether it is destructive, supportsDryRun, and ready-to-run examples. Read it once; the schemas are the contract package's own, so what validates here validates at the server.

Rules an agent can rely on:

  • A destructive command never runs without --yes — it exits 7 first, before any network call.
  • Validation and credential checks happen before any request; exit 2 and 3 mean nothing was sent.
  • --dry-run on sourcemap upload and sourcemap inject touches nothing and needs no key. On any other command it is refused (exit 3) rather than ignored.
  • Creating with the same --external-id twice is safe: the second call answers created:false and returns no secret.
  • stdout is always parseable when the exit code is 0 or 6.

MCP

reopt-data mcp

serves the same tools over the Model Context Protocol on stdio — one entry per command, named reopt_data_<group>_<command> (reopt_data_project_create, reopt_data_query_funnel, …). Credentials come from the environment the client starts the server with. Destructive tools take a required confirmed: true argument instead of --yes; dry-runnable ones take dryRun. Annotations (readOnlyHint, destructiveHint) are derived from the same definitions, and a failed call returns the CLI's error envelope as its text with isError: true.

{
  "mcpServers": {
    "reopt-data": {
      "command": "npx",
      "args": ["-y", "@reopt-ai/data-cli", "mcp"],
      "env": { "REOPT_DATA_ORG_KEY": "…" }
    }
  }
}

The same registry is importable for in-process use:

import { allTools, run, toolCatalog } from "@reopt-ai/data-cli";

Event catalogue as code

Declare the project's event catalogue in reopt-data.events.json next to the code that emits the events, and let CI keep the server in step with the commit that ships:

{
  "$schema": "https://data.reopt.ai/schemas/event-catalog.v1.json",
  "version": 1,
  "projectId": "prj_123",
  "events": {
    "purchase": { "displayName": "Purchase", "conversion": true, "rollupProperties": ["plan", "currency"] },
    "healthcheck": { "status": "internal" },
    "$pageview": {},
  },
}

The file is the truth: a field you leave out is the default, and an event you remove is archived (never deleted). A lock file beside it (reopt-data.events.lock.json, commit it) records the last sync so diff can tell your edits from console edits.

reopt-data event init --project-id prj_123    # or: event pull, to start from what the server has
reopt-data event diff --format text           # + create  ~ update  - archive  ! changed on the server
reopt-data event push                         # plan only
reopt-data event push --apply --yes           # write; --yes covers metric-changing and expensive changes
reopt-data event verify                       # CI gate: exit 8 on drift
reopt-data event types --out src/reopt-events.d.ts   # ReoptEventName / ReoptEventProperties for a typed track()

Changes are graded: safe (display fields), metric-changing (conversion, status) and expensive (rollupProperties, which queues a rollup rebuild); the last two need --yes. A push sends the last sync's updatedAt with every event, so a console edit made in between is refused as a whole (409) instead of half-applied — event pull first, or --force to overwrite.

Source maps in CI

# after `next build`
reopt-data sourcemap inject --dir .next/static
reopt-data sourcemap upload --dir .next/static \
  --url-prefix https://shop.example.com/_next/static --project-id "$REOPT_DATA_PROJECT_ID" \
  --release "$GIT_SHA" --delete-after-upload

One bundle serving many projects uploads once per host app, keyed by path:

reopt-data sourcemap upload --dir .next/static --path-prefix /_next/static \
  --host-app studio-web --organization-id org_abc --release "$GIT_SHA"

inject-chunk-ids and upload-sourcemaps — the spellings from @reopt-ai/data-sdk-server's bin — still work, as do its --api-key (either upload key) and --silent (= --quiet) flags. Note the exit code for a partial failure is 6, where the old bin used 1.

License

MIT