@prisma-next/cli 0.3.0-dev.12 → 0.3.0-dev.123
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/LICENSE +201 -0
- package/README.md +470 -134
- package/dist/cli-errors-ByGuoqNj.mjs +3 -0
- package/dist/cli-errors-D6HxRn3A.d.mts +2 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.js +1 -2350
- package/dist/cli.mjs +242 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/client-612RJJD_.mjs +1069 -0
- package/dist/client-612RJJD_.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts +7 -0
- package/dist/commands/contract-emit.d.mts.map +1 -0
- package/dist/commands/contract-emit.mjs +8 -0
- package/dist/commands/contract-infer.d.mts +7 -0
- package/dist/commands/contract-infer.d.mts.map +1 -0
- package/dist/commands/contract-infer.mjs +9 -0
- package/dist/commands/db-init.d.mts +7 -0
- package/dist/commands/db-init.d.mts.map +1 -0
- package/dist/commands/db-init.mjs +125 -0
- package/dist/commands/db-init.mjs.map +1 -0
- package/dist/commands/db-schema.d.mts +7 -0
- package/dist/commands/db-schema.d.mts.map +1 -0
- package/dist/commands/db-schema.mjs +55 -0
- package/dist/commands/db-schema.mjs.map +1 -0
- package/dist/commands/db-sign.d.mts +7 -0
- package/dist/commands/db-sign.d.mts.map +1 -0
- package/dist/commands/db-sign.mjs +136 -0
- package/dist/commands/db-sign.mjs.map +1 -0
- package/dist/commands/db-update.d.mts +7 -0
- package/dist/commands/db-update.d.mts.map +1 -0
- package/dist/commands/db-update.mjs +122 -0
- package/dist/commands/db-update.mjs.map +1 -0
- package/dist/commands/db-verify.d.mts +7 -0
- package/dist/commands/db-verify.d.mts.map +1 -0
- package/dist/commands/db-verify.mjs +311 -0
- package/dist/commands/db-verify.mjs.map +1 -0
- package/dist/commands/migration-apply.d.mts +36 -0
- package/dist/commands/migration-apply.d.mts.map +1 -0
- package/dist/commands/migration-apply.mjs +241 -0
- package/dist/commands/migration-apply.mjs.map +1 -0
- package/dist/commands/migration-plan.d.mts +47 -0
- package/dist/commands/migration-plan.d.mts.map +1 -0
- package/dist/commands/migration-plan.mjs +288 -0
- package/dist/commands/migration-plan.mjs.map +1 -0
- package/dist/commands/migration-ref.d.mts +43 -0
- package/dist/commands/migration-ref.d.mts.map +1 -0
- package/dist/commands/migration-ref.mjs +194 -0
- package/dist/commands/migration-ref.mjs.map +1 -0
- package/dist/commands/migration-show.d.mts +28 -0
- package/dist/commands/migration-show.d.mts.map +1 -0
- package/dist/commands/migration-show.mjs +139 -0
- package/dist/commands/migration-show.mjs.map +1 -0
- package/dist/commands/migration-status.d.mts +85 -0
- package/dist/commands/migration-status.d.mts.map +1 -0
- package/dist/commands/migration-status.mjs +8 -0
- package/dist/commands/migration-verify.d.mts +16 -0
- package/dist/commands/migration-verify.d.mts.map +1 -0
- package/dist/commands/migration-verify.mjs +87 -0
- package/dist/commands/migration-verify.mjs.map +1 -0
- package/dist/config-loader-d_KF19Tw.mjs +43 -0
- package/dist/config-loader-d_KF19Tw.mjs.map +1 -0
- package/dist/{config-loader.d.ts → config-loader.d.mts} +8 -3
- package/dist/config-loader.d.mts.map +1 -0
- package/dist/config-loader.mjs +3 -0
- package/dist/contract-emit-CVv7dbQ9.mjs +187 -0
- package/dist/contract-emit-CVv7dbQ9.mjs.map +1 -0
- package/dist/contract-infer-Bvw8u8Eu.mjs +83 -0
- package/dist/contract-infer-Bvw8u8Eu.mjs.map +1 -0
- package/dist/exports/config-types.d.mts +2 -0
- package/dist/exports/config-types.mjs +3 -0
- package/dist/exports/control-api.d.mts +626 -0
- package/dist/exports/control-api.d.mts.map +1 -0
- package/dist/exports/control-api.mjs +107 -0
- package/dist/exports/control-api.mjs.map +1 -0
- package/dist/{load-ts-contract.d.ts → exports/index.d.mts} +10 -5
- package/dist/exports/index.d.mts.map +1 -0
- package/dist/exports/index.mjs +134 -0
- package/dist/exports/index.mjs.map +1 -0
- package/dist/extract-sql-ddl-Jf5blEO0.mjs +26 -0
- package/dist/extract-sql-ddl-Jf5blEO0.mjs.map +1 -0
- package/dist/framework-components-M2j-qPfr.mjs +59 -0
- package/dist/framework-components-M2j-qPfr.mjs.map +1 -0
- package/dist/inspect-live-schema-BQe5i4YE.mjs +90 -0
- package/dist/inspect-live-schema-BQe5i4YE.mjs.map +1 -0
- package/dist/migration-command-scaffold-SLrjcKXS.mjs +104 -0
- package/dist/migration-command-scaffold-SLrjcKXS.mjs.map +1 -0
- package/dist/migration-status-B7OVZ-Ka.mjs +1576 -0
- package/dist/migration-status-B7OVZ-Ka.mjs.map +1 -0
- package/dist/migrations-Db_ea9eE.mjs +173 -0
- package/dist/migrations-Db_ea9eE.mjs.map +1 -0
- package/dist/progress-adapter-DRNe2idZ.mjs +43 -0
- package/dist/progress-adapter-DRNe2idZ.mjs.map +1 -0
- package/dist/terminal-ui-DAcMBRKf.mjs +980 -0
- package/dist/terminal-ui-DAcMBRKf.mjs.map +1 -0
- package/dist/verify-DXKxBFvU.mjs +385 -0
- package/dist/verify-DXKxBFvU.mjs.map +1 -0
- package/package.json +85 -40
- package/src/cli.ts +109 -58
- package/src/commands/contract-emit.ts +236 -143
- package/src/commands/contract-infer-paths.ts +32 -0
- package/src/commands/contract-infer.ts +131 -0
- package/src/commands/db-init.ts +211 -425
- package/src/commands/db-schema.ts +77 -0
- package/src/commands/db-sign.ts +207 -228
- package/src/commands/db-update.ts +236 -0
- package/src/commands/db-verify.ts +484 -186
- package/src/commands/inspect-live-schema.ts +171 -0
- package/src/commands/migration-apply.ts +416 -0
- package/src/commands/migration-plan.ts +451 -0
- package/src/commands/migration-ref.ts +305 -0
- package/src/commands/migration-show.ts +246 -0
- package/src/commands/migration-status.ts +838 -0
- package/src/commands/migration-verify.ts +134 -0
- package/src/config-loader.ts +13 -3
- package/src/control-api/client.ts +614 -0
- package/src/control-api/contract-enrichment.ts +135 -0
- package/src/control-api/errors.ts +9 -0
- package/src/control-api/operations/contract-emit.ts +173 -0
- package/src/control-api/operations/db-init.ts +286 -0
- package/src/control-api/operations/db-update.ts +221 -0
- package/src/control-api/operations/extract-sql-ddl.ts +47 -0
- package/src/control-api/operations/migration-apply.ts +194 -0
- package/src/control-api/operations/migration-helpers.ts +49 -0
- package/src/control-api/types.ts +683 -0
- package/src/exports/config-types.ts +4 -3
- package/src/exports/control-api.ts +56 -0
- package/src/load-ts-contract.ts +16 -11
- package/src/utils/cli-errors.ts +5 -2
- package/src/utils/command-helpers.ts +293 -3
- package/src/utils/formatters/emit.ts +67 -0
- package/src/utils/formatters/errors.ts +82 -0
- package/src/utils/formatters/graph-migration-mapper.ts +220 -0
- package/src/utils/formatters/graph-render.ts +1317 -0
- package/src/utils/formatters/graph-types.ts +114 -0
- package/src/utils/formatters/help.ts +380 -0
- package/src/utils/formatters/helpers.ts +28 -0
- package/src/utils/formatters/migrations.ts +346 -0
- package/src/utils/formatters/styled.ts +212 -0
- package/src/utils/formatters/verify.ts +620 -0
- package/src/utils/global-flags.ts +41 -23
- package/src/utils/migration-command-scaffold.ts +187 -0
- package/src/utils/migration-types.ts +12 -0
- package/src/utils/progress-adapter.ts +75 -0
- package/src/utils/result-handler.ts +12 -13
- package/src/utils/shutdown.ts +92 -0
- package/src/utils/suggest-command.ts +31 -0
- package/src/utils/terminal-ui.ts +276 -0
- package/dist/chunk-BZMBKEEQ.js +0 -997
- package/dist/chunk-BZMBKEEQ.js.map +0 -1
- package/dist/chunk-CVNWLFXO.js +0 -91
- package/dist/chunk-CVNWLFXO.js.map +0 -1
- package/dist/chunk-HWYQOCAJ.js +0 -47
- package/dist/chunk-HWYQOCAJ.js.map +0 -1
- package/dist/chunk-QUPBU4KV.js +0 -131
- package/dist/chunk-QUPBU4KV.js.map +0 -1
- package/dist/cli.d.ts +0 -2
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/contract-emit.d.ts +0 -3
- package/dist/commands/contract-emit.d.ts.map +0 -1
- package/dist/commands/contract-emit.js +0 -9
- package/dist/commands/contract-emit.js.map +0 -1
- package/dist/commands/db-init.d.ts +0 -3
- package/dist/commands/db-init.d.ts.map +0 -1
- package/dist/commands/db-init.js +0 -337
- package/dist/commands/db-init.js.map +0 -1
- package/dist/commands/db-introspect.d.ts +0 -3
- package/dist/commands/db-introspect.d.ts.map +0 -1
- package/dist/commands/db-introspect.js +0 -186
- package/dist/commands/db-introspect.js.map +0 -1
- package/dist/commands/db-schema-verify.d.ts +0 -3
- package/dist/commands/db-schema-verify.d.ts.map +0 -1
- package/dist/commands/db-schema-verify.js +0 -160
- package/dist/commands/db-schema-verify.js.map +0 -1
- package/dist/commands/db-sign.d.ts +0 -3
- package/dist/commands/db-sign.d.ts.map +0 -1
- package/dist/commands/db-sign.js +0 -195
- package/dist/commands/db-sign.js.map +0 -1
- package/dist/commands/db-verify.d.ts +0 -3
- package/dist/commands/db-verify.d.ts.map +0 -1
- package/dist/commands/db-verify.js +0 -169
- package/dist/commands/db-verify.js.map +0 -1
- package/dist/config-loader.d.ts.map +0 -1
- package/dist/config-loader.js +0 -7
- package/dist/config-loader.js.map +0 -1
- package/dist/exports/config-types.d.ts +0 -3
- package/dist/exports/config-types.d.ts.map +0 -1
- package/dist/exports/config-types.js +0 -6
- package/dist/exports/config-types.js.map +0 -1
- package/dist/exports/index.d.ts +0 -4
- package/dist/exports/index.d.ts.map +0 -1
- package/dist/exports/index.js +0 -175
- package/dist/exports/index.js.map +0 -1
- package/dist/load-ts-contract.d.ts.map +0 -1
- package/dist/utils/action.d.ts +0 -16
- package/dist/utils/action.d.ts.map +0 -1
- package/dist/utils/cli-errors.d.ts +0 -7
- package/dist/utils/cli-errors.d.ts.map +0 -1
- package/dist/utils/command-helpers.d.ts +0 -12
- package/dist/utils/command-helpers.d.ts.map +0 -1
- package/dist/utils/framework-components.d.ts +0 -70
- package/dist/utils/framework-components.d.ts.map +0 -1
- package/dist/utils/global-flags.d.ts +0 -25
- package/dist/utils/global-flags.d.ts.map +0 -1
- package/dist/utils/output.d.ts +0 -142
- package/dist/utils/output.d.ts.map +0 -1
- package/dist/utils/result-handler.d.ts +0 -15
- package/dist/utils/result-handler.d.ts.map +0 -1
- package/dist/utils/spinner.d.ts +0 -29
- package/dist/utils/spinner.d.ts.map +0 -1
- package/src/commands/db-introspect.ts +0 -256
- package/src/commands/db-schema-verify.ts +0 -232
- package/src/utils/action.ts +0 -43
- package/src/utils/output.ts +0 -1471
- package/src/utils/spinner.ts +0 -67
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ Provide a command-line interface that:
|
|
|
22
22
|
- **Extension Pack Descriptor Assembly**: Collect adapter and extension descriptors for emission
|
|
23
23
|
- **Help Output Formatting**: Custom styled help output with command trees and formatted descriptions
|
|
24
24
|
- **Config Management**: Load and validate `prisma-next.config.ts` files using Arktype validation
|
|
25
|
+
- **CLI Binary Compatibility**: Build emits `dist/cli.mjs` and also writes a compatibility shim at `dist/cli.js`
|
|
25
26
|
|
|
26
27
|
### Wiring validation
|
|
27
28
|
|
|
@@ -31,9 +32,9 @@ This prevents runtime mismatches (for example: a contract that declares extensio
|
|
|
31
32
|
|
|
32
33
|
Commands that enforce wiring validation:
|
|
33
34
|
- **`db verify`**
|
|
34
|
-
- **`db introspect`** (when a contract is provided)
|
|
35
35
|
- **`db sign`**
|
|
36
36
|
- **`db init`**
|
|
37
|
+
- **`db update`**
|
|
37
38
|
|
|
38
39
|
If you hit a wiring validation error: add the required descriptors to `config.extensionPacks` (matched by descriptor `id`) and re-run the command.
|
|
39
40
|
|
|
@@ -56,17 +57,17 @@ Emit `contract.json` and `contract.d.ts` from `config.contract`.
|
|
|
56
57
|
|
|
57
58
|
**Canonical command:**
|
|
58
59
|
```bash
|
|
59
|
-
prisma-next contract emit [--config <path>] [--json] [-v] [-q] [--
|
|
60
|
+
prisma-next contract emit [--config <path>] [--json] [-v] [-q] [--color/--no-color]
|
|
60
61
|
```
|
|
61
62
|
|
|
62
63
|
**Config File Requirements:**
|
|
63
64
|
|
|
64
|
-
The `contract emit` command
|
|
65
|
+
The `contract emit` command does not require a `driver` in the config since it doesn't connect to a database:
|
|
65
66
|
|
|
66
67
|
```typescript
|
|
67
68
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
69
|
+
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
|
|
68
70
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
69
|
-
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
70
71
|
import postgres from '@prisma-next/target-postgres/control';
|
|
71
72
|
import sql from '@prisma-next/family-sql/control';
|
|
72
73
|
import { contract } from './prisma/contract';
|
|
@@ -75,13 +76,8 @@ export default defineConfig({
|
|
|
75
76
|
family: sql,
|
|
76
77
|
target: postgres,
|
|
77
78
|
adapter: postgresAdapter,
|
|
78
|
-
driver: postgresDriver, // Required even though emit doesn't use it
|
|
79
79
|
extensionPacks: [],
|
|
80
|
-
contract:
|
|
81
|
-
source: contract,
|
|
82
|
-
output: 'src/prisma/contract.json',
|
|
83
|
-
types: 'src/prisma/contract.d.ts',
|
|
84
|
-
},
|
|
80
|
+
contract: typescriptContract(contract, 'src/prisma/contract.json'),
|
|
85
81
|
});
|
|
86
82
|
```
|
|
87
83
|
|
|
@@ -91,7 +87,6 @@ Options:
|
|
|
91
87
|
- `-q, --quiet`: Quiet mode (errors only)
|
|
92
88
|
- `-v, --verbose`: Verbose output (debug info, timings)
|
|
93
89
|
- `-vv, --trace`: Trace output (deep internals, stack traces)
|
|
94
|
-
- `--timestamps`: Add timestamps to output
|
|
95
90
|
- `--color/--no-color`: Force/disable color output
|
|
96
91
|
|
|
97
92
|
Examples:
|
|
@@ -102,27 +97,30 @@ prisma-next contract emit
|
|
|
102
97
|
# JSON output
|
|
103
98
|
prisma-next contract emit --json
|
|
104
99
|
|
|
105
|
-
# Verbose output
|
|
106
|
-
prisma-next contract emit -v
|
|
100
|
+
# Verbose output
|
|
101
|
+
prisma-next contract emit -v
|
|
107
102
|
```
|
|
108
103
|
|
|
109
104
|
### `prisma-next db verify`
|
|
110
105
|
|
|
111
|
-
Verify that a database instance matches the emitted contract by checking marker
|
|
106
|
+
Verify that a database instance matches the emitted contract by checking the marker first and, by default, the live schema second.
|
|
112
107
|
|
|
113
108
|
**Command:**
|
|
114
109
|
```bash
|
|
115
|
-
prisma-next db verify [--db <url>] [--config <path>] [--json] [-v] [-q] [--
|
|
110
|
+
prisma-next db verify [--db <url>] [--config <path>] [--marker-only | --schema-only] [--strict] [--json] [-v] [-q] [--color/--no-color]
|
|
116
111
|
```
|
|
117
112
|
|
|
118
113
|
Options:
|
|
119
|
-
- `--db <url>`: Database connection string (optional; defaults to `config.db.
|
|
114
|
+
- `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
|
|
120
115
|
- `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
|
|
116
|
+
- `--marker-only`: Skip schema verification and only check the database marker
|
|
117
|
+
- `--schema-only`: Skip marker verification and only check whether the live schema satisfies the contract
|
|
118
|
+
- `--strict`: When schema verification runs, schema elements not present in the contract are considered an error
|
|
119
|
+
- `--marker-only` cannot be combined with `--schema-only` or `--strict` (exit code 2, `PN-CLI-4012`). `--schema-only --strict` is valid.
|
|
121
120
|
- `--json`: Output as JSON object
|
|
122
121
|
- `-q, --quiet`: Quiet mode (errors only)
|
|
123
122
|
- `-v, --verbose`: Verbose output (debug info, timings)
|
|
124
123
|
- `-vv, --trace`: Trace output (deep internals, stack traces)
|
|
125
|
-
- `--timestamps`: Add timestamps to output
|
|
126
124
|
- `--color/--no-color`: Force/disable color output
|
|
127
125
|
|
|
128
126
|
Examples:
|
|
@@ -133,11 +131,20 @@ prisma-next db verify
|
|
|
133
131
|
# Specify database URL
|
|
134
132
|
prisma-next db verify --db postgresql://user:pass@localhost/db
|
|
135
133
|
|
|
134
|
+
# Marker-only verification when callers accept the trade-off
|
|
135
|
+
prisma-next db verify --db postgresql://user:pass@localhost/db --marker-only
|
|
136
|
+
|
|
137
|
+
# Schema-only verification without relying on marker state
|
|
138
|
+
prisma-next db verify --db postgresql://user:pass@localhost/db --schema-only
|
|
139
|
+
|
|
140
|
+
# Strict schema verification (extras fail)
|
|
141
|
+
prisma-next db verify --db postgresql://user:pass@localhost/db --strict
|
|
142
|
+
|
|
136
143
|
# JSON output
|
|
137
144
|
prisma-next db verify --json
|
|
138
145
|
|
|
139
|
-
# Verbose output
|
|
140
|
-
prisma-next db verify -v
|
|
146
|
+
# Verbose output
|
|
147
|
+
prisma-next db verify -v
|
|
141
148
|
```
|
|
142
149
|
|
|
143
150
|
**Config File Requirements:**
|
|
@@ -146,6 +153,7 @@ The `db verify` command requires a `driver` in the config to connect to the data
|
|
|
146
153
|
|
|
147
154
|
```typescript
|
|
148
155
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
156
|
+
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
|
|
149
157
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
150
158
|
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
151
159
|
import postgres from '@prisma-next/target-postgres/control';
|
|
@@ -158,13 +166,9 @@ export default defineConfig({
|
|
|
158
166
|
adapter: postgresAdapter,
|
|
159
167
|
driver: postgresDriver,
|
|
160
168
|
extensionPacks: [],
|
|
161
|
-
contract:
|
|
162
|
-
source: contract,
|
|
163
|
-
output: 'src/prisma/contract.json',
|
|
164
|
-
types: 'src/prisma/contract.d.ts',
|
|
165
|
-
},
|
|
169
|
+
contract: typescriptContract(contract, 'src/prisma/contract.json'),
|
|
166
170
|
db: {
|
|
167
|
-
|
|
171
|
+
connection: process.env.DATABASE_URL, // Optional: can also use --db flag
|
|
168
172
|
},
|
|
169
173
|
});
|
|
170
174
|
```
|
|
@@ -173,52 +177,80 @@ export default defineConfig({
|
|
|
173
177
|
|
|
174
178
|
1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
|
|
175
179
|
2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
|
|
176
|
-
3. **Create Family Instance**:
|
|
177
|
-
4. **Verify**: Calls `familyInstance.verify()` which:
|
|
180
|
+
3. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
|
|
181
|
+
4. **Verify Marker**: Calls `familyInstance.verify()` which:
|
|
178
182
|
- Reads the contract marker from the database
|
|
179
|
-
- Compares marker presence: Returns `PN-
|
|
180
|
-
- Compares target compatibility: Returns `PN-
|
|
181
|
-
- Compares
|
|
182
|
-
- Compares profile hash: Returns `PN-
|
|
183
|
+
- Compares marker presence: Returns `PN-RUN-3001` if marker is missing
|
|
184
|
+
- Compares target compatibility: Returns `PN-RUN-3003` if contract target doesn't match config target
|
|
185
|
+
- Compares storage hash: Returns `PN-RUN-3002` if `storageHash` doesn't match
|
|
186
|
+
- Compares profile hash: Returns `PN-RUN-3002` if `profileHash` doesn't match (when present)
|
|
183
187
|
- Checks codec coverage (optional): Compares contract column types against supported codec types and reports missing codecs
|
|
188
|
+
5. **Verify Schema (default)**: Unless `--marker-only` is provided, calls `familyInstance.schemaVerify()` to catch schema mismatches such as missing tables or columns after manual DDL. By default this runs in tolerant mode; `--strict` treats schema elements not present in the contract as an error.
|
|
189
|
+
6. **Schema-only mode**: `--schema-only` skips marker verification entirely and runs only `schemaVerify()`. This is useful for brownfield adoption and corrupt-marker diagnosis.
|
|
184
190
|
|
|
185
191
|
**Output Format (TTY):**
|
|
186
192
|
|
|
187
193
|
Success:
|
|
188
|
-
```
|
|
189
|
-
✔ Database
|
|
190
|
-
|
|
194
|
+
```text
|
|
195
|
+
✔ Database marker and schema match contract
|
|
196
|
+
verification: marker + schema
|
|
197
|
+
storageHash: sha256:abc123...
|
|
191
198
|
profileHash: sha256:def456...
|
|
192
199
|
```
|
|
193
200
|
|
|
194
|
-
|
|
201
|
+
Marker-only success:
|
|
202
|
+
```text
|
|
203
|
+
✔ Database marker matches contract
|
|
204
|
+
verification: marker only (--marker-only)
|
|
205
|
+
storageHash: sha256:abc123...
|
|
206
|
+
profileHash: sha256:def456...
|
|
207
|
+
|
|
208
|
+
⚠ Schema verification skipped because --marker-only was provided
|
|
195
209
|
```
|
|
196
|
-
|
|
210
|
+
|
|
211
|
+
Marker failure:
|
|
212
|
+
```text
|
|
213
|
+
✖ Marker missing (PN-RUN-3001)
|
|
197
214
|
Why: Contract marker not found in database
|
|
198
215
|
Fix: Run `prisma-next db sign --db <url>` to create marker
|
|
199
216
|
```
|
|
200
217
|
|
|
218
|
+
Schema drift failure:
|
|
219
|
+
`db verify` prints the schema verification tree / JSON payload and exits with code 1.
|
|
220
|
+
|
|
201
221
|
**Output Format (JSON):**
|
|
202
222
|
|
|
203
223
|
```json
|
|
204
224
|
{
|
|
205
225
|
"ok": true,
|
|
206
|
-
"summary": "Database
|
|
226
|
+
"summary": "Database marker and schema match contract",
|
|
227
|
+
"mode": "full",
|
|
207
228
|
"contract": {
|
|
208
|
-
"
|
|
229
|
+
"storageHash": "sha256:abc123...",
|
|
209
230
|
"profileHash": "sha256:def456..."
|
|
210
231
|
},
|
|
211
232
|
"marker": {
|
|
212
|
-
"
|
|
233
|
+
"storageHash": "sha256:abc123...",
|
|
213
234
|
"profileHash": "sha256:def456..."
|
|
214
235
|
},
|
|
215
236
|
"target": {
|
|
216
237
|
"expected": "postgres"
|
|
217
238
|
},
|
|
218
239
|
"missingCodecs": [],
|
|
240
|
+
"schema": {
|
|
241
|
+
"summary": "Database schema satisfies contract",
|
|
242
|
+
"counts": {
|
|
243
|
+
"pass": 12,
|
|
244
|
+
"warn": 0,
|
|
245
|
+
"fail": 0,
|
|
246
|
+
"totalNodes": 12
|
|
247
|
+
},
|
|
248
|
+
"strict": false
|
|
249
|
+
},
|
|
219
250
|
"meta": {
|
|
220
251
|
"configPath": "/path/to/prisma-next.config.ts",
|
|
221
|
-
"contractPath": "/path/to/src/prisma/contract.json"
|
|
252
|
+
"contractPath": "/path/to/src/prisma/contract.json",
|
|
253
|
+
"schemaVerification": "performed"
|
|
222
254
|
},
|
|
223
255
|
"timings": {
|
|
224
256
|
"total": 42
|
|
@@ -229,22 +261,27 @@ Failure:
|
|
|
229
261
|
**Error Codes:**
|
|
230
262
|
|
|
231
263
|
- `PN-CLI-4010`: Missing driver in config — provide a driver descriptor
|
|
232
|
-
- `PN-
|
|
233
|
-
- `PN-
|
|
234
|
-
- `PN-
|
|
264
|
+
- `PN-RUN-3001`: Marker missing - Contract marker not found in database
|
|
265
|
+
- `PN-RUN-3002`: Hash mismatch - Contract hash does not match database marker
|
|
266
|
+
- `PN-RUN-3003`: Target mismatch - Contract target does not match config target
|
|
267
|
+
- Exit code 1 with schema verification payload: Schema does not match the contract (default mode or `--schema-only`)
|
|
235
268
|
|
|
236
269
|
**Family Requirements:**
|
|
237
270
|
|
|
238
|
-
The family must provide a `create()` method in the family descriptor that returns a `ControlFamilyInstance` with a `verify()` method:
|
|
271
|
+
The family must provide a `create()` method in the family descriptor that accepts a `ControlPlaneStack` and returns a `ControlFamilyInstance` with a `verify()` method:
|
|
239
272
|
|
|
240
273
|
```typescript
|
|
241
|
-
interface ControlFamilyDescriptor {
|
|
242
|
-
create(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
274
|
+
interface ControlFamilyDescriptor<TFamilyId, TFamilyInstance> {
|
|
275
|
+
create<TTargetId extends string>(
|
|
276
|
+
stack: ControlPlaneStack<TFamilyId, TTargetId>,
|
|
277
|
+
): TFamilyInstance;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
interface ControlPlaneStack<TFamilyId, TTargetId> {
|
|
281
|
+
readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;
|
|
282
|
+
readonly adapter: ControlAdapterDescriptor<TFamilyId, TTargetId>;
|
|
283
|
+
readonly driver: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined;
|
|
284
|
+
readonly extensionPacks: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[];
|
|
248
285
|
}
|
|
249
286
|
|
|
250
287
|
interface ControlFamilyInstance {
|
|
@@ -258,48 +295,89 @@ interface ControlFamilyInstance {
|
|
|
258
295
|
}
|
|
259
296
|
```
|
|
260
297
|
|
|
261
|
-
|
|
298
|
+
Use `createControlPlaneStack()` from `@prisma-next/core-control-plane/stack` to create the stack with sensible defaults (`driver` defaults to `undefined`, `extensionPacks` defaults to `[]`).
|
|
262
299
|
|
|
263
|
-
|
|
300
|
+
The SQL family provides this via `@prisma-next/family-sql/control`. The `verify()` method handles marker checks, full `db verify` follows it with `schemaVerify()`, `--marker-only` skips that schema step, and `--schema-only` runs `schemaVerify()` without marker checks.
|
|
264
301
|
|
|
265
|
-
|
|
302
|
+
### `prisma-next db schema`
|
|
303
|
+
|
|
304
|
+
Inspect the live database schema and display it as a human-readable tree or machine-consumable JSON. This command is read-only and never writes files.
|
|
266
305
|
|
|
267
306
|
**Command:**
|
|
268
307
|
```bash
|
|
269
|
-
prisma-next db
|
|
308
|
+
prisma-next db schema [--db <url>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
|
|
270
309
|
```
|
|
271
310
|
|
|
272
311
|
Options:
|
|
273
|
-
- `--db <url>`: Database connection string (optional; defaults to `config.db.
|
|
312
|
+
- `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
|
|
274
313
|
- `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
|
|
275
314
|
- `--json`: Output as JSON object
|
|
276
315
|
- `-q, --quiet`: Quiet mode (errors only)
|
|
277
316
|
- `-v, --verbose`: Verbose output (debug info, timings)
|
|
278
317
|
- `-vv, --trace`: Trace output (deep internals, stack traces)
|
|
279
|
-
- `--timestamps`: Add timestamps to output
|
|
280
318
|
- `--color/--no-color`: Force/disable color output
|
|
281
319
|
|
|
282
320
|
Examples:
|
|
283
321
|
```bash
|
|
284
322
|
# Use config defaults
|
|
285
|
-
prisma-next db
|
|
323
|
+
prisma-next db schema
|
|
286
324
|
|
|
287
325
|
# Specify database URL
|
|
288
|
-
prisma-next db
|
|
326
|
+
prisma-next db schema --db postgresql://user:pass@localhost/db
|
|
289
327
|
|
|
290
328
|
# JSON output
|
|
291
|
-
prisma-next db
|
|
329
|
+
prisma-next db schema --json
|
|
330
|
+
|
|
331
|
+
# Verbose output
|
|
332
|
+
prisma-next db schema -v
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### `prisma-next contract infer`
|
|
336
|
+
|
|
337
|
+
Inspect the live database schema and write an inferred PSL contract to disk. Use this for brownfield adoption when you want a starting `contract.prisma` before running `contract emit` and `db sign`.
|
|
338
|
+
|
|
339
|
+
**Command:**
|
|
340
|
+
```bash
|
|
341
|
+
prisma-next contract infer [--db <url>] [--config <path>] [--output <path>] [--json] [-v] [-q] [--color/--no-color]
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Options:
|
|
345
|
+
- `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
|
|
346
|
+
- `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
|
|
347
|
+
- `--output <path>`: Write the inferred PSL contract to the specified path
|
|
348
|
+
- `--json`: Output a JSON result envelope (includes `psl.path`)
|
|
349
|
+
- `-q, --quiet`: Quiet mode (errors only)
|
|
350
|
+
- `-v, --verbose`: Verbose output (debug info, timings)
|
|
351
|
+
- `-vv, --trace`: Trace output (deep internals, stack traces)
|
|
352
|
+
- `--color/--no-color`: Force/disable color output
|
|
353
|
+
|
|
354
|
+
Examples:
|
|
355
|
+
```bash
|
|
356
|
+
# Infer contract.prisma next to the configured contract.json output
|
|
357
|
+
prisma-next contract infer
|
|
358
|
+
|
|
359
|
+
# Specify database URL
|
|
360
|
+
prisma-next contract infer --db postgresql://user:pass@localhost/db
|
|
361
|
+
|
|
362
|
+
# Override the output path
|
|
363
|
+
prisma-next contract infer --output ./prisma/contract.prisma
|
|
292
364
|
|
|
293
|
-
#
|
|
294
|
-
prisma-next
|
|
365
|
+
# JSON output
|
|
366
|
+
prisma-next contract infer --json
|
|
295
367
|
```
|
|
296
368
|
|
|
369
|
+
By default, `contract infer` writes to:
|
|
370
|
+
1. `--output <path>`, if provided
|
|
371
|
+
2. `contract.prisma` next to `config.contract.output`
|
|
372
|
+
3. `contract.prisma` in the current working directory
|
|
373
|
+
|
|
297
374
|
**Config File Requirements:**
|
|
298
375
|
|
|
299
|
-
|
|
376
|
+
Both `db schema` and `contract infer` require a `driver` in the config to connect to the database:
|
|
300
377
|
|
|
301
378
|
```typescript
|
|
302
379
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
380
|
+
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
|
|
303
381
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
304
382
|
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
305
383
|
import postgres from '@prisma-next/target-postgres/control';
|
|
@@ -312,7 +390,7 @@ export default defineConfig({
|
|
|
312
390
|
driver: postgresDriver,
|
|
313
391
|
extensionPacks: [],
|
|
314
392
|
db: {
|
|
315
|
-
|
|
393
|
+
connection: process.env.DATABASE_URL, // Optional: can also use --db flag
|
|
316
394
|
},
|
|
317
395
|
});
|
|
318
396
|
```
|
|
@@ -320,7 +398,7 @@ export default defineConfig({
|
|
|
320
398
|
**Introspection Process:**
|
|
321
399
|
|
|
322
400
|
1. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
|
|
323
|
-
2. **Create Family Instance**:
|
|
401
|
+
2. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
|
|
324
402
|
3. **Introspect**: Calls `familyInstance.introspect()` which:
|
|
325
403
|
- Queries the database catalog to discover schema structure
|
|
326
404
|
- Returns a family-specific schema IR (e.g., `SqlSchemaIR` for SQL family)
|
|
@@ -387,7 +465,7 @@ sql schema (tables: 2)
|
|
|
387
465
|
|
|
388
466
|
**Error Codes:**
|
|
389
467
|
- `PN-CLI-4010`: Missing driver in config — provide a driver descriptor
|
|
390
|
-
- `PN-CLI-4005`: Missing database
|
|
468
|
+
- `PN-CLI-4005`: Missing database connection — provide `--db <url>` or set `db.connection` in config
|
|
391
469
|
|
|
392
470
|
**Family Requirements:**
|
|
393
471
|
|
|
@@ -417,17 +495,16 @@ Mark the database as matching the emitted contract by writing or updating the co
|
|
|
417
495
|
|
|
418
496
|
**Command:**
|
|
419
497
|
```bash
|
|
420
|
-
prisma-next db sign [--db <url>] [--config <path>] [--json] [-v] [-q] [--
|
|
498
|
+
prisma-next db sign [--db <url>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
|
|
421
499
|
```
|
|
422
500
|
|
|
423
501
|
Options:
|
|
424
|
-
- `--db <url>`: Database connection string (optional; defaults to `config.db.
|
|
502
|
+
- `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
|
|
425
503
|
- `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
|
|
426
504
|
- `--json`: Output as JSON object
|
|
427
505
|
- `-q, --quiet`: Quiet mode (errors only)
|
|
428
506
|
- `-v, --verbose`: Verbose output (debug info, timings)
|
|
429
507
|
- `-vv, --trace`: Trace output (deep internals, stack traces)
|
|
430
|
-
- `--timestamps`: Add timestamps to output
|
|
431
508
|
- `--color/--no-color`: Force/disable color output
|
|
432
509
|
|
|
433
510
|
Examples:
|
|
@@ -441,8 +518,8 @@ prisma-next db sign --db postgresql://user:pass@localhost/db
|
|
|
441
518
|
# JSON output
|
|
442
519
|
prisma-next db sign --json
|
|
443
520
|
|
|
444
|
-
# Verbose output
|
|
445
|
-
prisma-next db sign -v
|
|
521
|
+
# Verbose output
|
|
522
|
+
prisma-next db sign -v
|
|
446
523
|
```
|
|
447
524
|
|
|
448
525
|
**Config File Requirements:**
|
|
@@ -463,13 +540,9 @@ export default defineConfig({
|
|
|
463
540
|
adapter: postgresAdapter,
|
|
464
541
|
driver: postgresDriver,
|
|
465
542
|
extensionPacks: [],
|
|
466
|
-
contract:
|
|
467
|
-
source: contract,
|
|
468
|
-
output: 'src/prisma/contract.json',
|
|
469
|
-
types: 'src/prisma/contract.d.ts',
|
|
470
|
-
},
|
|
543
|
+
contract: typescriptContract(contract, 'src/prisma/contract.json'),
|
|
471
544
|
db: {
|
|
472
|
-
|
|
545
|
+
connection: process.env.DATABASE_URL, // Optional: can also use --db flag
|
|
473
546
|
},
|
|
474
547
|
});
|
|
475
548
|
```
|
|
@@ -478,7 +551,7 @@ export default defineConfig({
|
|
|
478
551
|
|
|
479
552
|
1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
|
|
480
553
|
2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
|
|
481
|
-
3. **Create Family Instance**:
|
|
554
|
+
3. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
|
|
482
555
|
4. **Schema Verification (Precondition)**: Calls `familyInstance.schemaVerify()` to verify the database schema matches the contract:
|
|
483
556
|
- If verification fails: Prints schema verification output and exits with code 1 (marker is not written)
|
|
484
557
|
- If verification passes: Proceeds to marker signing
|
|
@@ -495,7 +568,7 @@ export default defineConfig({
|
|
|
495
568
|
Success (new marker):
|
|
496
569
|
```
|
|
497
570
|
✔ Database signed (marker created)
|
|
498
|
-
|
|
571
|
+
storageHash: sha256:abc123...
|
|
499
572
|
profileHash: sha256:def456...
|
|
500
573
|
Total time: 42ms
|
|
501
574
|
```
|
|
@@ -503,16 +576,16 @@ Success (new marker):
|
|
|
503
576
|
Success (updated marker):
|
|
504
577
|
```
|
|
505
578
|
✔ Database signed (marker updated from sha256:old-hash)
|
|
506
|
-
|
|
579
|
+
storageHash: sha256:abc123...
|
|
507
580
|
profileHash: sha256:def456...
|
|
508
|
-
previous
|
|
581
|
+
previous storageHash: sha256:old-hash
|
|
509
582
|
Total time: 42ms
|
|
510
583
|
```
|
|
511
584
|
|
|
512
585
|
Success (already up-to-date):
|
|
513
586
|
```
|
|
514
587
|
✔ Database already signed with this contract
|
|
515
|
-
|
|
588
|
+
storageHash: sha256:abc123...
|
|
516
589
|
profileHash: sha256:def456...
|
|
517
590
|
Total time: 42ms
|
|
518
591
|
```
|
|
@@ -530,7 +603,7 @@ Failure (schema mismatch):
|
|
|
530
603
|
"ok": true,
|
|
531
604
|
"summary": "Database signed (marker created)",
|
|
532
605
|
"contract": {
|
|
533
|
-
"
|
|
606
|
+
"storageHash": "sha256:abc123...",
|
|
534
607
|
"profileHash": "sha256:def456..."
|
|
535
608
|
},
|
|
536
609
|
"target": {
|
|
@@ -557,7 +630,7 @@ For updated markers:
|
|
|
557
630
|
"ok": true,
|
|
558
631
|
"summary": "Database signed (marker updated from sha256:old-hash)",
|
|
559
632
|
"contract": {
|
|
560
|
-
"
|
|
633
|
+
"storageHash": "sha256:abc123...",
|
|
561
634
|
"profileHash": "sha256:def456..."
|
|
562
635
|
},
|
|
563
636
|
"target": {
|
|
@@ -568,7 +641,7 @@ For updated markers:
|
|
|
568
641
|
"created": false,
|
|
569
642
|
"updated": true,
|
|
570
643
|
"previous": {
|
|
571
|
-
"
|
|
644
|
+
"storageHash": "sha256:old-hash",
|
|
572
645
|
"profileHash": "sha256:old-profile-hash"
|
|
573
646
|
}
|
|
574
647
|
},
|
|
@@ -584,12 +657,11 @@ For updated markers:
|
|
|
584
657
|
|
|
585
658
|
**Error Codes:**
|
|
586
659
|
- `PN-CLI-4010`: Missing driver in config — provide a driver descriptor
|
|
587
|
-
- `PN-CLI-4005`: Missing database
|
|
660
|
+
- `PN-CLI-4005`: Missing database connection — provide `--db <url>` or set `db.connection` in config
|
|
588
661
|
- Exit code 1: Schema verification failed — database schema does not match contract (marker is not written)
|
|
589
662
|
|
|
590
663
|
**Relationship to Other Commands:**
|
|
591
|
-
- **`db
|
|
592
|
-
- **`db verify`**: `db verify` checks that the marker exists and matches the contract. `db sign` writes the marker that `db verify` checks.
|
|
664
|
+
- **`db verify`**: `db verify` checks that the marker exists and matches the contract, then runs schema verification by default. `db sign` writes the marker that `db verify` checks. Use `db verify --marker-only` for marker-only verification and `db verify --schema-only` to inspect only the live schema.
|
|
593
665
|
|
|
594
666
|
**Idempotency:**
|
|
595
667
|
The `db sign` command is idempotent and safe to run multiple times:
|
|
@@ -627,18 +699,17 @@ Initialize a database schema from the contract. This command plans and applies *
|
|
|
627
699
|
|
|
628
700
|
**Command:**
|
|
629
701
|
```bash
|
|
630
|
-
prisma-next db init [--db <url>] [--config <path>] [--
|
|
702
|
+
prisma-next db init [--db <url>] [--config <path>] [--dry-run] [--json] [-v] [-q] [--color/--no-color]
|
|
631
703
|
```
|
|
632
704
|
|
|
633
705
|
Options:
|
|
634
|
-
- `--db <url>`: Database connection string (optional; defaults to `config.db.
|
|
706
|
+
- `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
|
|
635
707
|
- `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
|
|
636
|
-
- `--
|
|
708
|
+
- `--dry-run`: Only show the migration plan, do not apply it
|
|
637
709
|
- `--json [format]`: Output as JSON (`object` only; `ndjson` is not supported for this command)
|
|
638
710
|
- `-q, --quiet`: Quiet mode (errors only)
|
|
639
711
|
- `-v, --verbose`: Verbose output (debug info, timings)
|
|
640
712
|
- `-vv, --trace`: Trace output (deep internals, stack traces)
|
|
641
|
-
- `--timestamps`: Add timestamps to output
|
|
642
713
|
- `--color/--no-color`: Force/disable color output
|
|
643
714
|
|
|
644
715
|
Examples:
|
|
@@ -647,7 +718,7 @@ Examples:
|
|
|
647
718
|
prisma-next db init
|
|
648
719
|
|
|
649
720
|
# Preview migration plan without applying
|
|
650
|
-
prisma-next db init --
|
|
721
|
+
prisma-next db init --dry-run
|
|
651
722
|
|
|
652
723
|
# Specify database URL
|
|
653
724
|
prisma-next db init --db postgresql://user:pass@localhost/db
|
|
@@ -662,6 +733,7 @@ The `db init` command requires a `driver` in the config to connect to the databa
|
|
|
662
733
|
|
|
663
734
|
```typescript
|
|
664
735
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
736
|
+
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
|
|
665
737
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
666
738
|
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
667
739
|
import postgres from '@prisma-next/target-postgres/control';
|
|
@@ -674,13 +746,9 @@ export default defineConfig({
|
|
|
674
746
|
adapter: postgresAdapter,
|
|
675
747
|
driver: postgresDriver,
|
|
676
748
|
extensionPacks: [],
|
|
677
|
-
contract:
|
|
678
|
-
source: contract,
|
|
679
|
-
output: 'src/prisma/contract.json',
|
|
680
|
-
types: 'src/prisma/contract.d.ts',
|
|
681
|
-
},
|
|
749
|
+
contract: typescriptContract(contract, 'src/prisma/contract.json'),
|
|
682
750
|
db: {
|
|
683
|
-
|
|
751
|
+
connection: process.env.DATABASE_URL, // Optional: can also use --db flag
|
|
684
752
|
},
|
|
685
753
|
});
|
|
686
754
|
```
|
|
@@ -689,7 +757,7 @@ export default defineConfig({
|
|
|
689
757
|
|
|
690
758
|
1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
|
|
691
759
|
2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
|
|
692
|
-
3. **Create Family Instance**:
|
|
760
|
+
3. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
|
|
693
761
|
4. **Introspect Schema**: Calls `familyInstance.introspect()` to get the current database schema IR
|
|
694
762
|
5. **Validate wiring**: Ensures the contract is compatible with the CLI config:
|
|
695
763
|
- `contract.targetFamily` matches `config.family.familyId`
|
|
@@ -699,7 +767,7 @@ export default defineConfig({
|
|
|
699
767
|
7. **Plan Migration**: Calls `planner.plan()` with the contract IR, schema IR, additive-only policy, and `frameworkComponents` (the active target/adapter/extension descriptors)
|
|
700
768
|
- On conflict: Returns a structured failure with conflict list
|
|
701
769
|
- On success: Returns a migration plan with operations
|
|
702
|
-
8. **Apply Migration** (if not `--
|
|
770
|
+
8. **Apply Migration** (if not `--dry-run`):
|
|
703
771
|
- Calls `runner.execute()` to apply the plan
|
|
704
772
|
- After execution, verifies schema matches contract
|
|
705
773
|
- Writes contract marker (and records a ledger entry via the target runner)
|
|
@@ -722,7 +790,7 @@ prisma-next db init ➜ Bootstrap a database to match the current contract
|
|
|
722
790
|
Destination hash: sha256:abc123...
|
|
723
791
|
|
|
724
792
|
This is a dry run. No changes were applied.
|
|
725
|
-
Run without --
|
|
793
|
+
Run without --dry-run to apply changes.
|
|
726
794
|
```
|
|
727
795
|
|
|
728
796
|
**Output Format (TTY - Apply Mode):**
|
|
@@ -750,7 +818,7 @@ Applying migration plan and verifying schema...
|
|
|
750
818
|
"plan": {
|
|
751
819
|
"targetId": "postgres",
|
|
752
820
|
"destination": {
|
|
753
|
-
"
|
|
821
|
+
"storageHash": "sha256:abc123..."
|
|
754
822
|
},
|
|
755
823
|
"operations": [
|
|
756
824
|
{
|
|
@@ -765,7 +833,7 @@ Applying migration plan and verifying schema...
|
|
|
765
833
|
"operationsExecuted": 4
|
|
766
834
|
},
|
|
767
835
|
"marker": {
|
|
768
|
-
"
|
|
836
|
+
"storageHash": "sha256:abc123..."
|
|
769
837
|
}
|
|
770
838
|
}
|
|
771
839
|
```
|
|
@@ -777,12 +845,33 @@ Applying migration plan and verifying schema...
|
|
|
777
845
|
- `PN-CLI-4010`: Missing driver in config
|
|
778
846
|
- `PN-CLI-4020`: Migration planning failed (conflicts)
|
|
779
847
|
- `PN-CLI-4021`: Target does not support migrations
|
|
780
|
-
- `PN-
|
|
848
|
+
- `PN-RUN-3000`: Runtime error (includes marker mismatch failures)
|
|
781
849
|
|
|
782
850
|
**Behavior Notes:**
|
|
783
851
|
|
|
784
852
|
- If the database already has a marker that matches the destination contract, `db init` succeeds as a noop (0 operations planned/executed).
|
|
785
|
-
- If the database has a marker that does **not** match the destination contract, `db init` fails (including in `--
|
|
853
|
+
- If the database has a marker that does **not** match the destination contract, `db init` fails (including in `--dry-run` mode). Use `db init` for bootstrapping; use your migration workflow to reconcile existing databases.
|
|
854
|
+
|
|
855
|
+
### `prisma-next db update`
|
|
856
|
+
|
|
857
|
+
Update your database schema to match the currently emitted contract.
|
|
858
|
+
|
|
859
|
+
`db update` differs from `db init`:
|
|
860
|
+
|
|
861
|
+
- Works on any database, whether or not it has been initialized with `db init` (creates the signature table if missing)
|
|
862
|
+
- Allows `additive`, `widening`, and `destructive` operation classes where supported by planner/runner
|
|
863
|
+
- Disables per-operation runner execution checks by default (precheck/postcheck/idempotency)
|
|
864
|
+
- In `--dry-run` mode for SQL targets, prints a DDL preview derived from planned operations
|
|
865
|
+
- In interactive mode, destructive plans require confirmation before apply
|
|
866
|
+
- In non-interactive mode, destructive plans fail unless `-y, --yes` is provided
|
|
867
|
+
|
|
868
|
+
**Command:**
|
|
869
|
+
```bash
|
|
870
|
+
prisma-next db update [--db <url>] [--config <path>] [--dry-run] [-y|--yes] [--interactive|--no-interactive] [--json] [-v] [-q] [--color/--no-color]
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
**Error codes (additional to shared CLI/runtime codes):**
|
|
874
|
+
- `RUNNER_FAILED`: runner rejected apply (origin mismatch, failed checks, policy failures, or execution errors)
|
|
786
875
|
|
|
787
876
|
**Config File (`prisma-next.config.ts`):**
|
|
788
877
|
|
|
@@ -797,6 +886,7 @@ The CLI uses a config file to specify the target family, target, adapter, extens
|
|
|
797
886
|
|
|
798
887
|
```typescript
|
|
799
888
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
889
|
+
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
|
|
800
890
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
801
891
|
import postgres from '@prisma-next/target-postgres/control';
|
|
802
892
|
import sql from '@prisma-next/family-sql/control';
|
|
@@ -807,42 +897,192 @@ export default defineConfig({
|
|
|
807
897
|
target: postgres,
|
|
808
898
|
adapter: postgresAdapter,
|
|
809
899
|
extensionPacks: [],
|
|
810
|
-
contract:
|
|
811
|
-
source: contract, // Can be a value or a function: () => import('./contract').then(m => m.contract)
|
|
812
|
-
output: 'src/prisma/contract.json', // Optional: defaults to 'src/prisma/contract.json'
|
|
813
|
-
types: 'src/prisma/contract.d.ts', // Optional: defaults to output with .d.ts extension
|
|
814
|
-
},
|
|
900
|
+
contract: typescriptContract(contract, 'src/prisma/contract.json'),
|
|
815
901
|
});
|
|
816
902
|
```
|
|
817
903
|
|
|
818
|
-
|
|
819
|
-
-
|
|
820
|
-
-
|
|
821
|
-
-
|
|
904
|
+
Prefer helper utilities for authoring mode selection:
|
|
905
|
+
- `typescriptContract(contractIR, outputPath?)` from `@prisma-next/sql-contract-ts/config-types` for TS-authored contracts
|
|
906
|
+
- `prismaContract(schemaPath, { output?, target? })` from `@prisma-next/sql-contract-psl/provider` for PSL-authored providers
|
|
907
|
+
- Provider failures are returned as structured diagnostics for CLI rendering
|
|
822
908
|
|
|
823
909
|
The `contract.output` field specifies the path to `contract.json`. This is the canonical location where other CLI commands can find the contract JSON artifact. Defaults to `'src/prisma/contract.json'` if not specified.
|
|
824
910
|
|
|
825
|
-
|
|
911
|
+
`contract.d.ts` is always colocated with `contract.json` and derived from `contract.output` (`contract.json` → `contract.d.ts`).
|
|
826
912
|
|
|
827
913
|
**Output:**
|
|
828
914
|
- `contract.json`: Includes `_generated` metadata field indicating it's a generated artifact (excluded from canonicalization/hashing)
|
|
829
915
|
- `contract.d.ts`: Includes warning header comments indicating it's a generated file
|
|
830
916
|
|
|
917
|
+
### `prisma-next migration plan`
|
|
918
|
+
|
|
919
|
+
Plan a migration from contract changes. Compares the emitted contract against the latest on-disk migration state and produces a new migration package with the required operations. No database connection is needed — fully offline.
|
|
920
|
+
|
|
921
|
+
```bash
|
|
922
|
+
prisma-next migration plan [--config <path>] [--name <slug>] [--from <hash>] [--json] [-v] [-q] [--color/--no-color]
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
**Options:**
|
|
926
|
+
- `--config <path>`: Path to `prisma-next.config.ts`
|
|
927
|
+
- `--name <slug>`: Name slug for the migration directory (default: `migration`)
|
|
928
|
+
- `--from <hash>`: Explicit starting contract hash (overrides latest migration target detection)
|
|
929
|
+
- `--json`: Output as JSON object
|
|
930
|
+
- `-q, --quiet`: Quiet mode (errors only)
|
|
931
|
+
- `-v, --verbose`: Verbose output (debug info, timings)
|
|
932
|
+
|
|
933
|
+
**What it does:**
|
|
934
|
+
1. Loads config and reads `contract.json` (the "to" contract)
|
|
935
|
+
2. Reads existing migrations from `config.migrations.dir` (default: `migrations/`)
|
|
936
|
+
3. Determines the starting point: `--from <hash>` if provided, otherwise the latest migration target
|
|
937
|
+
4. Diffs the starting contract against the new contract using the target's migration planner
|
|
938
|
+
5. Writes a new migration package (`migration.json` + `ops.json`) and attests the `migrationId`
|
|
939
|
+
|
|
940
|
+
**Branching with `--from`:** Use `--from` to create a migration edge from a specific contract hash instead of the latest migration target. This enables branched migration graphs where multiple environments diverge from a common ancestor.
|
|
941
|
+
|
|
942
|
+
### `prisma-next migration show`
|
|
943
|
+
|
|
944
|
+
Display a migration package's operations, DDL preview, and metadata. Accepts a directory path, a hash prefix (git-style matching against `migrationId`), or defaults to the latest migration.
|
|
945
|
+
|
|
946
|
+
```bash
|
|
947
|
+
prisma-next migration show [target] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
**Options:**
|
|
951
|
+
- `[target]`: Migration directory path or migrationId hash prefix (defaults to latest)
|
|
952
|
+
- `--config <path>`: Path to `prisma-next.config.ts`
|
|
953
|
+
- `--json`: Output as JSON object
|
|
954
|
+
- `-q, --quiet`: Quiet mode (errors only)
|
|
955
|
+
- `-v, --verbose`: Verbose output
|
|
956
|
+
|
|
957
|
+
**What it does:**
|
|
958
|
+
1. If `target` is a path (contains `/` or `\`), reads that directory directly
|
|
959
|
+
2. If `target` is a hash prefix, scans all attested migrations and matches against `migrationId`
|
|
960
|
+
3. If no target, defaults to the latest migration
|
|
961
|
+
4. Displays operations with operation class badges, destructive warnings, and DDL preview
|
|
962
|
+
|
|
963
|
+
**Destructive warnings:** When a migration contains destructive operations (e.g., `DROP TABLE`, `ALTER COLUMN TYPE`), the output includes a prominent `⚠` warning about potential data loss.
|
|
964
|
+
|
|
965
|
+
### `prisma-next migration status`
|
|
966
|
+
|
|
967
|
+
Show the migration graph and applied status. Adapts based on context:
|
|
968
|
+
|
|
969
|
+
- **With DB connection**: Shows applied/pending markers and "you are here" indicators
|
|
970
|
+
- **Without DB connection**: Shows the graph structure from disk only
|
|
971
|
+
- **With `--ref`**: Targets a specific ref instead of the contract hash; all refs from `refs.json` are rendered on the graph
|
|
972
|
+
|
|
973
|
+
```bash
|
|
974
|
+
prisma-next migration status [--db <url>] [--ref <name>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
|
|
975
|
+
```
|
|
976
|
+
|
|
977
|
+
**Options:**
|
|
978
|
+
- `--db <url>`: Database connection string (enables online mode)
|
|
979
|
+
- `--ref <name>`: Target a named ref from `migrations/refs.json` instead of the current contract hash
|
|
980
|
+
- `--config <path>`: Path to `prisma-next.config.ts`
|
|
981
|
+
- `--json`: Output as JSON object
|
|
982
|
+
- `-q, --quiet`: Quiet mode (errors only)
|
|
983
|
+
- `-v, --verbose`: Verbose output
|
|
984
|
+
|
|
985
|
+
**What it does:**
|
|
986
|
+
1. Reads migration packages from disk and reconstructs the migration graph
|
|
987
|
+
2. Loads all refs from `migrations/refs.json` (if present) and renders them on the graph
|
|
988
|
+
3. If `--ref` is provided, uses the ref's hash as the target instead of the contract hash; the active ref is highlighted in bold, other refs are dimmed
|
|
989
|
+
4. If a DB connection is available, reads the marker to determine applied/pending status and shows distance from the ref target (e.g., "2 edge(s) behind ref")
|
|
990
|
+
5. Displays the graph with `◄ DB`, `◄ Contract`, and `◄ ref:<name>` markers
|
|
991
|
+
6. Shows operation summaries with destructive operation highlighting
|
|
992
|
+
7. In `--ref` mode, the `CONTRACT.AHEAD` warning is suppressed — contract being ahead of a ref target is expected in multi-environment workflows
|
|
993
|
+
|
|
994
|
+
**Branched graphs:** When the migration graph has multiple branches (divergence), status reports an `AMBIGUOUS_TARGET` error with the divergence point and branch details. Use `--ref` to target a specific branch.
|
|
995
|
+
|
|
996
|
+
### `prisma-next migration apply`
|
|
997
|
+
|
|
998
|
+
Apply planned migrations to the database. Executes previously planned migrations (created by `migration plan`). Compares the database marker against the migration graph to determine which migrations are pending, then executes them sequentially. Each migration runs in its own transaction. Does not plan new migrations — run `migration plan` first.
|
|
999
|
+
|
|
1000
|
+
```bash
|
|
1001
|
+
prisma-next migration apply [--db <url>] [--ref <name>] [--config <path>] [--json] [-v] [-q] [--color/--no-color]
|
|
1002
|
+
```
|
|
1003
|
+
|
|
1004
|
+
**Options:**
|
|
1005
|
+
- `--db <url>`: Database connection string (optional; defaults to `config.db.connection`)
|
|
1006
|
+
- `--ref <name>`: Target a named ref from `migrations/refs.json` instead of the current contract hash
|
|
1007
|
+
- `--config <path>`: Path to `prisma-next.config.ts`
|
|
1008
|
+
- `--json`: Output as JSON object
|
|
1009
|
+
- `-q, --quiet`: Quiet mode (errors only)
|
|
1010
|
+
- `-v, --verbose`: Verbose output (debug info, timings)
|
|
1011
|
+
|
|
1012
|
+
**What it does:**
|
|
1013
|
+
1. Reads attested migration packages from `config.migrations.dir`
|
|
1014
|
+
2. Reconstructs the migration graph (skips drafts with `migrationId: null`)
|
|
1015
|
+
3. Determines the destination hash: from `--ref` (via `refs.json`) or from `contract.json`
|
|
1016
|
+
4. Connects to the database and reads the current marker hash
|
|
1017
|
+
5. Finds the shortest path from the marker hash to the destination using graph pathfinding
|
|
1018
|
+
6. Executes each pending migration in order using the target's `MigrationRunner`
|
|
1019
|
+
7. Each migration runs in its own transaction with prechecks, postchecks, and idempotency checks enabled
|
|
1020
|
+
8. After each migration, the runner verifies the schema and updates the marker/ledger
|
|
1021
|
+
|
|
1022
|
+
**Config requirements:** Requires `driver` and `db.connection` (or `--db`). `migrations.dir` is optional and defaults to `migrations/`.
|
|
1023
|
+
|
|
1024
|
+
**Resume semantics:** If a migration fails, previously applied migrations are preserved. Re-running `migration apply` resumes from the last successful migration.
|
|
1025
|
+
|
|
1026
|
+
**Ref-based routing:** With `--ref`, apply targets the ref's hash instead of the contract hash. This enables multi-environment workflows where staging and production track different points in the migration graph.
|
|
1027
|
+
|
|
1028
|
+
### `prisma-next migration verify`
|
|
1029
|
+
|
|
1030
|
+
Verify a migration package's integrity by recomputing the content-addressed `migrationId`.
|
|
1031
|
+
|
|
1032
|
+
```bash
|
|
1033
|
+
prisma-next migration verify --dir <path>
|
|
1034
|
+
```
|
|
1035
|
+
|
|
1036
|
+
- **Verified**: stored `migrationId` matches recomputed value
|
|
1037
|
+
- **Draft**: `migrationId` is null — automatically attests the package
|
|
1038
|
+
- **Mismatch**: package has been modified since attestation (command exits non-zero)
|
|
1039
|
+
|
|
1040
|
+
### `prisma-next migration ref`
|
|
1041
|
+
|
|
1042
|
+
Manage named refs in `migrations/refs.json`. Refs map logical environment names (e.g., `staging`, `production`) to contract hashes, enabling multi-environment migration workflows where different environments track different points in the migration graph.
|
|
1043
|
+
|
|
1044
|
+
```bash
|
|
1045
|
+
prisma-next migration ref set <name> <hash> # Set a ref to a contract hash
|
|
1046
|
+
prisma-next migration ref get <name> # Get the hash for a ref
|
|
1047
|
+
prisma-next migration ref delete <name> # Delete a ref
|
|
1048
|
+
prisma-next migration ref list # List all refs
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
**Options (all subcommands):**
|
|
1052
|
+
- `--config <path>`: Path to `prisma-next.config.ts`
|
|
1053
|
+
- `--json`: Output as JSON object
|
|
1054
|
+
- `-q, --quiet`: Quiet mode (errors only)
|
|
1055
|
+
|
|
1056
|
+
**Ref naming rules:** Lowercase alphanumeric with hyphens or forward slashes (e.g., `staging`, `prod/us-east`). No `.` or `..` segments.
|
|
1057
|
+
|
|
1058
|
+
**Ref values:** Must be valid contract hashes (`sha256:<64 hex chars>` or `sha256:empty`).
|
|
1059
|
+
|
|
1060
|
+
**Atomic writes:** `refs.json` is written atomically via temp file + rename to prevent corruption from concurrent writes.
|
|
1061
|
+
|
|
831
1062
|
## Architecture
|
|
832
1063
|
|
|
833
1064
|
```mermaid
|
|
834
1065
|
flowchart TD
|
|
835
1066
|
CLI[CLI Entry Point]
|
|
836
|
-
|
|
1067
|
+
CMD_EMIT[Emit Command]
|
|
1068
|
+
CMD_DB[DB Commands]
|
|
1069
|
+
CMD_MIG[Migration Commands]
|
|
837
1070
|
LOAD[TS Contract Loader]
|
|
838
1071
|
EMIT[Emitter]
|
|
1072
|
+
CTRL[Control Client]
|
|
1073
|
+
MIG_TOOLS["@prisma-next/migration-tools"]
|
|
839
1074
|
FS[File System]
|
|
840
1075
|
|
|
841
|
-
CLI -->
|
|
842
|
-
|
|
1076
|
+
CLI --> CMD_EMIT
|
|
1077
|
+
CLI --> CMD_DB
|
|
1078
|
+
CLI --> CMD_MIG
|
|
1079
|
+
CMD_EMIT --> LOAD
|
|
843
1080
|
LOAD --> EMIT
|
|
844
|
-
|
|
845
|
-
|
|
1081
|
+
CMD_DB --> CTRL
|
|
1082
|
+
CMD_MIG --> CTRL
|
|
1083
|
+
CMD_MIG --> MIG_TOOLS
|
|
1084
|
+
MIG_TOOLS --> FS
|
|
1085
|
+
CTRL --> FS
|
|
846
1086
|
```
|
|
847
1087
|
|
|
848
1088
|
## Config Validation and Normalization
|
|
@@ -864,19 +1104,20 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
|
|
|
864
1104
|
- Exit codes: 0 (success), 1 (runtime error), 2 (usage/config error)
|
|
865
1105
|
- **Error Handling**: Uses `exitOverride()` to catch unhandled errors (non-structured errors that fail fast) and print stack traces. Commands handle structured errors themselves via `process.exit()`.
|
|
866
1106
|
- **Command Taxonomy**: Groups commands by domain/plane (e.g., `contract emit`)
|
|
867
|
-
- **Help Formatting**: Uses `configureHelp()` to customize help output with styled format matching normal command output. Root help shows "prisma-next" title with command tree; command help shows "prisma-next <command> ➜ <description>" with options and docs URLs. See `utils/
|
|
1107
|
+
- **Help Formatting**: Uses `configureHelp()` to customize help output with styled format matching normal command output. Root help shows "prisma-next" title with command tree; command help shows "prisma-next <command> ➜ <description>" with options and docs URLs. See `utils/formatters/help.ts` for help formatters.
|
|
868
1108
|
- **Command Descriptions**: See the “Command Descriptions” section above for `setCommandDescriptions()` usage.
|
|
869
1109
|
|
|
870
1110
|
### Contract Emit Command (`commands/contract-emit.ts`)
|
|
871
1111
|
- Canonical command implementation using commander
|
|
872
|
-
- Supports global flags (JSON, verbosity, color,
|
|
873
|
-
- **Error Handling**: Uses structured errors (`CliStructuredError`), Result pattern
|
|
1112
|
+
- Supports global flags (JSON, verbosity, color, interactive, yes)
|
|
1113
|
+
- **Error Handling**: Uses structured errors (`CliStructuredError`), Result pattern, and `process.exit()`. Commands return `Result<T, CliStructuredError>`, process results with `handleResult()`, and call `process.exit(exitCode)` directly. See `.cursor/rules/cli-error-handling.mdc` for details.
|
|
874
1114
|
- Loads the user's config module (`prisma-next.config.ts`)
|
|
875
|
-
- Resolves contract from
|
|
876
|
-
-
|
|
877
|
-
-
|
|
1115
|
+
- Resolves contract from provider:
|
|
1116
|
+
- Calls `config.contract.source()` and expects `Result<ContractIR, Diagnostics>`
|
|
1117
|
+
- Source-specific parsing/loading stays inside providers
|
|
1118
|
+
- Provider diagnostics are surfaced as actionable CLI failures
|
|
878
1119
|
- Throws error if `config.contract` is missing
|
|
879
|
-
- Uses artifact
|
|
1120
|
+
- Uses artifact path from `config.contract.output` (already normalized by `defineConfig()` with defaults applied)
|
|
880
1121
|
- Creates family instance via `config.family.create()` (assembles operation registry, type imports, extension IDs)
|
|
881
1122
|
- Calls `familyInstance.emitContract()` with raw contract (instance handles stripping mappings and validation internally)
|
|
882
1123
|
- Outputs human-readable or JSON format based on flags
|
|
@@ -890,12 +1131,12 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
|
|
|
890
1131
|
|
|
891
1132
|
### Error Handling (`utils/errors.ts`, `utils/cli-errors.ts`, `utils/result.ts`, `utils/result-handler.ts`)
|
|
892
1133
|
- **Structured Errors**: Call sites throw `CliStructuredError` instances with full context (why, fix, docsUrl, etc.)
|
|
893
|
-
- **Result Pattern**: Commands
|
|
1134
|
+
- **Result Pattern**: Commands return `Result<T, CliStructuredError>` and use `handleResult()` for output and exit codes
|
|
894
1135
|
- **Error Conversion**: `CliStructuredError.toEnvelope()` converts errors to envelopes for output formatting
|
|
895
1136
|
- **Result Processing**: `handleResult()` processes Results, formats output, and returns exit codes
|
|
896
1137
|
- **Exit Codes**:
|
|
897
1138
|
- Usage/config errors (PN-CLI-4001-4007) → exit code 2
|
|
898
|
-
- Runtime errors (PN-
|
|
1139
|
+
- Runtime errors (PN-RUN-3xxx) → exit code 1
|
|
899
1140
|
- Success → exit code 0
|
|
900
1141
|
- **Fail Fast**: Non-structured errors propagate and are caught by Commander.js's `exitOverride()` with stack traces
|
|
901
1142
|
- See `.cursor/rules/cli-error-handling.mdc` for detailed patterns
|
|
@@ -905,7 +1146,7 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
|
|
|
905
1146
|
- **Removed**: `pack-assembly.ts` has been removed. Pack assembly is now handled by family instances. For SQL family, tests can import pack-based helpers directly from `packages/2-sql/3-tooling/family/src/core/assembly.ts` using relative paths.
|
|
906
1147
|
- Assembly logic is family-specific and owned by each family's instance implementation (e.g., `createSqlFamilyInstance` in `@prisma-next/family-sql`).
|
|
907
1148
|
|
|
908
|
-
### Output Formatting (`utils/
|
|
1149
|
+
### Output Formatting (`utils/formatters/`)
|
|
909
1150
|
- **Command Output Formatters**: Format human-readable output for commands (emit, verify, etc.)
|
|
910
1151
|
- Paths are shown as relative paths from current working directory (using `relative(process.cwd(), path)`)
|
|
911
1152
|
- Success indicators use consistent checkmark (✔) throughout
|
|
@@ -947,7 +1188,7 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
|
|
|
947
1188
|
- `types.storage`: Storage type bindings (`typeId`, `nativeType`, etc.) used in authoring/emission.
|
|
948
1189
|
- **`operations`**: Operation signatures the component contributes (extensions), used for type generation and (optionally) validation/lowering.
|
|
949
1190
|
- **Component-specific metadata**:
|
|
950
|
-
- Extensions may also include control-plane-only metadata like `databaseDependencies` (used by verify
|
|
1191
|
+
- Extensions may also include control-plane-only metadata like `databaseDependencies` (used by verify and schema verification flows and not required at runtime).
|
|
951
1192
|
|
|
952
1193
|
Unlike the older **manifest-based IR** approach (separate JSON manifests + a parsing/validation step to build an IR), descriptors are imported directly from packages (e.g., `@prisma-next/*/control`). This removes a file-format boundary and keeps the data and its types co-located.
|
|
953
1194
|
- Benefits: fewer moving parts (no JSON parsing), easier refactors (TypeScript catches drift), and clearer ownership (the package exports the canonical descriptor object).
|
|
@@ -999,6 +1240,8 @@ export default defineConfig({
|
|
|
999
1240
|
- **`commander`**: CLI argument parsing and command routing
|
|
1000
1241
|
- **`esbuild`**: Bundling TypeScript contract files with import allowlisting
|
|
1001
1242
|
- **`@prisma-next/emitter`**: Contract emission engine (returns strings)
|
|
1243
|
+
- **`@prisma-next/migration-tools`**: On-disk migration I/O, attestation, and history reconstruction
|
|
1244
|
+
- **`@prisma-next/core-control-plane`**: Config types, migration operation types, error types, control plane stack
|
|
1002
1245
|
|
|
1003
1246
|
## Design Decisions
|
|
1004
1247
|
|
|
@@ -1058,18 +1301,111 @@ pnpm test:integration # Run integration tests only
|
|
|
1058
1301
|
pnpm test:e2e # Run e2e tests only
|
|
1059
1302
|
```
|
|
1060
1303
|
|
|
1304
|
+
## Programmatic Control API
|
|
1305
|
+
|
|
1306
|
+
The CLI package provides a programmatic control client for running control-plane operations without using the command line. This is useful for:
|
|
1307
|
+
|
|
1308
|
+
- Integration with build tools and CI pipelines
|
|
1309
|
+
- Custom orchestration workflows
|
|
1310
|
+
- Test automation
|
|
1311
|
+
- Programmatic database management
|
|
1312
|
+
|
|
1313
|
+
### Basic Usage
|
|
1314
|
+
|
|
1315
|
+
```typescript
|
|
1316
|
+
import { createControlClient } from '@prisma-next/cli/control-api';
|
|
1317
|
+
import sql from '@prisma-next/family-sql/control';
|
|
1318
|
+
import postgres from '@prisma-next/target-postgres/control';
|
|
1319
|
+
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
1320
|
+
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
1321
|
+
|
|
1322
|
+
// Create a control client with framework component descriptors
|
|
1323
|
+
const client = createControlClient({
|
|
1324
|
+
family: sql,
|
|
1325
|
+
target: postgres,
|
|
1326
|
+
adapter: postgresAdapter,
|
|
1327
|
+
driver: postgresDriver,
|
|
1328
|
+
extensionPacks: [],
|
|
1329
|
+
});
|
|
1330
|
+
|
|
1331
|
+
try {
|
|
1332
|
+
// Connect to database
|
|
1333
|
+
await client.connect(databaseUrl);
|
|
1334
|
+
|
|
1335
|
+
// Run operations
|
|
1336
|
+
const verifyResult = await client.verify({ contractIR });
|
|
1337
|
+
const initResult = await client.dbInit({ contractIR, mode: 'apply' });
|
|
1338
|
+
const updateResult = await client.dbUpdate({ contractIR, mode: 'apply' });
|
|
1339
|
+
const introspectResult = await client.introspect();
|
|
1340
|
+
} finally {
|
|
1341
|
+
// Clean up
|
|
1342
|
+
await client.close();
|
|
1343
|
+
}
|
|
1344
|
+
```
|
|
1345
|
+
|
|
1346
|
+
### Available Operations
|
|
1347
|
+
|
|
1348
|
+
| Method | Description |
|
|
1349
|
+
|--------|-------------|
|
|
1350
|
+
| `connect(url)` | Establishes database connection |
|
|
1351
|
+
| `close()` | Closes connection (idempotent) |
|
|
1352
|
+
| `readMarker()` | Reads contract marker from database (null if none) |
|
|
1353
|
+
| `verify(options)` | Verifies database marker matches contract |
|
|
1354
|
+
| `schemaVerify(options)` | Verifies database schema satisfies contract |
|
|
1355
|
+
| `sign(options)` | Writes contract marker to database |
|
|
1356
|
+
| `dbInit(options)` | Initializes database schema from contract |
|
|
1357
|
+
| `dbUpdate(options)` | Updates database schema to match contract |
|
|
1358
|
+
| `migrationApply(options)` | Applies pre-planned migration edges to database |
|
|
1359
|
+
| `introspect(options)` | Introspects database schema |
|
|
1360
|
+
|
|
1361
|
+
### Result Types
|
|
1362
|
+
|
|
1363
|
+
Operations return structured result types:
|
|
1364
|
+
|
|
1365
|
+
- `readMarker()` → `ContractMarkerRecord | null`
|
|
1366
|
+
- `verify()` → `VerifyDatabaseResult`
|
|
1367
|
+
- `schemaVerify()` → `VerifyDatabaseSchemaResult`
|
|
1368
|
+
- `sign()` → `SignDatabaseResult`
|
|
1369
|
+
- `dbInit()` → `Result<DbInitSuccess, DbInitFailure>` (uses Result pattern)
|
|
1370
|
+
- `dbUpdate()` → `Result<DbUpdateSuccess, DbUpdateFailure>` (uses Result pattern)
|
|
1371
|
+
- `migrationApply()` → `Result<MigrationApplySuccess, MigrationApplyFailure>` (uses Result pattern)
|
|
1372
|
+
- `introspect()` → Schema IR (family-specific)
|
|
1373
|
+
|
|
1374
|
+
### Error Handling
|
|
1375
|
+
|
|
1376
|
+
- **Connection errors**: Thrown as exceptions from `connect()`
|
|
1377
|
+
- **Not connected errors**: Thrown if operations called before `connect()`
|
|
1378
|
+
- **Driver not configured**: Thrown if driver is not provided in options
|
|
1379
|
+
- **Operation failures**: Returned as structured results (not thrown)
|
|
1380
|
+
|
|
1381
|
+
### Key Differences from CLI
|
|
1382
|
+
|
|
1383
|
+
| Aspect | CLI | Control API |
|
|
1384
|
+
|--------|-----|-------------|
|
|
1385
|
+
| Config | Reads `prisma-next.config.ts` | Accepts descriptors directly |
|
|
1386
|
+
| File I/O | Reads contract.json from disk | Accepts contract IR directly |
|
|
1387
|
+
| Output | Formats for console | Returns structured data |
|
|
1388
|
+
| Exit codes | Uses `process.exit()` | Returns results/throws |
|
|
1389
|
+
|
|
1061
1390
|
## Entrypoints
|
|
1062
1391
|
|
|
1063
1392
|
The CLI package exports several subpaths for different use cases:
|
|
1064
1393
|
|
|
1065
1394
|
- **`@prisma-next/cli`** (main export): Exports `loadContractFromTs` and `createContractEmitCommand`
|
|
1066
1395
|
- **`@prisma-next/cli/config-types`**: Exports `defineConfig` and config types
|
|
1396
|
+
- **`@prisma-next/cli/control-api`**: Exports `createControlClient` and control API types
|
|
1067
1397
|
- **`@prisma-next/cli/commands/db-init`**: Exports `createDbInitCommand`
|
|
1068
|
-
- **`@prisma-next/cli/commands/db-
|
|
1069
|
-
- **`@prisma-next/cli/commands/db-schema
|
|
1398
|
+
- **`@prisma-next/cli/commands/db-update`**: Exports `createDbUpdateCommand`
|
|
1399
|
+
- **`@prisma-next/cli/commands/db-schema`**: Exports `createDbSchemaCommand`
|
|
1070
1400
|
- **`@prisma-next/cli/commands/db-sign`**: Exports `createDbSignCommand`
|
|
1071
1401
|
- **`@prisma-next/cli/commands/db-verify`**: Exports `createDbVerifyCommand`
|
|
1072
1402
|
- **`@prisma-next/cli/commands/contract-emit`**: Exports `createContractEmitCommand`
|
|
1403
|
+
- **`@prisma-next/cli/commands/contract-infer`**: Exports `createContractInferCommand`
|
|
1404
|
+
- **`@prisma-next/cli/commands/migration-plan`**: Exports `createMigrationPlanCommand`
|
|
1405
|
+
- **`@prisma-next/cli/commands/migration-show`**: Exports `createMigrationShowCommand`
|
|
1406
|
+
- **`@prisma-next/cli/commands/migration-status`**: Exports `createMigrationStatusCommand`
|
|
1407
|
+
- **`@prisma-next/cli/commands/migration-apply`**: Exports `createMigrationApplyCommand`
|
|
1408
|
+
- **`@prisma-next/cli/commands/migration-verify`**: Exports `createMigrationVerifyCommand`
|
|
1073
1409
|
- **`@prisma-next/cli/config-loader`**: Exports `loadConfig` function
|
|
1074
1410
|
|
|
1075
1411
|
**Important**: `loadContractFromTs` is exported from the main package (`@prisma-next/cli`). See `.cursor/rules/cli-package-exports.mdc` for import patterns.
|