@prisma-next/cli 0.5.0-dev.8 → 0.5.0-dev.81
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/README.md +56 -21
- package/dist/cli-errors-B9OBbled.d.mts +3 -0
- package/dist/cli-errors-D3_sMh2K.mjs +33 -0
- package/dist/cli-errors-D3_sMh2K.mjs.map +1 -0
- package/dist/cli.mjs +16 -78
- package/dist/cli.mjs.map +1 -1
- package/dist/client-qVH-rEgd.mjs +1595 -0
- package/dist/client-qVH-rEgd.mjs.map +1 -0
- package/dist/{result-handler-Ba3zWQsI.mjs → command-helpers-BeZHkxV8.mjs} +70 -47
- package/dist/command-helpers-BeZHkxV8.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +2 -4
- package/dist/commands/contract-infer.d.mts.map +1 -1
- package/dist/commands/contract-infer.mjs +2 -4
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +16 -13
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.d.mts.map +1 -1
- package/dist/commands/db-schema.mjs +6 -7
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +9 -9
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +15 -13
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.d.mts.map +1 -1
- package/dist/commands/db-verify.mjs +1 -321
- package/dist/commands/migration-apply.d.mts +28 -13
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +55 -151
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts +0 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +34 -40
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +33 -6
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +2 -348
- package/dist/commands/migration-ref.d.mts +1 -1
- package/dist/commands/migration-ref.d.mts.map +1 -1
- package/dist/commands/migration-ref.mjs +8 -12
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +13 -7
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +35 -36
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +126 -5
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -4
- package/dist/{config-loader-C25b63rJ.mjs → config-loader-B6sJjXTv.mjs} +3 -5
- package/dist/config-loader-B6sJjXTv.mjs.map +1 -0
- package/dist/config-loader.d.mts +0 -1
- package/dist/config-loader.d.mts.map +1 -1
- package/dist/config-loader.mjs +2 -3
- package/dist/contract-emit-9DBda5Ou.mjs +150 -0
- package/dist/contract-emit-9DBda5Ou.mjs.map +1 -0
- package/dist/contract-emit-B77TsJqf.mjs +327 -0
- package/dist/contract-emit-B77TsJqf.mjs.map +1 -0
- package/dist/{contract-enrichment-CAOELa-H.mjs → contract-enrichment-Dani0mMW.mjs} +4 -6
- package/dist/contract-enrichment-Dani0mMW.mjs.map +1 -0
- package/dist/{contract-infer-D9cC3rJm.mjs → contract-infer-BK9YFGEG.mjs} +13 -22
- package/dist/contract-infer-BK9YFGEG.mjs.map +1 -0
- package/dist/db-verify-C0y1PCO2.mjs +404 -0
- package/dist/db-verify-C0y1PCO2.mjs.map +1 -0
- package/dist/exports/config-types.mjs +1 -2
- package/dist/exports/control-api.d.mts +101 -586
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +4 -6
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +28 -30
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts +2 -4
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +2 -3
- package/dist/extension-pack-inputs-C7xgE-vv.mjs +74 -0
- package/dist/extension-pack-inputs-C7xgE-vv.mjs.map +1 -0
- package/dist/{framework-components-Cr--XBKy.mjs → framework-components-ChqVUxR-.mjs} +3 -4
- package/dist/{framework-components-Cr--XBKy.mjs.map → framework-components-ChqVUxR-.mjs.map} +1 -1
- package/dist/global-flags-Icqpxk23.d.mts +12 -0
- package/dist/global-flags-Icqpxk23.d.mts.map +1 -0
- package/dist/helpers-eqdN8tH6.mjs +25 -0
- package/dist/helpers-eqdN8tH6.mjs.map +1 -0
- package/dist/{init-C5220SY9.mjs → init-CoDVPvQ4.mjs} +26 -35
- package/dist/init-CoDVPvQ4.mjs.map +1 -0
- package/dist/{inspect-live-schema-yrHAvG71.mjs → inspect-live-schema-CWYxGKlb.mjs} +10 -11
- package/dist/inspect-live-schema-CWYxGKlb.mjs.map +1 -0
- package/dist/migration-cli.d.mts +41 -12
- package/dist/migration-cli.d.mts.map +1 -1
- package/dist/migration-cli.mjs +309 -86
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-B3B09et6.mjs → migration-command-scaffold-B5dORFEv.mjs} +8 -9
- package/dist/migration-command-scaffold-B5dORFEv.mjs.map +1 -0
- package/dist/migration-plan-C6lVaHsO.mjs +554 -0
- package/dist/migration-plan-C6lVaHsO.mjs.map +1 -0
- package/dist/{migration-status-DUMiH8_G.mjs → migration-status-CZ-D5k7k.mjs} +272 -65
- package/dist/migration-status-CZ-D5k7k.mjs.map +1 -0
- package/dist/migrations-D_UJnpuW.mjs +216 -0
- package/dist/migrations-D_UJnpuW.mjs.map +1 -0
- package/dist/{output-BpcQrnnq.mjs → output-B16Kefzx.mjs} +9 -3
- package/dist/output-B16Kefzx.mjs.map +1 -0
- package/dist/{progress-adapter-DvQWB1nK.mjs → progress-adapter-DFfvZcYL.mjs} +2 -2
- package/dist/{progress-adapter-DvQWB1nK.mjs.map → progress-adapter-DFfvZcYL.mjs.map} +1 -1
- package/dist/result-handler-rmPVKIP2.mjs +25 -0
- package/dist/result-handler-rmPVKIP2.mjs.map +1 -0
- package/dist/rolldown-runtime-twds-ZHy.mjs +14 -0
- package/dist/{terminal-ui-C3ZLwQxK.mjs → terminal-ui-C_hFNbAn.mjs} +4 -28
- package/dist/terminal-ui-C_hFNbAn.mjs.map +1 -0
- package/dist/types-D7x-IFLO.d.mts +858 -0
- package/dist/types-D7x-IFLO.d.mts.map +1 -0
- package/dist/{verify-Bkycc-Tf.mjs → verify-CiwNWM9N.mjs} +3 -4
- package/dist/verify-CiwNWM9N.mjs.map +1 -0
- package/package.json +26 -24
- package/src/cli.ts +32 -6
- package/src/commands/contract-emit.ts +67 -163
- package/src/commands/contract-infer.ts +7 -20
- package/src/commands/db-init.ts +15 -3
- package/src/commands/db-update.ts +9 -4
- package/src/commands/db-verify.ts +47 -15
- package/src/commands/init/index.ts +1 -1
- package/src/commands/init/init.ts +2 -2
- package/src/commands/init/templates/code-templates.ts +12 -4
- package/src/commands/inspect-live-schema.ts +10 -5
- package/src/commands/migration-apply.ts +114 -212
- package/src/commands/migration-new.ts +42 -45
- package/src/commands/migration-plan.ts +212 -72
- package/src/commands/migration-ref.ts +8 -7
- package/src/commands/migration-show.ts +60 -41
- package/src/commands/migration-status.ts +483 -64
- package/src/config-path-validation.ts +0 -1
- package/src/control-api/client.ts +85 -5
- package/src/control-api/contract-enrichment.ts +6 -4
- package/src/control-api/operations/apply-aggregate.ts +290 -0
- package/src/control-api/operations/contract-emit.ts +198 -115
- package/src/control-api/operations/db-apply-aggregate.ts +397 -0
- package/src/control-api/operations/db-init.ts +51 -253
- package/src/control-api/operations/db-update.ts +66 -183
- package/src/control-api/operations/db-verify.ts +342 -0
- package/src/control-api/operations/migration-apply.ts +424 -131
- package/src/control-api/types.ts +280 -29
- package/src/exports/control-api.ts +15 -3
- package/src/load-ts-contract.ts +28 -26
- package/src/migration-cli.ts +445 -122
- package/src/utils/cli-errors.ts +49 -2
- package/src/utils/combine-schema-results.ts +84 -0
- package/src/utils/command-helpers.ts +69 -25
- package/src/utils/contract-space-aggregate-loader.ts +204 -0
- package/src/utils/contract-space-extension-migrations-pass.ts +120 -0
- package/src/utils/contract-space-migrate-pass.ts +156 -0
- package/src/utils/emit-queue.ts +26 -0
- package/src/utils/extension-pack-inputs.ts +170 -0
- package/src/utils/formatters/graph-migration-mapper.ts +7 -3
- package/src/utils/formatters/migrations.ts +197 -61
- package/src/utils/publish-contract-artifact-pair.ts +134 -0
- package/dist/cli-errors-BFYgBH3L.d.mts +0 -4
- package/dist/cli-errors-Cd79vmTH.mjs +0 -5
- package/dist/client-CrsnY58k.mjs +0 -997
- package/dist/client-CrsnY58k.mjs.map +0 -1
- package/dist/commands/db-verify.mjs.map +0 -1
- package/dist/commands/migration-plan.mjs.map +0 -1
- package/dist/config-loader-C25b63rJ.mjs.map +0 -1
- package/dist/contract-emit--feXyNd7.mjs +0 -4
- package/dist/contract-emit-NJ01hiiv.mjs +0 -195
- package/dist/contract-emit-NJ01hiiv.mjs.map +0 -1
- package/dist/contract-emit-V5SSitUT.mjs +0 -122
- package/dist/contract-emit-V5SSitUT.mjs.map +0 -1
- package/dist/contract-enrichment-CAOELa-H.mjs.map +0 -1
- package/dist/contract-infer-D9cC3rJm.mjs.map +0 -1
- package/dist/extract-operation-statements-DsFfxXVZ.mjs +0 -13
- package/dist/extract-operation-statements-DsFfxXVZ.mjs.map +0 -1
- package/dist/extract-sql-ddl-D9UbZDyz.mjs +0 -26
- package/dist/extract-sql-ddl-D9UbZDyz.mjs.map +0 -1
- package/dist/init-C5220SY9.mjs.map +0 -1
- package/dist/inspect-live-schema-yrHAvG71.mjs.map +0 -1
- package/dist/migration-command-scaffold-B3B09et6.mjs.map +0 -1
- package/dist/migration-status-DUMiH8_G.mjs.map +0 -1
- package/dist/migrations-Bo5WtTla.mjs +0 -153
- package/dist/migrations-Bo5WtTla.mjs.map +0 -1
- package/dist/output-BpcQrnnq.mjs.map +0 -1
- package/dist/result-handler-Ba3zWQsI.mjs.map +0 -1
- package/dist/terminal-ui-C3ZLwQxK.mjs.map +0 -1
- package/dist/validate-contract-deps-B_Cs29TL.mjs +0 -37
- package/dist/validate-contract-deps-B_Cs29TL.mjs.map +0 -1
- package/dist/verify-Bkycc-Tf.mjs.map +0 -1
- package/src/control-api/operations/extract-operation-statements.ts +0 -14
- package/src/control-api/operations/extract-sql-ddl.ts +0 -47
package/src/control-api/types.ts
CHANGED
|
@@ -12,11 +12,15 @@ import type {
|
|
|
12
12
|
CoreSchemaView,
|
|
13
13
|
MigrationPlannerConflict,
|
|
14
14
|
MigrationPlanOperation,
|
|
15
|
+
OperationPreview,
|
|
15
16
|
SignDatabaseResult,
|
|
16
17
|
VerifyDatabaseResult,
|
|
17
18
|
VerifyDatabaseSchemaResult,
|
|
18
19
|
} from '@prisma-next/framework-components/control';
|
|
20
|
+
import type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';
|
|
21
|
+
import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
|
|
19
22
|
import type { Result } from '@prisma-next/utils/result';
|
|
23
|
+
import type { ExecuteDbVerifyResult } from './operations/db-verify';
|
|
20
24
|
|
|
21
25
|
// ============================================================================
|
|
22
26
|
// Client Options
|
|
@@ -63,6 +67,7 @@ export interface ControlClientOptions {
|
|
|
63
67
|
export type ControlActionName =
|
|
64
68
|
| 'dbInit'
|
|
65
69
|
| 'dbUpdate'
|
|
70
|
+
| 'dbVerify'
|
|
66
71
|
| 'migrationApply'
|
|
67
72
|
| 'verify'
|
|
68
73
|
| 'schemaVerify'
|
|
@@ -189,6 +194,13 @@ export interface DbInitOptions {
|
|
|
189
194
|
* The type is driver-specific (e.g., string URL for Postgres).
|
|
190
195
|
*/
|
|
191
196
|
readonly connection?: unknown;
|
|
197
|
+
/**
|
|
198
|
+
* On-disk migrations directory. Always required — every `db init`
|
|
199
|
+
* routes through the per-space flow, which reads on-disk
|
|
200
|
+
* `refs/head.json` and extension destination contracts from this
|
|
201
|
+
* root.
|
|
202
|
+
*/
|
|
203
|
+
readonly migrationsDir: string;
|
|
192
204
|
/** Optional progress callback for observing operation progress */
|
|
193
205
|
readonly onProgress?: OnControlProgress;
|
|
194
206
|
}
|
|
@@ -219,10 +231,35 @@ export interface DbUpdateOptions {
|
|
|
219
231
|
* or re-run with -y/--yes.
|
|
220
232
|
*/
|
|
221
233
|
readonly acceptDataLoss?: boolean;
|
|
234
|
+
/**
|
|
235
|
+
* On-disk migrations directory. Always required — every `db update`
|
|
236
|
+
* routes through the per-space flow, which reads on-disk
|
|
237
|
+
* `refs/head.json` and extension destination contracts from this
|
|
238
|
+
* root.
|
|
239
|
+
*/
|
|
240
|
+
readonly migrationsDir: string;
|
|
222
241
|
/** Optional progress callback for observing operation progress */
|
|
223
242
|
readonly onProgress?: OnControlProgress;
|
|
224
243
|
}
|
|
225
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Options for the dbVerify operation.
|
|
247
|
+
*
|
|
248
|
+
* Drives the loader → aggregate-verifier pipeline. `strict` maps to
|
|
249
|
+
* `verifyAggregate({ mode: 'strict' | 'lenient' })`; `skipSchema`
|
|
250
|
+
* mirrors the `--marker-only` CLI flag and short-circuits the schema
|
|
251
|
+
* portion of the verifier.
|
|
252
|
+
*/
|
|
253
|
+
export interface DbVerifyOptions {
|
|
254
|
+
readonly contract: unknown;
|
|
255
|
+
readonly migrationsDir: string;
|
|
256
|
+
readonly strict: boolean;
|
|
257
|
+
readonly skipSchema: boolean;
|
|
258
|
+
readonly skipMarker: boolean;
|
|
259
|
+
readonly connection?: unknown;
|
|
260
|
+
readonly onProgress?: OnControlProgress;
|
|
261
|
+
}
|
|
262
|
+
|
|
226
263
|
/**
|
|
227
264
|
* Options for the introspect operation.
|
|
228
265
|
*/
|
|
@@ -272,6 +309,42 @@ export interface EmitOptions {
|
|
|
272
309
|
// Result Types
|
|
273
310
|
// ============================================================================
|
|
274
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Per-space breakdown of an aggregate plan / apply.
|
|
314
|
+
*
|
|
315
|
+
* Surfaces the canonical schedule shape — extensions alphabetically,
|
|
316
|
+
* then app — together with the operations attributed to each space and,
|
|
317
|
+
* when the run was applied, the resulting per-space marker hash.
|
|
318
|
+
*
|
|
319
|
+
* M6 sub-spec § Output shape contract — every space involved in a run
|
|
320
|
+
* is observable in the success summary, including its post-apply
|
|
321
|
+
* marker, so the per-space invariant is visible to the user (closing
|
|
322
|
+
* F4 / F7 from `e2e-verification.md`).
|
|
323
|
+
*/
|
|
324
|
+
export interface AggregatePerSpaceExecutionEntry {
|
|
325
|
+
readonly spaceId: string;
|
|
326
|
+
/** `'app'` for the application's contract space; `'extension'` for any extension space. */
|
|
327
|
+
readonly kind: 'app' | 'extension';
|
|
328
|
+
/**
|
|
329
|
+
* Operations attributed to this space (display ops). In `mode: 'plan'`
|
|
330
|
+
* this is the planned set; in `mode: 'apply'` it is the same set
|
|
331
|
+
* (every op was executed in order, the runner does not skip).
|
|
332
|
+
*/
|
|
333
|
+
readonly operations: ReadonlyArray<{
|
|
334
|
+
readonly id: string;
|
|
335
|
+
readonly label: string;
|
|
336
|
+
readonly operationClass: string;
|
|
337
|
+
}>;
|
|
338
|
+
/**
|
|
339
|
+
* Post-apply marker hash for this space. Present only when the run
|
|
340
|
+
* was applied (i.e. `mode: 'apply'` and the runner returned ok).
|
|
341
|
+
* Equals the per-space plan's `destination.storageHash`.
|
|
342
|
+
*/
|
|
343
|
+
readonly marker?: {
|
|
344
|
+
readonly storageHash: string;
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
275
348
|
/**
|
|
276
349
|
* Successful dbInit result.
|
|
277
350
|
*/
|
|
@@ -283,7 +356,14 @@ export interface DbInitSuccess {
|
|
|
283
356
|
readonly label: string;
|
|
284
357
|
readonly operationClass: string;
|
|
285
358
|
}>;
|
|
286
|
-
|
|
359
|
+
/**
|
|
360
|
+
* Family-agnostic textual preview of the planned operations, e.g.
|
|
361
|
+
* `language: 'sql'` for SQL families and `language: 'mongodb-shell'`
|
|
362
|
+
* for the Mongo family. Replaces the previous `sql?: readonly string[]`
|
|
363
|
+
* field; consumers that previously read `plan.sql` should read
|
|
364
|
+
* `plan.preview?.statements.map((s) => s.text)`.
|
|
365
|
+
*/
|
|
366
|
+
readonly preview?: OperationPreview;
|
|
287
367
|
};
|
|
288
368
|
readonly destination: {
|
|
289
369
|
readonly storageHash: string;
|
|
@@ -297,6 +377,14 @@ export interface DbInitSuccess {
|
|
|
297
377
|
readonly storageHash: string;
|
|
298
378
|
readonly profileHash?: string;
|
|
299
379
|
};
|
|
380
|
+
/**
|
|
381
|
+
* Per-space breakdown in canonical schedule order (extensions
|
|
382
|
+
* alphabetically, then app). Present whenever the aggregate flow
|
|
383
|
+
* produced one — both `mode: 'plan'` and `mode: 'apply'`.
|
|
384
|
+
*
|
|
385
|
+
* See {@link AggregatePerSpaceExecutionEntry}.
|
|
386
|
+
*/
|
|
387
|
+
readonly perSpace?: ReadonlyArray<AggregatePerSpaceExecutionEntry>;
|
|
300
388
|
readonly summary: string;
|
|
301
389
|
}
|
|
302
390
|
|
|
@@ -341,7 +429,14 @@ export interface DbUpdateSuccess {
|
|
|
341
429
|
readonly label: string;
|
|
342
430
|
readonly operationClass: string;
|
|
343
431
|
}>;
|
|
344
|
-
|
|
432
|
+
/**
|
|
433
|
+
* Family-agnostic textual preview of the planned operations, e.g.
|
|
434
|
+
* `language: 'sql'` for SQL families and `language: 'mongodb-shell'`
|
|
435
|
+
* for the Mongo family. Replaces the previous `sql?: readonly string[]`
|
|
436
|
+
* field; consumers that previously read `plan.sql` should read
|
|
437
|
+
* `plan.preview?.statements.map((s) => s.text)`.
|
|
438
|
+
*/
|
|
439
|
+
readonly preview?: OperationPreview;
|
|
345
440
|
};
|
|
346
441
|
readonly destination: {
|
|
347
442
|
readonly storageHash: string;
|
|
@@ -355,6 +450,11 @@ export interface DbUpdateSuccess {
|
|
|
355
450
|
readonly storageHash: string;
|
|
356
451
|
readonly profileHash?: string;
|
|
357
452
|
};
|
|
453
|
+
/**
|
|
454
|
+
* Per-space breakdown in canonical schedule order (extensions
|
|
455
|
+
* alphabetically, then app). See {@link AggregatePerSpaceExecutionEntry}.
|
|
456
|
+
*/
|
|
457
|
+
readonly perSpace?: ReadonlyArray<AggregatePerSpaceExecutionEntry>;
|
|
358
458
|
readonly summary: string;
|
|
359
459
|
}
|
|
360
460
|
|
|
@@ -427,36 +527,48 @@ export type EmitResult = Result<EmitSuccess, EmitFailure>;
|
|
|
427
527
|
// ============================================================================
|
|
428
528
|
|
|
429
529
|
/**
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Options for the migrationApply operation.
|
|
530
|
+
* Options for the aggregate-walking `migrationApply` operation.
|
|
531
|
+
*
|
|
532
|
+
* The control-api operation is responsible for: loading the
|
|
533
|
+
* contract-space aggregate, reading per-space marker rows from the
|
|
534
|
+
* live database, plotting per-space paths via `graphWalkStrategy`
|
|
535
|
+
* (replay-only — no synth, no introspection), and dispatching
|
|
536
|
+
* through the shared `applyAggregate` primitive. The CLI command
|
|
537
|
+
* just resolves the descriptor surface (config, refs, contract
|
|
538
|
+
* envelope, app-space migration packages) and hands the inputs in.
|
|
539
|
+
*
|
|
540
|
+
* Sub-spec § `migration apply` semantics + § Required changes 1.
|
|
443
541
|
*/
|
|
444
542
|
export interface MigrationApplyOptions {
|
|
543
|
+
/** Already-validated app contract (the canonical "where we are heading" hash). */
|
|
544
|
+
readonly contract: unknown;
|
|
545
|
+
/** Migrations root directory (`migrations/` under the project). */
|
|
546
|
+
readonly migrationsDir: string;
|
|
445
547
|
/**
|
|
446
|
-
*
|
|
447
|
-
*
|
|
548
|
+
* Already-loaded app-space migration packages. The CLI loads these
|
|
549
|
+
* via `loadMigrationPackages(appMigrationsDir)` before invoking
|
|
550
|
+
* `migrationApply`.
|
|
448
551
|
*/
|
|
449
|
-
readonly
|
|
552
|
+
readonly appMigrationPackages: ReadonlyArray<OnDiskMigrationPackage>;
|
|
450
553
|
/**
|
|
451
|
-
*
|
|
452
|
-
*
|
|
554
|
+
* Optional app-space ref override. When provided, the app member's
|
|
555
|
+
* graph-walk targets this hash instead of `contract.storage.storageHash`.
|
|
556
|
+
* Extension members always walk to their own `headRef.hash`.
|
|
453
557
|
*/
|
|
454
|
-
readonly
|
|
558
|
+
readonly refHash?: string;
|
|
455
559
|
/**
|
|
456
|
-
*
|
|
457
|
-
*
|
|
560
|
+
* Required invariants on the user-supplied app-space ref. Threaded
|
|
561
|
+
* into the graph-walk's `required` calculation so the planner picks
|
|
562
|
+
* an invariant-bearing path. Ignored when `refHash` is absent.
|
|
458
563
|
*/
|
|
459
|
-
readonly
|
|
564
|
+
readonly refInvariants?: readonly string[];
|
|
565
|
+
/**
|
|
566
|
+
* Resolved name of the user-supplied app-space ref (the literal the
|
|
567
|
+
* user passed to `--ref`). Decorates `pathDecision.refName` and any
|
|
568
|
+
* `MIGRATION.NO_INVARIANT_PATH` envelope raised during graph-walk.
|
|
569
|
+
* Ignored when `refHash` is absent.
|
|
570
|
+
*/
|
|
571
|
+
readonly refName?: string;
|
|
460
572
|
/**
|
|
461
573
|
* Database connection. If provided, migrationApply will connect before executing.
|
|
462
574
|
* If omitted, the client must already be connected.
|
|
@@ -467,23 +579,102 @@ export interface MigrationApplyOptions {
|
|
|
467
579
|
}
|
|
468
580
|
|
|
469
581
|
/**
|
|
470
|
-
*
|
|
582
|
+
* A single on-disk migration package surfaced to the operation. The
|
|
583
|
+
* SQL family already produces this shape via `loadMigrationPackages`;
|
|
584
|
+
* the operation hands it through to the framework-neutral aggregate
|
|
585
|
+
* loader's `appMigrationPackages` slot.
|
|
586
|
+
*
|
|
587
|
+
* (Originally named `MigrationApplyStep` for the legacy single-space
|
|
588
|
+
* apply path; the name is kept for compatibility with existing CLI
|
|
589
|
+
* callers and tests.)
|
|
590
|
+
*/
|
|
591
|
+
export interface MigrationApplyStep {
|
|
592
|
+
readonly dirName: string;
|
|
593
|
+
readonly from: string | null;
|
|
594
|
+
readonly to: string;
|
|
595
|
+
readonly toContract: Contract;
|
|
596
|
+
readonly operations: readonly MigrationPlanOperation[];
|
|
597
|
+
/**
|
|
598
|
+
* Sorted, deduplicated invariant ids from `migration.json.providedInvariants`.
|
|
599
|
+
* Verified at load time by `readMigrationPackage` (manifest copy must equal
|
|
600
|
+
* the value derived from `ops.json`).
|
|
601
|
+
*/
|
|
602
|
+
readonly providedInvariants: readonly string[];
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Record of a successfully applied per-space migration. One entry per
|
|
607
|
+
* contract space that had pending migrations — empty `applied` means
|
|
608
|
+
* every space was already at its head.
|
|
609
|
+
*/
|
|
610
|
+
/**
|
|
611
|
+
* One entry per authored migration package applied. Preserves the
|
|
612
|
+
* single-space `migrationsApplied` count semantics (each entry is
|
|
613
|
+
* one migration directory) so `applied.length === migrationsApplied`.
|
|
614
|
+
*
|
|
615
|
+
* Per-space aggregate detail (markers, ops grouped by space) lives
|
|
616
|
+
* on `perSpace[]`; this list is the per-edge view.
|
|
471
617
|
*/
|
|
472
618
|
export interface MigrationApplyAppliedEntry {
|
|
619
|
+
readonly spaceId: string;
|
|
473
620
|
readonly dirName: string;
|
|
621
|
+
readonly migrationHash: string;
|
|
474
622
|
readonly from: string;
|
|
475
623
|
readonly to: string;
|
|
476
624
|
readonly operationsExecuted: number;
|
|
477
625
|
}
|
|
478
626
|
|
|
479
627
|
/**
|
|
480
|
-
* Successful migrationApply result.
|
|
628
|
+
* Successful migrationApply result. Carries both the legacy
|
|
629
|
+
* single-space fields (`markerHash` is the **app member's** post-apply
|
|
630
|
+
* marker, surfaced for back-compat with single-space callers) and the
|
|
631
|
+
* per-space breakdown (`perSpace` — markers / operations / canonical
|
|
632
|
+
* order, per M6 sub-spec § Output shape).
|
|
481
633
|
*/
|
|
634
|
+
/**
|
|
635
|
+
* Path-decision summary for the **app member** post-apply. Surfaced
|
|
636
|
+
* for back-compat with single-space callers (and the cli-journeys
|
|
637
|
+
* suite, which inspects `requiredInvariants`/`satisfiedInvariants`/
|
|
638
|
+
* `selectedPath` to validate invariant routing).
|
|
639
|
+
*
|
|
640
|
+
* Per-space path decisions for extension members are not surfaced —
|
|
641
|
+
* extensions own their own ref/invariant control.
|
|
642
|
+
*/
|
|
643
|
+
export interface MigrationApplyPathDecision {
|
|
644
|
+
readonly fromHash: string;
|
|
645
|
+
readonly toHash: string;
|
|
646
|
+
readonly alternativeCount: number;
|
|
647
|
+
readonly tieBreakReasons: readonly string[];
|
|
648
|
+
readonly refName?: string;
|
|
649
|
+
readonly requiredInvariants: readonly string[];
|
|
650
|
+
readonly satisfiedInvariants: readonly string[];
|
|
651
|
+
readonly selectedPath: readonly {
|
|
652
|
+
readonly dirName: string;
|
|
653
|
+
readonly migrationHash: string;
|
|
654
|
+
readonly from: string;
|
|
655
|
+
readonly to: string;
|
|
656
|
+
readonly invariants: readonly string[];
|
|
657
|
+
}[];
|
|
658
|
+
}
|
|
659
|
+
|
|
482
660
|
export interface MigrationApplySuccess {
|
|
483
661
|
readonly migrationsApplied: number;
|
|
484
662
|
readonly markerHash: string;
|
|
485
663
|
readonly applied: readonly MigrationApplyAppliedEntry[];
|
|
486
664
|
readonly summary: string;
|
|
665
|
+
/**
|
|
666
|
+
* Per-space breakdown in canonical schedule order (extensions
|
|
667
|
+
* alphabetically, then app). See {@link AggregatePerSpaceExecutionEntry}.
|
|
668
|
+
* Always present for the aggregate-walking operation.
|
|
669
|
+
*/
|
|
670
|
+
readonly perSpace: ReadonlyArray<AggregatePerSpaceExecutionEntry>;
|
|
671
|
+
/**
|
|
672
|
+
* Path-decision data for the app member. Present whenever the
|
|
673
|
+
* graph-walk strategy ran for the app (i.e. always for the
|
|
674
|
+
* aggregate-walking apply path). Absent only for the no-op
|
|
675
|
+
* "Already up to date" early return when the app has no plan.
|
|
676
|
+
*/
|
|
677
|
+
readonly pathDecision?: MigrationApplyPathDecision;
|
|
487
678
|
}
|
|
488
679
|
|
|
489
680
|
/**
|
|
@@ -512,18 +703,31 @@ export type MigrationApplyResult = Result<MigrationApplySuccess, MigrationApplyF
|
|
|
512
703
|
|
|
513
704
|
/**
|
|
514
705
|
* Options for the standalone executeContractEmit function.
|
|
515
|
-
*
|
|
516
|
-
*
|
|
706
|
+
*
|
|
707
|
+
* `executeContractEmit` is the canonical publication path for both the
|
|
708
|
+
* `prisma-next contract emit` CLI command and the `@prisma-next/vite-plugin-contract-emit`
|
|
709
|
+
* Vite plugin. Do not duplicate the load → emit → publish dance elsewhere; if a
|
|
710
|
+
* caller needs additional behavior, extend this options shape and update the
|
|
711
|
+
* single implementation rather than building a parallel publication path.
|
|
712
|
+
*
|
|
713
|
+
* Concurrent calls for the same output JSON path are serialized per-output via
|
|
714
|
+
* a FIFO queue; concurrent calls for distinct outputs run in parallel.
|
|
517
715
|
*/
|
|
518
716
|
export interface ContractEmitOptions {
|
|
519
717
|
/** Path to the prisma-next.config.ts file */
|
|
520
718
|
readonly configPath: string;
|
|
521
|
-
/** Optional AbortSignal for
|
|
719
|
+
/** Optional AbortSignal for cancelling the in-flight emit */
|
|
522
720
|
readonly signal?: AbortSignal;
|
|
721
|
+
/** Optional progress callback for observing source-resolution and emit spans */
|
|
722
|
+
readonly onProgress?: OnControlProgress;
|
|
523
723
|
}
|
|
524
724
|
|
|
525
725
|
/**
|
|
526
726
|
* Result from the standalone executeContractEmit function.
|
|
727
|
+
*
|
|
728
|
+
* Always describes the bytes that were just published to disk. Failures throw
|
|
729
|
+
* (config / source-resolution / emit / publish) — callers do not need to
|
|
730
|
+
* branch on a result discriminator.
|
|
527
731
|
*/
|
|
528
732
|
export interface ContractEmitResult {
|
|
529
733
|
/** Hash of the storage contract (schema-level) */
|
|
@@ -539,6 +743,12 @@ export interface ContractEmitResult {
|
|
|
539
743
|
/** Path to the emitted contract.d.ts file */
|
|
540
744
|
readonly dts: string;
|
|
541
745
|
};
|
|
746
|
+
/**
|
|
747
|
+
* Warning surfaced by `validateContractDeps` after a successful publication.
|
|
748
|
+
* Callers (CLI, Vite plugin) decide how to render this; the operation does
|
|
749
|
+
* not write to stderr itself. Undefined when no warning was raised.
|
|
750
|
+
*/
|
|
751
|
+
readonly validationWarning?: string;
|
|
542
752
|
}
|
|
543
753
|
|
|
544
754
|
// ============================================================================
|
|
@@ -634,6 +844,21 @@ export interface ControlClient {
|
|
|
634
844
|
*/
|
|
635
845
|
dbUpdate(options: DbUpdateOptions): Promise<DbUpdateResult>;
|
|
636
846
|
|
|
847
|
+
/**
|
|
848
|
+
* Verifies the database against every contract space (app + extensions).
|
|
849
|
+
*
|
|
850
|
+
* Loader → aggregate-verifier pipeline:
|
|
851
|
+
* - The loader catches layout / drift / disjointness violations.
|
|
852
|
+
* - The aggregate verifier surfaces marker-vs-on-disk drift and orphan
|
|
853
|
+
* markers, and (unless `skipSchema` is true) per-space schema
|
|
854
|
+
* verification with pre-projection (closes F23).
|
|
855
|
+
*
|
|
856
|
+
* @returns Result pattern: per-space schema results on success;
|
|
857
|
+
* structured CLI error on marker / loader failure.
|
|
858
|
+
* @throws If not connected or infrastructure failure
|
|
859
|
+
*/
|
|
860
|
+
dbVerify(options: DbVerifyOptions): Promise<ExecuteDbVerifyResult>;
|
|
861
|
+
|
|
637
862
|
/**
|
|
638
863
|
* Reads the contract marker from the database.
|
|
639
864
|
* Returns null if no marker exists (fresh database).
|
|
@@ -642,6 +867,13 @@ export interface ControlClient {
|
|
|
642
867
|
*/
|
|
643
868
|
readMarker(): Promise<ContractMarkerRecord | null>;
|
|
644
869
|
|
|
870
|
+
/**
|
|
871
|
+
* Reads every marker row (one per contract space). Used by the
|
|
872
|
+
* per-space verifier to detect orphan marker rows and marker-vs-on-disk
|
|
873
|
+
* drift after a database connection has been established.
|
|
874
|
+
*/
|
|
875
|
+
readAllMarkers(): Promise<ReadonlyMap<string, ContractMarkerRecord>>;
|
|
876
|
+
|
|
645
877
|
/**
|
|
646
878
|
* Applies pre-planned on-disk migrations to the database.
|
|
647
879
|
* Each migration runs in its own transaction with full execution checks.
|
|
@@ -672,6 +904,25 @@ export interface ControlClient {
|
|
|
672
904
|
*/
|
|
673
905
|
toSchemaView(schemaIR: unknown): CoreSchemaView | undefined;
|
|
674
906
|
|
|
907
|
+
/**
|
|
908
|
+
* Infers a PSL contract AST from an introspected schema IR.
|
|
909
|
+
* Delegates to the family instance's inferPslContract method.
|
|
910
|
+
*
|
|
911
|
+
* @param schemaIR - The schema IR from introspect()
|
|
912
|
+
* @returns PslDocumentAst if the family supports the capability, undefined otherwise
|
|
913
|
+
*/
|
|
914
|
+
inferPslContract(schemaIR: unknown): PslDocumentAst | undefined;
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* Renders a textual preview of a migration plan's operations for the CLI's
|
|
918
|
+
* "DDL preview" output. Delegates to the family instance's
|
|
919
|
+
* `toOperationPreview` method.
|
|
920
|
+
*
|
|
921
|
+
* @param operations - The migration plan operations to render
|
|
922
|
+
* @returns OperationPreview if the family supports the capability, undefined otherwise
|
|
923
|
+
*/
|
|
924
|
+
toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview | undefined;
|
|
925
|
+
|
|
675
926
|
/**
|
|
676
927
|
* Emits the contract to JSON and TypeScript declarations.
|
|
677
928
|
* This is an offline operation that does NOT require a database connection.
|
|
@@ -20,10 +20,20 @@ export { createControlClient } from '../control-api/client';
|
|
|
20
20
|
|
|
21
21
|
// Contract enrichment (merges framework-derived capabilities and extension pack metadata)
|
|
22
22
|
export { enrichContract } from '../control-api/contract-enrichment';
|
|
23
|
-
|
|
24
|
-
// Standalone operations (for tooling that doesn't need full client)
|
|
25
23
|
export { executeContractEmit } from '../control-api/operations/contract-emit';
|
|
26
|
-
|
|
24
|
+
// Standalone operations (for tooling that doesn't need full client).
|
|
25
|
+
// These drive the aggregate-pipeline `db init` / `db update` / `db verify`
|
|
26
|
+
// flow against a loaded contract-space aggregate.
|
|
27
|
+
export { type ExecuteDbInitOptions, executeDbInit } from '../control-api/operations/db-init';
|
|
28
|
+
export {
|
|
29
|
+
type ExecuteDbUpdateOptions,
|
|
30
|
+
executeDbUpdate,
|
|
31
|
+
} from '../control-api/operations/db-update';
|
|
32
|
+
export {
|
|
33
|
+
type ExecuteDbVerifyOptions,
|
|
34
|
+
type ExecuteDbVerifyResult,
|
|
35
|
+
executeDbVerify,
|
|
36
|
+
} from '../control-api/operations/db-verify';
|
|
27
37
|
// CLI-specific types
|
|
28
38
|
export type {
|
|
29
39
|
ContractEmitOptions,
|
|
@@ -54,3 +64,5 @@ export type {
|
|
|
54
64
|
SignOptions,
|
|
55
65
|
VerifyOptions,
|
|
56
66
|
} from '../control-api/types';
|
|
67
|
+
// Lifecycle helpers for hosts that publish to many output paths
|
|
68
|
+
export { disposeEmitQueue } from '../utils/emit-queue';
|
package/src/load-ts-contract.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { pathToFileURL } from 'node:url';
|
|
|
4
4
|
import type { Contract } from '@prisma-next/contract/types';
|
|
5
5
|
import type { Plugin } from 'esbuild';
|
|
6
6
|
import { build } from 'esbuild';
|
|
7
|
-
import { join } from 'pathe';
|
|
7
|
+
import { join, resolve as resolvePath } from 'pathe';
|
|
8
8
|
|
|
9
9
|
export interface LoadTsContractOptions {
|
|
10
10
|
readonly allowlist?: ReadonlyArray<string>;
|
|
@@ -78,7 +78,21 @@ function validatePurity(value: unknown): void {
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
function createImportAllowlistPlugin(
|
|
81
|
+
function createImportAllowlistPlugin(
|
|
82
|
+
allowlist: ReadonlyArray<string>,
|
|
83
|
+
entryPath: string,
|
|
84
|
+
collected: Set<string>,
|
|
85
|
+
): Plugin {
|
|
86
|
+
// Match against several path forms that esbuild may use as the importer:
|
|
87
|
+
// the absolute resolved entry, the value the caller passed (which may be
|
|
88
|
+
// relative), and the conventional `<stdin>` placeholder. This is more
|
|
89
|
+
// forgiving than `===` against a single form, which broke when esbuild
|
|
90
|
+
// resolved the entry to an absolute path while the caller passed a
|
|
91
|
+
// relative one (or vice versa).
|
|
92
|
+
const entryAbs = resolvePath(entryPath);
|
|
93
|
+
function isFromEntry(importer: string): boolean {
|
|
94
|
+
return importer === entryAbs || importer === entryPath || importer === '<stdin>';
|
|
95
|
+
}
|
|
82
96
|
return {
|
|
83
97
|
name: 'import-allowlist',
|
|
84
98
|
setup(build) {
|
|
@@ -89,8 +103,8 @@ function createImportAllowlistPlugin(allowlist: ReadonlyArray<string>, entryPath
|
|
|
89
103
|
if (args.path.startsWith('.') || args.path.startsWith('/')) {
|
|
90
104
|
return undefined;
|
|
91
105
|
}
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
if (isFromEntry(args.importer) && !isAllowedImport(args.path, allowlist)) {
|
|
107
|
+
collected.add(args.path);
|
|
94
108
|
return {
|
|
95
109
|
path: args.path,
|
|
96
110
|
external: true,
|
|
@@ -132,6 +146,13 @@ export async function loadContractFromTs(
|
|
|
132
146
|
`prisma-next-contract-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`,
|
|
133
147
|
);
|
|
134
148
|
|
|
149
|
+
// Disallowed imports are collected by the allowlist resolver plugin itself,
|
|
150
|
+
// which has the `importer` context to distinguish entry-direct imports from
|
|
151
|
+
// transitive imports made inside allowlisted (`@prisma-next/*`) dependencies.
|
|
152
|
+
// The metafile is intentionally not re-walked: it would surface internal
|
|
153
|
+
// `node:*` imports inside framework code as false positives.
|
|
154
|
+
const disallowedFromEntry = new Set<string>();
|
|
155
|
+
|
|
135
156
|
try {
|
|
136
157
|
const result = await build({
|
|
137
158
|
entryPoints: [entryPath],
|
|
@@ -142,7 +163,7 @@ export async function loadContractFromTs(
|
|
|
142
163
|
outfile: tempFile,
|
|
143
164
|
write: false,
|
|
144
165
|
metafile: true,
|
|
145
|
-
plugins: [createImportAllowlistPlugin(allowlist, entryPath)],
|
|
166
|
+
plugins: [createImportAllowlistPlugin(allowlist, entryPath, disallowedFromEntry)],
|
|
146
167
|
logLevel: 'error',
|
|
147
168
|
});
|
|
148
169
|
|
|
@@ -155,28 +176,9 @@ export async function loadContractFromTs(
|
|
|
155
176
|
throw new Error('No output files generated from bundling');
|
|
156
177
|
}
|
|
157
178
|
|
|
158
|
-
|
|
159
|
-
if (result.metafile) {
|
|
160
|
-
const inputs = result.metafile.inputs;
|
|
161
|
-
for (const [, inputData] of Object.entries(inputs)) {
|
|
162
|
-
const imports =
|
|
163
|
-
(inputData as { imports?: Array<{ path: string; external?: boolean }> }).imports || [];
|
|
164
|
-
for (const imp of imports) {
|
|
165
|
-
if (
|
|
166
|
-
imp.external &&
|
|
167
|
-
!imp.path.startsWith('.') &&
|
|
168
|
-
!imp.path.startsWith('/') &&
|
|
169
|
-
!isAllowedImport(imp.path, allowlist)
|
|
170
|
-
) {
|
|
171
|
-
disallowedImports.push(imp.path);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (disallowedImports.length > 0) {
|
|
179
|
+
if (disallowedFromEntry.size > 0) {
|
|
178
180
|
throw new Error(
|
|
179
|
-
`Disallowed imports detected. Only imports matching the allowlist are permitted:\n Allowlist: ${allowlist.join(', ')}\n Disallowed imports: ${
|
|
181
|
+
`Disallowed imports detected. Only imports matching the allowlist are permitted:\n Allowlist: ${allowlist.join(', ')}\n Disallowed imports: ${[...disallowedFromEntry].join(', ')}`,
|
|
180
182
|
);
|
|
181
183
|
}
|
|
182
184
|
|