@prisma-next/cli 0.12.0-dev.48 → 0.12.0-dev.49

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 (115) hide show
  1. package/dist/cli.mjs +12 -12
  2. package/dist/{client-CJWPvdKj.mjs → client-DC-UlBLy.mjs} +4 -4
  3. package/dist/{client-CJWPvdKj.mjs.map → client-DC-UlBLy.mjs.map} +1 -1
  4. package/dist/{command-helpers-C6lqKJG1.mjs → command-helpers-esJGBD4W.mjs} +5 -5
  5. package/dist/command-helpers-esJGBD4W.mjs.map +1 -0
  6. package/dist/commands/contract-emit.mjs +1 -1
  7. package/dist/commands/contract-infer.mjs +1 -1
  8. package/dist/commands/db-init.mjs +3 -3
  9. package/dist/commands/db-schema.mjs +3 -3
  10. package/dist/commands/db-sign.mjs +4 -4
  11. package/dist/commands/db-update.mjs +4 -4
  12. package/dist/commands/db-verify.mjs +1 -1
  13. package/dist/commands/migrate.d.mts +1 -1
  14. package/dist/commands/migrate.mjs +4 -4
  15. package/dist/commands/migration-check.d.mts +3 -15
  16. package/dist/commands/migration-check.d.mts.map +1 -1
  17. package/dist/commands/migration-check.mjs +3 -2
  18. package/dist/commands/migration-graph.d.mts +9 -18
  19. package/dist/commands/migration-graph.d.mts.map +1 -1
  20. package/dist/commands/migration-graph.mjs +33 -20
  21. package/dist/commands/migration-graph.mjs.map +1 -1
  22. package/dist/commands/migration-list.d.mts +4 -4
  23. package/dist/commands/migration-list.mjs +1 -1
  24. package/dist/commands/migration-log.d.mts +5 -20
  25. package/dist/commands/migration-log.d.mts.map +1 -1
  26. package/dist/commands/migration-log.mjs +1 -1
  27. package/dist/commands/migration-new.mjs +3 -3
  28. package/dist/commands/migration-plan.d.mts +1 -1
  29. package/dist/commands/migration-plan.mjs +1 -1
  30. package/dist/commands/migration-show.d.mts +17 -18
  31. package/dist/commands/migration-show.d.mts.map +1 -1
  32. package/dist/commands/migration-show.mjs +13 -13
  33. package/dist/commands/migration-show.mjs.map +1 -1
  34. package/dist/commands/migration-status.d.mts +24 -26
  35. package/dist/commands/migration-status.d.mts.map +1 -1
  36. package/dist/commands/migration-status.mjs +3 -2
  37. package/dist/commands/ref.d.mts +1 -1
  38. package/dist/commands/ref.mjs +2 -2
  39. package/dist/commands/telemetry/index.mjs +1 -1
  40. package/dist/{contract-at-errors-CVQsgp3V.mjs → contract-at-errors-COZAemUl.mjs} +2 -2
  41. package/dist/{contract-at-errors-CVQsgp3V.mjs.map → contract-at-errors-COZAemUl.mjs.map} +1 -1
  42. package/dist/{contract-emit-DnUkRd-7.mjs → contract-emit-Bv46RAIO.mjs} +3 -3
  43. package/dist/{contract-emit-DnUkRd-7.mjs.map → contract-emit-Bv46RAIO.mjs.map} +1 -1
  44. package/dist/{contract-emit-Iyq5V7OU.mjs → contract-emit-DIWImLqS.mjs} +3 -3
  45. package/dist/{contract-emit-Iyq5V7OU.mjs.map → contract-emit-DIWImLqS.mjs.map} +1 -1
  46. package/dist/{contract-infer-MmQMIms7.mjs → contract-infer-DpGN9SAj.mjs} +3 -3
  47. package/dist/{contract-infer-MmQMIms7.mjs.map → contract-infer-DpGN9SAj.mjs.map} +1 -1
  48. package/dist/{contract-space-aggregate-loader-BSWfMkFY.mjs → contract-space-aggregate-loader-CpNVrBqW.mjs} +2 -2
  49. package/dist/{contract-space-aggregate-loader-BSWfMkFY.mjs.map → contract-space-aggregate-loader-CpNVrBqW.mjs.map} +1 -1
  50. package/dist/{db-verify-B-YOEESk.mjs → db-verify-Cq16Obsw.mjs} +4 -4
  51. package/dist/{db-verify-B-YOEESk.mjs.map → db-verify-Cq16Obsw.mjs.map} +1 -1
  52. package/dist/exports/control-api.d.mts +1 -1
  53. package/dist/exports/control-api.mjs +2 -2
  54. package/dist/exports/index.mjs +1 -1
  55. package/dist/exports/init-output.mjs +1 -1
  56. package/dist/{framework-components-D6VMhw2T.mjs → framework-components-BO9VO43s.mjs} +2 -2
  57. package/dist/{framework-components-D6VMhw2T.mjs.map → framework-components-BO9VO43s.mjs.map} +1 -1
  58. package/dist/{global-flags-DG4uY5tV.d.mts → global-flags-CV5LhrFg.d.mts} +1 -1
  59. package/dist/{global-flags-DG4uY5tV.d.mts.map → global-flags-CV5LhrFg.d.mts.map} +1 -1
  60. package/dist/{init-Ceib8PNc.mjs → init-C0rjiQ9I.mjs} +4 -4
  61. package/dist/{init-Ceib8PNc.mjs.map → init-C0rjiQ9I.mjs.map} +1 -1
  62. package/dist/{inspect-live-schema-CjMZ0RkS.mjs → inspect-live-schema-CRDKTNcf.mjs} +3 -3
  63. package/dist/{inspect-live-schema-CjMZ0RkS.mjs.map → inspect-live-schema-CRDKTNcf.mjs.map} +1 -1
  64. package/dist/{migration-check-DkNcCXZC.mjs → migration-check-CCXNXMXJ.mjs} +49 -30
  65. package/dist/migration-check-CCXNXMXJ.mjs.map +1 -0
  66. package/dist/{migration-command-scaffold-CrRysYxV.mjs → migration-command-scaffold-BDd9abqW.mjs} +3 -3
  67. package/dist/{migration-command-scaffold-CrRysYxV.mjs.map → migration-command-scaffold-BDd9abqW.mjs.map} +1 -1
  68. package/dist/{migration-graph-space-render-ByJ83gxp.mjs → migration-graph-space-render-CeNXh_Wy.mjs} +13 -13
  69. package/dist/migration-graph-space-render-CeNXh_Wy.mjs.map +1 -0
  70. package/dist/{migration-list-ip7fKesI.mjs → migration-list-vJWFuXca.mjs} +17 -17
  71. package/dist/migration-list-vJWFuXca.mjs.map +1 -0
  72. package/dist/{migration-log-BX9vu5c9.mjs → migration-log-6rcHQSI4.mjs} +15 -8
  73. package/dist/migration-log-6rcHQSI4.mjs.map +1 -0
  74. package/dist/{migration-path-target-ByduK0eI.mjs → migration-path-target-UkxkgXnv.mjs} +2 -2
  75. package/dist/{migration-path-target-ByduK0eI.mjs.map → migration-path-target-UkxkgXnv.mjs.map} +1 -1
  76. package/dist/{migration-plan-DLbbc_7z.mjs → migration-plan-CHu_erQ5.mjs} +5 -5
  77. package/dist/{migration-plan-DLbbc_7z.mjs.map → migration-plan-CHu_erQ5.mjs.map} +1 -1
  78. package/dist/{migration-status-BtdaOuQJ.mjs → migration-status-DzdlZQJ3.mjs} +39 -35
  79. package/dist/migration-status-DzdlZQJ3.mjs.map +1 -0
  80. package/dist/{output-CF_hqzI-.mjs → output-BD61elic.mjs} +1 -1
  81. package/dist/{output-CF_hqzI-.mjs.map → output-BD61elic.mjs.map} +1 -1
  82. package/dist/schemas-BL33A3i-.d.mts +193 -0
  83. package/dist/schemas-BL33A3i-.d.mts.map +1 -0
  84. package/dist/schemas-DJY2O09F.mjs +112 -0
  85. package/dist/schemas-DJY2O09F.mjs.map +1 -0
  86. package/dist/{telemetry-CxbY4NKn.mjs → telemetry-CZkgkR_O.mjs} +2 -2
  87. package/dist/{telemetry-CxbY4NKn.mjs.map → telemetry-CZkgkR_O.mjs.map} +1 -1
  88. package/dist/{terminal-ui-5Y6mrg93.d.mts → terminal-ui-BgLiAOYi.d.mts} +1 -1
  89. package/dist/{terminal-ui-5Y6mrg93.d.mts.map → terminal-ui-BgLiAOYi.d.mts.map} +1 -1
  90. package/dist/{types-Cculk5KV.d.mts → types-qV41eEXH.d.mts} +1 -1
  91. package/dist/{types-Cculk5KV.d.mts.map → types-qV41eEXH.d.mts.map} +1 -1
  92. package/dist/{verify-Df-8Kwat.mjs → verify-IilvIk_E.mjs} +2 -2
  93. package/dist/{verify-Df-8Kwat.mjs.map → verify-IilvIk_E.mjs.map} +1 -1
  94. package/package.json +18 -18
  95. package/src/commands/json/schemas.ts +195 -0
  96. package/src/commands/migration-check.ts +33 -24
  97. package/src/commands/migration-graph.ts +34 -36
  98. package/src/commands/migration-list.ts +14 -14
  99. package/src/commands/migration-log.ts +6 -7
  100. package/src/commands/migration-show.ts +21 -28
  101. package/src/commands/migration-status.ts +69 -67
  102. package/src/utils/formatters/migration-list-graph-topology.ts +4 -4
  103. package/src/utils/formatters/migration-list-render.ts +12 -12
  104. package/src/utils/formatters/migration-list-types.ts +5 -21
  105. package/src/utils/formatters/migration-log-table.ts +12 -7
  106. package/src/utils/formatters/migrations.ts +8 -10
  107. package/src/utils/integrity-violation-to-check-failure.ts +28 -19
  108. package/dist/command-helpers-C6lqKJG1.mjs.map +0 -1
  109. package/dist/migration-check-DkNcCXZC.mjs.map +0 -1
  110. package/dist/migration-graph-space-render-ByJ83gxp.mjs.map +0 -1
  111. package/dist/migration-list-ip7fKesI.mjs.map +0 -1
  112. package/dist/migration-list-types-DS63IdFd.d.mts +0 -23
  113. package/dist/migration-list-types-DS63IdFd.d.mts.map +0 -1
  114. package/dist/migration-log-BX9vu5c9.mjs.map +0 -1
  115. package/dist/migration-status-BtdaOuQJ.mjs.map +0 -1
@@ -47,10 +47,7 @@ import { formatErrorJson, formatErrorOutput } from '../utils/formatters/errors';
47
47
  import { formatStyledHeader } from '../utils/formatters/styled';
48
48
  import type { CommonCommandOptions } from '../utils/global-flags';
49
49
  import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
50
- import {
51
- type CheckFailure,
52
- integrityViolationToCheckFailure,
53
- } from '../utils/integrity-violation-to-check-failure';
50
+ import { integrityViolationToCheckFailure } from '../utils/integrity-violation-to-check-failure';
54
51
  import {
55
52
  findPackageByDirPath,
56
53
  looksLikePath,
@@ -58,6 +55,7 @@ import {
58
55
  resolveTargetPathAcrossSpaces,
59
56
  } from '../utils/migration-path-target';
60
57
  import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
58
+ import type { CheckFailure, MigrationCheckResult } from './json/schemas';
61
59
  import { INTEGRITY_FAILED, OK, PRECONDITION } from './migration-check/exit-codes';
62
60
 
63
61
  interface MigrationCheckOptions extends CommonCommandOptions {
@@ -65,13 +63,8 @@ interface MigrationCheckOptions extends CommonCommandOptions {
65
63
  readonly space?: string;
66
64
  }
67
65
 
68
- export type { CheckFailure } from '../utils/integrity-violation-to-check-failure';
69
-
70
- export interface MigrationCheckResult {
71
- readonly ok: boolean;
72
- readonly failures: readonly CheckFailure[];
73
- readonly summary: string;
74
- }
66
+ export type { CheckFailure, MigrationCheckResult } from './json/schemas';
67
+ export { migrationCheckResultSchema } from './json/schemas';
75
68
 
76
69
  function migrationPathRelative(dirPath: string): string {
77
70
  return relative(process.cwd(), dirPath);
@@ -81,10 +74,16 @@ function migrationFileRelative(dirPath: string, fileName: string): string {
81
74
  return join(migrationPathRelative(dirPath), fileName);
82
75
  }
83
76
 
84
- function checkFileExists(dirPath: string, dirName: string, fileName: string): CheckFailure | null {
77
+ function checkFileExists(
78
+ spaceId: string,
79
+ dirPath: string,
80
+ dirName: string,
81
+ fileName: string,
82
+ ): CheckFailure | null {
85
83
  if (!existsSync(join(dirPath, fileName))) {
86
84
  return {
87
- pnCode: 'PN-MIG-CHECK-002',
85
+ space: spaceId,
86
+ code: 'PN-MIG-CHECK-002',
88
87
  where: migrationFileRelative(dirPath, fileName),
89
88
  why: `${fileName} is missing from ${dirName}`,
90
89
  fix: 'Re-emit the migration package or restore from version control.',
@@ -93,7 +92,10 @@ function checkFileExists(dirPath: string, dirName: string, fileName: string): Ch
93
92
  return null;
94
93
  }
95
94
 
96
- function checkSnapshotConsistency(pkg: OnDiskMigrationPackage): CheckFailure | null {
95
+ function checkSnapshotConsistency(
96
+ spaceId: string,
97
+ pkg: OnDiskMigrationPackage,
98
+ ): CheckFailure | null {
97
99
  const endContractPath = join(pkg.dirPath, 'end-contract.json');
98
100
  if (!existsSync(endContractPath)) return null;
99
101
  try {
@@ -102,7 +104,8 @@ function checkSnapshotConsistency(pkg: OnDiskMigrationPackage): CheckFailure | n
102
104
  const snapshotHash = storage?.['storageHash'];
103
105
  if (typeof snapshotHash === 'string' && snapshotHash !== pkg.metadata.to) {
104
106
  return {
105
- pnCode: 'PN-MIG-CHECK-005',
107
+ space: spaceId,
108
+ code: 'PN-MIG-CHECK-005',
106
109
  where: migrationPathRelative(pkg.dirPath),
107
110
  why: `Migration "${pkg.dirName}" declares to=${pkg.metadata.to} but end-contract.json has storageHash=${snapshotHash}`,
108
111
  fix: 'Re-emit the migration package so migration.json and end-contract.json agree.',
@@ -110,7 +113,8 @@ function checkSnapshotConsistency(pkg: OnDiskMigrationPackage): CheckFailure | n
110
113
  }
111
114
  } catch {
112
115
  return {
113
- pnCode: 'PN-MIG-CHECK-006',
116
+ space: spaceId,
117
+ code: 'PN-MIG-CHECK-006',
114
118
  where: migrationPathRelative(pkg.dirPath),
115
119
  why: `Migration "${pkg.dirName}" has an unparseable end-contract.json.`,
116
120
  fix: 'Re-emit the migration package to repair the snapshot file.',
@@ -189,7 +193,7 @@ function checkManifestFilesPresent(space: CheckSpace): readonly CheckFailure[] {
189
193
  }
190
194
  if (!loadedDirNames.has(entry)) {
191
195
  for (const f of ['migration.json', 'ops.json']) {
192
- const fail = checkFileExists(entryPath, entry, f);
196
+ const fail = checkFileExists(space.spaceId, entryPath, entry, f);
193
197
  if (fail) failures.push(fail);
194
198
  }
195
199
  }
@@ -207,7 +211,8 @@ function checkReachability(space: CheckSpace): readonly CheckFailure[] {
207
211
  pkg.metadata.from === 'sha256:empty';
208
212
  if (!isReachable) {
209
213
  failures.push({
210
- pnCode: 'PN-MIG-CHECK-003',
214
+ space: space.spaceId,
215
+ code: 'PN-MIG-CHECK-003',
211
216
  where: migrationPathRelative(pkg.dirPath),
212
217
  why: `Migration "${pkg.dirName}" starts from ${pkg.metadata.from} which no other migration produces`,
213
218
  fix: 'This migration is unreachable in the graph. Delete it or re-emit a connecting migration.',
@@ -222,7 +227,8 @@ function checkDanglingRefs(space: CheckSpace): readonly CheckFailure[] {
222
227
  for (const [name, entry] of Object.entries(space.refs)) {
223
228
  if (!space.graph.nodes.has(entry.hash)) {
224
229
  failures.push({
225
- pnCode: 'PN-MIG-CHECK-004',
230
+ space: space.spaceId,
231
+ code: 'PN-MIG-CHECK-004',
226
232
  where: relative(process.cwd(), join(space.refsDir, `${name}.json`)),
227
233
  why: `Ref "${name}" points at ${entry.hash} which does not exist in the migration graph`,
228
234
  fix: `Update the ref with \`prisma-next ref set ${name} <valid-hash>\` or delete it.`,
@@ -235,7 +241,9 @@ function checkDanglingRefs(space: CheckSpace): readonly CheckFailure[] {
235
241
  function checkSpace(space: CheckSpace): readonly CheckFailure[] {
236
242
  return [
237
243
  ...checkManifestFilesPresent(space),
238
- ...space.packages.map(checkSnapshotConsistency).filter((f): f is CheckFailure => f !== null),
244
+ ...space.packages
245
+ .map((pkg) => checkSnapshotConsistency(space.spaceId, pkg))
246
+ .filter((f): f is CheckFailure => f !== null),
239
247
  ...checkReachability(space),
240
248
  ...checkDanglingRefs(space),
241
249
  ];
@@ -535,21 +543,22 @@ async function checkSingleTarget(
535
543
  const failures: CheckFailure[] = [...checkManifestFilesPresent(matchedSpace)];
536
544
 
537
545
  for (const f of ['migration.json', 'ops.json']) {
538
- const fail = checkFileExists(matchedPkg.dirPath, matchedPkg.dirName, f);
546
+ const fail = checkFileExists(matchedSpace.spaceId, matchedPkg.dirPath, matchedPkg.dirName, f);
539
547
  if (fail) failures.push(fail);
540
548
  }
541
549
 
542
550
  const verification = verifyMigrationHash(matchedPkg);
543
551
  if (!verification.ok) {
544
552
  failures.push({
545
- pnCode: 'PN-MIG-CHECK-001',
553
+ space: matchedSpace.spaceId,
554
+ code: 'PN-MIG-CHECK-001',
546
555
  where: migrationFileRelative(matchedPkg.dirPath, 'migration.json'),
547
556
  why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,
548
557
  fix: 'Re-emit the migration package or restore from version control.',
549
558
  });
550
559
  }
551
560
 
552
- const snapshotFailure = checkSnapshotConsistency(matchedPkg);
561
+ const snapshotFailure = checkSnapshotConsistency(matchedSpace.spaceId, matchedPkg);
553
562
  if (snapshotFailure) failures.push(snapshotFailure);
554
563
 
555
564
  const resolvedSpaceId = matchedSpace.spaceId !== 'app' ? matchedSpace.spaceId : undefined;
@@ -641,7 +650,7 @@ export function createMigrationCheckCommand(): Command {
641
650
  ui.log(`✔ ${result.summary}${spaceSuffix}`);
642
651
  } else {
643
652
  for (const f of result.failures) {
644
- ui.log(`✗ [${f.pnCode}] ${f.where}: ${f.why}`);
653
+ ui.log(`✗ [${f.code}] ${f.where}: ${f.why}`);
645
654
  ui.log(` fix: ${f.fix}`);
646
655
  }
647
656
  ui.log(`\n${result.summary}`);
@@ -1,3 +1,4 @@
1
+ import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
1
2
  import type { MigrationGraph } from '@prisma-next/migration-tools/graph';
2
3
  import { ifDefined } from '@prisma-next/utils/defined';
3
4
  import { ok, type Result } from '@prisma-next/utils/result';
@@ -25,6 +26,7 @@ import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags'
25
26
  import { shouldShowLegend, validateLegendOptions } from '../utils/legend';
26
27
  import { handleResult } from '../utils/result-handler';
27
28
  import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
29
+ import type { MigrationGraphJsonResult, MigrationSpaceGraphEntry } from './json/schemas';
28
30
  import {
29
31
  listRefsByContractHash,
30
32
  migrationSpaceListEntriesFromAggregate,
@@ -40,42 +42,32 @@ interface MigrationGraphOptions extends CommonCommandOptions {
40
42
  }
41
43
 
42
44
  export interface MigrationGraphTreeSection {
43
- readonly spaceId: string;
45
+ readonly space: string;
44
46
  readonly tree: string;
45
47
  readonly showHeading: boolean;
46
48
  }
47
49
 
48
50
  export interface MigrationGraphResult {
49
51
  readonly ok: true;
50
- /** App-space graph for `--json` / `--dot` (unchanged machine output). */
52
+ /** App-space graph for the `--dot` Graphviz output. */
51
53
  readonly graph: MigrationGraph;
54
+ /** Nested per-space contracts + migrations for `--json`. */
55
+ readonly spaces: readonly MigrationSpaceGraphEntry[];
52
56
  readonly treeSections: readonly MigrationGraphTreeSection[];
53
57
  readonly summary: string;
54
58
  }
55
59
 
56
- export interface MigrationGraphJsonEdge {
57
- readonly dirName: string;
58
- readonly from: string;
59
- readonly to: string;
60
- readonly migrationHash: string;
61
- }
62
-
63
- export interface MigrationGraphJsonResult {
64
- readonly ok: true;
65
- readonly nodes: readonly string[];
66
- readonly edges: readonly MigrationGraphJsonEdge[];
67
- readonly summary: string;
68
- }
69
-
70
- function computeGraphSummary(graph: MigrationGraph): string {
71
- return `${graph.nodes.size} node(s), ${graph.migrationByHash.size} edge(s)`;
60
+ function computeGraphSummary(spaces: readonly MigrationSpaceGraphEntry[]): string {
61
+ const contractCount = spaces.reduce((count, space) => count + space.contracts.length, 0);
62
+ const migrationCount = spaces.reduce((count, space) => count + space.migrations.length, 0);
63
+ return `${spaces.length} space(s), ${contractCount} contract(s), ${migrationCount} migration(s)`;
72
64
  }
73
65
 
74
66
  export function formatMigrationGraphHumanOutput(result: MigrationGraphResult): string {
75
67
  const sections: string[] = [];
76
68
  for (const section of result.treeSections) {
77
69
  if (section.showHeading) {
78
- sections.push(`${section.spaceId}:`);
70
+ sections.push(`${section.space}:`);
79
71
  }
80
72
  if (section.tree.length > 0) {
81
73
  sections.push(section.tree);
@@ -148,7 +140,7 @@ export async function executeMigrationGraphCommand(
148
140
  ? scopedSpaces
149
141
  .filter((spaceEntry) => spaceEntry.migrations.length > 0)
150
142
  .map((spaceEntry) => ({
151
- graph: aggregate.space(spaceEntry.spaceId)!.graph(),
143
+ graph: aggregate.space(spaceEntry.space)!.graph(),
152
144
  liveContractHash,
153
145
  }))
154
146
  : [];
@@ -160,12 +152,14 @@ export async function executeMigrationGraphCommand(
160
152
  globalLayoutInputs.length > 0 ? computeGlobalMaxDirNameWidth(globalLayoutInputs) : undefined;
161
153
 
162
154
  const treeSections: MigrationGraphTreeSection[] = [];
155
+ const spaces: MigrationSpaceGraphEntry[] = [];
163
156
  for (const spaceEntry of scopedSpaces) {
164
- const member = aggregate.space(spaceEntry.spaceId);
157
+ const member = aggregate.space(spaceEntry.space);
165
158
  if (member === undefined) {
166
159
  continue;
167
160
  }
168
161
  const graph = member.graph();
162
+ const refsByHash = listRefsByContractHash(member);
169
163
  const tree =
170
164
  spaceEntry.migrations.length === 0
171
165
  ? ''
@@ -175,24 +169,38 @@ export async function executeMigrationGraphCommand(
175
169
  liveContractHash,
176
170
  glyphMode,
177
171
  colorize,
178
- refsByHash: listRefsByContractHash(member),
172
+ refsByHash,
179
173
  ...(globalMaxEdgeTreePrefixWidth !== undefined ? { globalMaxEdgeTreePrefixWidth } : {}),
180
174
  ...(globalMaxDirNameWidth !== undefined ? { globalMaxDirNameWidth } : {}),
181
175
  });
182
176
  const displayTree =
183
177
  showSpaceHeadings && tree.length > 0 ? indentMigrationGraphTreeBlock(tree, ' ') : tree;
184
178
  treeSections.push({
185
- spaceId: spaceEntry.spaceId,
179
+ space: spaceEntry.space,
186
180
  tree: displayTree,
187
181
  showHeading: showSpaceHeadings,
188
182
  });
183
+ spaces.push({
184
+ space: spaceEntry.space,
185
+ contracts: [...graph.nodes].map((hash) => ({
186
+ hash,
187
+ refs: [...(refsByHash.get(hash) ?? [])],
188
+ })),
189
+ migrations: [...graph.migrationByHash.values()].map((edge) => ({
190
+ name: edge.dirName,
191
+ hash: edge.migrationHash,
192
+ fromContract: edge.from === EMPTY_CONTRACT_HASH ? null : edge.from,
193
+ toContract: edge.to,
194
+ })),
195
+ });
189
196
  }
190
197
 
191
198
  return ok({
192
199
  ok: true,
193
200
  graph: appGraph,
201
+ spaces,
194
202
  treeSections,
195
- summary: computeGraphSummary(appGraph),
203
+ summary: computeGraphSummary(spaces),
196
204
  });
197
205
  }
198
206
 
@@ -246,20 +254,10 @@ export function createMigrationGraphCommand(): Command {
246
254
  lines.push('}');
247
255
  ui.output(lines.join('\n'));
248
256
  } else if (flags.json) {
249
- const nodes = [...graphResult.graph.nodes];
250
- const edges = [...graphResult.graph.migrationByHash.values()].map(
251
- (e): MigrationGraphJsonEdge => ({
252
- dirName: e.dirName,
253
- from: e.from,
254
- to: e.to,
255
- migrationHash: e.migrationHash,
256
- }),
257
- );
258
257
  const jsonResult: MigrationGraphJsonResult = {
259
258
  ok: true,
260
- nodes,
261
- edges,
262
- summary: `${graphResult.graph.nodes.size} node(s), ${graphResult.graph.migrationByHash.size} edge(s)`,
259
+ spaces: [...graphResult.spaces],
260
+ summary: graphResult.summary,
263
261
  };
264
262
  ui.output(JSON.stringify(jsonResult, null, 2));
265
263
  } else if (!flags.quiet) {
@@ -52,8 +52,8 @@ function compareSpaceIds(a: string, b: string): number {
52
52
  }
53
53
 
54
54
  function compareDirNamesDescending(a: MigrationListEntry, b: MigrationListEntry): number {
55
- if (a.dirName < b.dirName) return 1;
56
- if (a.dirName > b.dirName) return -1;
55
+ if (a.name < b.name) return 1;
56
+ if (a.name > b.name) return -1;
57
57
  return 0;
58
58
  }
59
59
 
@@ -110,18 +110,18 @@ export async function migrationSpaceListEntriesFromAggregate(
110
110
  const refsByHash = listRefsByContractHash(member);
111
111
  const migrations: MigrationListEntry[] = member.packages
112
112
  .map((pkg) => ({
113
- dirName: pkg.dirName,
114
- from: pkg.metadata.from,
115
- to: pkg.metadata.to,
116
- migrationHash: pkg.metadata.migrationHash,
113
+ name: pkg.dirName,
114
+ hash: pkg.metadata.migrationHash,
115
+ fromContract: pkg.metadata.from,
116
+ toContract: pkg.metadata.to,
117
117
  operationCount: pkg.ops.length,
118
118
  createdAt: pkg.metadata.createdAt,
119
- refs: refsByHash.get(pkg.metadata.to) ?? [],
120
- providedInvariants: pkg.metadata.providedInvariants,
119
+ refs: [...(refsByHash.get(pkg.metadata.to) ?? [])],
120
+ providedInvariants: [...pkg.metadata.providedInvariants],
121
121
  }))
122
122
  .sort(compareDirNamesDescending);
123
123
 
124
- spaces.push({ spaceId, migrations });
124
+ spaces.push({ space: spaceId, migrations });
125
125
  }
126
126
 
127
127
  return spaces;
@@ -198,19 +198,19 @@ export function runMigrationList(
198
198
  return notOk(errorInvalidSpaceId(spaceFilter));
199
199
  }
200
200
 
201
- if (spaceFilter !== undefined && !spaces.some((s) => s.spaceId === spaceFilter)) {
202
- return notOk(errorSpaceNotFound(spaceFilter, spaces.map((s) => s.spaceId).sort()));
201
+ if (spaceFilter !== undefined && !spaces.some((s) => s.space === spaceFilter)) {
202
+ return notOk(errorSpaceNotFound(spaceFilter, spaces.map((s) => s.space).sort()));
203
203
  }
204
204
 
205
205
  const scopedSpaces =
206
- spaceFilter !== undefined ? spaces.filter((s) => s.spaceId === spaceFilter) : spaces;
206
+ spaceFilter !== undefined ? spaces.filter((s) => s.space === spaceFilter) : spaces;
207
207
 
208
208
  const resultSpaces: readonly MigrationSpaceListEntry[] =
209
- scopedSpaces.length === 0 ? [{ spaceId: APP_SPACE_ID, migrations: [] }] : scopedSpaces;
209
+ scopedSpaces.length === 0 ? [{ space: APP_SPACE_ID, migrations: [] }] : scopedSpaces;
210
210
 
211
211
  return ok({
212
212
  ok: true,
213
- spaces: resultSpaces,
213
+ spaces: [...resultSpaces],
214
214
  summary: computeSummary(resultSpaces),
215
215
  });
216
216
  }
@@ -24,7 +24,6 @@ import { createAnsiMigrationListStyler } from '../utils/formatters/migration-lis
24
24
  import {
25
25
  MIGRATION_LOG_EMPTY_MESSAGE,
26
26
  renderMigrationLogTable,
27
- type SerializedLedgerEntryRecord,
28
27
  serializeLedgerEntriesForJson,
29
28
  } from '../utils/formatters/migration-log-table';
30
29
  import { formatStyledHeader } from '../utils/formatters/styled';
@@ -32,6 +31,9 @@ import type { CommonCommandOptions } from '../utils/global-flags';
32
31
  import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
33
32
  import { handleResult } from '../utils/result-handler';
34
33
  import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
34
+ import type { MigrationLogResult } from './json/schemas';
35
+
36
+ export type { MigrationLogResult };
35
37
 
36
38
  interface MigrationLogOptions extends CommonCommandOptions {
37
39
  readonly db?: string;
@@ -40,11 +42,6 @@ interface MigrationLogOptions extends CommonCommandOptions {
40
42
  readonly ascii?: boolean;
41
43
  }
42
44
 
43
- export interface MigrationLogResult {
44
- readonly ok: true;
45
- readonly entries: readonly SerializedLedgerEntryRecord[];
46
- }
47
-
48
45
  export async function executeMigrationLogCommand(
49
46
  options: MigrationLogOptions,
50
47
  flags: GlobalFlags,
@@ -138,9 +135,11 @@ export function createMigrationLogCommand(): Command {
138
135
  const result = await executeMigrationLogCommand(options, flags, ui);
139
136
  const exitCode = handleResult(result, flags, ui, (entries) => {
140
137
  if (flags.json) {
138
+ const records = serializeLedgerEntriesForJson(entries);
141
139
  const result: MigrationLogResult = {
142
140
  ok: true,
143
- entries: serializeLedgerEntriesForJson(entries),
141
+ records,
142
+ summary: `${records.length} migration(s) applied`,
144
143
  };
145
144
  ui.output(JSON.stringify(result, null, 2));
146
145
  } else if (!flags.quiet) {
@@ -4,7 +4,6 @@ import {
4
4
  APP_SPACE_ID,
5
5
  createControlStack,
6
6
  type MigrationPlanOperation,
7
- type OperationPreview,
8
7
  } from '@prisma-next/framework-components/control';
9
8
  import { loadContractSpaceAggregate } from '@prisma-next/migration-tools/aggregate';
10
9
  import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
@@ -43,32 +42,26 @@ import {
43
42
  } from '../utils/migration-path-target';
44
43
  import { handleResult } from '../utils/result-handler';
45
44
  import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
45
+ import type { MigrationShowResult } from './json/schemas';
46
46
 
47
47
  interface MigrationShowOptions extends CommonCommandOptions {
48
48
  readonly config?: string;
49
49
  }
50
50
 
51
51
  export interface MigrationShowPresent {
52
- readonly spaceId: string;
53
- readonly dirName: string;
54
- readonly dirPath: string;
55
- readonly from: string | null;
56
- readonly to: string;
57
- readonly migrationHash: string;
52
+ readonly space: string;
53
+ readonly name: string;
54
+ readonly fromContract: string | null;
55
+ readonly toContract: string;
56
+ readonly hash: string;
58
57
  readonly createdAt: string;
59
- readonly operations: readonly {
60
- readonly id: string;
61
- readonly label: string;
62
- readonly operationClass: string;
63
- }[];
64
- readonly preview: OperationPreview;
65
- readonly summary: string;
58
+ readonly operations: { id: string; label: string; operationClass: string }[];
59
+ readonly preview: {
60
+ statements: { text: string; language: string }[];
61
+ };
66
62
  }
67
63
 
68
- export interface MigrationShowResult {
69
- readonly ok: true;
70
- readonly migration: MigrationShowPresent;
71
- }
64
+ export type { MigrationShowResult };
72
65
 
73
66
  function pkgToPresent(
74
67
  spaceId: string,
@@ -76,22 +69,20 @@ function pkgToPresent(
76
69
  client: ReturnType<typeof createControlClient>,
77
70
  ): MigrationShowPresent {
78
71
  const ops = castAs<readonly MigrationPlanOperation[]>(pkg.ops);
79
- const preview: OperationPreview = client.toOperationPreview(ops) ?? { statements: [] };
72
+ const rawPreview = client.toOperationPreview(ops) ?? { statements: [] };
80
73
  return {
81
- spaceId,
82
- dirName: pkg.dirName,
83
- dirPath: relative(process.cwd(), pkg.dirPath),
84
- from: pkg.metadata.from,
85
- to: pkg.metadata.to,
86
- migrationHash: pkg.metadata.migrationHash,
74
+ space: spaceId,
75
+ name: pkg.dirName,
76
+ fromContract: pkg.metadata.from,
77
+ toContract: pkg.metadata.to,
78
+ hash: pkg.metadata.migrationHash,
87
79
  createdAt: pkg.metadata.createdAt,
88
80
  operations: ops.map((op) => ({
89
81
  id: op.id,
90
82
  label: op.label,
91
83
  operationClass: op.operationClass,
92
84
  })),
93
- preview,
94
- summary: `${ops.length} operation(s)`,
85
+ preview: { statements: [...rawPreview.statements] },
95
86
  };
96
87
  }
97
88
 
@@ -218,9 +209,11 @@ async function executeMigrationShowCommand(
218
209
  appPkg = matchedPkg;
219
210
  }
220
211
 
212
+ const migration = pkgToPresent(APP_SPACE_ID, appPkg, client);
221
213
  return ok({
222
214
  ok: true,
223
- migration: pkgToPresent(APP_SPACE_ID, appPkg, client),
215
+ summary: `Migration ${migration.name} in ${migration.space}: ${migration.operations.length} operation(s)`,
216
+ migration,
224
217
  });
225
218
  }
226
219