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

@the-meridian/cli

v1.0.0

Published

Meridian CLI — managed remote development databases for Shopify apps built on Meridian.

Readme

@the-meridian/cli

A managed remote MySQL development database for every developer on your team, with no local database setup.

meridian dev provisions a private MySQL 8.4 database on Meridian's Cloud SQL instance, starts the Cloud SQL Auth Proxy on a local port, writes DATABASE_URL into your .env, and runs your app's dev server. Prisma, mysql, and anything else that reads DATABASE_URL then talk to 127.0.0.1 as if the database were local.

npm install -g @the-meridian/cli

meridian login          # once per machine
meridian link           # once per project
meridian dev            # every day

Requirements

  • Node.js 20 or newer
  • A Meridian account with access to at least one organization and app

You do not need Docker, a local MySQL server, gcloud, or the Cloud SQL Auth Proxy — the CLI downloads and manages the proxy for you.

How it works

meridian dev
  │
  ├─ POST /app/cli/apps/{app}/dev-database          ensure a database exists (polls until ready)
  ├─ POST …/dev-database/credentials                short-lived MySQL user + password
  ├─ POST …/dev-database/proxy-token                short-lived GCP access token
  ├─ download cloud-sql-proxy v2 → ~/.meridian/bin  cached, SHA-256 verified
  ├─ spawn proxy on 127.0.0.1:<free port>           token passed in the environment, refreshed before it expires
  ├─ patch DATABASE_URL into .env                   every other line preserved
  └─ run your dev command                           npm run dev by default

Both child processes are shut down together: quitting your dev server stops the proxy, and Ctrl-C stops both.

Commands

Run meridian <command> --help for the full flag list. Every command also accepts the global flags.

meridian login

Device-code login: prints a short user code, opens your browser to the verification URL, and polls until you approve. The resulting token is written to ~/.meridian/config.json with 0600 permissions.

| Flag | Behavior | | --- | --- | | --force | Re-authenticate even when a valid token is stored | | --no-browser | Print the URL instead of opening a browser (also implied by CI or MERIDIAN_NO_BROWSER) | | --hostname <name> | Hostname reported to Meridian for this device |

meridian logout

Deletes the stored token. Leaves .meridian/project.json alone, and exits 0 when you were not logged in.

meridian whoami

Shows the logged-in user, org memberships, and the linked project. --offline skips the API call and reports only cached state. Supports --json.

meridian link / meridian unlink

link prompts for an organization and app, then writes .meridian/project.json in the project root. Pass --org and --app (id, name, or slug) to skip the prompts, --dev-command to override what meridian dev runs, and --force to replace an existing link. unlink removes the file and leaves snapshots in place.

meridian dev

Starts the proxy and your dev server together (see How it works).

| Flag | Behavior | | --- | --- | | --port <port> | Preferred local proxy port; a free port is picked if it's taken | | --env-file <file> | Patch a file other than .env | | --no-env | Don't touch any file; print the DATABASE_URL for manual use |

The command to run is resolved in this order: meridian dev -- <cmd>dev_command in project.jsonnpm run dev. If your npm run dev script itself calls meridian dev, the CLI detects the recursion and stops instead of forking forever.

meridian migrate

Snapshots the database to .meridian/snapshots/<timestamp>.sql, runs npx prisma migrate dev, and restores the snapshot if the migration fails. Either way the outcome is reported to the API. Extra arguments go to Prisma verbatim: meridian migrate -- --name add_orders.

Rollback is automatic and unprompted: a failed migration resets the schema through the API and replays the snapshot, on the assumption that a half-applied migration is worse than the state you started in. Use --no-rollback to keep the snapshot and decide yourself, or --skip-snapshot when you don't want the dump at all. Pruning to --keep-snapshots only happens after a successful run, so a failure never removes the file you might need.

| Flag | Behavior | | --- | --- | | --skip-snapshot | Faster, but no rollback is possible | | --no-rollback | Keep the snapshot but don't restore automatically | | --keep-snapshots <n> | Snapshots to retain after success (default 5) | | --port, --env-file | As for meridian dev |

meridian db reset

Drops and recreates every table (the MySQL user is kept). Asks you to type the database name to confirm, then offers to run npx prisma migrate deploy and your seed script. Use --migrate and --seed to skip the follow-up prompts, or --yes to skip confirmation in scripts.

meridian db seed

Runs npx prisma db seed with the proxy up and DATABASE_URL set. Extra args: meridian db seed -- --arg.

meridian db shell

Opens a SQL shell against the dev database: the real mysql client when it's on PATH (the password is passed via MYSQL_PWD, so it never appears in ps), otherwise a small built-in REPL over mysql2. --repl forces the built-in one, and -e "SELECT 1" runs a single statement and exits (--json formats the rows as JSON).

Global flags

Accepted before or after the command name, so both meridian --json whoami and meridian whoami --json work.

| Flag | Behavior | | --- | --- | | --api-url <url> | Override the API base URL for this invocation | | --json | Machine-readable JSON on stdout (human logs stay on stderr) | | -q, --quiet | Warnings and errors only | | --verbose | Debug output, including stack traces and proxy logs | | --no-color | Disable ANSI colors (also honors NO_COLOR) | | -y, --yes | Pre-approve confirmation prompts | | --no-input | Never prompt; fail with an explanation instead | | --cwd <dir> | Run as if started in <dir> |

Configuration files

| Path | Contents | | --- | --- | | ~/.meridian/config.json | token, token_expires_at, user, api_base_url. Mode 0600 | | ~/.meridian/bin/ | Cached, checksum-verified cloud-sql-proxy binaries | | <project>/.meridian/project.json | org_id, app_id, app_name, optional dev_command and skip_datasource_check | | <project>/.meridian/snapshots/ | Pre-migration dumps, pruned to the newest few | | <project>/.meridian/.gitignore | Written for you, so snapshots and logs stay out of git |

Commit .meridian/project.json if your whole team uses Meridian; each developer still gets their own isolated database, because databases are provisioned per user and app.

API base URL

Resolved in this order, first match wins:

  1. --api-url <url>
  2. MERIDIAN_API_URL
  3. api_base_url in ~/.meridian/config.json (stored automatically when you log in against a non-default URL)
  4. https://api.the-meridian.ai

How DATABASE_URL is handled

Before starting your dev command, the CLI writes a line like this into .env:

DATABASE_URL="mysql://devu_88_15:<password>@127.0.0.1:3307/devdb_88_u15"
SHADOW_DATABASE_URL="mysql://devu_88_15:<password>@127.0.0.1:3307/devdb_88_u15_shadow"
  • SHADOW_DATABASE_URL points at a second database provisioned for you, which prisma migrate dev needs (see below). It is reachable with the same credentials and is dropped when your dev database is.
  • Every other line — comments, ordering, blank lines, quoting style — is preserved; only these two are replaced.
  • The first time a file is modified, a one-time copy is saved as .env.backup, with the same permissions as the file it copies.
  • An existing file keeps its permissions; a file the CLI creates is 0600, because the line it writes contains a live password.
  • The port changes between runs when the preferred port is busy, so re-running meridian dev rewrites the line.
  • Credentials are short-lived and rotate. Treat the value as a cache, not a secret to share, and keep .env out of git.
  • --no-env prints the URL instead of writing it, for cases where you manage .env yourself.

Your dev command also receives both variables directly in its environment, so it works even if you skip the file.

The Prisma datasource

Your schema has to read both variables, or the CLI stops before provisioning anything:

datasource db {
  provider          = "mysql"
  url               = env("DATABASE_URL")
  shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
}

meridian migrate offers to add the shadowDatabaseUrl line for you the first time it finds it missing, and writes it in place. It asks rather than just doing it, because a schema is source you keep in git, unlike the generated .env. A datasource that already names some other variable is left alone.

shadowDatabaseUrl is required because prisma migrate dev does not apply migrations directly: it replays your migration history into a throwaway shadow database and diffs that against your schema to detect drift. Prisma creates that database itself when it can, and your dev user cannot — it holds privileges on its own two databases and nothing else, so CREATE DATABASE is denied and Prisma reports P3014. Meridian provisions the shadow database per developer instead of granting the privilege, because Prisma names shadow databases with a fixed prisma_migrate_shadow_db_* prefix: a grant broad enough to cover that would be shared by every developer on the instance.

Only meridian migrate needs it. dev, db seed and db shell run fine without it.

Non-interactive and CI use

Prompts are skipped automatically when stdin/stderr aren't TTYs, when CI is set, or when MERIDIAN_NON_INTERACTIVE is set — in that mode a command that would have prompted fails with a message naming the flag or variable to set instead.

| Variable | Purpose | | --- | --- | | MERIDIAN_API_URL | API base URL | | MERIDIAN_HOME | Relocate ~/.meridian (useful for sandboxes and tests) | | MERIDIAN_ORG, MERIDIAN_APP | Answers for meridian link's prompts | | MERIDIAN_YES | Same as --yes | | MERIDIAN_NON_INTERACTIVE | Same as --no-input | | MERIDIAN_NO_BROWSER | Same as login --no-browser | | MERIDIAN_DEV_ACTIVE | Set to 1 in every process meridian dev starts. Read it to detect that your script is already inside a session; setting it yourself makes meridian dev refuse to start | | MERIDIAN_DEV_DATABASE_ID | Exported (alongside DATABASE_URL) into the children of meridian dev, migrate and db …, holding the id of the dev database that session provisioned. The Meridian SDK sends it as devDatabaseId on its identify call, so installs a locally-run app creates are billed to your dev database. Set by the CLI only — never set it yourself | | MERIDIAN_PROXY_PATH | Use an existing proxy binary instead of downloading one | | MERIDIAN_PROXY_VERSION | Pin a different proxy version (checksum is fetched from that release) | | MERIDIAN_PROXY_SKIP_CHECKSUM=1 | Allow install when no checksum is published. Use only if you trust the source | | NO_COLOR / FORCE_COLOR | Color detection |

Read commands support --json. Errors are also JSON in that mode:

{ "error": { "message": "Your Meridian CLI token is no longer valid (401).", "hint": "Run `meridian login` again to issue a fresh token." } }

Troubleshooting

You are not logged in to Meridian. — Run meridian login.

This project is not linked to a Meridian app. — Run meridian link in the project root. The CLI looks for .meridian/project.json in the current directory and its parents.

Your Meridian CLI token is no longer valid (401). — The token was revoked or expired. Run meridian login again.

Provisioning the development database failed. — Provisioning ended in an error state on Meridian's side; the reason the API reports is appended to the message. Check the dashboard for the full history, then re-run meridian dev to retry.

The development database is not ready yet. — A credentials or reset call arrived before provisioning finished (HTTP 409). meridian dev polls for you, so this normally only appears when a command runs against a database that is still being created.

Could not reach 127.0.0.1:<port>/<db> (ECONNREFUSED). — Nothing is listening. meridian dev and meridian migrate start the proxy themselves; if you're running Prisma directly, keep meridian dev running in another terminal.

Timed out waiting for MySQL … — The proxy is up but can't reach Cloud SQL. Check whether a VPN, firewall, or corporate proxy blocks outbound connections, then retry with --verbose to see the proxy's own logs.

Another process is already listening on that port. — Pass --port to choose a different one.

Proxy download fails (air-gapped network, blocked storage.googleapis.com) — Install the Cloud SQL Auth Proxy yourself and set MERIDIAN_PROXY_PATH to it.

Checksum verification failed — A cached binary that no longer matches its published SHA-256 is deleted and downloaded again automatically. If a fresh download also fails verification the CLI refuses to install it, which usually means something on the network is rewriting the response. Don't reach for MERIDIAN_PROXY_SKIP_CHECKSUM in that situation.

A migration failed and left the schema half-appliedmeridian migrate restores the pre-migration snapshot automatically. To redo it by hand, use the newest file in .meridian/snapshots/, or run meridian db reset for a clean slate.

The rollback itself failed — Treat the database as unsafe: the reset succeeded but the replay didn't finish, so the schema is partial. Start the proxy with meridian dev in another terminal and replay the snapshot by hand (mysql … < .meridian/snapshots/<timestamp>.sql, or meridian db shell and paste it), or take the clean slate with meridian db reset --migrate. The failing statement's index is in the error message.

meridian dev says it would call itself — Your npm run dev script invokes meridian dev. Point dev_command in .meridian/project.json at the real dev server (for example next dev), or run meridian dev -- next dev.

"…would not touch the managed development database" — Your Prisma datasource does not read DATABASE_URL, so Prisma would ignore the database the CLI just connected you to and use whatever the schema hardcodes (typically file:dev.sqlite). Set provider = "mysql" and url = env("DATABASE_URL"), and regenerate any migrations created for the old database — their SQL is dialect-specific and MySQL will reject it. Projects that deliberately manage their datasource some other way can set "skip_datasource_check": true in .meridian/project.json.

"written for a different database engine"migrate screens prisma/migrations before it provisions anything, because a history generated for another engine cannot apply to MySQL. SQLite and Postgres quote identifiers as "Session", which MySQL reads as a string literal, and SQLite's TEXT primary keys are invalid as MySQL keys. Migration SQL is dialect-specific, so the history has to be regenerated: if it has only ever run locally, delete prisma/migrations and re-run. This is the normal state of a Shopify app template, which ships SQLite migrations. --allow-foreign-migrations waives the check.

If an earlier attempt already failed against the database, run meridian db reset before retrying. Prisma records the failure in _prisma_migrations, and once the history is deleted that row names a migration that no longer exists on disk, which Prisma reports as drift and refuses to work past.

"declares no shadowDatabaseUrl", or Prisma's P3014prisma migrate dev needs a shadow database and your dev user cannot create one. Meridian provisions it and exports SHADOW_DATABASE_URL; add shadowDatabaseUrl = env("SHADOW_DATABASE_URL") to your datasource. If you hit P3014 despite having that line, your dev database predates shadow databases — meridian db reset re-provisions it.

Development

npm install
npm run test:run     # vitest, fully offline: no network, no real binaries
npm run typecheck    # tsc --noEmit
npm run build        # tsup → dist/index.js

Tests mock the network, child processes, and MySQL, and the suite clears ambient MERIDIAN_*/CI variables so local runs match CI.

License

MIT