@the-meridian/cli 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +21 -21
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @the-meridian/cli
|
|
2
2
|
|
|
3
|
+
## 1.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- faaf2bf: Clarify punctuation in the README.
|
|
8
|
+
|
|
9
|
+
## 1.0.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 5eb0d4f: Clarify punctuation in developer-facing messages.
|
|
14
|
+
|
|
3
15
|
## 1.0.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ meridian dev # every day
|
|
|
17
17
|
- Node.js 20 or newer
|
|
18
18
|
- A Meridian account with access to at least one organization and app
|
|
19
19
|
|
|
20
|
-
You do **not** need Docker, a local MySQL server, `gcloud`, or the Cloud SQL Auth Proxy
|
|
20
|
+
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.
|
|
21
21
|
|
|
22
22
|
## How it works
|
|
23
23
|
|
|
@@ -144,7 +144,7 @@ SHADOW_DATABASE_URL="mysql://devu_88_15:<password>@127.0.0.1:3307/devdb_88_u15_s
|
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
- `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.
|
|
147
|
-
- Every other line
|
|
147
|
+
- Every other line (comments, ordering, blank lines, quoting style) is preserved; only these two are replaced.
|
|
148
148
|
- 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.
|
|
149
149
|
- An existing file keeps its permissions; a file the CLI creates is `0600`, because the line it writes contains a live password.
|
|
150
150
|
- The port changes between runs when the preferred port is busy, so re-running `meridian dev` rewrites the line.
|
|
@@ -167,13 +167,13 @@ datasource db {
|
|
|
167
167
|
|
|
168
168
|
`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.
|
|
169
169
|
|
|
170
|
-
`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
|
|
170
|
+
`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.
|
|
171
171
|
|
|
172
172
|
Only `meridian migrate` needs it. `dev`, `db seed` and `db shell` run fine without it.
|
|
173
173
|
|
|
174
174
|
## Non-interactive and CI use
|
|
175
175
|
|
|
176
|
-
Prompts are skipped automatically when stdin/stderr aren't TTYs, when `CI` is set, or when `MERIDIAN_NON_INTERACTIVE` is set
|
|
176
|
+
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.
|
|
177
177
|
|
|
178
178
|
| Variable | Purpose |
|
|
179
179
|
| --- | --- |
|
|
@@ -184,7 +184,7 @@ Prompts are skipped automatically when stdin/stderr aren't TTYs, when `CI` is se
|
|
|
184
184
|
| `MERIDIAN_NON_INTERACTIVE` | Same as `--no-input` |
|
|
185
185
|
| `MERIDIAN_NO_BROWSER` | Same as `login --no-browser` |
|
|
186
186
|
| `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 |
|
|
187
|
-
| `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
|
|
187
|
+
| `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 |
|
|
188
188
|
| `MERIDIAN_PROXY_PATH` | Use an existing proxy binary instead of downloading one |
|
|
189
189
|
| `MERIDIAN_PROXY_VERSION` | Pin a different proxy version (checksum is fetched from that release) |
|
|
190
190
|
| `MERIDIAN_PROXY_SKIP_CHECKSUM=1` | Allow install when no checksum is published. Use only if you trust the source |
|
|
@@ -198,39 +198,39 @@ Read commands support `--json`. Errors are also JSON in that mode:
|
|
|
198
198
|
|
|
199
199
|
## Troubleshooting
|
|
200
200
|
|
|
201
|
-
**`You are not logged in to Meridian
|
|
201
|
+
**`You are not logged in to Meridian.`**: Run `meridian login`.
|
|
202
202
|
|
|
203
|
-
**`This project is not linked to a Meridian app
|
|
203
|
+
**`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.
|
|
204
204
|
|
|
205
|
-
**`Your Meridian CLI token is no longer valid (401)
|
|
205
|
+
**`Your Meridian CLI token is no longer valid (401).`**: The token was revoked or expired. Run `meridian login` again.
|
|
206
206
|
|
|
207
|
-
**`Provisioning the development database failed
|
|
207
|
+
**`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.
|
|
208
208
|
|
|
209
|
-
**`The development database is not ready yet
|
|
209
|
+
**`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.
|
|
210
210
|
|
|
211
|
-
**`Could not reach 127.0.0.1:<port>/<db> (ECONNREFUSED)
|
|
211
|
+
**`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.
|
|
212
212
|
|
|
213
|
-
**`Timed out waiting for MySQL
|
|
213
|
+
**`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.
|
|
214
214
|
|
|
215
|
-
**`Another process is already listening on that port
|
|
215
|
+
**`Another process is already listening on that port.`**: Pass `--port` to choose a different one.
|
|
216
216
|
|
|
217
|
-
**Proxy download fails** (air-gapped network, blocked storage.googleapis.com)
|
|
217
|
+
**Proxy download fails** (air-gapped network, blocked storage.googleapis.com): Install the [Cloud SQL Auth Proxy](https://github.com/GoogleCloudPlatform/cloud-sql-proxy) yourself and set `MERIDIAN_PROXY_PATH` to it.
|
|
218
218
|
|
|
219
|
-
**Checksum verification failed
|
|
219
|
+
**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.
|
|
220
220
|
|
|
221
|
-
**A migration failed and left the schema half-applied
|
|
221
|
+
**A migration failed and left the schema half-applied**: `meridian 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.
|
|
222
222
|
|
|
223
|
-
**The rollback itself failed
|
|
223
|
+
**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.
|
|
224
224
|
|
|
225
|
-
**`meridian dev` says it would call itself
|
|
225
|
+
**`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`.
|
|
226
226
|
|
|
227
|
-
**"…would not touch the managed development database"
|
|
227
|
+
**"…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, because 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`.
|
|
228
228
|
|
|
229
|
-
**"written for a different database engine"
|
|
229
|
+
**"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.
|
|
230
230
|
|
|
231
231
|
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.
|
|
232
232
|
|
|
233
|
-
**"declares no `shadowDatabaseUrl`"**, or Prisma's **`P3014
|
|
233
|
+
**"declares no `shadowDatabaseUrl`"**, or Prisma's **`P3014`**: `prisma 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.
|
|
234
234
|
|
|
235
235
|
## Development
|
|
236
236
|
|
package/dist/index.js
CHANGED
|
@@ -453,7 +453,7 @@ function extractErrorCode(body) {
|
|
|
453
453
|
}
|
|
454
454
|
var HINTS_BY_ERROR_CODE = {
|
|
455
455
|
dev_database_limit_reached: "Your plan does not include a development database for you on this app. Every collaborator gets their own out of the plan's allowance, so upgrading the organization's plan in the Meridian dashboard is what unlocks it.",
|
|
456
|
-
dev_database_over_storage_limit: "Run `meridian db reset` to drop and recreate the schema
|
|
456
|
+
dev_database_over_storage_limit: "Run `meridian db reset` to drop and recreate the schema. Reset and delete stay available while you're over the limit.",
|
|
457
457
|
FEATURE_NOT_ENTITLED: "Your organization's plan does not include managed development databases; upgrade it in the Meridian dashboard."
|
|
458
458
|
};
|
|
459
459
|
function hintForError(status, errorCode) {
|
|
@@ -465,7 +465,7 @@ function hintForError(status, errorCode) {
|
|
|
465
465
|
if (status === 403) return "You may not have access to this organization or app; check your Meridian membership.";
|
|
466
466
|
if (status === 404) return "Run `meridian link` to select a valid organization and app.";
|
|
467
467
|
if (status === 409) {
|
|
468
|
-
return "The development database is not ready yet. Wait for provisioning to finish, then try again
|
|
468
|
+
return "The development database is not ready yet. Wait for provisioning to finish, then try again. `meridian dev` polls for you.";
|
|
469
469
|
}
|
|
470
470
|
if (status === 422) return "Check the request for validation errors and try again.";
|
|
471
471
|
if (status === 429) return "You're being rate limited by the Meridian API; wait a moment and try again.";
|
|
@@ -720,7 +720,7 @@ function toDatabaseError(error2, info) {
|
|
|
720
720
|
if (code === "ER_ACCESS_DENIED_ERROR") {
|
|
721
721
|
return build(
|
|
722
722
|
`Access denied connecting to ${target} as "${info.user}".`,
|
|
723
|
-
"Database credentials are short-lived and rotate automatically
|
|
723
|
+
"Database credentials are short-lived and rotate automatically. Run `meridian dev` again to fetch fresh ones."
|
|
724
724
|
);
|
|
725
725
|
}
|
|
726
726
|
if (code === "ER_BAD_DB_ERROR") {
|
|
@@ -1508,7 +1508,7 @@ import {
|
|
|
1508
1508
|
} from "fs";
|
|
1509
1509
|
import { dirname as dirname3 } from "path";
|
|
1510
1510
|
var CREATED_ENV_MODE = 384;
|
|
1511
|
-
var MANAGED_HEADER = "# Managed by the Meridian CLI
|
|
1511
|
+
var MANAGED_HEADER = "# Managed by the Meridian CLI. DATABASE_URL is rewritten by `meridian dev`.";
|
|
1512
1512
|
var LINE_RE = /^([ \t]*)(export[ \t]+)?([A-Za-z_][A-Za-z0-9_]*)([ \t]*=[ \t]*)(.*)$/;
|
|
1513
1513
|
function splitLines(content) {
|
|
1514
1514
|
const lines = [];
|
|
@@ -1883,7 +1883,7 @@ function assertShadowDatasource(root) {
|
|
|
1883
1883
|
if (shadow !== null && shadow.kind === "env" && shadow.name === REQUIRED_SHADOW_URL_ENV) return;
|
|
1884
1884
|
const problem = shadow === null ? "declares no `shadowDatabaseUrl`" : shadow.kind === "literal" ? `hardcodes \`shadowDatabaseUrl = "${shadow.value}"\`` : `reads \`env("${shadow.name}")\` for its shadow database, but Meridian sets \`${REQUIRED_SHADOW_URL_ENV}\``;
|
|
1885
1885
|
throw new CliError(`\`${datasource.schemaPath}\` ${problem}.`, {
|
|
1886
|
-
hint: `\`prisma migrate dev\` diffs your migrations in a throwaway shadow database, and your dev user cannot create one
|
|
1886
|
+
hint: `\`prisma migrate dev\` diffs your migrations in a throwaway shadow database, and your dev user cannot create one, so Meridian provisions it for you and exports \`${REQUIRED_SHADOW_URL_ENV}\`. Add \`shadowDatabaseUrl = env("${REQUIRED_SHADOW_URL_ENV}")\` to the \`${datasource.name}\` datasource. ${BYPASS_HINT}`
|
|
1887
1887
|
});
|
|
1888
1888
|
}
|
|
1889
1889
|
var FOREIGN_DIALECT_DDL = /\b(?:CREATE\s+(?:UNIQUE\s+)?(?:TABLE|INDEX)|ALTER\s+TABLE|REFERENCES)\s+"/i;
|
|
@@ -1912,7 +1912,7 @@ function findForeignDialectMigration(root) {
|
|
|
1912
1912
|
return offender === void 0 ? null : relative(root, offender);
|
|
1913
1913
|
}
|
|
1914
1914
|
function foreignDialectExplanation(offender) {
|
|
1915
|
-
return `\`${offender}\` was generated for SQLite or Postgres
|
|
1915
|
+
return `\`${offender}\` was generated for SQLite or Postgres. It quotes identifiers with double quotes, which MySQL reads as string literals. Migration SQL is dialect-specific and cannot be replayed against MySQL. If this history has only ever run locally, delete \`prisma/migrations\` and re-run to regenerate it for MySQL; run \`meridian db reset\` first if an earlier attempt already failed, since Prisma records that failure in \`_prisma_migrations\` and will not continue while it is there.`;
|
|
1916
1916
|
}
|
|
1917
1917
|
function assertMigrationDialect(root) {
|
|
1918
1918
|
const offender = findForeignDialectMigration(root);
|
|
@@ -3910,7 +3910,7 @@ async function runMigration(session, deps, ctx) {
|
|
|
3910
3910
|
"Snapshotting the development database...",
|
|
3911
3911
|
() => deps.createSnapshot(session.connection, { dir, now: deps.now }),
|
|
3912
3912
|
{
|
|
3913
|
-
success: (result) => result.path === null ? "Development database is empty
|
|
3913
|
+
success: (result) => result.path === null ? "Development database is empty. Nothing to snapshot." : `Snapshot saved to ${style.path(result.path)} (${formatSize(result.bytes)}).`
|
|
3914
3914
|
}
|
|
3915
3915
|
);
|
|
3916
3916
|
}
|
|
@@ -3961,9 +3961,9 @@ async function runMigration(session, deps, ctx) {
|
|
|
3961
3961
|
status = "rolled_back";
|
|
3962
3962
|
rolledBack = true;
|
|
3963
3963
|
} catch {
|
|
3964
|
-
error("Automatic rollback failed. The development database may be in a partial state
|
|
3964
|
+
error("Automatic rollback failed. The development database may be in a partial state. Treat it as unsafe.");
|
|
3965
3965
|
if (snapshotPath === null) {
|
|
3966
|
-
hint("Recover by hand with `meridian db reset
|
|
3966
|
+
hint("Recover by hand with `meridian db reset`. The database was empty before this migration.");
|
|
3967
3967
|
} else {
|
|
3968
3968
|
detail(`Pre-migration snapshot: ${snapshotPath}`);
|
|
3969
3969
|
hint(
|