@prisma-next/cli 0.14.0-dev.4 → 0.14.0-dev.40

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 (140) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.mjs +27 -13
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/{client-CJzuo5wX.mjs → client-CWTNqJdj.mjs} +76 -72
  5. package/dist/client-CWTNqJdj.mjs.map +1 -0
  6. package/dist/{command-helpers-DGMvGBeX.mjs → command-helpers-6cNJZ863.mjs} +3 -3
  7. package/dist/{command-helpers-DGMvGBeX.mjs.map → command-helpers-6cNJZ863.mjs.map} +1 -1
  8. package/dist/commands/contract-emit.mjs +1 -1
  9. package/dist/commands/contract-infer.mjs +1 -1
  10. package/dist/commands/db-init.mjs +3 -3
  11. package/dist/commands/db-schema.mjs +3 -3
  12. package/dist/commands/db-sign.mjs +5 -5
  13. package/dist/commands/db-sign.mjs.map +1 -1
  14. package/dist/commands/db-update.mjs +4 -4
  15. package/dist/commands/db-verify.mjs +1 -1
  16. package/dist/commands/migrate.d.mts +1 -1
  17. package/dist/commands/migrate.d.mts.map +1 -1
  18. package/dist/commands/migrate.mjs +35 -35
  19. package/dist/commands/migrate.mjs.map +1 -1
  20. package/dist/commands/migration-check.d.mts +1 -1
  21. package/dist/commands/migration-check.mjs +1 -1
  22. package/dist/commands/migration-graph.d.mts +1 -1
  23. package/dist/commands/migration-graph.mjs +8 -8
  24. package/dist/commands/migration-graph.mjs.map +1 -1
  25. package/dist/commands/migration-list.d.mts +6 -6
  26. package/dist/commands/migration-list.d.mts.map +1 -1
  27. package/dist/commands/migration-list.mjs +1 -1
  28. package/dist/commands/migration-log.d.mts +1 -1
  29. package/dist/commands/migration-log.mjs +1 -1
  30. package/dist/commands/migration-new.mjs +4 -4
  31. package/dist/commands/migration-new.mjs.map +1 -1
  32. package/dist/commands/migration-plan.mjs +1 -1
  33. package/dist/commands/migration-show.mjs +4 -4
  34. package/dist/commands/migration-show.mjs.map +1 -1
  35. package/dist/commands/migration-status.d.mts +1 -1
  36. package/dist/commands/migration-status.mjs +1 -1
  37. package/dist/commands/ref.d.mts +1 -1
  38. package/dist/commands/ref.mjs +3 -3
  39. package/dist/commands/ref.mjs.map +1 -1
  40. package/dist/commands/telemetry/index.mjs +1 -1
  41. package/dist/{contract-at-errors-CFXsstzm.mjs → contract-at-errors-DdxWRjMc.mjs} +2 -2
  42. package/dist/{contract-at-errors-CFXsstzm.mjs.map → contract-at-errors-DdxWRjMc.mjs.map} +1 -1
  43. package/dist/{contract-emit-C8HmtboH.mjs → contract-emit-CMwCj7_m.mjs} +8 -6
  44. package/dist/contract-emit-CMwCj7_m.mjs.map +1 -0
  45. package/dist/{contract-emit-B_qriF8B.mjs → contract-emit-klH7zzaV.mjs} +6 -6
  46. package/dist/contract-emit-klH7zzaV.mjs.map +1 -0
  47. package/dist/{contract-infer-BYT_ra_U.mjs → contract-infer-B__56PGb.mjs} +3 -3
  48. package/dist/{contract-infer-BYT_ra_U.mjs.map → contract-infer-B__56PGb.mjs.map} +1 -1
  49. package/dist/{contract-space-aggregate-loader-ClI1KN6d.mjs → contract-space-aggregate-loader-Bu2fjSWV.mjs} +2 -2
  50. package/dist/{contract-space-aggregate-loader-ClI1KN6d.mjs.map → contract-space-aggregate-loader-Bu2fjSWV.mjs.map} +1 -1
  51. package/dist/{db-verify-C24FKhb7.mjs → db-verify-DlqHvkkA.mjs} +69 -49
  52. package/dist/db-verify-DlqHvkkA.mjs.map +1 -0
  53. package/dist/exports/control-api.d.mts +3 -3
  54. package/dist/exports/control-api.mjs +2 -2
  55. package/dist/exports/index.mjs +2 -2
  56. package/dist/extension-pack-inputs-1ySHqxKG.mjs.map +1 -1
  57. package/dist/{format-C8yv6mXH.mjs → format-C3XdaDuA.mjs} +3 -3
  58. package/dist/format-C3XdaDuA.mjs.map +1 -0
  59. package/dist/{framework-components-YVQHhPH7.mjs → framework-components-5RljWT7Q.mjs} +2 -2
  60. package/dist/{framework-components-YVQHhPH7.mjs.map → framework-components-5RljWT7Q.mjs.map} +1 -1
  61. package/dist/{init-a3-ljrL3.mjs → init-BF3s9NcB.mjs} +3 -3
  62. package/dist/{init-a3-ljrL3.mjs.map → init-BF3s9NcB.mjs.map} +1 -1
  63. package/dist/{inspect-live-schema-DF6IwcDl.mjs → inspect-live-schema-Dd1Ft0dw.mjs} +4 -4
  64. package/dist/inspect-live-schema-Dd1Ft0dw.mjs.map +1 -0
  65. package/dist/{migration-check-VwM8xCZV.mjs → migration-check-UoHMvsP3.mjs} +10 -11
  66. package/dist/migration-check-UoHMvsP3.mjs.map +1 -0
  67. package/dist/migration-cli.mjs +1 -1
  68. package/dist/migration-cli.mjs.map +1 -1
  69. package/dist/{migration-command-scaffold-DA-Lhx6o.mjs → migration-command-scaffold-DW2BpjZW.mjs} +4 -4
  70. package/dist/migration-command-scaffold-DW2BpjZW.mjs.map +1 -0
  71. package/dist/{migration-list-DlJJ_38Z.mjs → migration-list-BOzQzJK4.mjs} +15 -15
  72. package/dist/migration-list-BOzQzJK4.mjs.map +1 -0
  73. package/dist/{migration-log-CG0qQAFm.mjs → migration-log-q50rqMiU.mjs} +4 -4
  74. package/dist/migration-log-q50rqMiU.mjs.map +1 -0
  75. package/dist/{migration-path-target-Ce6OZImp.mjs → migration-path-target-zK6RG6JY.mjs} +2 -2
  76. package/dist/{migration-path-target-Ce6OZImp.mjs.map → migration-path-target-zK6RG6JY.mjs.map} +1 -1
  77. package/dist/{migration-plan-W_E8FQOk.mjs → migration-plan-BwJLPkwV.mjs} +24 -24
  78. package/dist/migration-plan-BwJLPkwV.mjs.map +1 -0
  79. package/dist/{migration-status-CD-LC2Ip.mjs → migration-status-27NzO2SC.mjs} +13 -14
  80. package/dist/migration-status-27NzO2SC.mjs.map +1 -0
  81. package/dist/{telemetry-BIM4beEO.mjs → telemetry-BckOSUWG.mjs} +2 -2
  82. package/dist/{telemetry-BIM4beEO.mjs.map → telemetry-BckOSUWG.mjs.map} +1 -1
  83. package/dist/{types-C_tYiJYx.d.mts → types-CKgJmH02.d.mts} +26 -20
  84. package/dist/types-CKgJmH02.d.mts.map +1 -0
  85. package/dist/{verify-DcOYZ1tH.mjs → verify-DC14_nPu.mjs} +29 -6
  86. package/dist/verify-DC14_nPu.mjs.map +1 -0
  87. package/package.json +21 -24
  88. package/src/cli.ts +3 -0
  89. package/src/commands/contract-emit.ts +1 -1
  90. package/src/commands/db-sign.ts +1 -1
  91. package/src/commands/db-verify.ts +32 -20
  92. package/src/commands/inspect-live-schema.ts +1 -1
  93. package/src/commands/lsp.ts +32 -0
  94. package/src/commands/migrate.ts +45 -42
  95. package/src/commands/migration-check.ts +6 -6
  96. package/src/commands/migration-graph.ts +5 -5
  97. package/src/commands/migration-list.ts +13 -13
  98. package/src/commands/migration-log.ts +1 -1
  99. package/src/commands/migration-new.ts +1 -1
  100. package/src/commands/migration-plan.ts +4 -4
  101. package/src/commands/migration-show.ts +1 -1
  102. package/src/commands/migration-status.ts +10 -10
  103. package/src/commands/ref.ts +1 -1
  104. package/src/control-api/client.ts +5 -3
  105. package/src/control-api/operations/contract-emit.ts +8 -7
  106. package/src/control-api/operations/db-init.ts +2 -2
  107. package/src/control-api/operations/db-run.ts +7 -7
  108. package/src/control-api/operations/db-verify.ts +38 -33
  109. package/src/control-api/operations/format.ts +1 -2
  110. package/src/control-api/operations/migrate.ts +66 -66
  111. package/src/control-api/operations/run-migration.ts +2 -2
  112. package/src/control-api/types.ts +7 -7
  113. package/src/migration-cli.ts +1 -1
  114. package/src/utils/combine-verify-results.ts +113 -0
  115. package/src/utils/extension-pack-inputs.ts +1 -1
  116. package/src/utils/formatters/verify.ts +44 -3
  117. package/src/utils/migration-command-scaffold.ts +1 -1
  118. package/src/utils/plan-resolution.ts +18 -18
  119. package/dist/client-CJzuo5wX.mjs.map +0 -1
  120. package/dist/config-loader-p9JMrekQ.mjs +0 -88
  121. package/dist/config-loader-p9JMrekQ.mjs.map +0 -1
  122. package/dist/config-loader.d.mts +0 -16
  123. package/dist/config-loader.d.mts.map +0 -1
  124. package/dist/config-loader.mjs +0 -2
  125. package/dist/contract-emit-B_qriF8B.mjs.map +0 -1
  126. package/dist/contract-emit-C8HmtboH.mjs.map +0 -1
  127. package/dist/db-verify-C24FKhb7.mjs.map +0 -1
  128. package/dist/format-C8yv6mXH.mjs.map +0 -1
  129. package/dist/inspect-live-schema-DF6IwcDl.mjs.map +0 -1
  130. package/dist/migration-check-VwM8xCZV.mjs.map +0 -1
  131. package/dist/migration-command-scaffold-DA-Lhx6o.mjs.map +0 -1
  132. package/dist/migration-list-DlJJ_38Z.mjs.map +0 -1
  133. package/dist/migration-log-CG0qQAFm.mjs.map +0 -1
  134. package/dist/migration-plan-W_E8FQOk.mjs.map +0 -1
  135. package/dist/migration-status-CD-LC2Ip.mjs.map +0 -1
  136. package/dist/types-C_tYiJYx.d.mts.map +0 -1
  137. package/dist/verify-DcOYZ1tH.mjs.map +0 -1
  138. package/src/config-loader.ts +0 -92
  139. package/src/config-path-validation.ts +0 -74
  140. package/src/utils/combine-schema-results.ts +0 -84
@@ -98,9 +98,9 @@ export interface ExecuteRunOptions<TFamilyId extends string, TTargetId extends s
98
98
  * 2. **Read DB state**: marker rows (`familyInstance.readAllMarkers`)
99
99
  * + introspected schema (`familyInstance.introspect`).
100
100
  * 3. **Plan**: {@link planMigration} chooses graph-walk vs synth per
101
- * member according to `callerPolicy.ignoreGraphFor`. The app member
101
+ * space according to `callerPolicy.ignoreGraphFor`. The app space
102
102
  * is forced through synth (today's daily-driver behaviour); every
103
- * extension member walks its on-disk graph.
103
+ * extension space walks its on-disk graph.
104
104
  * 4. **Apply** (when `mode === 'apply'`): every per-space `MigrationPlan`
105
105
  * feeds into the runner's `execute` — one outer
106
106
  * transaction across every space; failure on any space rolls back
@@ -200,7 +200,7 @@ export async function executeRun<TFamilyId extends string, TTargetId extends str
200
200
  const appResolution = orderedResolutions.find((r) => r.spaceId === aggregate.app.spaceId);
201
201
  if (!appResolution) {
202
202
  throw new Error(
203
- 'Aggregate planner returned no plan for the app member — the planner is supposed to always emit one.',
203
+ 'Aggregate planner returned no plan for the app space — the planner is supposed to always emit one.',
204
204
  );
205
205
  }
206
206
  const appPlan = appResolution.entry.plan;
@@ -280,14 +280,14 @@ function aggregatePlannerWarnings(
280
280
 
281
281
  /**
282
282
  * Compare the live `_prisma_marker` rows against the aggregate's
283
- * declared members. Any marker row whose `space` is not a member of
283
+ * declared contract spaces. Any marker row whose `space` is not a space of
284
284
  * the aggregate is an "orphan" — typically a marker left behind by
285
285
  * an extension that was removed from `extensionPacks` without first
286
286
  * cleaning up its on-disk migrations / database tables.
287
287
  *
288
288
  * Returns a {@link CliStructuredError} envelope (code `5002`,
289
289
  * `kind: 'orphanMarker'`) for the first orphan it finds, or `null`
290
- * when every marker row maps to a declared member. Mirrors the M2
290
+ * when every marker row maps to a declared contract space. Mirrors the M2
291
291
  * `runContractSpaceVerifierMarkerCheck` envelope so downstream
292
292
  * tooling (integration tests, JSON consumers) keeps asserting on the
293
293
  * same shape.
@@ -296,13 +296,13 @@ function detectOrphanMarkers(
296
296
  aggregate: ContractSpaceAggregate,
297
297
  markerRows: ReadonlyMap<string, unknown>,
298
298
  ): CliStructuredError | null {
299
- const memberSpaceIds = new Set<string>([
299
+ const aggregateSpaceIds = new Set<string>([
300
300
  aggregate.app.spaceId,
301
301
  ...aggregate.extensions.map((m) => m.spaceId),
302
302
  ]);
303
303
  const orphans: string[] = [];
304
304
  for (const [spaceId, row] of markerRows) {
305
- if (row !== null && row !== undefined && !memberSpaceIds.has(spaceId)) {
305
+ if (row !== null && row !== undefined && !aggregateSpaceIds.has(spaceId)) {
306
306
  orphans.push(spaceId);
307
307
  }
308
308
  }
@@ -7,13 +7,13 @@ import type {
7
7
  VerifyDatabaseSchemaResult,
8
8
  } from '@prisma-next/framework-components/control';
9
9
  import {
10
- type ContractSpaceMember,
10
+ type AggregateContractSpace,
11
11
  collectAggregateNamespaces,
12
12
  requireHeadRef,
13
13
  type VerifierOutput,
14
14
  verifyMigration,
15
15
  } from '@prisma-next/migration-tools/aggregate';
16
- import { blindCast, castAs } from '@prisma-next/utils/casts';
16
+ import { castAs } from '@prisma-next/utils/casts';
17
17
  import { notOk, ok, type Result } from '@prisma-next/utils/result';
18
18
  import { CliStructuredError } from '../../utils/cli-errors';
19
19
  import {
@@ -37,9 +37,9 @@ const SPAN_IDS = {
37
37
  *
38
38
  * Loader → verifier pipeline. The loader (sole descriptor-import
39
39
  * boundary) builds a {@link import('@prisma-next/migration-tools/aggregate').ContractSpaceAggregate};
40
- * the aggregate verifier bundles `markerCheck` + per-space pre-projected
41
- * `schemaCheck`. `mode: 'strict' | 'lenient'` maps directly to the user
42
- * facing `--strict` flag.
40
+ * the aggregate verifier bundles `markerCheck` + per-space `schemaCheck`
41
+ * (each contract space verified against the full schema; extras stripped to its own view).
42
+ * `mode: 'strict' | 'lenient'` maps directly to the user facing `--strict` flag.
43
43
  */
44
44
  export interface ExecuteDbVerifyOptions<TFamilyId extends string, TTargetId extends string> {
45
45
  readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
@@ -63,13 +63,19 @@ export interface ExecuteDbVerifyOptions<TFamilyId extends string, TTargetId exte
63
63
  * emitted, so downstream tooling and integration tests assert on the
64
64
  * same shape).
65
65
  *
66
- * On success, the per-space schema results are returned for the CLI to
66
+ * On success, the per-space verify results are returned for the CLI to
67
67
  * render. When `skipSchema` is true (`--marker-only`), the schema map
68
68
  * is empty.
69
69
  */
70
70
  export interface ExecuteDbVerifySuccess {
71
71
  readonly schemaResults: ReadonlyMap<string, VerifyDatabaseSchemaResult>;
72
- readonly memberOrder: readonly string[];
72
+ /**
73
+ * Live element names no contract space declares, deduplicated and reported
74
+ * once for the whole database (never per space). Strict mode fails on a
75
+ * non-empty list; lenient mode surfaces it informationally.
76
+ */
77
+ readonly unclaimed: readonly string[];
78
+ readonly spaceOrder: readonly string[];
73
79
  readonly appSpaceId: string;
74
80
  }
75
81
 
@@ -85,11 +91,11 @@ export type ExecuteDbVerifyResult = Result<ExecuteDbVerifySuccess, CliStructured
85
91
  * structured CLI error.
86
92
  * 2. **Read DB state**: marker rows + (when `skipSchema` is `false`)
87
93
  * schema introspection.
88
- * 3. **Verify**: {@link verifyMigration} returns per-space
89
- * `markerCheck` + per-space pre-projected `schemaCheck` (closes F23).
90
- * Marker mismatches map to `CliStructuredError` (code `5002`) so
91
- * callers (CLI command) can render and exit. Schema results are
92
- * returned to the caller verbatim.
94
+ * 3. **Verify**: {@link verifyMigration} returns per-space `markerCheck` +
95
+ * per-space `schemaCheck` (each contract space verified against the full schema,
96
+ * then scoped to its own contract space). Marker mismatches map to
97
+ * `CliStructuredError` (code `5002`) so callers (CLI command) can render
98
+ * and exit. Verify results are returned to the caller verbatim.
93
99
  */
94
100
  export async function executeDbVerify<TFamilyId extends string, TTargetId extends string>(
95
101
  options: ExecuteDbVerifyOptions<TFamilyId, TTargetId>,
@@ -115,7 +121,7 @@ export async function executeDbVerify<TFamilyId extends string, TTargetId extend
115
121
  markersBySpaceId,
116
122
  schemaIntrospection,
117
123
  mode: options.mode,
118
- verifySchemaForMember: createPerMemberVerifier(options),
124
+ verifySchemaForSpace: createPerSpaceVerifier(options),
119
125
  });
120
126
  return finaliseVerifyResult({ verifyResult, aggregate, skipMarker, onProgress });
121
127
  }
@@ -166,30 +172,27 @@ async function runIntrospection<TFamilyId extends string, TTargetId extends stri
166
172
  }
167
173
 
168
174
  /**
169
- * Build the per-member schema callback handed to the aggregate verifier.
175
+ * Build the per-space schema callback handed to the aggregate verifier.
170
176
  * When `skipSchema` is true the callback short-circuits with a synthetic
171
177
  * `ok` result so the verifier still runs the (cheap) schemaCheck loop
172
178
  * without invoking the family's verification path.
173
179
  */
174
- export function createPerMemberVerifier<TFamilyId extends string, TTargetId extends string>(
180
+ export function createPerSpaceVerifier<TFamilyId extends string, TTargetId extends string>(
175
181
  options: ExecuteDbVerifyOptions<TFamilyId, TTargetId>,
176
182
  ): (
177
- projectedSchema: unknown,
178
- member: ContractSpaceMember,
183
+ schema: unknown,
184
+ space: AggregateContractSpace,
179
185
  verifyMode: 'strict' | 'lenient',
180
186
  ) => VerifyDatabaseSchemaResult {
181
187
  const { skipSchema, familyInstance, frameworkComponents } = options;
182
- return (projectedSchema, member, verifyMode) => {
183
- if (skipSchema) return buildSkippedSchemaResult(member);
188
+ return (schema, space, verifyMode) => {
189
+ if (skipSchema) return buildSkippedSchemaResult(space);
184
190
  return familyInstance.verifySchema({
185
- contract: member.contract(),
186
- // The family's `TSchemaIR` is opaque to migration-tools; the
187
- // aggregate verifier passes through whatever we hand it. The
188
- // family expects its own IR shape on the way back.
189
- schema: blindCast<
190
- never,
191
- 'family TSchemaIR is opaque to migration-tools; projectedSchema is passed straight through'
192
- >(projectedSchema),
191
+ contract: space.contract(),
192
+ // `familyInstance` is `ControlFamilyInstance<_, unknown>`, so `verifySchema`
193
+ // takes its `TSchemaIR` as `unknown` the introspected schema passes
194
+ // straight through; the family narrows to its own IR node internally.
195
+ schema,
193
196
  strict: verifyMode === 'strict',
194
197
  frameworkComponents,
195
198
  });
@@ -223,7 +226,7 @@ function emitVerifySpan(
223
226
  * by the CLI's `--schema-only` mode.
224
227
  */
225
228
  function finaliseVerifyResult(args: {
226
- verifyResult: VerifierOutput<VerifyDatabaseSchemaResult>;
229
+ verifyResult: VerifierOutput;
227
230
  aggregate: {
228
231
  readonly app: { readonly spaceId: string };
229
232
  readonly extensions: ReadonlyArray<{ readonly spaceId: string }>;
@@ -253,14 +256,15 @@ function finaliseVerifyResult(args: {
253
256
  emitVerifySpan(onProgress, 'spanEndOk');
254
257
  return ok({
255
258
  schemaResults: verifyResult.value.schemaCheck.perSpace,
256
- memberOrder: [aggregate.app.spaceId, ...aggregate.extensions.map((e) => e.spaceId)],
259
+ unclaimed: verifyResult.value.schemaCheck.unclaimed,
260
+ spaceOrder: [aggregate.app.spaceId, ...aggregate.extensions.map((e) => e.spaceId)],
257
261
  appSpaceId: aggregate.app.spaceId,
258
262
  });
259
263
  }
260
264
 
261
- function buildSkippedSchemaResult(member: ContractSpaceMember): VerifyDatabaseSchemaResult {
262
- const contract = member.contract();
263
- const headRef = requireHeadRef(member);
265
+ function buildSkippedSchemaResult(space: AggregateContractSpace): VerifyDatabaseSchemaResult {
266
+ const contract = space.contract();
267
+ const headRef = requireHeadRef(space);
264
268
  const profileHash = castAs<{ profileHash?: string }>(contract).profileHash;
265
269
  return {
266
270
  ok: true,
@@ -272,10 +276,11 @@ function buildSkippedSchemaResult(member: ContractSpaceMember): VerifyDatabaseSc
272
276
  target: { expected: contract.target },
273
277
  schema: {
274
278
  issues: [],
279
+ schemaDiffIssues: [],
275
280
  root: {
276
281
  status: 'pass',
277
282
  kind: 'skipped',
278
- name: member.spaceId,
283
+ name: space.spaceId,
279
284
  contractPath: '',
280
285
  code: 'SKIPPED',
281
286
  message: 'Schema verification skipped',
@@ -1,13 +1,12 @@
1
1
  import { readFile, writeFile } from 'node:fs/promises';
2
2
  import { EOL } from 'node:os';
3
+ import { loadConfig } from '@prisma-next/config-loader';
3
4
  import { type FormatOptions, format, PslFormatError } from '@prisma-next/psl-parser/format';
4
5
  import { notOk, ok, type Result } from '@prisma-next/utils/result';
5
- import { loadConfig } from '../../config-loader';
6
6
  import { CliStructuredError, errorRuntime, errorUnexpected } from '../../utils/cli-errors';
7
7
 
8
8
  export interface FormatOperationOptions {
9
9
  readonly configPath?: string;
10
- /** Injected at the CLI boundary so the formatter engine never reads `os`. */
11
10
  readonly eol?: string;
12
11
  }
13
12
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Backs the `migrate` command. Strategy: graph-walk-all-members, replay-only (no introspect/synth/planner).
2
+ * Backs the `migrate` command. Strategy: graph-walk-all-spaces, replay-only (no introspect/synth/planner).
3
3
  */
4
4
 
5
5
  import type { Contract } from '@prisma-next/contract/types';
@@ -11,10 +11,10 @@ import type {
11
11
  TargetMigrationsCapability,
12
12
  } from '@prisma-next/framework-components/control';
13
13
  import {
14
+ type AggregateContractSpace,
14
15
  buildSynthMigrationEdge,
15
16
  type ContractMarkerRecordLike,
16
17
  type ContractSpaceAggregate,
17
- type ContractSpaceMember,
18
18
  graphWalkStrategy,
19
19
  type PerSpacePlan,
20
20
  requireHeadRef,
@@ -62,8 +62,8 @@ export interface ExecuteMigrateOptions<TFamilyId extends string, TTargetId exten
62
62
  readonly extensionPacks: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
63
63
  readonly targetId: TTargetId;
64
64
  /**
65
- * Optional app-space ref override. When provided, the app member's
66
- * graph-walk targets this hash instead of `member.headRef.hash`.
65
+ * Optional app-space ref override. When provided, the app space's
66
+ * graph-walk targets this hash instead of `space.headRef.hash`.
67
67
  * Extensions are unaffected — they always walk to their own head.
68
68
  */
69
69
  readonly refHash?: string;
@@ -72,7 +72,7 @@ export interface ExecuteMigrateOptions<TFamilyId extends string, TTargetId exten
72
72
  * Threaded into the graph-walk's `required` calculation so the
73
73
  * planner picks an invariant-bearing path and surfaces the
74
74
  * required/satisfied set on the success envelope. When `refHash`
75
- * is absent the file's `member.headRef.invariants` are used.
75
+ * is absent the file's `space.headRef.invariants` are used.
76
76
  */
77
77
  readonly refInvariants?: readonly string[];
78
78
  /**
@@ -89,16 +89,16 @@ export interface ExecuteMigrateOptions<TFamilyId extends string, TTargetId exten
89
89
  /**
90
90
  * Apply pending migrations across every contract space (app +
91
91
  * extensions). Replay-only: graph-walk against the on-disk graph for
92
- * every member; no synth, no introspection.
92
+ * every contract space; no synth, no introspection.
93
93
  *
94
94
  * Pipeline:
95
95
  *
96
96
  * 1. Load aggregate from disk (loader hydrates extension graphs;
97
97
  * caller provides app-space packages).
98
98
  * 2. Read live marker rows per space (`familyInstance.readAllMarkers`).
99
- * 3. Per member: `graphWalkStrategy` plots the path from the live
100
- * marker to `member.headRef.hash` (or `refHash` for the app
101
- * member when provided). Empty-graph members fail loudly — a
99
+ * 3. Per space: `graphWalkStrategy` plots the path from the live
100
+ * marker to `space.headRef.hash` (or `refHash` for the app
101
+ * space when provided). Empty-graph spaces fail loudly — a
102
102
  * "never planned" space is a user-error condition for replay.
103
103
  * 4. Hand off to {@link runMigration} (the runner-driving tail
104
104
  * shared with `db init` / `db update`). Marker advancement is
@@ -140,41 +140,41 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
140
140
 
141
141
  const markerRows = await familyInstance.readAllMarkers({ driver });
142
142
 
143
- // Plan every member via graph-walk. App member targets `refHash`
143
+ // Plan every space via graph-walk. App space targets `refHash`
144
144
  // when provided, otherwise its own head; extensions always walk
145
145
  // to their own head ref.
146
- const allMembers: ReadonlyArray<ContractSpaceMember> = [aggregate.app, ...aggregate.extensions];
146
+ const allSpaces: ReadonlyArray<AggregateContractSpace> = [aggregate.app, ...aggregate.extensions];
147
147
  const perSpacePlans = new Map<string, PerSpacePlan>();
148
- // Already-at-head empty-graph members (typically extensions whose
148
+ // Already-at-head empty-graph spaces (typically extensions whose
149
149
  // head ref is the empty sentinel, or whose live marker already
150
150
  // matches the target). Kept out of the runner schedule so we don't
151
151
  // write spurious markers for greenfield extensions, but merged back
152
- // into the success envelope so every loaded member is represented.
152
+ // into the success envelope so every loaded space is represented.
153
153
  const atHeadResolutions = new Map<string, PerSpacePlan>();
154
- for (const member of allMembers) {
155
- const isAppMember = member.spaceId === aggregate.app.spaceId;
156
- // The aggregate passed the integrity gate, so every member's head ref
154
+ for (const space of allSpaces) {
155
+ const isAppSpace = space.spaceId === aggregate.app.spaceId;
156
+ // The aggregate passed the integrity gate, so every space's head ref
157
157
  // is resolved (the app's is synthesised from the live contract).
158
- const headRef = requireHeadRef(member);
159
- const memberTargetHash = isAppMember && refHash !== undefined ? refHash : headRef.hash;
160
- const memberRefInvariants = isAppMember && refHash !== undefined ? refInvariants : undefined;
161
- const liveMarker = markerRows.get(member.spaceId) ?? null;
158
+ const headRef = requireHeadRef(space);
159
+ const spaceTargetHash = isAppSpace && refHash !== undefined ? refHash : headRef.hash;
160
+ const spaceRefInvariants = isAppSpace && refHash !== undefined ? refInvariants : undefined;
161
+ const liveMarker = markerRows.get(space.spaceId) ?? null;
162
162
 
163
- const outcome = planMemberPath({
164
- member,
163
+ const outcome = planSpacePath({
164
+ space,
165
165
  aggregate,
166
- targetHash: memberTargetHash,
167
- refInvariants: memberRefInvariants,
166
+ targetHash: spaceTargetHash,
167
+ refInvariants: spaceRefInvariants,
168
168
  liveMarker,
169
- ...(isAppMember ? { refName } : {}),
169
+ ...(isAppSpace ? { refName } : {}),
170
170
  });
171
171
 
172
172
  if (outcome.kind === 'at-head') {
173
- // Empty-graph member whose live marker already matches the target.
173
+ // Empty-graph space whose live marker already matches the target.
174
174
  // Kept out of the runner schedule so we don't write spurious markers
175
175
  // for greenfield extensions, but merged back into the success envelope
176
- // so every loaded member is represented.
177
- atHeadResolutions.set(member.spaceId, outcome.plan);
176
+ // so every loaded space is represented.
177
+ atHeadResolutions.set(space.spaceId, outcome.plan);
178
178
  continue;
179
179
  }
180
180
  if (outcome.kind === 'never-planned') {
@@ -197,9 +197,9 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
197
197
  // is never a graph node, producing an empty `structuralPath` and
198
198
  // a less actionable diagnostic.
199
199
  const structural = findPathWithDecision(
200
- outcome.targetMember.graph(),
200
+ outcome.targetSpace.graph(),
201
201
  outcome.liveHash,
202
- memberTargetHash,
202
+ spaceTargetHash,
203
203
  { required: new Set<string>() },
204
204
  );
205
205
  const structuralPath =
@@ -220,14 +220,14 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
220
220
  });
221
221
  }
222
222
 
223
- perSpacePlans.set(member.spaceId, outcome.plan);
223
+ perSpacePlans.set(space.spaceId, outcome.plan);
224
224
  }
225
225
 
226
226
  const canonicalOrder = [...aggregate.extensions.map((m) => m.spaceId), aggregate.app.spaceId];
227
227
  const applyOrder = canonicalOrder.filter((spaceId) => perSpacePlans.has(spaceId));
228
228
 
229
229
  // Short-circuit: nothing pending across any space (no runner-bound
230
- // plans). Surfaces every loaded member — including at-head empty-
230
+ // plans). Surfaces every loaded space — including at-head empty-
231
231
  // graph extensions — in `perSpace[]` so the result reflects the
232
232
  // full aggregate, not just the spaces the runner would have touched.
233
233
  const totalPlannedOps = sumPlannedOps(applyOrder, perSpacePlans);
@@ -285,7 +285,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
285
285
  }
286
286
 
287
287
  // Merge at-head zero-op resolutions back into the canonical order
288
- // so the success envelope surfaces every loaded member, not just
288
+ // so the success envelope surfaces every loaded space, not just
289
289
  // those the runner executed.
290
290
  const orderedAll = canonicalOrder
291
291
  .filter((spaceId) => perSpacePlans.has(spaceId) || atHeadResolutions.has(spaceId))
@@ -321,7 +321,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
321
321
  }
322
322
 
323
323
  /**
324
- * Outcome variants for one member's path computation.
324
+ * Outcome variants for one space's path computation.
325
325
  *
326
326
  * Callers switch on `kind` and map to their own error representation:
327
327
  * `executeMigrate` throws / returns `notOk`; `executeMigrateShowCommand`
@@ -330,7 +330,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
330
330
  *
331
331
  * @internal Exported for `executeMigrateShowCommand` to call.
332
332
  */
333
- export type MemberPathOutcome =
333
+ export type SpacePathOutcome =
334
334
  | { readonly kind: 'ok'; readonly plan: PerSpacePlan }
335
335
  | { readonly kind: 'at-head'; readonly plan: PerSpacePlan }
336
336
  | { readonly kind: 'never-planned'; readonly spaceId: string; readonly targetHash: string }
@@ -343,16 +343,16 @@ export type MemberPathOutcome =
343
343
  | {
344
344
  readonly kind: 'unsatisfiable';
345
345
  readonly spaceId: string;
346
- readonly isAppMember: boolean;
346
+ readonly isAppSpace: boolean;
347
347
  readonly missing: readonly string[];
348
348
  readonly targetInvariants: readonly string[];
349
- readonly targetMember: ContractSpaceMember;
349
+ readonly targetSpace: AggregateContractSpace;
350
350
  readonly liveHash: string;
351
351
  readonly refName: string | undefined;
352
352
  };
353
353
 
354
354
  /**
355
- * Compute the graph-walk path for one contract-space member.
355
+ * Compute the graph-walk path for one contract space.
356
356
  *
357
357
  * Encapsulates the invariant-correct input assembly that both
358
358
  * `executeMigrate` and `executeMigrateShowCommand` must use:
@@ -361,71 +361,71 @@ export type MemberPathOutcome =
361
361
  * - `targetInvariants` uses the caller-supplied `refInvariants` when a
362
362
  * `--to` ref was resolved (not always the file head ref's invariants).
363
363
  *
364
- * Both callers map the returned `MemberPathOutcome` to their own error
364
+ * Both callers map the returned `SpacePathOutcome` to their own error
365
365
  * representation; the path-compute logic is shared and identical.
366
366
  *
367
367
  * @internal Exported for `executeMigrateShowCommand`.
368
368
  */
369
- export function planMemberPath({
370
- member,
369
+ export function planSpacePath({
370
+ space,
371
371
  aggregate,
372
372
  targetHash,
373
373
  refInvariants,
374
374
  liveMarker,
375
375
  refName,
376
376
  }: {
377
- readonly member: ContractSpaceMember;
377
+ readonly space: AggregateContractSpace;
378
378
  readonly aggregate: Pick<ContractSpaceAggregate, 'targetId' | 'app'>;
379
379
  readonly targetHash: string;
380
380
  readonly refInvariants: readonly string[] | undefined;
381
381
  readonly liveMarker: ContractMarkerRecordLike | null;
382
382
  readonly refName?: string;
383
- }): MemberPathOutcome {
384
- const isAppMember = member.spaceId === aggregate.app.spaceId;
385
- const headRef = requireHeadRef(member);
383
+ }): SpacePathOutcome {
384
+ const isAppSpace = space.spaceId === aggregate.app.spaceId;
385
+ const headRef = requireHeadRef(space);
386
386
 
387
- if (member.graph().nodes.size === 0) {
387
+ if (space.graph().nodes.size === 0) {
388
388
  const liveHash = liveMarker?.storageHash;
389
389
  if (targetHash === liveHash || (liveHash === undefined && targetHash === EMPTY_CONTRACT_HASH)) {
390
390
  return {
391
391
  kind: 'at-head',
392
392
  plan: buildAtHeadResolution({
393
393
  aggregateTargetId: aggregate.targetId,
394
- member,
394
+ space,
395
395
  targetHash,
396
396
  liveMarker,
397
397
  }),
398
398
  };
399
399
  }
400
- return { kind: 'never-planned', spaceId: member.spaceId, targetHash };
400
+ return { kind: 'never-planned', spaceId: space.spaceId, targetHash };
401
401
  }
402
402
 
403
403
  const targetInvariants =
404
- isAppMember && refInvariants !== undefined ? refInvariants : headRef.invariants;
405
- const targetMember: ContractSpaceMember =
404
+ isAppSpace && refInvariants !== undefined ? refInvariants : headRef.invariants;
405
+ const targetSpace: AggregateContractSpace =
406
406
  targetHash === headRef.hash && targetInvariants === headRef.invariants
407
- ? member
408
- : { ...member, headRef: { hash: targetHash, invariants: targetInvariants } };
407
+ ? space
408
+ : { ...space, headRef: { hash: targetHash, invariants: targetInvariants } };
409
409
 
410
410
  const walked = graphWalkStrategy({
411
411
  aggregateTargetId: aggregate.targetId,
412
- member: targetMember,
412
+ space: targetSpace,
413
413
  currentMarker: liveMarker,
414
- ...(isAppMember && refName !== undefined ? { refName } : {}),
414
+ ...(isAppSpace && refName !== undefined ? { refName } : {}),
415
415
  });
416
416
 
417
417
  if (walked.kind === 'unreachable') {
418
- return { kind: 'unreachable', spaceId: member.spaceId, liveMarker, targetHash };
418
+ return { kind: 'unreachable', spaceId: space.spaceId, liveMarker, targetHash };
419
419
  }
420
420
  if (walked.kind === 'unsatisfiable') {
421
421
  const liveHash = liveMarker?.storageHash ?? EMPTY_CONTRACT_HASH;
422
422
  return {
423
423
  kind: 'unsatisfiable',
424
- spaceId: member.spaceId,
425
- isAppMember,
424
+ spaceId: space.spaceId,
425
+ isAppSpace,
426
426
  missing: walked.missing,
427
427
  targetInvariants,
428
- targetMember,
428
+ targetSpace,
429
429
  liveHash,
430
430
  refName,
431
431
  };
@@ -435,29 +435,29 @@ export function planMemberPath({
435
435
 
436
436
  /**
437
437
  * Build a zero-op {@link PerSpacePlan} for an empty-graph
438
- * member whose live marker already matches the target. Lets the apply
439
- * pipeline thread the member through `perSpacePlans` -> `applyOrder`
438
+ * space whose live marker already matches the target. Lets the apply
439
+ * pipeline thread the space through `perSpacePlans` -> `applyOrder`
440
440
  * -> the success envelope's `perSpace[]` block so the result reflects
441
441
  * every loaded space, even when there is nothing to execute.
442
442
  */
443
443
  function buildAtHeadResolution(args: {
444
444
  readonly aggregateTargetId: string;
445
- readonly member: ContractSpaceMember;
445
+ readonly space: AggregateContractSpace;
446
446
  readonly targetHash: string;
447
447
  readonly liveMarker: ContractMarkerRecordLike | null;
448
448
  }): PerSpacePlan {
449
- const { aggregateTargetId, member, targetHash, liveMarker } = args;
449
+ const { aggregateTargetId, space, targetHash, liveMarker } = args;
450
450
  return {
451
451
  plan: {
452
452
  targetId: aggregateTargetId,
453
- spaceId: member.spaceId,
453
+ spaceId: space.spaceId,
454
454
  origin: liveMarker === null ? null : { storageHash: liveMarker.storageHash },
455
455
  destination: { storageHash: targetHash },
456
456
  operations: [],
457
457
  providedInvariants: [],
458
458
  },
459
459
  displayOps: [],
460
- destinationContract: member.contract(),
460
+ destinationContract: space.contract(),
461
461
  strategy: 'graph-walk',
462
462
  migrationEdges: [
463
463
  buildSynthMigrationEdge({
@@ -494,7 +494,7 @@ interface BuildSuccessArgs {
494
494
  }
495
495
 
496
496
  function buildSuccess(args: BuildSuccessArgs): MigrateSuccess {
497
- // The marker hash surfaced at the top level is the **app member's**
497
+ // The marker hash surfaced at the top level is the **app space's**
498
498
  // post-migrate marker (the top-level `markerHash` field).
499
499
  // Per-space markers live on `perSpace[].marker.storageHash`.
500
500
  const appResolution = args.orderedResolutions.find(
@@ -586,7 +586,7 @@ export function buildPathNotFoundFailure(
586
586
  const fromHash = marker?.storageHash ?? '<empty>';
587
587
  // The app-case phrasing names the user-visible condition (a
588
588
  // contract has been emitted that no on-disk migration reaches) so
589
- // the error reads naturally for the app member. Extension spaces
589
+ // the error reads naturally for the app space. Extension spaces
590
590
  // see the same condition expressed against the offending space.
591
591
  const summary =
592
592
  spaceId === 'app'
@@ -48,7 +48,7 @@ export interface RunMigrationInputs<TFamilyId extends string, TTargetId extends
48
48
  * {@link planMigration} pipeline (`db init` / `db update` — synth
49
49
  * for the app, graph-walk for extensions) or by direct
50
50
  * {@link graphWalkStrategy} calls (`migrate` — graph-walk
51
- * for every member). Either way, the runner consumes the same shape.
51
+ * for every contract space). Either way, the runner consumes the same shape.
52
52
  */
53
53
  readonly perSpacePlans: ReadonlyMap<string, PerSpacePlan>;
54
54
  /**
@@ -229,7 +229,7 @@ export function buildPerSpaceBreakdown(
229
229
 
230
230
  /**
231
231
  * Materialise the `applyOrder` ordering into resolved per-space
232
- * entries. Throws if the planner output is missing a member listed
232
+ * entries. Throws if the planner output is missing a contract space listed
233
233
  * in `applyOrder` — a wiring bug that should never reach runtime.
234
234
  *
235
235
  * Exported so callers building their own success envelopes after a
@@ -557,9 +557,9 @@ export interface MigrateOptions {
557
557
  /** Migrations root directory (`migrations/` under the project). */
558
558
  readonly migrationsDir: string;
559
559
  /**
560
- * Optional app-space ref override. When provided, the app member's
560
+ * Optional app-space ref override. When provided, the app space's
561
561
  * graph-walk targets this hash instead of `contract.storage.storageHash`.
562
- * Extension members always walk to their own `headRef.hash`.
562
+ * Extension spaces always walk to their own `headRef.hash`.
563
563
  */
564
564
  readonly refHash?: string;
565
565
  /**
@@ -631,17 +631,17 @@ export interface MigrateRanEntry {
631
631
 
632
632
  /**
633
633
  * Successful migrate result. Carries both the top-level fields
634
- * (`markerHash` is the **app member's** post-migrate marker) and the
634
+ * (`markerHash` is the **app space's** post-migrate marker) and the
635
635
  * per-space breakdown (`perSpace` — markers / operations in canonical
636
636
  * schedule order).
637
637
  */
638
638
  /**
639
- * Path-decision summary for the **app member** post-migrate. Surfaced
639
+ * Path-decision summary for the **app space** post-migrate. Surfaced
640
640
  * at the top level (and consumed by the cli-journeys suite, which
641
641
  * inspects `requiredInvariants`/`satisfiedInvariants`/
642
642
  * `selectedPath` to validate invariant routing).
643
643
  *
644
- * Per-space path decisions for extension members are not surfaced —
644
+ * Per-space path decisions for extension spaces are not surfaced —
645
645
  * extensions own their own ref/invariant control.
646
646
  */
647
647
  export interface MigratePathDecision {
@@ -673,7 +673,7 @@ export interface MigrateSuccess {
673
673
  */
674
674
  readonly perSpace: ReadonlyArray<PerSpaceExecutionEntry>;
675
675
  /**
676
- * Path-decision data for the app member. Present whenever the
676
+ * Path-decision data for the app space. Present whenever the
677
677
  * graph-walk strategy ran for the app (i.e. always for the
678
678
  * aggregate-walking migrate path). Absent only for the no-op
679
679
  * "Already up to date" early return when the app has no plan.
@@ -864,7 +864,7 @@ export interface ControlClient {
864
864
  * markers, and (unless `skipSchema` is true) per-space schema
865
865
  * verification with pre-projection (closes F23).
866
866
  *
867
- * @returns Result pattern: per-space schema results on success;
867
+ * @returns Result pattern: per-space verify results on success;
868
868
  * structured CLI error on marker / loader failure.
869
869
  * @throws If not connected or infrastructure failure
870
870
  */
@@ -45,6 +45,7 @@
45
45
  import { readFileSync, realpathSync, writeFileSync } from 'node:fs';
46
46
  import type { Writable } from 'node:stream';
47
47
  import { fileURLToPath } from 'node:url';
48
+ import { loadConfig } from '@prisma-next/config-loader';
48
49
  import {
49
50
  CliStructuredError,
50
51
  errorMigrationCliInvalidConfigArg,
@@ -57,7 +58,6 @@ import type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';
57
58
  import { buildMigrationArtifacts, type Migration } from '@prisma-next/migration-tools/migration';
58
59
  import { Cli, Command, Option, UsageError } from 'clipanion';
59
60
  import { dirname, join } from 'pathe';
60
- import { loadConfig } from './config-loader';
61
61
 
62
62
  /**
63
63
  * Constructor shape accepted by `MigrationCLI.run`. `Migration` subclasses