@prisma-next/cli 0.8.0 → 0.9.0-dev.1

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 (163) hide show
  1. package/README.md +8 -9
  2. package/dist/{cli-errors-D3_sMh2K.mjs → cli-errors-CF60g2cG.mjs} +40 -2
  3. package/dist/cli-errors-CF60g2cG.mjs.map +1 -0
  4. package/dist/cli.mjs +67 -19
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/{client-BCnP7cHo.mjs → client-Brv4qlfB.mjs} +28 -30
  7. package/dist/client-Brv4qlfB.mjs.map +1 -0
  8. package/dist/{command-helpers-BeZHkxV8.mjs → command-helpers-D3vL5yi8.mjs} +29 -6
  9. package/dist/command-helpers-D3vL5yi8.mjs.map +1 -0
  10. package/dist/commands/contract-emit.mjs +1 -1
  11. package/dist/commands/contract-infer.mjs +1 -1
  12. package/dist/commands/db-init.mjs +7 -7
  13. package/dist/commands/db-schema.mjs +5 -5
  14. package/dist/commands/db-sign.d.mts.map +1 -1
  15. package/dist/commands/db-sign.mjs +67 -25
  16. package/dist/commands/db-sign.mjs.map +1 -1
  17. package/dist/commands/db-update.d.mts.map +1 -1
  18. package/dist/commands/db-update.mjs +37 -9
  19. package/dist/commands/db-update.mjs.map +1 -1
  20. package/dist/commands/db-verify.d.mts.map +1 -1
  21. package/dist/commands/db-verify.mjs +1 -1
  22. package/dist/commands/migrate.d.mts +28 -0
  23. package/dist/commands/migrate.d.mts.map +1 -0
  24. package/dist/commands/{migration-apply.mjs → migrate.mjs} +65 -39
  25. package/dist/commands/migrate.mjs.map +1 -0
  26. package/dist/commands/migration-check.d.mts +18 -0
  27. package/dist/commands/migration-check.d.mts.map +1 -0
  28. package/dist/commands/migration-check.mjs +284 -0
  29. package/dist/commands/migration-check.mjs.map +1 -0
  30. package/dist/commands/migration-graph.d.mts +16 -0
  31. package/dist/commands/migration-graph.d.mts.map +1 -0
  32. package/dist/commands/migration-graph.mjs +141 -0
  33. package/dist/commands/migration-graph.mjs.map +1 -0
  34. package/dist/commands/migration-list.d.mts +20 -0
  35. package/dist/commands/migration-list.d.mts.map +1 -0
  36. package/dist/commands/migration-list.mjs +107 -0
  37. package/dist/commands/migration-list.mjs.map +1 -0
  38. package/dist/commands/migration-log.d.mts +21 -0
  39. package/dist/commands/migration-log.d.mts.map +1 -0
  40. package/dist/commands/migration-log.mjs +146 -0
  41. package/dist/commands/migration-log.mjs.map +1 -0
  42. package/dist/commands/migration-new.d.mts.map +1 -1
  43. package/dist/commands/migration-new.mjs +30 -29
  44. package/dist/commands/migration-new.mjs.map +1 -1
  45. package/dist/commands/migration-plan.d.mts +2 -2
  46. package/dist/commands/migration-plan.d.mts.map +1 -1
  47. package/dist/commands/migration-plan.mjs +1 -1
  48. package/dist/commands/migration-show.d.mts +1 -1
  49. package/dist/commands/migration-show.d.mts.map +1 -1
  50. package/dist/commands/migration-show.mjs +90 -52
  51. package/dist/commands/migration-show.mjs.map +1 -1
  52. package/dist/commands/migration-status.d.mts +5 -17
  53. package/dist/commands/migration-status.d.mts.map +1 -1
  54. package/dist/commands/migration-status.mjs +732 -1
  55. package/dist/commands/migration-status.mjs.map +1 -0
  56. package/dist/commands/ref.d.mts +34 -0
  57. package/dist/commands/ref.d.mts.map +1 -0
  58. package/dist/commands/{migration-ref.mjs → ref.mjs} +28 -57
  59. package/dist/commands/ref.mjs.map +1 -0
  60. package/dist/{contract-emit-9DBda5Ou.mjs → contract-emit-C3STUIBg.mjs} +6 -6
  61. package/dist/{contract-emit-9DBda5Ou.mjs.map → contract-emit-C3STUIBg.mjs.map} +1 -1
  62. package/dist/{contract-emit-B77TsJqf.mjs → contract-emit-iynA3BCA.mjs} +9 -5
  63. package/dist/contract-emit-iynA3BCA.mjs.map +1 -0
  64. package/dist/{contract-infer-ByxhPjpW.mjs → contract-infer-Cnj8G1E2.mjs} +5 -5
  65. package/dist/{contract-infer-ByxhPjpW.mjs.map → contract-infer-Cnj8G1E2.mjs.map} +1 -1
  66. package/dist/{contract-space-aggregate-loader-BrwKK6Q6.mjs → contract-space-aggregate-loader-pAc8CDfY.mjs} +4 -4
  67. package/dist/{contract-space-aggregate-loader-BrwKK6Q6.mjs.map → contract-space-aggregate-loader-pAc8CDfY.mjs.map} +1 -1
  68. package/dist/{db-verify-Czm5T-J4.mjs → db-verify-D7cyH_zz.mjs} +12 -9
  69. package/dist/db-verify-D7cyH_zz.mjs.map +1 -0
  70. package/dist/errors-Cw6kyTyV.mjs +56 -0
  71. package/dist/errors-Cw6kyTyV.mjs.map +1 -0
  72. package/dist/exports/control-api.d.mts +1 -1
  73. package/dist/exports/control-api.d.mts.map +1 -1
  74. package/dist/exports/control-api.mjs +2 -2
  75. package/dist/exports/index.mjs +1 -1
  76. package/dist/exports/index.mjs.map +1 -1
  77. package/dist/exports/init-output.mjs +1 -1
  78. package/dist/{framework-components-ChqVUxR-.mjs → framework-components-xFLFpZUO.mjs} +2 -2
  79. package/dist/{framework-components-ChqVUxR-.mjs.map → framework-components-xFLFpZUO.mjs.map} +1 -1
  80. package/dist/{global-flags-Icqpxk23.d.mts → global-flags-DGmw6Kqg.d.mts} +1 -1
  81. package/dist/{global-flags-Icqpxk23.d.mts.map → global-flags-DGmw6Kqg.d.mts.map} +1 -1
  82. package/dist/{migration-status-By9G5p2H.mjs → graph-render-eJDcLWny.mjs} +3 -692
  83. package/dist/graph-render-eJDcLWny.mjs.map +1 -0
  84. package/dist/{init-B-k3a1Qw.mjs → init-Bqg5JWg7.mjs} +133 -61
  85. package/dist/init-Bqg5JWg7.mjs.map +1 -0
  86. package/dist/{inspect-live-schema-DxdBd4Er.mjs → inspect-live-schema-CWLK_lgs.mjs} +4 -4
  87. package/dist/{inspect-live-schema-DxdBd4Er.mjs.map → inspect-live-schema-CWLK_lgs.mjs.map} +1 -1
  88. package/dist/migration-cli.mjs +1 -1
  89. package/dist/migration-cli.mjs.map +1 -1
  90. package/dist/{migration-command-scaffold-BdV8JYXV.mjs → migration-command-scaffold-CmXXC1UZ.mjs} +4 -4
  91. package/dist/{migration-command-scaffold-BdV8JYXV.mjs.map → migration-command-scaffold-CmXXC1UZ.mjs.map} +1 -1
  92. package/dist/{migration-plan-mRu5K81L.mjs → migration-plan-CHyUlBV0.mjs} +76 -37
  93. package/dist/migration-plan-CHyUlBV0.mjs.map +1 -0
  94. package/dist/migration-types-D2FW63pr.d.mts +15 -0
  95. package/dist/migration-types-D2FW63pr.d.mts.map +1 -0
  96. package/dist/{migrations-CTsyBXCA.mjs → migrations-DyUf5lTt.mjs} +2 -2
  97. package/dist/migrations-DyUf5lTt.mjs.map +1 -0
  98. package/dist/{output-BVj6a971.mjs → output-B60Gw5fu.mjs} +12 -11
  99. package/dist/{output-BVj6a971.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
  100. package/dist/{result-handler-rmPVKIP2.mjs → result-handler-Bm_6dDYg.mjs} +2 -2
  101. package/dist/{result-handler-rmPVKIP2.mjs.map → result-handler-Bm_6dDYg.mjs.map} +1 -1
  102. package/dist/{terminal-ui-C_hFNbAn.mjs → terminal-ui-XtOQsqe9.mjs} +2 -54
  103. package/dist/terminal-ui-XtOQsqe9.mjs.map +1 -0
  104. package/dist/{types-LItU7E4l.d.mts → types-0aS865QN.d.mts} +14 -8
  105. package/dist/types-0aS865QN.d.mts.map +1 -0
  106. package/dist/{verify-CiwNWM9N.mjs → verify-D7ypCCe6.mjs} +1 -1
  107. package/dist/{verify-CiwNWM9N.mjs.map → verify-D7ypCCe6.mjs.map} +1 -1
  108. package/package.json +39 -23
  109. package/src/cli.ts +78 -15
  110. package/src/commands/db-sign.ts +102 -32
  111. package/src/commands/db-update.ts +56 -4
  112. package/src/commands/db-verify.ts +19 -3
  113. package/src/commands/init/agent-skill-install.ts +145 -43
  114. package/src/commands/init/errors.ts +2 -2
  115. package/src/commands/init/exit-codes.ts +2 -2
  116. package/src/commands/init/index.ts +1 -1
  117. package/src/commands/init/init.ts +15 -6
  118. package/src/commands/init/inputs.ts +1 -1
  119. package/src/commands/init/output.ts +22 -17
  120. package/src/commands/{migration-apply.ts → migrate.ts} +77 -73
  121. package/src/commands/migration-check/exit-codes.ts +3 -0
  122. package/src/commands/migration-check.ts +369 -0
  123. package/src/commands/migration-graph.ts +184 -0
  124. package/src/commands/migration-list.ts +155 -0
  125. package/src/commands/migration-log.ts +218 -0
  126. package/src/commands/migration-new.ts +30 -22
  127. package/src/commands/migration-plan.ts +104 -35
  128. package/src/commands/migration-show.ts +141 -65
  129. package/src/commands/migration-status.ts +82 -69
  130. package/src/commands/{migration-ref.ts → ref.ts} +32 -86
  131. package/src/control-api/client.ts +30 -21
  132. package/src/control-api/operations/apply-aggregate.ts +4 -4
  133. package/src/control-api/operations/contract-emit.ts +26 -3
  134. package/src/control-api/operations/db-apply-aggregate.ts +4 -3
  135. package/src/control-api/operations/db-verify.ts +2 -2
  136. package/src/control-api/operations/migration-apply.ts +5 -4
  137. package/src/control-api/types.ts +12 -7
  138. package/src/load-ts-contract.ts +9 -1
  139. package/src/migration-cli.ts +1 -1
  140. package/src/utils/cli-errors.ts +37 -0
  141. package/src/utils/command-helpers.ts +28 -3
  142. package/src/utils/contract-space-aggregate-loader.ts +4 -4
  143. package/src/utils/contract-space-seed-phase.ts +2 -2
  144. package/src/utils/formatters/help.ts +12 -2
  145. package/src/utils/formatters/migrations.ts +2 -2
  146. package/dist/cli-errors-D3_sMh2K.mjs.map +0 -1
  147. package/dist/client-BCnP7cHo.mjs.map +0 -1
  148. package/dist/command-helpers-BeZHkxV8.mjs.map +0 -1
  149. package/dist/commands/migration-apply.d.mts +0 -51
  150. package/dist/commands/migration-apply.d.mts.map +0 -1
  151. package/dist/commands/migration-apply.mjs.map +0 -1
  152. package/dist/commands/migration-ref.d.mts +0 -45
  153. package/dist/commands/migration-ref.d.mts.map +0 -1
  154. package/dist/commands/migration-ref.mjs.map +0 -1
  155. package/dist/contract-emit-B77TsJqf.mjs.map +0 -1
  156. package/dist/db-verify-Czm5T-J4.mjs.map +0 -1
  157. package/dist/init-B-k3a1Qw.mjs.map +0 -1
  158. package/dist/migration-plan-mRu5K81L.mjs.map +0 -1
  159. package/dist/migration-status-By9G5p2H.mjs.map +0 -1
  160. package/dist/migrations-CTsyBXCA.mjs.map +0 -1
  161. package/dist/terminal-ui-C_hFNbAn.mjs.map +0 -1
  162. package/dist/types-LItU7E4l.d.mts.map +0 -1
  163. /package/dist/{cli-errors-B9OBbled.d.mts → cli-errors-DdcjVLJV.d.mts} +0 -0
@@ -49,7 +49,7 @@ export interface ApplyAggregateInputs<TFamilyId extends string, TTargetId extend
49
49
  * Per-space plans, keyed by `spaceId`. Produced by either the full
50
50
  * {@link planAggregate} pipeline (`db init` / `db update` — synth
51
51
  * for the app, graph-walk for extensions) or by direct
52
- * {@link graphWalkStrategy} calls (`migration apply` — graph-walk
52
+ * {@link graphWalkStrategy} calls (`migrate` — graph-walk
53
53
  * for every member). Either way, the runner consumes the same shape.
54
54
  */
55
55
  readonly perSpacePlans: ReadonlyMap<string, AggregatePerSpacePlan>;
@@ -100,7 +100,7 @@ export type ApplyAggregateResult = Result<ApplyAggregateValue, AggregateApplyRun
100
100
 
101
101
  /**
102
102
  * Runner-driving tail shared by every aggregate apply caller — `db init`,
103
- * `db update`, and `migration apply`. Consumes already-resolved per-space
103
+ * `db update`, and `migrate`. Consumes already-resolved per-space
104
104
  * plans (the planner-vs-replay distinction is owned by the caller) and
105
105
  * dispatches them to the multi-space runner in canonical order.
106
106
  *
@@ -264,7 +264,7 @@ export function collectOrdered(
264
264
  /**
265
265
  * Action-appropriate label for the `spanStart` event the apply
266
266
  * primitive emits. `applyAggregate` is shared by `db init`, `db update`,
267
- * and `migration apply`; the span label tracks the user-visible action
267
+ * and `migrate`; the span label tracks the user-visible action
268
268
  * so structured-progress output reads naturally for each surface.
269
269
  */
270
270
  export function progressLabelForAction(action: AggregateApplyAction): string {
@@ -285,6 +285,6 @@ function labelForAction(action: AggregateApplyAction): string {
285
285
  case 'dbUpdate':
286
286
  return 'db update';
287
287
  case 'migrationApply':
288
- return 'migration apply';
288
+ return 'migrate';
289
289
  }
290
290
  }
@@ -4,6 +4,7 @@ import { emit, getEmittedArtifactPaths } from '@prisma-next/emitter';
4
4
  import { createControlStack } from '@prisma-next/framework-components/control';
5
5
  import { abortable } from '@prisma-next/utils/abortable';
6
6
  import { ifDefined } from '@prisma-next/utils/defined';
7
+ import type { JsonObject } from '@prisma-next/utils/json';
7
8
  import { dirname } from 'pathe';
8
9
  import { loadConfig } from '../../config-loader';
9
10
  import { errorContractConfigMissing, errorRuntime } from '../../utils/cli-errors';
@@ -231,10 +232,32 @@ export async function executeContractEmit(
231
232
  config.target.targetId,
232
233
  rawComponents,
233
234
  );
234
- const enrichedIR = enrichContract(validatedContract.value as Contract, frameworkComponents);
235
- familyInstance.validateContract(enrichedIR);
235
+ // Blind cast: `validateProviderResult` upstream has already
236
+ // pinned `validatedContract.value` to the provider's loose
237
+ // `Contract` envelope, but the local `Contract` type at this
238
+ // call site is the precise structural interface. Re-narrowing
239
+ // the envelope into the precise type is exactly what the
240
+ // `familyInstance.deserializeContract(enrichedIR)` call on the
241
+ // next line does — the cast just defers the structural check
242
+ // by one statement so `enrichContract` can decorate first.
243
+ const enrichedIR = enrichContract(
244
+ validatedContract.value as unknown as Contract,
245
+ frameworkComponents,
246
+ );
247
+ familyInstance.deserializeContract(enrichedIR);
248
+ // Each target's descriptor ships a `contractSerializer` SPI; the
249
+ // framework canonicalizer threads its `serializeContract` so the
250
+ // on-disk JSON envelope is constructed by target-owned code
251
+ // rather than by walking the in-memory contract with
252
+ // `Object.entries` (which would leak runtime-only class API
253
+ // fields into the persisted shape).
254
+ const serializeContract = (c: Contract): JsonObject =>
255
+ config.target.contractSerializer.serializeContract(c);
236
256
  emitResult = await unlessAborted(
237
- emit(enrichedIR, stack, config.family.emission, { outputJsonPath }),
257
+ emit(enrichedIR, stack, config.family.emission, {
258
+ outputJsonPath,
259
+ serializeContract,
260
+ }),
238
261
  );
239
262
  } catch (error) {
240
263
  endSpan(onProgress, 'emit', 'error');
@@ -116,7 +116,7 @@ export async function executeAggregateApply<TFamilyId extends string, TTargetId
116
116
  migrationsDir,
117
117
  appContract: contract,
118
118
  extensionPacks,
119
- validateContract: (json) => familyInstance.validateContract(json),
119
+ deserializeContract: (json) => familyInstance.deserializeContract(json),
120
120
  };
121
121
  const loaded = await buildContractSpaceAggregate(loadInputs);
122
122
  if (!loaded.ok) {
@@ -207,9 +207,10 @@ export async function executeAggregateApply<TFamilyId extends string, TTargetId
207
207
 
208
208
  // 5. Apply mode: hand off to the shared `applyAggregate` primitive.
209
209
  // The runner-driving tail is identical for `db init` / `db update` /
210
- // `migration apply` — only how each caller produces `perSpacePlans`
210
+ // `migrate` — only how each caller produces `perSpacePlans`
211
211
  // differs (synth + graph-walk via planAggregate here; graph-walk
212
- // only for migration apply). See M6 sub-spec § Required changes 1.
212
+ // only for migrate). Each caller produces perSpacePlans differently;
213
+ // this helper handles the shared apply tail.
213
214
  const applied = await applyAggregate({
214
215
  aggregate,
215
216
  perSpacePlans: planResult.value.perSpace,
@@ -120,7 +120,7 @@ function buildLoadInputs<TFamilyId extends string, TTargetId extends string>(
120
120
  migrationsDir: options.migrationsDir,
121
121
  appContract: options.contract,
122
122
  extensionPacks: options.extensionPacks,
123
- validateContract: (json) => options.familyInstance.validateContract(json),
123
+ deserializeContract: (json) => options.familyInstance.deserializeContract(json),
124
124
  };
125
125
  }
126
126
 
@@ -172,7 +172,7 @@ function createPerMemberVerifier<TFamilyId extends string, TTargetId extends str
172
172
  const { skipSchema, familyInstance, frameworkComponents } = options;
173
173
  return (projectedSchema, member, verifyMode) => {
174
174
  if (skipSchema) return buildSkippedSchemaResult(member);
175
- return familyInstance.schemaVerifyAgainstSchema({
175
+ return familyInstance.verifySchema({
176
176
  contract: member.contract,
177
177
  // The family's `TSchemaIR` is opaque to migration-tools; the
178
178
  // aggregate verifier passes through whatever we hand it. The
@@ -34,7 +34,7 @@ import type {
34
34
  import { applyAggregate, buildPerSpaceBreakdown } from './apply-aggregate';
35
35
 
36
36
  /**
37
- * Inputs for the aggregate-walking `migration apply` control-api
37
+ * Inputs for the aggregate-walking `migrate` control-api
38
38
  * operation.
39
39
  *
40
40
  * The CLI command resolves the descriptor surface (config, refs,
@@ -110,7 +110,8 @@ export interface ExecuteMigrationApplyOptions<TFamilyId extends string, TTargetI
110
110
  * shared with `db init` / `db update`). Marker advancement is
111
111
  * inside the per-space transaction.
112
112
  *
113
- * Sub-spec § `migration apply` semantics + § Required changes 1.
113
+ * Encodes the replay-only contract: every contract space must have an
114
+ * authored migration graph on disk before this operation can advance it.
114
115
  */
115
116
  export async function executeMigrationApply<TFamilyId extends string, TTargetId extends string>(
116
117
  options: ExecuteMigrationApplyOptions<TFamilyId, TTargetId>,
@@ -136,7 +137,7 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
136
137
  migrationsDir,
137
138
  appContract: contract,
138
139
  extensionPacks,
139
- validateContract: (json) => familyInstance.validateContract(json),
140
+ deserializeContract: (json) => familyInstance.deserializeContract(json),
140
141
  appMigrationPackages,
141
142
  };
142
143
  const loaded = await buildContractSpaceAggregate(loadInputs);
@@ -461,7 +462,7 @@ function buildNeverPlannedFailure(spaceId: string, targetHash: string): Migratio
461
462
  return {
462
463
  code: 'MIGRATION_PATH_NOT_FOUND',
463
464
  summary: `No on-disk migrations for contract space "${spaceId}"`,
464
- why: `migration apply is replay-only: every contract space must have an authored migration graph on disk. Space "${spaceId}" has no migrations under \`migrations/${spaceId}/\` but its head ref targets "${targetHash}". Run \`prisma-next migration plan\` first to materialise the path.`,
465
+ why: `migrate is replay-only: every contract space must have an authored migration graph on disk. Space "${spaceId}" has no migrations under \`migrations/${spaceId}/\` but its head ref targets "${targetHash}". Run \`prisma-next migration plan\` first to materialise the path.`,
465
466
  meta: { spaceId, target: targetHash, kind: 'neverPlanned' },
466
467
  };
467
468
  }
@@ -118,7 +118,7 @@ export type OnControlProgress = (event: ControlProgressEvent) => void;
118
118
  * Options for the verify operation.
119
119
  */
120
120
  export interface VerifyOptions {
121
- /** Contract or unvalidated JSON - validated at runtime via familyInstance.validateContract() */
121
+ /** Contract or unvalidated JSON - validated at runtime via familyInstance.deserializeContract() */
122
122
  readonly contract: unknown;
123
123
  /**
124
124
  * Database connection. If provided, verify will connect before executing.
@@ -134,7 +134,7 @@ export interface VerifyOptions {
134
134
  * Options for the schemaVerify operation.
135
135
  */
136
136
  export interface SchemaVerifyOptions {
137
- /** Contract or unvalidated JSON - validated at runtime via familyInstance.validateContract() */
137
+ /** Contract or unvalidated JSON - validated at runtime via familyInstance.deserializeContract() */
138
138
  readonly contract: unknown;
139
139
  /**
140
140
  * Whether to use strict mode for schema verification.
@@ -156,7 +156,7 @@ export interface SchemaVerifyOptions {
156
156
  * Options for the sign operation.
157
157
  */
158
158
  export interface SignOptions {
159
- /** Contract or unvalidated JSON - validated at runtime via familyInstance.validateContract() */
159
+ /** Contract or unvalidated JSON - validated at runtime via familyInstance.deserializeContract() */
160
160
  readonly contract: unknown;
161
161
  /**
162
162
  * Path to the contract file (for metadata in the result).
@@ -180,7 +180,7 @@ export interface SignOptions {
180
180
  * Options for the dbInit operation.
181
181
  */
182
182
  export interface DbInitOptions {
183
- /** Contract or unvalidated JSON - validated at runtime via familyInstance.validateContract() */
183
+ /** Contract or unvalidated JSON - validated at runtime via familyInstance.deserializeContract() */
184
184
  readonly contract: unknown;
185
185
  /**
186
186
  * Mode for the dbInit operation.
@@ -209,7 +209,7 @@ export interface DbInitOptions {
209
209
  * Options for the dbUpdate operation.
210
210
  */
211
211
  export interface DbUpdateOptions {
212
- /** Contract or unvalidated JSON - validated at runtime via familyInstance.validateContract() */
212
+ /** Contract or unvalidated JSON - validated at runtime via familyInstance.deserializeContract() */
213
213
  readonly contract: unknown;
214
214
  /**
215
215
  * Mode for the dbUpdate operation.
@@ -251,7 +251,13 @@ export interface DbUpdateOptions {
251
251
  * portion of the verifier.
252
252
  */
253
253
  export interface DbVerifyOptions {
254
- readonly contract: unknown;
254
+ /**
255
+ * Already-deserialized contract. Callers cross the family
256
+ * `deserializeContract` seam at the read site (TML-2536) and pass the
257
+ * hydrated value through unchanged; this op no longer re-runs the
258
+ * SerializerBase pipeline.
259
+ */
260
+ readonly contract: Contract;
255
261
  readonly migrationsDir: string;
256
262
  readonly strict: boolean;
257
263
  readonly skipSchema: boolean;
@@ -590,7 +596,6 @@ export interface MigrationApplyStep {
590
596
  readonly dirName: string;
591
597
  readonly from: string | null;
592
598
  readonly to: string;
593
- readonly toContract: Contract;
594
599
  readonly operations: readonly MigrationPlanOperation[];
595
600
  /**
596
601
  * Sorted, deduplicated invariant ids from `migration.json.providedInvariants`.
@@ -212,7 +212,15 @@ export async function loadContractFromTs(
212
212
 
213
213
  validatePurity(contract);
214
214
 
215
- return contract as Contract;
215
+ // Blind cast: the loaded module was authored by user code
216
+ // (typically via `defineContract` / a contract builder) and
217
+ // its runtime shape is structurally a `Contract`, but the
218
+ // dynamic import collapses the source typing. The contract
219
+ // structural validation that asserts the shape happens
220
+ // downstream at the `familyInstance.deserializeContract` seam
221
+ // (e.g. in `executeContractEmit`); this helper only checks
222
+ // purity here.
223
+ return contract as unknown as Contract;
216
224
  } catch (error) {
217
225
  try {
218
226
  if (tempFile) {
@@ -3,7 +3,7 @@
3
3
  * `node migration.ts` directly.
4
4
  *
5
5
  * Naming: this is *not* a "migration runner" in the apply-time sense. The
6
- * apply-time runner is the thing `prisma-next migration apply` uses to
6
+ * apply-time runner is the thing `prisma-next migrate` uses to
7
7
  * execute migration JSON ops against a database. `MigrationCLI` is the
8
8
  * tiny CLI surface owned by an authored `migration.ts` file: parse the
9
9
  * file's argv, load the project's `prisma-next.config.ts`, assemble a
@@ -25,6 +25,7 @@ import {
25
25
  } from '@prisma-next/errors/control';
26
26
  import { errorRuntime } from '@prisma-next/errors/execution';
27
27
  import type { MigrationToolsError } from '@prisma-next/migration-tools/errors';
28
+ import type { RefResolutionError } from '@prisma-next/migration-tools/ref-resolution';
28
29
 
29
30
  export {
30
31
  ERROR_CODE_DESTRUCTIVE_CHANGES,
@@ -85,3 +86,39 @@ export function mapMigrationToolsError(error: MigrationToolsError): CliStructure
85
86
  meta: { code: error.code, ...(error.details ?? {}) },
86
87
  });
87
88
  }
89
+
90
+ /**
91
+ * Maps a `RefResolutionError` from the contract/migration reference
92
+ * resolver into a CLI structured error envelope.
93
+ */
94
+ export function mapRefResolutionError(error: RefResolutionError): CliStructuredError {
95
+ switch (error.kind) {
96
+ case 'not-found':
97
+ return errorRuntime(`Not a known ${error.grammar} reference: "${error.input}"`, {
98
+ why: `No ${error.grammar} matching "${error.input}" exists in the migration graph or refs index.`,
99
+ fix:
100
+ error.grammar === 'contract'
101
+ ? 'Provide a valid contract hash, ref name, or migration directory name.'
102
+ : 'Provide a valid migration directory name or migration hash.',
103
+ meta: { input: error.input, grammar: error.grammar },
104
+ });
105
+ case 'ambiguous':
106
+ return errorRuntime(`Ambiguous ${error.grammar} reference: "${error.input}"`, {
107
+ why: `"${error.input}" matches multiple ${error.grammar}s: ${error.candidates.join(', ')}`,
108
+ fix: 'Provide a longer prefix or use the full hash to disambiguate.',
109
+ meta: { input: error.input, candidates: error.candidates, grammar: error.grammar },
110
+ });
111
+ case 'wrong-grammar':
112
+ return errorRuntime(error.message, {
113
+ why: error.message,
114
+ fix: error.fix,
115
+ meta: { input: error.input, expectedGrammar: error.expectedGrammar },
116
+ });
117
+ case 'invalid-format':
118
+ return errorRuntime(`Invalid reference format: "${error.input}"`, {
119
+ why: error.reason,
120
+ fix: 'Provide a valid contract hash, ref name, or migration directory name.',
121
+ meta: { input: error.input },
122
+ });
123
+ }
124
+ }
@@ -17,6 +17,10 @@ import { parseGlobalFlags } from './global-flags';
17
17
 
18
18
  const longDescriptions = new WeakMap<Command, string>();
19
19
  const commandExamples = new WeakMap<Command, readonly string[]>();
20
+ const commandSeeAlso = new WeakMap<
21
+ Command,
22
+ readonly { readonly verb: string; readonly oneLiner: string }[]
23
+ >();
20
24
 
21
25
  /**
22
26
  * Sets both short and long descriptions for a command.
@@ -57,6 +61,27 @@ export function getCommandExamples(command: Command): readonly string[] | undefi
57
61
  return commandExamples.get(command);
58
62
  }
59
63
 
64
+ /**
65
+ * Sets cross-references to related commands, rendered in a "See also"
66
+ * section below the Examples block in help output.
67
+ */
68
+ export function setCommandSeeAlso(
69
+ command: Command,
70
+ refs: readonly { readonly verb: string; readonly oneLiner: string }[],
71
+ ): Command {
72
+ commandSeeAlso.set(command, refs);
73
+ return command;
74
+ }
75
+
76
+ /**
77
+ * Gets the see-also cross-references from a command.
78
+ */
79
+ export function getCommandSeeAlso(
80
+ command: Command,
81
+ ): readonly { readonly verb: string; readonly oneLiner: string }[] | undefined {
82
+ return commandSeeAlso.get(command);
83
+ }
84
+
60
85
  /**
61
86
  * Shared CLI options interface for migration commands (db init, db update).
62
87
  * These are the Commander.js parsed options common to both commands.
@@ -79,13 +104,13 @@ export function resolveContractPath(config: { contract?: { output?: string } }):
79
104
 
80
105
  /**
81
106
  * Resolves the migrations directory and config path from CLI options.
82
- * Shared by migration-apply, migration-plan, and migration-status.
107
+ * Shared by migrate, migration-plan, and migration-status.
83
108
  *
84
109
  * - `migrationsDir` is the project's top-level `migrations/` directory
85
110
  * (the root that the aggregate loader walks for every contract space).
86
111
  * - `appMigrationsDir` is the app subspace directory under it
87
112
  * (`<migrationsDir>/<APP_SPACE_ID>/`). Every per-app reader / writer
88
- * (`migration new`, `migration plan`, `migration apply`,
113
+ * (`migration new`, `migration plan`, `migrate`,
89
114
  * `migration status`, `migration show`, `migration ref`) operates on
90
115
  * this directory. Extensions own their own `migrations/<spaceId>/`.
91
116
  * - `refsDir` is the app's refs directory (`<appMigrationsDir>/refs/`).
@@ -159,7 +184,7 @@ export function collectDeclaredInvariants(graph: MigrationGraph): ReadonlySet<st
159
184
  /**
160
185
  * Maps a `MigrationEdge` to the structural-edge shape used in the
161
186
  * `MIGRATION.NO_INVARIANT_PATH` error envelope. Shared between
162
- * `migration apply` and `migration status` so both commands surface
187
+ * `migrate` and `migration status` so both commands surface
163
188
  * the same JSON wire shape when an invariant-aware route is unsatisfiable.
164
189
  */
165
190
  export function toStructuralEdge(edge: MigrationEdge): NoInvariantPathStructuralEdge {
@@ -120,7 +120,7 @@ export interface BuildAggregateInputs<TFamilyId extends string, TTargetId extend
120
120
  readonly migrationsDir: string;
121
121
  readonly appContract: Contract;
122
122
  readonly extensionPacks: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
123
- readonly validateContract: (contractJson: unknown) => Contract;
123
+ readonly deserializeContract: (contractJson: unknown) => Contract;
124
124
  /**
125
125
  * App-space migration packages to hydrate the app member's
126
126
  * migration graph with. Defaults to `[]` (matches the `db init` /
@@ -128,7 +128,7 @@ export interface BuildAggregateInputs<TFamilyId extends string, TTargetId extend
128
128
  * `migrations/` graph is not walked — the planner uses the synth
129
129
  * strategy for the app member instead).
130
130
  *
131
- * `migration apply` callers thread the user's authored app-space
131
+ * `migrate` callers thread the user's authored app-space
132
132
  * packages (loaded via `loadMigrationPackages(appMigrationsDir)`)
133
133
  * through here so the graph-walk strategy can plot a path through
134
134
  * them — the prod-time replay path explicitly forbids synth.
@@ -144,7 +144,7 @@ export interface BuildAggregateInputs<TFamilyId extends string, TTargetId extend
144
144
  * (defaulting to `[]`). `db init` / `db update` leave it empty: the
145
145
  * planner's `synth` strategy is used for the app member (driven by
146
146
  * `callerPolicy.ignoreGraphFor`), so the app's authored `migrations/`
147
- * graph does not need to be walked. `migration apply` threads the
147
+ * graph does not need to be walked. `migrate` threads the
148
148
  * already-loaded app-space packages through so the graph-walk strategy
149
149
  * can plot a path through them — replay forbids synth.
150
150
  *
@@ -165,7 +165,7 @@ export async function buildContractSpaceAggregate<
165
165
  migrationsDir: inputs.migrationsDir,
166
166
  appContract: inputs.appContract,
167
167
  declaredExtensions,
168
- validateContract: inputs.validateContract,
168
+ deserializeContract: inputs.deserializeContract,
169
169
  appMigrationPackages: inputs.appMigrationPackages ?? [],
170
170
  };
171
171
 
@@ -91,7 +91,7 @@ export interface ContractSpaceSeedPhaseResult {
91
91
  * Output ordering is deterministic and alphabetical by spaceId (via
92
92
  * {@link planAllSpaces}, which also detects duplicate spaceIds). This
93
93
  * matches the canonical sort order used by every other aggregate
94
- * surface (`migration apply`, `migration status`, the runner).
94
+ * surface (`migrate`, `migration status`, the runner).
95
95
  */
96
96
  export async function runContractSpaceSeedPhase(
97
97
  inputs: ContractSpaceSeedPhaseInputs,
@@ -193,7 +193,7 @@ function buildPlaceholderContractDts(spaceId: string): string {
193
193
  ' * alongside `contract.json` and `refs/head.json`. A typed `.d.ts`',
194
194
  ' * rendering pass for extension contracts is tracked separately;',
195
195
  ' * until that ships, consumers should import `contract.json`',
196
- ' * directly with `validateContract<…>(…)`.',
196
+ ' * and pass it through the target descriptor’s `contractSerializer`.',
197
197
  ' */',
198
198
  'export {};',
199
199
  '',
@@ -2,7 +2,7 @@ import { blue, bold, cyan, dim, green, magenta } from 'colorette';
2
2
  import type { Command } from 'commander';
3
3
  import wrapAnsi from 'wrap-ansi';
4
4
 
5
- import { getCommandExamples, getLongDescription } from '../command-helpers';
5
+ import { getCommandExamples, getCommandSeeAlso, getLongDescription } from '../command-helpers';
6
6
  import type { GlobalFlags } from '../global-flags';
7
7
  import { formatDim } from './helpers';
8
8
  import { padToFixedWidth, renderCommandTree } from './styled';
@@ -134,7 +134,7 @@ function getCommandDocsUrl(commandPath: string): string | undefined {
134
134
  'db verify': 'https://pris.ly/db-verify',
135
135
  'db update': 'https://pris.ly/db-update',
136
136
  'migration plan': 'https://pris.ly/migration-plan',
137
- 'migration apply': 'https://pris.ly/migration-apply',
137
+ migrate: 'https://pris.ly/migrate',
138
138
  'migration show': 'https://pris.ly/migration-show',
139
139
  'migration status': 'https://pris.ly/migration-status',
140
140
  };
@@ -268,6 +268,16 @@ export function formatCommandHelp(options: {
268
268
  }
269
269
  }
270
270
 
271
+ // See also (cross-references to related commands)
272
+ const seeAlso = getCommandSeeAlso(command);
273
+ if (seeAlso && seeAlso.length > 0) {
274
+ lines.push(formatDimText('│'));
275
+ lines.push(`${formatDimText('│')} ${formatDimText('See also:')}`);
276
+ for (const ref of seeAlso) {
277
+ lines.push(`${formatDimText('│')} ${ref.verb} ${formatDimText(ref.oneLiner)}`);
278
+ }
279
+ }
280
+
271
281
  // Multi-line description (if present) - shown after all other content
272
282
  if (longDescription) {
273
283
  lines.push(formatDimText('│'));
@@ -90,7 +90,7 @@ export interface MigrationCommandResult {
90
90
 
91
91
  /**
92
92
  * Render the shared per-space execution block consumed by the `db init`
93
- * / `db update` / `migration apply` summaries. Always shows: space
93
+ * / `db update` / `migrate` summaries. Always shows: space
94
94
  * label (`Extension space: <id>` or `App space`) → per-op lines under
95
95
  * each space → per-space marker hash (when known).
96
96
  *
@@ -254,7 +254,7 @@ export interface MigrationApplyCommandOutputResult {
254
254
  /**
255
255
  * Per-space breakdown in canonical schedule order (extensions
256
256
  * alphabetically, then app). Always present for the aggregate-walking
257
- * `migration apply` command.
257
+ * `migrate` command.
258
258
  */
259
259
  readonly perSpace: readonly AggregatePerSpaceExecutionEntry[];
260
260
  readonly timings?: {
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-errors-D3_sMh2K.mjs","names":[],"sources":["../src/utils/cli-errors.ts"],"sourcesContent":["/**\n * Re-export all domain error factories from @prisma-next/errors for convenience.\n * CLI-specific errors (e.g., Commander argument validation in the main CLI, or\n * clipanion parse errors in the migration-file CLI) can be added here if needed.\n */\nexport type { CliErrorConflict, CliErrorEnvelope } from '@prisma-next/errors/control';\n\nimport {\n CliStructuredError,\n errorConfigFileNotFound,\n errorConfigValidation,\n errorContractConfigMissing,\n errorContractMissingExtensionPacks,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFamilyReadMarkerSqlRequired,\n errorFileNotFound,\n errorMigrationCliInvalidConfigArg,\n errorMigrationCliUnknownFlag,\n errorMigrationPlanningFailed,\n errorQueryRunnerFactoryRequired,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n} from '@prisma-next/errors/control';\nimport { errorRuntime } from '@prisma-next/errors/execution';\nimport type { MigrationToolsError } from '@prisma-next/migration-tools/errors';\n\nexport {\n ERROR_CODE_DESTRUCTIVE_CHANGES,\n errorDestructiveChanges,\n errorHashMismatch,\n errorMarkerMissing,\n errorMarkerRequired,\n errorRunnerFailed,\n errorRuntime,\n errorSchemaVerificationFailed,\n errorTargetMismatch,\n} from '@prisma-next/errors/execution';\nexport {\n errorMigrationFileMissing,\n errorMigrationInvalidDefaultExport,\n errorMigrationPlanNotArray,\n errorUnfilledPlaceholder,\n placeholder,\n} from '@prisma-next/errors/migration';\nexport {\n CliStructuredError,\n errorConfigFileNotFound,\n errorConfigValidation,\n errorContractConfigMissing,\n errorContractMissingExtensionPacks,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFamilyReadMarkerSqlRequired,\n errorFileNotFound,\n errorMigrationCliInvalidConfigArg,\n errorMigrationCliUnknownFlag,\n errorMigrationPlanningFailed,\n errorQueryRunnerFactoryRequired,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n};\n\n/**\n * Maps a `MigrationToolsError` raised by the migration-tools loader/graph\n * surface (`readMigrationPackage`, `readMigrationsDir`, `readRefs`,\n * `resolveRef`, `reconstructGraph`, ...) into a CLI `errorRuntime` envelope.\n *\n * The full `error.details` payload is forwarded into `meta` so machine\n * consumers (`--json`) see structural fields like `dir`, `storedHash`,\n * `computedHash` (for `MIGRATION.HASH_MISMATCH`) alongside the stable\n * `code`. The user-visible `summary`/`why`/`fix` text is unchanged.\n *\n * Callers are expected to gate on `MigrationToolsError.is(error)` first\n * (mirroring the original inline pattern); non-`MigrationToolsError`\n * values are caller-classified (rethrow, wrap with command-specific\n * `errorUnexpected`, etc.).\n */\nexport function mapMigrationToolsError(error: MigrationToolsError): CliStructuredError {\n return errorRuntime(error.message, {\n why: error.why,\n fix: error.fix,\n meta: { code: error.code, ...(error.details ?? {}) },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgFA,SAAgB,uBAAuB,OAAgD;CACrF,OAAO,aAAa,MAAM,SAAS;EACjC,KAAK,MAAM;EACX,KAAK,MAAM;EACX,MAAM;GAAE,MAAM,MAAM;GAAM,GAAI,MAAM,WAAW,EAAE;GAAG;EACrD,CAAC"}