@prisma-next/cli 0.3.0-dev.5 → 0.3.0-dev.53

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 (130) hide show
  1. package/README.md +145 -74
  2. package/dist/cli.d.mts +1 -0
  3. package/dist/cli.js +1 -2376
  4. package/dist/cli.mjs +169 -0
  5. package/dist/cli.mjs.map +1 -0
  6. package/dist/client-BSZKpZTF.mjs +711 -0
  7. package/dist/client-BSZKpZTF.mjs.map +1 -0
  8. package/dist/commands/contract-emit.d.mts +7 -0
  9. package/dist/commands/contract-emit.d.mts.map +1 -0
  10. package/dist/commands/contract-emit.mjs +147 -0
  11. package/dist/commands/contract-emit.mjs.map +1 -0
  12. package/dist/commands/db-init.d.mts +7 -0
  13. package/dist/commands/db-init.d.mts.map +1 -0
  14. package/dist/commands/db-init.mjs +179 -0
  15. package/dist/commands/db-init.mjs.map +1 -0
  16. package/dist/commands/db-introspect.d.mts +7 -0
  17. package/dist/commands/db-introspect.d.mts.map +1 -0
  18. package/dist/commands/db-introspect.mjs +120 -0
  19. package/dist/commands/db-introspect.mjs.map +1 -0
  20. package/dist/commands/db-schema-verify.d.mts +7 -0
  21. package/dist/commands/db-schema-verify.d.mts.map +1 -0
  22. package/dist/commands/db-schema-verify.mjs +116 -0
  23. package/dist/commands/db-schema-verify.mjs.map +1 -0
  24. package/dist/commands/db-sign.d.mts +7 -0
  25. package/dist/commands/db-sign.d.mts.map +1 -0
  26. package/dist/commands/db-sign.mjs +138 -0
  27. package/dist/commands/db-sign.mjs.map +1 -0
  28. package/dist/commands/db-verify.d.mts +7 -0
  29. package/dist/commands/db-verify.d.mts.map +1 -0
  30. package/dist/commands/db-verify.mjs +129 -0
  31. package/dist/commands/db-verify.mjs.map +1 -0
  32. package/dist/config-loader-BJ8HsEdA.mjs +42 -0
  33. package/dist/config-loader-BJ8HsEdA.mjs.map +1 -0
  34. package/dist/{config-loader.d.ts → config-loader.d.mts} +8 -3
  35. package/dist/config-loader.d.mts.map +1 -0
  36. package/dist/config-loader.mjs +3 -0
  37. package/dist/exports/config-types.d.mts +2 -0
  38. package/dist/exports/config-types.mjs +3 -0
  39. package/dist/exports/control-api.d.mts +433 -0
  40. package/dist/exports/control-api.d.mts.map +1 -0
  41. package/dist/exports/control-api.mjs +96 -0
  42. package/dist/exports/control-api.mjs.map +1 -0
  43. package/dist/{load-ts-contract.d.ts → exports/index.d.mts} +10 -5
  44. package/dist/exports/index.d.mts.map +1 -0
  45. package/dist/exports/index.mjs +132 -0
  46. package/dist/exports/index.mjs.map +1 -0
  47. package/dist/result-handler-BZPY7HX4.mjs +1029 -0
  48. package/dist/result-handler-BZPY7HX4.mjs.map +1 -0
  49. package/package.json +48 -37
  50. package/src/commands/contract-emit.ts +205 -111
  51. package/src/commands/db-init.ts +258 -359
  52. package/src/commands/db-introspect.ts +151 -184
  53. package/src/commands/db-schema-verify.ts +151 -149
  54. package/src/commands/db-sign.ts +202 -200
  55. package/src/commands/db-verify.ts +181 -155
  56. package/src/control-api/client.ts +610 -0
  57. package/src/control-api/operations/contract-emit.ts +161 -0
  58. package/src/control-api/operations/db-init.ts +281 -0
  59. package/src/control-api/types.ts +475 -0
  60. package/src/exports/control-api.ts +48 -0
  61. package/src/load-ts-contract.ts +16 -11
  62. package/src/utils/cli-errors.ts +1 -1
  63. package/src/utils/framework-components.ts +11 -30
  64. package/src/utils/output.ts +16 -10
  65. package/src/utils/progress-adapter.ts +86 -0
  66. package/dist/chunk-464LNZCE.js +0 -134
  67. package/dist/chunk-464LNZCE.js.map +0 -1
  68. package/dist/chunk-BZMBKEEQ.js +0 -997
  69. package/dist/chunk-BZMBKEEQ.js.map +0 -1
  70. package/dist/chunk-HWYQOCAJ.js +0 -47
  71. package/dist/chunk-HWYQOCAJ.js.map +0 -1
  72. package/dist/chunk-ZKYEJROM.js +0 -94
  73. package/dist/chunk-ZKYEJROM.js.map +0 -1
  74. package/dist/cli.d.ts +0 -2
  75. package/dist/cli.d.ts.map +0 -1
  76. package/dist/cli.js.map +0 -1
  77. package/dist/commands/contract-emit.d.ts +0 -3
  78. package/dist/commands/contract-emit.d.ts.map +0 -1
  79. package/dist/commands/contract-emit.js +0 -9
  80. package/dist/commands/contract-emit.js.map +0 -1
  81. package/dist/commands/db-init.d.ts +0 -3
  82. package/dist/commands/db-init.d.ts.map +0 -1
  83. package/dist/commands/db-init.js +0 -341
  84. package/dist/commands/db-init.js.map +0 -1
  85. package/dist/commands/db-introspect.d.ts +0 -3
  86. package/dist/commands/db-introspect.d.ts.map +0 -1
  87. package/dist/commands/db-introspect.js +0 -190
  88. package/dist/commands/db-introspect.js.map +0 -1
  89. package/dist/commands/db-schema-verify.d.ts +0 -3
  90. package/dist/commands/db-schema-verify.d.ts.map +0 -1
  91. package/dist/commands/db-schema-verify.js +0 -164
  92. package/dist/commands/db-schema-verify.js.map +0 -1
  93. package/dist/commands/db-sign.d.ts +0 -3
  94. package/dist/commands/db-sign.d.ts.map +0 -1
  95. package/dist/commands/db-sign.js +0 -199
  96. package/dist/commands/db-sign.js.map +0 -1
  97. package/dist/commands/db-verify.d.ts +0 -3
  98. package/dist/commands/db-verify.d.ts.map +0 -1
  99. package/dist/commands/db-verify.js +0 -173
  100. package/dist/commands/db-verify.js.map +0 -1
  101. package/dist/config-loader.d.ts.map +0 -1
  102. package/dist/config-loader.js +0 -7
  103. package/dist/config-loader.js.map +0 -1
  104. package/dist/exports/config-types.d.ts +0 -3
  105. package/dist/exports/config-types.d.ts.map +0 -1
  106. package/dist/exports/config-types.js +0 -6
  107. package/dist/exports/config-types.js.map +0 -1
  108. package/dist/exports/index.d.ts +0 -4
  109. package/dist/exports/index.d.ts.map +0 -1
  110. package/dist/exports/index.js +0 -175
  111. package/dist/exports/index.js.map +0 -1
  112. package/dist/load-ts-contract.d.ts.map +0 -1
  113. package/dist/utils/action.d.ts +0 -16
  114. package/dist/utils/action.d.ts.map +0 -1
  115. package/dist/utils/cli-errors.d.ts +0 -7
  116. package/dist/utils/cli-errors.d.ts.map +0 -1
  117. package/dist/utils/command-helpers.d.ts +0 -12
  118. package/dist/utils/command-helpers.d.ts.map +0 -1
  119. package/dist/utils/framework-components.d.ts +0 -81
  120. package/dist/utils/framework-components.d.ts.map +0 -1
  121. package/dist/utils/global-flags.d.ts +0 -25
  122. package/dist/utils/global-flags.d.ts.map +0 -1
  123. package/dist/utils/output.d.ts +0 -142
  124. package/dist/utils/output.d.ts.map +0 -1
  125. package/dist/utils/result-handler.d.ts +0 -15
  126. package/dist/utils/result-handler.d.ts.map +0 -1
  127. package/dist/utils/spinner.d.ts +0 -29
  128. package/dist/utils/spinner.d.ts.map +0 -1
  129. package/src/utils/action.ts +0 -43
  130. 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
 
@@ -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
  ```
@@ -797,6 +790,7 @@ The CLI uses a config file to specify the target family, target, adapter, extens
797
790
 
798
791
  ```typescript
799
792
  import { defineConfig } from '@prisma-next/cli/config-types';
793
+ import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
800
794
  import postgresAdapter from '@prisma-next/adapter-postgres/control';
801
795
  import postgres from '@prisma-next/target-postgres/control';
802
796
  import sql from '@prisma-next/family-sql/control';
@@ -807,22 +801,18 @@ export default defineConfig({
807
801
  target: postgres,
808
802
  adapter: postgresAdapter,
809
803
  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
- },
804
+ contract: typescriptContract(contract, 'src/prisma/contract.json'),
815
805
  });
816
806
  ```
817
807
 
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)`
808
+ Prefer helper utilities for authoring mode selection:
809
+ - `typescriptContract(contractIR, outputPath?)` from `@prisma-next/sql-contract-ts/config-types` for TS-authored contracts
810
+ - `prismaContract(schemaPath, { output?, target? })` from `@prisma-next/sql-contract-psl/provider` for PSL-authored providers
811
+ - Provider failures are returned as structured diagnostics for CLI rendering
822
812
 
823
813
  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
814
 
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).
815
+ `contract.d.ts` is always colocated with `contract.json` and derived from `contract.output` (`contract.json` `contract.d.ts`).
826
816
 
827
817
  **Output:**
828
818
  - `contract.json`: Includes `_generated` metadata field indicating it's a generated artifact (excluded from canonicalization/hashing)
@@ -865,18 +855,19 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
865
855
  - **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
856
  - **Command Taxonomy**: Groups commands by domain/plane (e.g., `contract emit`)
867
857
  - **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`.
858
+ - **Command Descriptions**: See the “Command Descriptions” section above for `setCommandDescriptions()` usage.
869
859
 
870
860
  ### Contract Emit Command (`commands/contract-emit.ts`)
871
861
  - Canonical command implementation using commander
872
862
  - Supports global flags (JSON, verbosity, color, timestamps)
873
863
  - **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
864
  - 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)
865
+ - Resolves contract from provider:
866
+ - Calls `config.contract.source()` and expects `Result<ContractIR, Diagnostics>`
867
+ - Source-specific parsing/loading stays inside providers
868
+ - Provider diagnostics are surfaced as actionable CLI failures
878
869
  - Throws error if `config.contract` is missing
879
- - Uses artifact paths from `config.contract.output/types` (already normalized by `defineConfig()` with defaults applied)
870
+ - Uses artifact path from `config.contract.output` (already normalized by `defineConfig()` with defaults applied)
880
871
  - Creates family instance via `config.family.create()` (assembles operation registry, type imports, extension IDs)
881
872
  - Calls `familyInstance.emitContract()` with raw contract (instance handles stripping mappings and validation internally)
882
873
  - Outputs human-readable or JSON format based on flags
@@ -1058,12 +1049,92 @@ pnpm test:integration # Run integration tests only
1058
1049
  pnpm test:e2e # Run e2e tests only
1059
1050
  ```
1060
1051
 
1052
+ ## Programmatic Control API
1053
+
1054
+ The CLI package provides a programmatic control client for running control-plane operations without using the command line. This is useful for:
1055
+
1056
+ - Integration with build tools and CI pipelines
1057
+ - Custom orchestration workflows
1058
+ - Test automation
1059
+ - Programmatic database management
1060
+
1061
+ ### Basic Usage
1062
+
1063
+ ```typescript
1064
+ import { createControlClient } from '@prisma-next/cli/control-api';
1065
+ import sql from '@prisma-next/family-sql/control';
1066
+ import postgres from '@prisma-next/target-postgres/control';
1067
+ import postgresAdapter from '@prisma-next/adapter-postgres/control';
1068
+ import postgresDriver from '@prisma-next/driver-postgres/control';
1069
+
1070
+ // Create a control client with framework component descriptors
1071
+ const client = createControlClient({
1072
+ family: sql,
1073
+ target: postgres,
1074
+ adapter: postgresAdapter,
1075
+ driver: postgresDriver,
1076
+ extensionPacks: [],
1077
+ });
1078
+
1079
+ try {
1080
+ // Connect to database
1081
+ await client.connect(databaseUrl);
1082
+
1083
+ // Run operations
1084
+ const verifyResult = await client.verify({ contractIR });
1085
+ const initResult = await client.dbInit({ contractIR, mode: 'apply' });
1086
+ const introspectResult = await client.introspect();
1087
+ } finally {
1088
+ // Clean up
1089
+ await client.close();
1090
+ }
1091
+ ```
1092
+
1093
+ ### Available Operations
1094
+
1095
+ | Method | Description |
1096
+ |--------|-------------|
1097
+ | `connect(url)` | Establishes database connection |
1098
+ | `close()` | Closes connection (idempotent) |
1099
+ | `verify(options)` | Verifies database marker matches contract |
1100
+ | `schemaVerify(options)` | Verifies database schema satisfies contract |
1101
+ | `sign(options)` | Writes contract marker to database |
1102
+ | `dbInit(options)` | Initializes database schema from contract |
1103
+ | `introspect(options)` | Introspects database schema |
1104
+
1105
+ ### Result Types
1106
+
1107
+ Operations return structured result types:
1108
+
1109
+ - `verify()` → `VerifyDatabaseResult`
1110
+ - `schemaVerify()` → `VerifyDatabaseSchemaResult`
1111
+ - `sign()` → `SignDatabaseResult`
1112
+ - `dbInit()` → `Result<DbInitSuccess, DbInitFailure>` (uses Result pattern)
1113
+ - `introspect()` → Schema IR (family-specific)
1114
+
1115
+ ### Error Handling
1116
+
1117
+ - **Connection errors**: Thrown as exceptions from `connect()`
1118
+ - **Not connected errors**: Thrown if operations called before `connect()`
1119
+ - **Driver not configured**: Thrown if driver is not provided in options
1120
+ - **Operation failures**: Returned as structured results (not thrown)
1121
+
1122
+ ### Key Differences from CLI
1123
+
1124
+ | Aspect | CLI | Control API |
1125
+ |--------|-----|-------------|
1126
+ | Config | Reads `prisma-next.config.ts` | Accepts descriptors directly |
1127
+ | File I/O | Reads contract.json from disk | Accepts contract IR directly |
1128
+ | Output | Formats for console | Returns structured data |
1129
+ | Exit codes | Uses `process.exit()` | Returns results/throws |
1130
+
1061
1131
  ## Entrypoints
1062
1132
 
1063
1133
  The CLI package exports several subpaths for different use cases:
1064
1134
 
1065
1135
  - **`@prisma-next/cli`** (main export): Exports `loadContractFromTs` and `createContractEmitCommand`
1066
1136
  - **`@prisma-next/cli/config-types`**: Exports `defineConfig` and config types
1137
+ - **`@prisma-next/cli/control-api`**: Exports `createControlClient` and control API types
1067
1138
  - **`@prisma-next/cli/commands/db-init`**: Exports `createDbInitCommand`
1068
1139
  - **`@prisma-next/cli/commands/db-introspect`**: Exports `createDbIntrospectCommand`
1069
1140
  - **`@prisma-next/cli/commands/db-schema-verify`**: Exports `createDbSchemaVerifyCommand`
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export { };