@prisma-next/cli 0.3.0-dev.6 → 0.3.0-dev.64

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.
Files changed (180) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +314 -80
  3. package/dist/cli-errors-JlPTsazx.mjs +3 -0
  4. package/dist/cli.d.mts +1 -0
  5. package/dist/cli.js +1 -2376
  6. package/dist/cli.mjs +203 -0
  7. package/dist/cli.mjs.map +1 -0
  8. package/dist/client-PimzSD1f.mjs +981 -0
  9. package/dist/client-PimzSD1f.mjs.map +1 -0
  10. package/dist/commands/contract-emit.d.mts +7 -0
  11. package/dist/commands/contract-emit.d.mts.map +1 -0
  12. package/dist/commands/contract-emit.mjs +151 -0
  13. package/dist/commands/contract-emit.mjs.map +1 -0
  14. package/dist/commands/db-init.d.mts +7 -0
  15. package/dist/commands/db-init.d.mts.map +1 -0
  16. package/dist/commands/db-init.mjs +134 -0
  17. package/dist/commands/db-init.mjs.map +1 -0
  18. package/dist/commands/db-introspect.d.mts +7 -0
  19. package/dist/commands/db-introspect.d.mts.map +1 -0
  20. package/dist/commands/db-introspect.mjs +118 -0
  21. package/dist/commands/db-introspect.mjs.map +1 -0
  22. package/dist/commands/db-schema-verify.d.mts +7 -0
  23. package/dist/commands/db-schema-verify.d.mts.map +1 -0
  24. package/dist/commands/db-schema-verify.mjs +120 -0
  25. package/dist/commands/db-schema-verify.mjs.map +1 -0
  26. package/dist/commands/db-sign.d.mts +7 -0
  27. package/dist/commands/db-sign.d.mts.map +1 -0
  28. package/dist/commands/db-sign.mjs +142 -0
  29. package/dist/commands/db-sign.mjs.map +1 -0
  30. package/dist/commands/db-update.d.mts +7 -0
  31. package/dist/commands/db-update.d.mts.map +1 -0
  32. package/dist/commands/db-update.mjs +123 -0
  33. package/dist/commands/db-update.mjs.map +1 -0
  34. package/dist/commands/db-verify.d.mts +7 -0
  35. package/dist/commands/db-verify.d.mts.map +1 -0
  36. package/dist/commands/db-verify.mjs +133 -0
  37. package/dist/commands/db-verify.mjs.map +1 -0
  38. package/dist/commands/migration-apply.d.mts +23 -0
  39. package/dist/commands/migration-apply.d.mts.map +1 -0
  40. package/dist/commands/migration-apply.mjs +250 -0
  41. package/dist/commands/migration-apply.mjs.map +1 -0
  42. package/dist/commands/migration-plan.d.mts +25 -0
  43. package/dist/commands/migration-plan.d.mts.map +1 -0
  44. package/dist/commands/migration-plan.mjs +266 -0
  45. package/dist/commands/migration-plan.mjs.map +1 -0
  46. package/dist/commands/migration-show.d.mts +28 -0
  47. package/dist/commands/migration-show.d.mts.map +1 -0
  48. package/dist/commands/migration-show.mjs +138 -0
  49. package/dist/commands/migration-show.mjs.map +1 -0
  50. package/dist/commands/migration-status.d.mts +35 -0
  51. package/dist/commands/migration-status.d.mts.map +1 -0
  52. package/dist/commands/migration-status.mjs +260 -0
  53. package/dist/commands/migration-status.mjs.map +1 -0
  54. package/dist/commands/migration-verify.d.mts +16 -0
  55. package/dist/commands/migration-verify.d.mts.map +1 -0
  56. package/dist/commands/migration-verify.mjs +86 -0
  57. package/dist/commands/migration-verify.mjs.map +1 -0
  58. package/dist/config-loader-PPf4CtDj.mjs +43 -0
  59. package/dist/config-loader-PPf4CtDj.mjs.map +1 -0
  60. package/dist/{config-loader.d.ts → config-loader.d.mts} +8 -3
  61. package/dist/config-loader.d.mts.map +1 -0
  62. package/dist/config-loader.mjs +3 -0
  63. package/dist/exports/config-types.d.mts +2 -0
  64. package/dist/exports/config-types.mjs +3 -0
  65. package/dist/exports/control-api.d.mts +621 -0
  66. package/dist/exports/control-api.d.mts.map +1 -0
  67. package/dist/exports/control-api.mjs +98 -0
  68. package/dist/exports/control-api.mjs.map +1 -0
  69. package/dist/{load-ts-contract.d.ts → exports/index.d.mts} +10 -5
  70. package/dist/exports/index.d.mts.map +1 -0
  71. package/dist/exports/index.mjs +135 -0
  72. package/dist/exports/index.mjs.map +1 -0
  73. package/dist/extract-sql-ddl-BmlKvk4o.mjs +26 -0
  74. package/dist/extract-sql-ddl-BmlKvk4o.mjs.map +1 -0
  75. package/dist/framework-components-CjV_jD8f.mjs +59 -0
  76. package/dist/framework-components-CjV_jD8f.mjs.map +1 -0
  77. package/dist/migration-command-scaffold-DfY_F3ev.mjs +97 -0
  78. package/dist/migration-command-scaffold-DfY_F3ev.mjs.map +1 -0
  79. package/dist/progress-adapter-DENrzF6I.mjs +49 -0
  80. package/dist/progress-adapter-DENrzF6I.mjs.map +1 -0
  81. package/dist/result-handler-iA9JtUC7.mjs +1186 -0
  82. package/dist/result-handler-iA9JtUC7.mjs.map +1 -0
  83. package/package.json +75 -38
  84. package/src/cli.ts +43 -0
  85. package/src/commands/contract-emit.ts +221 -111
  86. package/src/commands/db-init.ts +217 -426
  87. package/src/commands/db-introspect.ts +148 -185
  88. package/src/commands/db-schema-verify.ts +162 -149
  89. package/src/commands/db-sign.ts +215 -202
  90. package/src/commands/db-update.ts +220 -0
  91. package/src/commands/db-verify.ts +193 -156
  92. package/src/commands/migration-apply.ts +431 -0
  93. package/src/commands/migration-plan.ts +446 -0
  94. package/src/commands/migration-show.ts +255 -0
  95. package/src/commands/migration-status.ts +436 -0
  96. package/src/commands/migration-verify.ts +151 -0
  97. package/src/config-loader.ts +13 -3
  98. package/src/control-api/client.ts +605 -0
  99. package/src/control-api/errors.ts +9 -0
  100. package/src/control-api/operations/contract-emit.ts +161 -0
  101. package/src/control-api/operations/db-init.ts +286 -0
  102. package/src/control-api/operations/db-update.ts +221 -0
  103. package/src/control-api/operations/extract-sql-ddl.ts +47 -0
  104. package/src/control-api/operations/migration-apply.ts +195 -0
  105. package/src/control-api/operations/migration-helpers.ts +49 -0
  106. package/src/control-api/types.ts +687 -0
  107. package/src/exports/config-types.ts +3 -3
  108. package/src/exports/control-api.ts +53 -0
  109. package/src/load-ts-contract.ts +16 -11
  110. package/src/utils/cli-errors.ts +3 -1
  111. package/src/utils/command-helpers.ts +92 -3
  112. package/src/utils/framework-components.ts +11 -30
  113. package/src/utils/migration-command-scaffold.ts +190 -0
  114. package/src/utils/output.ts +363 -25
  115. package/src/utils/progress-adapter.ts +86 -0
  116. package/dist/chunk-464LNZCE.js +0 -134
  117. package/dist/chunk-464LNZCE.js.map +0 -1
  118. package/dist/chunk-BZMBKEEQ.js +0 -997
  119. package/dist/chunk-BZMBKEEQ.js.map +0 -1
  120. package/dist/chunk-HWYQOCAJ.js +0 -47
  121. package/dist/chunk-HWYQOCAJ.js.map +0 -1
  122. package/dist/chunk-ZKYEJROM.js +0 -94
  123. package/dist/chunk-ZKYEJROM.js.map +0 -1
  124. package/dist/cli.d.ts +0 -2
  125. package/dist/cli.d.ts.map +0 -1
  126. package/dist/cli.js.map +0 -1
  127. package/dist/commands/contract-emit.d.ts +0 -3
  128. package/dist/commands/contract-emit.d.ts.map +0 -1
  129. package/dist/commands/contract-emit.js +0 -9
  130. package/dist/commands/contract-emit.js.map +0 -1
  131. package/dist/commands/db-init.d.ts +0 -3
  132. package/dist/commands/db-init.d.ts.map +0 -1
  133. package/dist/commands/db-init.js +0 -341
  134. package/dist/commands/db-init.js.map +0 -1
  135. package/dist/commands/db-introspect.d.ts +0 -3
  136. package/dist/commands/db-introspect.d.ts.map +0 -1
  137. package/dist/commands/db-introspect.js +0 -190
  138. package/dist/commands/db-introspect.js.map +0 -1
  139. package/dist/commands/db-schema-verify.d.ts +0 -3
  140. package/dist/commands/db-schema-verify.d.ts.map +0 -1
  141. package/dist/commands/db-schema-verify.js +0 -164
  142. package/dist/commands/db-schema-verify.js.map +0 -1
  143. package/dist/commands/db-sign.d.ts +0 -3
  144. package/dist/commands/db-sign.d.ts.map +0 -1
  145. package/dist/commands/db-sign.js +0 -199
  146. package/dist/commands/db-sign.js.map +0 -1
  147. package/dist/commands/db-verify.d.ts +0 -3
  148. package/dist/commands/db-verify.d.ts.map +0 -1
  149. package/dist/commands/db-verify.js +0 -173
  150. package/dist/commands/db-verify.js.map +0 -1
  151. package/dist/config-loader.d.ts.map +0 -1
  152. package/dist/config-loader.js +0 -7
  153. package/dist/config-loader.js.map +0 -1
  154. package/dist/exports/config-types.d.ts +0 -3
  155. package/dist/exports/config-types.d.ts.map +0 -1
  156. package/dist/exports/config-types.js +0 -6
  157. package/dist/exports/config-types.js.map +0 -1
  158. package/dist/exports/index.d.ts +0 -4
  159. package/dist/exports/index.d.ts.map +0 -1
  160. package/dist/exports/index.js +0 -175
  161. package/dist/exports/index.js.map +0 -1
  162. package/dist/load-ts-contract.d.ts.map +0 -1
  163. package/dist/utils/action.d.ts +0 -16
  164. package/dist/utils/action.d.ts.map +0 -1
  165. package/dist/utils/cli-errors.d.ts +0 -7
  166. package/dist/utils/cli-errors.d.ts.map +0 -1
  167. package/dist/utils/command-helpers.d.ts +0 -12
  168. package/dist/utils/command-helpers.d.ts.map +0 -1
  169. package/dist/utils/framework-components.d.ts +0 -81
  170. package/dist/utils/framework-components.d.ts.map +0 -1
  171. package/dist/utils/global-flags.d.ts +0 -25
  172. package/dist/utils/global-flags.d.ts.map +0 -1
  173. package/dist/utils/output.d.ts +0 -142
  174. package/dist/utils/output.d.ts.map +0 -1
  175. package/dist/utils/result-handler.d.ts +0 -15
  176. package/dist/utils/result-handler.d.ts.map +0 -1
  177. package/dist/utils/spinner.d.ts +0 -29
  178. package/dist/utils/spinner.d.ts.map +0 -1
  179. package/src/utils/action.ts +0 -43
  180. 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
 
@@ -46,7 +47,7 @@ Commands use separate short and long descriptions via `setCommandDescriptions()`
46
47
  - **Short description**: One-liner used in command trees and headers (e.g., "Emit signed contract artifacts")
47
48
  - **Long description**: Multiline text shown at the bottom of help output with detailed context
48
49
 
49
- See `.cursor/rules/cli-command-descriptions.mdc` for details.
50
+ See `src/utils/command-helpers.ts` for `setCommandDescriptions()` and `getLongDescription()`.
50
51
 
51
52
  ## Commands
52
53
 
@@ -61,12 +62,12 @@ prisma-next contract emit [--config <path>] [--json] [-v] [-q] [--timestamps] [-
61
62
 
62
63
  **Config File Requirements:**
63
64
 
64
- The `contract emit` command requires a `driver` in the config (even though it doesn't use it) because `ControlFamilyDescriptor.create()` requires it for consistency:
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
 
@@ -116,7 +112,7 @@ prisma-next db verify [--db <url>] [--config <path>] [--json] [-v] [-q] [--times
116
112
  ```
117
113
 
118
114
  Options:
119
- - `--db <url>`: Database connection string (optional; defaults to `config.db.url` if set)
115
+ - `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
120
116
  - `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
121
117
  - `--json`: Output as JSON object
122
118
  - `-q, --quiet`: Quiet mode (errors only)
@@ -146,6 +142,7 @@ The `db verify` command requires a `driver` in the config to connect to the data
146
142
 
147
143
  ```typescript
148
144
  import { defineConfig } from '@prisma-next/cli/config-types';
145
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
149
146
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
150
147
  import postgresDriver from '@prisma-next/driver-postgres/control';
151
148
  import postgres from '@prisma-next/target-postgres/control';
@@ -158,13 +155,9 @@ export default defineConfig({
158
155
  adapter: postgresAdapter,
159
156
  driver: postgresDriver,
160
157
  extensionPacks: [],
161
- contract: {
162
- source: contract,
163
- output: 'src/prisma/contract.json',
164
- types: 'src/prisma/contract.d.ts',
165
- },
158
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
166
159
  db: {
167
- url: process.env.DATABASE_URL, // Optional: can also use --db flag
160
+ connection: process.env.DATABASE_URL, // Optional: can also use --db flag
168
161
  },
169
162
  });
170
163
  ```
@@ -173,12 +166,12 @@ export default defineConfig({
173
166
 
174
167
  1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
175
168
  2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
176
- 3. **Create Family Instance**: Calls `config.family.create()` with target, adapter, driver, and `extensionPacks` (passed as `extensions`) to create a family instance
169
+ 3. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
177
170
  4. **Verify**: Calls `familyInstance.verify()` which:
178
171
  - Reads the contract marker from the database
179
172
  - Compares marker presence: Returns `PN-RTM-3001` if marker is missing
180
173
  - Compares target compatibility: Returns `PN-RTM-3003` if contract target doesn't match config target
181
- - Compares core hash: Returns `PN-RTM-3002` if `coreHash` doesn't match
174
+ - Compares storage hash: Returns `PN-RTM-3002` if `storageHash` doesn't match
182
175
  - Compares profile hash: Returns `PN-RTM-3002` if `profileHash` doesn't match (when present)
183
176
  - Checks codec coverage (optional): Compares contract column types against supported codec types and reports missing codecs
184
177
 
@@ -187,7 +180,7 @@ export default defineConfig({
187
180
  Success:
188
181
  ```
189
182
  ✔ Database matches contract
190
- coreHash: sha256:abc123...
183
+ storageHash: sha256:abc123...
191
184
  profileHash: sha256:def456...
192
185
  ```
193
186
 
@@ -205,11 +198,11 @@ Failure:
205
198
  "ok": true,
206
199
  "summary": "Database matches contract",
207
200
  "contract": {
208
- "coreHash": "sha256:abc123...",
201
+ "storageHash": "sha256:abc123...",
209
202
  "profileHash": "sha256:def456..."
210
203
  },
211
204
  "marker": {
212
- "coreHash": "sha256:abc123...",
205
+ "storageHash": "sha256:abc123...",
213
206
  "profileHash": "sha256:def456..."
214
207
  },
215
208
  "target": {
@@ -235,16 +228,20 @@ Failure:
235
228
 
236
229
  **Family Requirements:**
237
230
 
238
- The family must provide a `create()` method in the family descriptor that returns a `ControlFamilyInstance` with a `verify()` method:
231
+ The family must provide a `create()` method in the family descriptor that accepts a `ControlPlaneStack` and returns a `ControlFamilyInstance` with a `verify()` method:
239
232
 
240
233
  ```typescript
241
- interface ControlFamilyDescriptor {
242
- create(options: {
243
- target: ControlTargetDescriptor;
244
- adapter: ControlAdapterDescriptor;
245
- driver: ControlDriverDescriptor;
246
- extensions: ControlExtensionDescriptor[];
247
- }): ControlFamilyInstance;
234
+ interface ControlFamilyDescriptor<TFamilyId, TFamilyInstance> {
235
+ create<TTargetId extends string>(
236
+ stack: ControlPlaneStack<TFamilyId, TTargetId>,
237
+ ): TFamilyInstance;
238
+ }
239
+
240
+ interface ControlPlaneStack<TFamilyId, TTargetId> {
241
+ readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;
242
+ readonly adapter: ControlAdapterDescriptor<TFamilyId, TTargetId>;
243
+ readonly driver: ControlDriverDescriptor<TFamilyId, TTargetId> | undefined;
244
+ readonly extensionPacks: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[];
248
245
  }
249
246
 
250
247
  interface ControlFamilyInstance {
@@ -258,6 +255,8 @@ interface ControlFamilyInstance {
258
255
  }
259
256
  ```
260
257
 
258
+ Use `createControlPlaneStack()` from `@prisma-next/core-control-plane/stack` to create the stack with sensible defaults (`driver` defaults to `undefined`, `extensionPacks` defaults to `[]`).
259
+
261
260
  The SQL family provides this via `@prisma-next/family-sql/control`. The `verify()` method handles reading the marker, comparing hashes, and checking codec coverage internally.
262
261
 
263
262
  ### `prisma-next db introspect`
@@ -270,7 +269,7 @@ prisma-next db introspect [--db <url>] [--config <path>] [--json] [-v] [-q] [--t
270
269
  ```
271
270
 
272
271
  Options:
273
- - `--db <url>`: Database connection string (optional; defaults to `config.db.url` if set)
272
+ - `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
274
273
  - `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
275
274
  - `--json`: Output as JSON object
276
275
  - `-q, --quiet`: Quiet mode (errors only)
@@ -300,6 +299,7 @@ The `db introspect` command requires a `driver` in the config to connect to the
300
299
 
301
300
  ```typescript
302
301
  import { defineConfig } from '@prisma-next/cli/config-types';
302
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
303
303
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
304
304
  import postgresDriver from '@prisma-next/driver-postgres/control';
305
305
  import postgres from '@prisma-next/target-postgres/control';
@@ -312,7 +312,7 @@ export default defineConfig({
312
312
  driver: postgresDriver,
313
313
  extensionPacks: [],
314
314
  db: {
315
- url: process.env.DATABASE_URL, // Optional: can also use --db flag
315
+ connection: process.env.DATABASE_URL, // Optional: can also use --db flag
316
316
  },
317
317
  });
318
318
  ```
@@ -320,7 +320,7 @@ export default defineConfig({
320
320
  **Introspection Process:**
321
321
 
322
322
  1. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
323
- 2. **Create Family Instance**: Calls `config.family.create()` with target, adapter, driver, and `extensionPacks` (passed as `extensions`) to create a family instance
323
+ 2. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
324
324
  3. **Introspect**: Calls `familyInstance.introspect()` which:
325
325
  - Queries the database catalog to discover schema structure
326
326
  - Returns a family-specific schema IR (e.g., `SqlSchemaIR` for SQL family)
@@ -387,7 +387,7 @@ sql schema (tables: 2)
387
387
 
388
388
  **Error Codes:**
389
389
  - `PN-CLI-4010`: Missing driver in config — provide a driver descriptor
390
- - `PN-CLI-4005`: Missing database URL — provide `--db <url>` or set `db.url` in config
390
+ - `PN-CLI-4005`: Missing database connection — provide `--db <url>` or set `db.connection` in config
391
391
 
392
392
  **Family Requirements:**
393
393
 
@@ -421,7 +421,7 @@ prisma-next db sign [--db <url>] [--config <path>] [--json] [-v] [-q] [--timesta
421
421
  ```
422
422
 
423
423
  Options:
424
- - `--db <url>`: Database connection string (optional; defaults to `config.db.url` if set)
424
+ - `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
425
425
  - `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
426
426
  - `--json`: Output as JSON object
427
427
  - `-q, --quiet`: Quiet mode (errors only)
@@ -463,13 +463,9 @@ export default defineConfig({
463
463
  adapter: postgresAdapter,
464
464
  driver: postgresDriver,
465
465
  extensionPacks: [],
466
- contract: {
467
- source: contract,
468
- output: 'src/prisma/contract.json',
469
- types: 'src/prisma/contract.d.ts',
470
- },
466
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
471
467
  db: {
472
- url: process.env.DATABASE_URL, // Optional: can also use --db flag
468
+ connection: process.env.DATABASE_URL, // Optional: can also use --db flag
473
469
  },
474
470
  });
475
471
  ```
@@ -478,7 +474,7 @@ export default defineConfig({
478
474
 
479
475
  1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
480
476
  2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
481
- 3. **Create Family Instance**: Calls `config.family.create()` with target, adapter, driver, and `extensionPacks` (passed as `extensions`) to create a family instance
477
+ 3. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
482
478
  4. **Schema Verification (Precondition)**: Calls `familyInstance.schemaVerify()` to verify the database schema matches the contract:
483
479
  - If verification fails: Prints schema verification output and exits with code 1 (marker is not written)
484
480
  - If verification passes: Proceeds to marker signing
@@ -495,7 +491,7 @@ export default defineConfig({
495
491
  Success (new marker):
496
492
  ```
497
493
  ✔ Database signed (marker created)
498
- coreHash: sha256:abc123...
494
+ storageHash: sha256:abc123...
499
495
  profileHash: sha256:def456...
500
496
  Total time: 42ms
501
497
  ```
@@ -503,16 +499,16 @@ Success (new marker):
503
499
  Success (updated marker):
504
500
  ```
505
501
  ✔ Database signed (marker updated from sha256:old-hash)
506
- coreHash: sha256:abc123...
502
+ storageHash: sha256:abc123...
507
503
  profileHash: sha256:def456...
508
- previous coreHash: sha256:old-hash
504
+ previous storageHash: sha256:old-hash
509
505
  Total time: 42ms
510
506
  ```
511
507
 
512
508
  Success (already up-to-date):
513
509
  ```
514
510
  ✔ Database already signed with this contract
515
- coreHash: sha256:abc123...
511
+ storageHash: sha256:abc123...
516
512
  profileHash: sha256:def456...
517
513
  Total time: 42ms
518
514
  ```
@@ -530,7 +526,7 @@ Failure (schema mismatch):
530
526
  "ok": true,
531
527
  "summary": "Database signed (marker created)",
532
528
  "contract": {
533
- "coreHash": "sha256:abc123...",
529
+ "storageHash": "sha256:abc123...",
534
530
  "profileHash": "sha256:def456..."
535
531
  },
536
532
  "target": {
@@ -557,7 +553,7 @@ For updated markers:
557
553
  "ok": true,
558
554
  "summary": "Database signed (marker updated from sha256:old-hash)",
559
555
  "contract": {
560
- "coreHash": "sha256:abc123...",
556
+ "storageHash": "sha256:abc123...",
561
557
  "profileHash": "sha256:def456..."
562
558
  },
563
559
  "target": {
@@ -568,7 +564,7 @@ For updated markers:
568
564
  "created": false,
569
565
  "updated": true,
570
566
  "previous": {
571
- "coreHash": "sha256:old-hash",
567
+ "storageHash": "sha256:old-hash",
572
568
  "profileHash": "sha256:old-profile-hash"
573
569
  }
574
570
  },
@@ -584,7 +580,7 @@ For updated markers:
584
580
 
585
581
  **Error Codes:**
586
582
  - `PN-CLI-4010`: Missing driver in config — provide a driver descriptor
587
- - `PN-CLI-4005`: Missing database URL — provide `--db <url>` or set `db.url` in config
583
+ - `PN-CLI-4005`: Missing database connection — provide `--db <url>` or set `db.connection` in config
588
584
  - Exit code 1: Schema verification failed — database schema does not match contract (marker is not written)
589
585
 
590
586
  **Relationship to Other Commands:**
@@ -631,7 +627,7 @@ prisma-next db init [--db <url>] [--config <path>] [--plan] [--json] [-v] [-q] [
631
627
  ```
632
628
 
633
629
  Options:
634
- - `--db <url>`: Database connection string (optional; defaults to `config.db.url` if set)
630
+ - `--db <url>`: Database connection string (optional; defaults to `config.db.connection` if set)
635
631
  - `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
636
632
  - `--plan`: Only show the migration plan, do not apply it
637
633
  - `--json [format]`: Output as JSON (`object` only; `ndjson` is not supported for this command)
@@ -662,6 +658,7 @@ The `db init` command requires a `driver` in the config to connect to the databa
662
658
 
663
659
  ```typescript
664
660
  import { defineConfig } from '@prisma-next/cli/config-types';
661
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
665
662
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
666
663
  import postgresDriver from '@prisma-next/driver-postgres/control';
667
664
  import postgres from '@prisma-next/target-postgres/control';
@@ -674,13 +671,9 @@ export default defineConfig({
674
671
  adapter: postgresAdapter,
675
672
  driver: postgresDriver,
676
673
  extensionPacks: [],
677
- contract: {
678
- source: contract,
679
- output: 'src/prisma/contract.json',
680
- types: 'src/prisma/contract.d.ts',
681
- },
674
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
682
675
  db: {
683
- url: process.env.DATABASE_URL, // Optional: can also use --db flag
676
+ connection: process.env.DATABASE_URL, // Optional: can also use --db flag
684
677
  },
685
678
  });
686
679
  ```
@@ -689,7 +682,7 @@ export default defineConfig({
689
682
 
690
683
  1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
691
684
  2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
692
- 3. **Create Family Instance**: Calls `config.family.create()` with target, adapter, driver, and `extensionPacks` (passed as `extensions`)
685
+ 3. **Create Family Instance**: Creates a `ControlPlaneStack` via `createControlPlaneStack()` and passes it to `config.family.create(stack)` to create a family instance
693
686
  4. **Introspect Schema**: Calls `familyInstance.introspect()` to get the current database schema IR
694
687
  5. **Validate wiring**: Ensures the contract is compatible with the CLI config:
695
688
  - `contract.targetFamily` matches `config.family.familyId`
@@ -750,7 +743,7 @@ Applying migration plan and verifying schema...
750
743
  "plan": {
751
744
  "targetId": "postgres",
752
745
  "destination": {
753
- "coreHash": "sha256:abc123..."
746
+ "storageHash": "sha256:abc123..."
754
747
  },
755
748
  "operations": [
756
749
  {
@@ -765,7 +758,7 @@ Applying migration plan and verifying schema...
765
758
  "operationsExecuted": 4
766
759
  },
767
760
  "marker": {
768
- "coreHash": "sha256:abc123..."
761
+ "storageHash": "sha256:abc123..."
769
762
  }
770
763
  }
771
764
  ```
@@ -784,6 +777,25 @@ Applying migration plan and verifying schema...
784
777
  - If the database already has a marker that matches the destination contract, `db init` succeeds as a noop (0 operations planned/executed).
785
778
  - If the database has a marker that does **not** match the destination contract, `db init` fails (including in `--plan` mode). Use `db init` for bootstrapping; use your migration workflow to reconcile existing databases.
786
779
 
780
+ ### `prisma-next db update`
781
+
782
+ Update your database schema to match the currently emitted contract.
783
+
784
+ `db update` differs from `db init`:
785
+
786
+ - Works on any database, whether or not it has been initialized with `db init` (creates the signature table if missing)
787
+ - Allows `additive`, `widening`, and `destructive` operation classes where supported by planner/runner
788
+ - Disables per-operation runner execution checks by default (precheck/postcheck/idempotency)
789
+ - In `--plan` mode for SQL targets, prints a DDL preview derived from planned operations
790
+
791
+ **Command:**
792
+ ```bash
793
+ prisma-next db update [--db <url>] [--config <path>] [--plan] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
794
+ ```
795
+
796
+ **Error codes (additional to shared CLI/runtime codes):**
797
+ - `RUNNER_FAILED`: runner rejected apply (origin mismatch, failed checks, policy failures, or execution errors)
798
+
787
799
  **Config File (`prisma-next.config.ts`):**
788
800
 
789
801
  The CLI uses a config file to specify the target family, target, adapter, extensionPacks, and contract.
@@ -797,6 +809,7 @@ The CLI uses a config file to specify the target family, target, adapter, extens
797
809
 
798
810
  ```typescript
799
811
  import { defineConfig } from '@prisma-next/cli/config-types';
812
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
800
813
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
801
814
  import postgres from '@prisma-next/target-postgres/control';
802
815
  import sql from '@prisma-next/family-sql/control';
@@ -807,42 +820,167 @@ export default defineConfig({
807
820
  target: postgres,
808
821
  adapter: postgresAdapter,
809
822
  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
- },
823
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
815
824
  });
816
825
  ```
817
826
 
818
- The `contract.source` field can be:
819
- - A direct value: `source: contract`
820
- - A synchronous function: `source: () => contract`
821
- - An asynchronous function: `source: () => import('./contract').then(m => m.contract)`
827
+ Prefer helper utilities for authoring mode selection:
828
+ - `typescriptContract(contractIR, outputPath?)` from `@prisma-next/sql-contract-ts/config-types` for TS-authored contracts
829
+ - `prismaContract(schemaPath, { output?, target? })` from `@prisma-next/sql-contract-psl/provider` for PSL-authored providers
830
+ - Provider failures are returned as structured diagnostics for CLI rendering
822
831
 
823
832
  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
833
 
825
- The `contract.types` field specifies the path to `contract.d.ts`. Defaults to `output` with `.d.ts` extension (replaces `.json` with `.d.ts` if output ends with `.json`, otherwise appends `contract.d.ts` to the directory containing output).
834
+ `contract.d.ts` is always colocated with `contract.json` and derived from `contract.output` (`contract.json` `contract.d.ts`).
826
835
 
827
836
  **Output:**
828
837
  - `contract.json`: Includes `_generated` metadata field indicating it's a generated artifact (excluded from canonicalization/hashing)
829
838
  - `contract.d.ts`: Includes warning header comments indicating it's a generated file
830
839
 
840
+ ### `prisma-next migration plan`
841
+
842
+ 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.
843
+
844
+ ```bash
845
+ prisma-next migration plan [--config <path>] [--name <slug>] [--from <hash>] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
846
+ ```
847
+
848
+ **Options:**
849
+ - `--config <path>`: Path to `prisma-next.config.ts`
850
+ - `--name <slug>`: Name slug for the migration directory (default: `migration`)
851
+ - `--from <hash>`: Explicit starting contract hash (overrides latest chain leaf detection)
852
+ - `--json`: Output as JSON object
853
+ - `-q, --quiet`: Quiet mode (errors only)
854
+ - `-v, --verbose`: Verbose output (debug info, timings)
855
+ - `--timestamps`: Add timestamps to output
856
+
857
+ **What it does:**
858
+ 1. Loads config and reads `contract.json` (the "to" contract)
859
+ 2. Reads existing migrations from `config.migrations.dir` (default: `migrations/`)
860
+ 3. Reconstructs the migration chain and finds the leaf (current state)
861
+ 4. Diffs the leaf contract against the new contract using the target's migration planner (same planner as `db init`)
862
+ 5. Writes a new migration package (`migration.json` + `ops.json`) and attests the `migrationId`
863
+
864
+ ### `prisma-next migration show`
865
+
866
+ 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.
867
+
868
+ ```bash
869
+ prisma-next migration show [target] [--config <path>] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
870
+ ```
871
+
872
+ **Options:**
873
+ - `[target]`: Migration directory path or migrationId hash prefix (defaults to latest)
874
+ - `--config <path>`: Path to `prisma-next.config.ts`
875
+ - `--json`: Output as JSON object
876
+ - `-q, --quiet`: Quiet mode (errors only)
877
+ - `-v, --verbose`: Verbose output
878
+ - `--timestamps`: Add timestamps to output
879
+
880
+ **What it does:**
881
+ 1. If `target` is a path (contains `/` or `\`), reads that directory directly
882
+ 2. If `target` is a hash prefix, scans all attested migrations and matches against `migrationId`
883
+ 3. If no target, defaults to the latest migration (chain leaf)
884
+ 4. Displays operations with operation class badges, destructive warnings, and DDL preview
885
+
886
+ **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.
887
+
888
+ ### `prisma-next migration status`
889
+
890
+ Show the migration graph and applied status. Adapts based on context:
891
+
892
+ - **With DB connection**: Shows applied/pending markers and "you are here" indicators
893
+ - **Without DB connection**: Shows the graph structure from disk only
894
+
895
+ ```bash
896
+ prisma-next migration status [--db <url>] [--config <path>] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
897
+ ```
898
+
899
+ **Options:**
900
+ - `--db <url>`: Database connection string (enables online mode)
901
+ - `--config <path>`: Path to `prisma-next.config.ts`
902
+ - `--json`: Output as JSON object
903
+ - `-q, --quiet`: Quiet mode (errors only)
904
+ - `-v, --verbose`: Verbose output
905
+ - `--timestamps`: Add timestamps to output
906
+
907
+ **What it does:**
908
+ 1. Reads migration packages from disk and reconstructs the chain
909
+ 2. If a DB connection is available, reads the marker to determine applied/pending status
910
+ 3. Displays the graph as a linear chain with `◄ DB` and `◄ Contract` markers
911
+ 4. Shows operation summaries with destructive operation highlighting
912
+ 5. Falls back to offline mode if DB connection fails
913
+
914
+ **Known limitation:** Branched migration graphs (multiple leaves) produce an error. Only linear chains are visualized.
915
+
916
+ ### `prisma-next migration apply`
917
+
918
+ Apply planned migrations to the database. Executes previously planned migrations (created by `migration plan`). Compares the database marker against the migration chain 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.
919
+
920
+ ```bash
921
+ prisma-next migration apply [--db <url>] [--config <path>] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
922
+ ```
923
+
924
+ **Options:**
925
+ - `--db <url>`: Database connection string (optional; defaults to `config.db.connection`)
926
+ - `--config <path>`: Path to `prisma-next.config.ts`
927
+ - `--json`: Output as JSON object
928
+ - `-q, --quiet`: Quiet mode (errors only)
929
+ - `-v, --verbose`: Verbose output (debug info, timings)
930
+ - `--timestamps`: Add timestamps to output
931
+
932
+ **What it does:**
933
+ 1. Reads attested migration packages from `config.migrations.dir`
934
+ 2. Reconstructs the migration chain (skips drafts with `migrationId: null`)
935
+ 3. Reads the current contract hash from `contract.json`
936
+ 4. Connects to the database and reads the current marker hash
937
+ 5. Finds the path from the marker hash to the current contract hash
938
+ 6. Executes each pending migration in order using the target's `MigrationRunner`
939
+ 7. Each migration runs in its own transaction with prechecks, postchecks, and idempotency checks enabled
940
+ 8. After each migration, the runner verifies the schema and updates the marker/ledger
941
+
942
+ **Config requirements:** Requires `driver` and `db.connection` (or `--db`). `migrations.dir` is optional and defaults to `migrations/`.
943
+
944
+ **Resume semantics:** If a migration fails, previously applied migrations are preserved. Re-running `migration apply` resumes from the last successful migration.
945
+
946
+ **Planning requirement:** `migration apply` now requires the current contract hash to exist in attested on-disk migrations. If the contract has changed and no migration was planned, apply exits with an error and asks you to run `migration plan`.
947
+
948
+ ### `prisma-next migration verify`
949
+
950
+ Verify a migration package's integrity by recomputing the content-addressed `migrationId`.
951
+
952
+ ```bash
953
+ prisma-next migration verify --dir <path>
954
+ ```
955
+
956
+ - **Verified**: stored `migrationId` matches recomputed value
957
+ - **Draft**: `migrationId` is null — automatically attests the package
958
+ - **Mismatch**: package has been modified since attestation (command exits non-zero)
959
+
831
960
  ## Architecture
832
961
 
833
962
  ```mermaid
834
963
  flowchart TD
835
964
  CLI[CLI Entry Point]
836
- CMD[Emit Command]
965
+ CMD_EMIT[Emit Command]
966
+ CMD_DB[DB Commands]
967
+ CMD_MIG[Migration Commands]
837
968
  LOAD[TS Contract Loader]
838
969
  EMIT[Emitter]
970
+ CTRL[Control Client]
971
+ MIG_TOOLS["@prisma-next/migration-tools"]
839
972
  FS[File System]
840
973
 
841
- CLI --> CMD
842
- CMD --> LOAD
974
+ CLI --> CMD_EMIT
975
+ CLI --> CMD_DB
976
+ CLI --> CMD_MIG
977
+ CMD_EMIT --> LOAD
843
978
  LOAD --> EMIT
844
- EMIT --> CMD
845
- CMD --> FS
979
+ CMD_DB --> CTRL
980
+ CMD_MIG --> CTRL
981
+ CMD_MIG --> MIG_TOOLS
982
+ MIG_TOOLS --> FS
983
+ CTRL --> FS
846
984
  ```
847
985
 
848
986
  ## Config Validation and Normalization
@@ -865,18 +1003,19 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
865
1003
  - **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
1004
  - **Command Taxonomy**: Groups commands by domain/plane (e.g., `contract emit`)
867
1005
  - **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/output.ts` for help formatters.
868
- - **Command Descriptions**: Commands use `setCommandDescriptions()` to set separate short and long descriptions. See `utils/command-helpers.ts` and `.cursor/rules/cli-command-descriptions.mdc`.
1006
+ - **Command Descriptions**: See the “Command Descriptions” section above for `setCommandDescriptions()` usage.
869
1007
 
870
1008
  ### Contract Emit Command (`commands/contract-emit.ts`)
871
1009
  - Canonical command implementation using commander
872
1010
  - Supports global flags (JSON, verbosity, color, timestamps)
873
1011
  - **Error Handling**: Uses structured errors (`CliStructuredError`), Result pattern (`performAction`), and `process.exit()`. Commands wrap logic in `performAction()`, process results with `handleResult()`, and call `process.exit(exitCode)` directly. See `.cursor/rules/cli-error-handling.mdc` for details.
874
1012
  - Loads the user's config module (`prisma-next.config.ts`)
875
- - Resolves contract from config:
876
- - Uses `config.contract.source` (supports sync and async functions)
877
- - User's config is responsible for loading the contract (can use `loadContractFromTs` or any other method)
1013
+ - Resolves contract from provider:
1014
+ - Calls `config.contract.source()` and expects `Result<ContractIR, Diagnostics>`
1015
+ - Source-specific parsing/loading stays inside providers
1016
+ - Provider diagnostics are surfaced as actionable CLI failures
878
1017
  - Throws error if `config.contract` is missing
879
- - Uses artifact paths from `config.contract.output/types` (already normalized by `defineConfig()` with defaults applied)
1018
+ - Uses artifact path from `config.contract.output` (already normalized by `defineConfig()` with defaults applied)
880
1019
  - Creates family instance via `config.family.create()` (assembles operation registry, type imports, extension IDs)
881
1020
  - Calls `familyInstance.emitContract()` with raw contract (instance handles stripping mappings and validation internally)
882
1021
  - Outputs human-readable or JSON format based on flags
@@ -999,6 +1138,8 @@ export default defineConfig({
999
1138
  - **`commander`**: CLI argument parsing and command routing
1000
1139
  - **`esbuild`**: Bundling TypeScript contract files with import allowlisting
1001
1140
  - **`@prisma-next/emitter`**: Contract emission engine (returns strings)
1141
+ - **`@prisma-next/migration-tools`**: On-disk migration I/O, attestation, and chain reconstruction
1142
+ - **`@prisma-next/core-control-plane`**: Config types, migration operation types, error types, control plane stack
1002
1143
 
1003
1144
  ## Design Decisions
1004
1145
 
@@ -1058,18 +1199,111 @@ pnpm test:integration # Run integration tests only
1058
1199
  pnpm test:e2e # Run e2e tests only
1059
1200
  ```
1060
1201
 
1202
+ ## Programmatic Control API
1203
+
1204
+ The CLI package provides a programmatic control client for running control-plane operations without using the command line. This is useful for:
1205
+
1206
+ - Integration with build tools and CI pipelines
1207
+ - Custom orchestration workflows
1208
+ - Test automation
1209
+ - Programmatic database management
1210
+
1211
+ ### Basic Usage
1212
+
1213
+ ```typescript
1214
+ import { createControlClient } from '@prisma-next/cli/control-api';
1215
+ import sql from '@prisma-next/family-sql/control';
1216
+ import postgres from '@prisma-next/target-postgres/control';
1217
+ import postgresAdapter from '@prisma-next/adapter-postgres/control';
1218
+ import postgresDriver from '@prisma-next/driver-postgres/control';
1219
+
1220
+ // Create a control client with framework component descriptors
1221
+ const client = createControlClient({
1222
+ family: sql,
1223
+ target: postgres,
1224
+ adapter: postgresAdapter,
1225
+ driver: postgresDriver,
1226
+ extensionPacks: [],
1227
+ });
1228
+
1229
+ try {
1230
+ // Connect to database
1231
+ await client.connect(databaseUrl);
1232
+
1233
+ // Run operations
1234
+ const verifyResult = await client.verify({ contractIR });
1235
+ const initResult = await client.dbInit({ contractIR, mode: 'apply' });
1236
+ const updateResult = await client.dbUpdate({ contractIR, mode: 'apply' });
1237
+ const introspectResult = await client.introspect();
1238
+ } finally {
1239
+ // Clean up
1240
+ await client.close();
1241
+ }
1242
+ ```
1243
+
1244
+ ### Available Operations
1245
+
1246
+ | Method | Description |
1247
+ |--------|-------------|
1248
+ | `connect(url)` | Establishes database connection |
1249
+ | `close()` | Closes connection (idempotent) |
1250
+ | `readMarker()` | Reads contract marker from database (null if none) |
1251
+ | `verify(options)` | Verifies database marker matches contract |
1252
+ | `schemaVerify(options)` | Verifies database schema satisfies contract |
1253
+ | `sign(options)` | Writes contract marker to database |
1254
+ | `dbInit(options)` | Initializes database schema from contract |
1255
+ | `dbUpdate(options)` | Updates database schema to match contract |
1256
+ | `migrationApply(options)` | Applies pre-planned migration edges to database |
1257
+ | `introspect(options)` | Introspects database schema |
1258
+
1259
+ ### Result Types
1260
+
1261
+ Operations return structured result types:
1262
+
1263
+ - `readMarker()` → `ContractMarkerRecord | null`
1264
+ - `verify()` → `VerifyDatabaseResult`
1265
+ - `schemaVerify()` → `VerifyDatabaseSchemaResult`
1266
+ - `sign()` → `SignDatabaseResult`
1267
+ - `dbInit()` → `Result<DbInitSuccess, DbInitFailure>` (uses Result pattern)
1268
+ - `dbUpdate()` → `Result<DbUpdateSuccess, DbUpdateFailure>` (uses Result pattern)
1269
+ - `migrationApply()` → `Result<MigrationApplySuccess, MigrationApplyFailure>` (uses Result pattern)
1270
+ - `introspect()` → Schema IR (family-specific)
1271
+
1272
+ ### Error Handling
1273
+
1274
+ - **Connection errors**: Thrown as exceptions from `connect()`
1275
+ - **Not connected errors**: Thrown if operations called before `connect()`
1276
+ - **Driver not configured**: Thrown if driver is not provided in options
1277
+ - **Operation failures**: Returned as structured results (not thrown)
1278
+
1279
+ ### Key Differences from CLI
1280
+
1281
+ | Aspect | CLI | Control API |
1282
+ |--------|-----|-------------|
1283
+ | Config | Reads `prisma-next.config.ts` | Accepts descriptors directly |
1284
+ | File I/O | Reads contract.json from disk | Accepts contract IR directly |
1285
+ | Output | Formats for console | Returns structured data |
1286
+ | Exit codes | Uses `process.exit()` | Returns results/throws |
1287
+
1061
1288
  ## Entrypoints
1062
1289
 
1063
1290
  The CLI package exports several subpaths for different use cases:
1064
1291
 
1065
1292
  - **`@prisma-next/cli`** (main export): Exports `loadContractFromTs` and `createContractEmitCommand`
1066
1293
  - **`@prisma-next/cli/config-types`**: Exports `defineConfig` and config types
1294
+ - **`@prisma-next/cli/control-api`**: Exports `createControlClient` and control API types
1067
1295
  - **`@prisma-next/cli/commands/db-init`**: Exports `createDbInitCommand`
1296
+ - **`@prisma-next/cli/commands/db-update`**: Exports `createDbUpdateCommand`
1068
1297
  - **`@prisma-next/cli/commands/db-introspect`**: Exports `createDbIntrospectCommand`
1069
1298
  - **`@prisma-next/cli/commands/db-schema-verify`**: Exports `createDbSchemaVerifyCommand`
1070
1299
  - **`@prisma-next/cli/commands/db-sign`**: Exports `createDbSignCommand`
1071
1300
  - **`@prisma-next/cli/commands/db-verify`**: Exports `createDbVerifyCommand`
1072
1301
  - **`@prisma-next/cli/commands/contract-emit`**: Exports `createContractEmitCommand`
1302
+ - **`@prisma-next/cli/commands/migration-plan`**: Exports `createMigrationPlanCommand`
1303
+ - **`@prisma-next/cli/commands/migration-show`**: Exports `createMigrationShowCommand`
1304
+ - **`@prisma-next/cli/commands/migration-status`**: Exports `createMigrationStatusCommand`
1305
+ - **`@prisma-next/cli/commands/migration-apply`**: Exports `createMigrationApplyCommand`
1306
+ - **`@prisma-next/cli/commands/migration-verify`**: Exports `createMigrationVerifyCommand`
1073
1307
  - **`@prisma-next/cli/config-loader`**: Exports `loadConfig` function
1074
1308
 
1075
1309
  **Important**: `loadContractFromTs` is exported from the main package (`@prisma-next/cli`). See `.cursor/rules/cli-package-exports.mdc` for import patterns.