@prisma-next/cli 0.12.0-dev.4 → 0.12.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 (165) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.mjs +180 -163
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/{client-KgJorIvG.mjs → client-BNdG504y.mjs} +80 -56
  5. package/dist/client-BNdG504y.mjs.map +1 -0
  6. package/dist/{command-helpers-Bbw1GbwL.mjs → command-helpers-xvg9oq4T.mjs} +301 -23
  7. package/dist/command-helpers-xvg9oq4T.mjs.map +1 -0
  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 +4 -5
  11. package/dist/commands/db-init.mjs.map +1 -1
  12. package/dist/commands/db-schema.mjs +3 -3
  13. package/dist/commands/db-sign.mjs +4 -4
  14. package/dist/commands/db-update.d.mts.map +1 -1
  15. package/dist/commands/db-update.mjs +10 -7
  16. package/dist/commands/db-update.mjs.map +1 -1
  17. package/dist/commands/db-verify.mjs +1 -1
  18. package/dist/commands/migrate.d.mts +2 -2
  19. package/dist/commands/migrate.d.mts.map +1 -1
  20. package/dist/commands/migrate.mjs +6 -8
  21. package/dist/commands/migrate.mjs.map +1 -1
  22. package/dist/commands/migration-check.d.mts +55 -1
  23. package/dist/commands/migration-check.d.mts.map +1 -1
  24. package/dist/commands/migration-check.mjs +2 -2
  25. package/dist/commands/migration-graph.d.mts +25 -7
  26. package/dist/commands/migration-graph.d.mts.map +1 -1
  27. package/dist/commands/migration-graph.mjs +170 -2
  28. package/dist/commands/migration-graph.mjs.map +1 -0
  29. package/dist/commands/migration-list.d.mts +24 -26
  30. package/dist/commands/migration-list.d.mts.map +1 -1
  31. package/dist/commands/migration-list.mjs +2 -190
  32. package/dist/commands/migration-log.d.mts +20 -15
  33. package/dist/commands/migration-log.d.mts.map +1 -1
  34. package/dist/commands/migration-log.mjs +1 -137
  35. package/dist/commands/migration-new.mjs +3 -3
  36. package/dist/commands/migration-plan.d.mts +1 -1
  37. package/dist/commands/migration-plan.mjs +1 -1
  38. package/dist/commands/migration-show.d.mts +1 -4
  39. package/dist/commands/migration-show.d.mts.map +1 -1
  40. package/dist/commands/migration-show.mjs +13 -25
  41. package/dist/commands/migration-show.mjs.map +1 -1
  42. package/dist/commands/migration-status.d.mts +41 -141
  43. package/dist/commands/migration-status.d.mts.map +1 -1
  44. package/dist/commands/migration-status.mjs +2 -759
  45. package/dist/commands/ref.d.mts +1 -1
  46. package/dist/commands/ref.mjs +3 -3
  47. package/dist/commands/telemetry/index.d.mts +7 -0
  48. package/dist/commands/telemetry/index.d.mts.map +1 -0
  49. package/dist/commands/telemetry/index.mjs +2 -0
  50. package/dist/{contract-at-errors-BxP-TOMl.mjs → contract-at-errors-Wj3u4Xco.mjs} +2 -2
  51. package/dist/{contract-at-errors-BxP-TOMl.mjs.map → contract-at-errors-Wj3u4Xco.mjs.map} +1 -1
  52. package/dist/{contract-emit-DxcGl4Uq.mjs → contract-emit-COg18szA.mjs} +3 -3
  53. package/dist/{contract-emit-DxcGl4Uq.mjs.map → contract-emit-COg18szA.mjs.map} +1 -1
  54. package/dist/{contract-emit-D-4jrNve.mjs → contract-emit-KyJNQK5-.mjs} +3 -3
  55. package/dist/{contract-emit-D-4jrNve.mjs.map → contract-emit-KyJNQK5-.mjs.map} +1 -1
  56. package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-IEp0227u.mjs} +3 -3
  57. package/dist/{contract-infer-D8uEbJuu.mjs.map → contract-infer-IEp0227u.mjs.map} +1 -1
  58. package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs → contract-space-aggregate-loader-BdRPfM3Q.mjs} +63 -5
  59. package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs.map → contract-space-aggregate-loader-BdRPfM3Q.mjs.map} +1 -1
  60. package/dist/{db-verify-v_vUKXTU.mjs → db-verify-C9k5KAyI.mjs} +4 -4
  61. package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-C9k5KAyI.mjs.map} +1 -1
  62. package/dist/exports/control-api.d.mts +2 -2
  63. package/dist/exports/control-api.d.mts.map +1 -1
  64. package/dist/exports/control-api.mjs +2 -2
  65. package/dist/exports/index.mjs +1 -1
  66. package/dist/exports/init-output.mjs +1 -1
  67. package/dist/{framework-components-fYXjz_in.mjs → framework-components-Be4inY3I.mjs} +2 -2
  68. package/dist/{framework-components-fYXjz_in.mjs.map → framework-components-Be4inY3I.mjs.map} +1 -1
  69. package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-DG4uY5tV.d.mts} +1 -1
  70. package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-DG4uY5tV.d.mts.map} +1 -1
  71. package/dist/{init-Cv9UzWL5.mjs → init-BIxw3l7t.mjs} +5 -58
  72. package/dist/init-BIxw3l7t.mjs.map +1 -0
  73. package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-DXUFGQDe.mjs} +3 -3
  74. package/dist/{inspect-live-schema-C6ohV_oQ.mjs.map → inspect-live-schema-DXUFGQDe.mjs.map} +1 -1
  75. package/dist/{migration-check-BiBJoYYW.mjs → migration-check-CUavU7U9.mjs} +236 -88
  76. package/dist/migration-check-CUavU7U9.mjs.map +1 -0
  77. package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-omgKpt3K.mjs} +3 -3
  78. package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-omgKpt3K.mjs.map} +1 -1
  79. package/dist/migration-graph-space-render-ByJ83gxp.mjs +1966 -0
  80. package/dist/migration-graph-space-render-ByJ83gxp.mjs.map +1 -0
  81. package/dist/migration-list-jK6QeczE.mjs +228 -0
  82. package/dist/migration-list-jK6QeczE.mjs.map +1 -0
  83. package/dist/migration-list-types-DS63IdFd.d.mts +23 -0
  84. package/dist/migration-list-types-DS63IdFd.d.mts.map +1 -0
  85. package/dist/migration-log-CW0EjxSr.mjs +215 -0
  86. package/dist/migration-log-CW0EjxSr.mjs.map +1 -0
  87. package/dist/migration-path-target-DqcrbOis.mjs +24 -0
  88. package/dist/migration-path-target-DqcrbOis.mjs.map +1 -0
  89. package/dist/{migration-plan-9DJ7q7_z.mjs → migration-plan-NHdlUwPG.mjs} +5 -6
  90. package/dist/{migration-plan-9DJ7q7_z.mjs.map → migration-plan-NHdlUwPG.mjs.map} +1 -1
  91. package/dist/migration-status-GZ6XfbWs.mjs +439 -0
  92. package/dist/migration-status-GZ6XfbWs.mjs.map +1 -0
  93. package/dist/{output-B60Gw5fu.mjs → output-CF_hqzI-.mjs} +1 -1
  94. package/dist/{output-B60Gw5fu.mjs.map → output-CF_hqzI-.mjs.map} +1 -1
  95. package/dist/{ref-advancement-DUZqsue6.mjs → ref-advancement-CJY9zOv7.mjs} +1 -1
  96. package/dist/{ref-advancement-DUZqsue6.mjs.map → ref-advancement-CJY9zOv7.mjs.map} +1 -1
  97. package/dist/telemetry-DQP0BvKv.mjs +122 -0
  98. package/dist/telemetry-DQP0BvKv.mjs.map +1 -0
  99. package/dist/{types-Dt_SfqFm.d.mts → types-Cculk5KV.d.mts} +44 -31
  100. package/dist/types-Cculk5KV.d.mts.map +1 -0
  101. package/dist/{verify-DCA9Sldu.mjs → verify-tvHRBBVP.mjs} +2 -2
  102. package/dist/{verify-DCA9Sldu.mjs.map → verify-tvHRBBVP.mjs.map} +1 -1
  103. package/package.json +22 -19
  104. package/src/cli.ts +5 -0
  105. package/src/commands/db-update.ts +7 -1
  106. package/src/commands/init/index.ts +6 -35
  107. package/src/commands/init/init.ts +1 -14
  108. package/src/commands/init/inputs.ts +0 -75
  109. package/src/commands/migrate.ts +6 -6
  110. package/src/commands/migration-check.ts +340 -117
  111. package/src/commands/migration-graph.ts +163 -90
  112. package/src/commands/migration-list.ts +55 -25
  113. package/src/commands/migration-log.ts +49 -98
  114. package/src/commands/migration-show.ts +10 -38
  115. package/src/commands/migration-status-overlay.ts +61 -0
  116. package/src/commands/migration-status.ts +440 -1056
  117. package/src/commands/telemetry/index.ts +107 -0
  118. package/src/commands/telemetry/status.ts +67 -0
  119. package/src/control-api/client.ts +17 -7
  120. package/src/control-api/operations/db-init.ts +3 -3
  121. package/src/control-api/operations/{db-apply.ts → db-run.ts} +37 -10
  122. package/src/control-api/operations/db-update.ts +4 -4
  123. package/src/control-api/operations/{migration-apply.ts → migrate.ts} +32 -24
  124. package/src/control-api/operations/{apply.ts → run-migration.ts} +33 -27
  125. package/src/control-api/types.ts +46 -29
  126. package/src/utils/cli-errors.ts +47 -2
  127. package/src/utils/formatters/errors.ts +11 -0
  128. package/src/utils/formatters/migration-graph-lane-colors.ts +194 -0
  129. package/src/utils/formatters/migration-graph-layout.ts +51 -7
  130. package/src/utils/formatters/migration-graph-rows.ts +128 -15
  131. package/src/utils/formatters/migration-graph-space-render.ts +138 -0
  132. package/src/utils/formatters/migration-graph-tree-render.ts +405 -77
  133. package/src/utils/formatters/migration-list-data-column.ts +4 -91
  134. package/src/utils/formatters/migration-list-graph-topology.ts +68 -90
  135. package/src/utils/formatters/migration-list-render.ts +122 -70
  136. package/src/utils/formatters/migration-list-styler.ts +48 -5
  137. package/src/utils/formatters/migration-log-table.ts +200 -0
  138. package/src/utils/formatters/migrations.ts +25 -1
  139. package/src/utils/global-flags.ts +35 -0
  140. package/src/utils/legend.ts +38 -0
  141. package/src/utils/migration-path-target.ts +39 -0
  142. package/src/utils/telemetry.ts +68 -32
  143. package/dist/client-KgJorIvG.mjs.map +0 -1
  144. package/dist/command-helpers-Bbw1GbwL.mjs.map +0 -1
  145. package/dist/commands/migration-list.mjs.map +0 -1
  146. package/dist/commands/migration-log.mjs.map +0 -1
  147. package/dist/commands/migration-status.mjs.map +0 -1
  148. package/dist/extension-pack-inputs-IDvjRCi3.mjs +0 -62
  149. package/dist/extension-pack-inputs-IDvjRCi3.mjs.map +0 -1
  150. package/dist/graph-render-rFAqZujX.mjs +0 -1081
  151. package/dist/graph-render-rFAqZujX.mjs.map +0 -1
  152. package/dist/init-Cv9UzWL5.mjs.map +0 -1
  153. package/dist/migration-check-BiBJoYYW.mjs.map +0 -1
  154. package/dist/migration-graph-D7DVUElV.mjs +0 -1232
  155. package/dist/migration-graph-D7DVUElV.mjs.map +0 -1
  156. package/dist/migration-list-styler-BRwF4-gy.mjs +0 -399
  157. package/dist/migration-list-styler-BRwF4-gy.mjs.map +0 -1
  158. package/dist/migration-types-D2FW63pr.d.mts +0 -15
  159. package/dist/migration-types-D2FW63pr.d.mts.map +0 -1
  160. package/dist/migrations-Cv2jxNNK.mjs +0 -228
  161. package/dist/migrations-Cv2jxNNK.mjs.map +0 -1
  162. package/dist/types-Dt_SfqFm.d.mts.map +0 -1
  163. package/src/utils/formatters/graph-migration-mapper.ts +0 -235
  164. package/src/utils/formatters/graph-render.ts +0 -1323
  165. package/src/utils/formatters/graph-types.ts +0 -120
@@ -0,0 +1,107 @@
1
+ import { userConfigPath, writeUserConfig } from '@prisma-next/cli-telemetry';
2
+ import { Command } from 'commander';
3
+ import {
4
+ addGlobalOptions,
5
+ setCommandDescriptions,
6
+ setCommandExamples,
7
+ } from '../../utils/command-helpers';
8
+ import { formatCommandHelp } from '../../utils/formatters/help';
9
+ import {
10
+ type CommonCommandOptions,
11
+ parseGlobalFlags,
12
+ parseGlobalFlagsOrExit,
13
+ } from '../../utils/global-flags';
14
+ import { isCI } from '../../utils/is-ci';
15
+ import { createTerminalUI } from '../../utils/terminal-ui';
16
+ import { formatTelemetryStatusLines, resolveTelemetryStatus } from './status';
17
+
18
+ function createTelemetryStatusCommand(): Command {
19
+ const command = new Command('status');
20
+ setCommandDescriptions(
21
+ command,
22
+ 'Show whether anonymous CLI telemetry is enabled and why',
23
+ 'Reports whether telemetry is currently enabled or disabled and the reason\n' +
24
+ '(default-on, stored opt-out, environment opt-out, or CI), the path to your\n' +
25
+ 'user-level config file, and whether an installation ID has been stored.\n' +
26
+ 'Read-only: never sends an event, never mints an ID, never writes anything.',
27
+ );
28
+ return addGlobalOptions(command).action((options: CommonCommandOptions) => {
29
+ const flags = parseGlobalFlagsOrExit(options);
30
+ const ui = createTerminalUI(flags);
31
+ const status = resolveTelemetryStatus({ env: process.env, inCI: isCI() });
32
+ if (flags.json) {
33
+ ui.output(JSON.stringify(status));
34
+ } else {
35
+ for (const line of formatTelemetryStatusLines(status)) {
36
+ ui.output(line);
37
+ }
38
+ }
39
+ process.exit(0);
40
+ });
41
+ }
42
+
43
+ function createTelemetryEnableCommand(): Command {
44
+ const command = new Command('enable');
45
+ setCommandDescriptions(
46
+ command,
47
+ 'Enable anonymous CLI telemetry',
48
+ 'Stores "enableTelemetry": true in your user-level config and mints an\n' +
49
+ 'installation ID if one is not already stored.',
50
+ );
51
+ return addGlobalOptions(command).action((options: CommonCommandOptions) => {
52
+ const flags = parseGlobalFlagsOrExit(options);
53
+ writeUserConfig({ enableTelemetry: true });
54
+ const ui = createTerminalUI(flags);
55
+ if (flags.json) {
56
+ ui.output(JSON.stringify({ enableTelemetry: true, configPath: userConfigPath() }));
57
+ } else {
58
+ ui.output(`Telemetry enabled. Preference stored in ${userConfigPath()}.`);
59
+ }
60
+ process.exit(0);
61
+ });
62
+ }
63
+
64
+ function createTelemetryDisableCommand(): Command {
65
+ const command = new Command('disable');
66
+ setCommandDescriptions(
67
+ command,
68
+ 'Disable anonymous CLI telemetry',
69
+ 'Stores "enableTelemetry": false in your user-level config. No installation\n' +
70
+ 'ID is minted and no event is sent.',
71
+ );
72
+ return addGlobalOptions(command).action((options: CommonCommandOptions) => {
73
+ const flags = parseGlobalFlagsOrExit(options);
74
+ writeUserConfig({ enableTelemetry: false });
75
+ const ui = createTerminalUI(flags);
76
+ if (flags.json) {
77
+ ui.output(JSON.stringify({ enableTelemetry: false, configPath: userConfigPath() }));
78
+ } else {
79
+ ui.output(`Telemetry disabled. Preference stored in ${userConfigPath()}.`);
80
+ }
81
+ process.exit(0);
82
+ });
83
+ }
84
+
85
+ export function createTelemetryCommand(): Command {
86
+ const command = new Command('telemetry');
87
+ setCommandDescriptions(
88
+ command,
89
+ 'Inspect and change anonymous CLI telemetry',
90
+ 'Show telemetry status, or enable / disable anonymous CLI usage data.\n' +
91
+ 'Telemetry is on by default (opt-out); see https://prisma-next.dev/docs/cli/telemetry\n' +
92
+ 'for what is collected and why.',
93
+ );
94
+ setCommandExamples(command, [
95
+ 'prisma-next telemetry status',
96
+ 'prisma-next telemetry disable',
97
+ 'prisma-next telemetry enable',
98
+ ]);
99
+ command.configureHelp({
100
+ formatHelp: (cmd) => formatCommandHelp({ command: cmd, flags: parseGlobalFlags({}) }),
101
+ subcommandDescription: () => '',
102
+ });
103
+ command.addCommand(createTelemetryStatusCommand());
104
+ command.addCommand(createTelemetryEnableCommand());
105
+ command.addCommand(createTelemetryDisableCommand());
106
+ return command;
107
+ }
@@ -0,0 +1,67 @@
1
+ import { readUserConfig, resolveGating, userConfigPath } from '@prisma-next/cli-telemetry';
2
+
3
+ /**
4
+ * Why telemetry resolves the way it does, in the order the CLI's
5
+ * `resolveTelemetryGate` evaluates: CI hard-disables first, then the env
6
+ * opt-outs, then the stored `enableTelemetry`, then the opt-out default.
7
+ */
8
+ export type TelemetryStatusReason =
9
+ | 'ci'
10
+ | 'env-opt-out'
11
+ | 'stored-opt-out'
12
+ | 'stored-opt-in'
13
+ | 'default-on';
14
+
15
+ export interface TelemetryStatus {
16
+ readonly enabled: boolean;
17
+ readonly reason: TelemetryStatusReason;
18
+ readonly configPath: string;
19
+ readonly installationIdStored: boolean;
20
+ }
21
+
22
+ /**
23
+ * Resolves the same gate the runtime uses (CI check + `resolveGating`) and
24
+ * projects it into a user-facing status. Pure read: never mints, never
25
+ * writes. The `installationId` value itself is never surfaced — only its
26
+ * presence — so `status` discloses nothing identifying.
27
+ */
28
+ export function resolveTelemetryStatus(inputs: {
29
+ readonly env: Readonly<Record<string, string | undefined>>;
30
+ readonly inCI: boolean;
31
+ }): TelemetryStatus {
32
+ const config = readUserConfig();
33
+ const configPath = userConfigPath();
34
+ const installationIdStored =
35
+ typeof config.installationId === 'string' && config.installationId.length > 0;
36
+
37
+ if (inputs.inCI) {
38
+ return { enabled: false, reason: 'ci', configPath, installationIdStored };
39
+ }
40
+
41
+ const gating = resolveGating({ env: inputs.env, config });
42
+ if (!gating.enabled) {
43
+ const reason: TelemetryStatusReason =
44
+ gating.reason === 'env-override' ? 'env-opt-out' : 'stored-opt-out';
45
+ return { enabled: false, reason, configPath, installationIdStored };
46
+ }
47
+
48
+ const reason: TelemetryStatusReason =
49
+ config.enableTelemetry === true ? 'stored-opt-in' : 'default-on';
50
+ return { enabled: true, reason, configPath, installationIdStored };
51
+ }
52
+
53
+ const REASON_EXPLANATION: Record<TelemetryStatusReason, string> = {
54
+ ci: 'CI environment detected — telemetry is hard-disabled.',
55
+ 'env-opt-out': 'an environment opt-out is set (DO_NOT_TRACK / PRISMA_NEXT_DISABLE_TELEMETRY).',
56
+ 'stored-opt-out': '"enableTelemetry": false is stored in your config.',
57
+ 'stored-opt-in': '"enableTelemetry": true is stored in your config.',
58
+ 'default-on': 'no explicit choice is stored, so the opt-out default applies.',
59
+ };
60
+
61
+ export function formatTelemetryStatusLines(status: TelemetryStatus): string[] {
62
+ return [
63
+ `Telemetry is ${status.enabled ? 'enabled' : 'disabled'}: ${REASON_EXPLANATION[status.reason]}`,
64
+ `Config file: ${status.configPath}`,
65
+ `Installation ID: ${status.installationIdStored ? 'stored' : 'not stored'}`,
66
+ ];
67
+ }
@@ -1,4 +1,8 @@
1
- import type { Contract, ContractMarkerRecord } from '@prisma-next/contract/types';
1
+ import type {
2
+ Contract,
3
+ ContractMarkerRecord,
4
+ LedgerEntryRecord,
5
+ } from '@prisma-next/contract/types';
2
6
  import { emit as emitContractArtifacts } from '@prisma-next/emitter';
3
7
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
4
8
  import type {
@@ -29,7 +33,7 @@ import { ContractValidationError } from './errors';
29
33
  import { executeDbInit } from './operations/db-init';
30
34
  import { executeDbUpdate } from './operations/db-update';
31
35
  import { type ExecuteDbVerifyResult, executeDbVerify } from './operations/db-verify';
32
- import { executeMigrationApply } from './operations/migration-apply';
36
+ import { executeMigrate } from './operations/migrate';
33
37
 
34
38
  import type {
35
39
  ControlActionName,
@@ -43,8 +47,8 @@ import type {
43
47
  EmitOptions,
44
48
  EmitResult,
45
49
  IntrospectOptions,
46
- MigrationApplyOptions,
47
- MigrationApplyResult,
50
+ MigrateOptions,
51
+ MigrateResult,
48
52
  OnControlProgress,
49
53
  SchemaVerifyOptions,
50
54
  SignOptions,
@@ -447,9 +451,15 @@ class ControlClientImpl implements ControlClient {
447
451
  return familyInstance.readAllMarkers({ driver });
448
452
  }
449
453
 
450
- async migrationApply(options: MigrationApplyOptions): Promise<MigrationApplyResult> {
454
+ /** Reads the per-migration journal; omit `space` to return every space. */
455
+ async readLedger(space?: string): Promise<readonly LedgerEntryRecord[]> {
456
+ const { driver, familyInstance } = await this.ensureConnected();
457
+ return familyInstance.readLedger({ driver, ...ifDefined('space', space) });
458
+ }
459
+
460
+ async migrate(options: MigrateOptions): Promise<MigrateResult> {
451
461
  const { onProgress } = options;
452
- await this.connectWithProgress(options.connection, 'migrationApply', onProgress);
462
+ await this.connectWithProgress(options.connection, 'migrate', onProgress);
453
463
  const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
454
464
 
455
465
  if (!hasMigrations(this.options.target)) {
@@ -464,7 +474,7 @@ class ControlClientImpl implements ControlClient {
464
474
  throw new ContractValidationError(message, error);
465
475
  }
466
476
 
467
- return executeMigrationApply({
477
+ return executeMigrate({
468
478
  driver,
469
479
  familyInstance,
470
480
  contract,
@@ -8,14 +8,14 @@ import type {
8
8
  } from '@prisma-next/framework-components/control';
9
9
  import { ifDefined } from '@prisma-next/utils/defined';
10
10
  import type { DbInitResult, OnControlProgress } from '../types';
11
- import { executeApply } from './db-apply';
11
+ import { executeRun } from './db-run';
12
12
 
13
13
  /**
14
14
  * Options for executing the `db init` operation.
15
15
  *
16
16
  * `db init` runs the loader → planner → runner pipeline:
17
17
  *
18
- * 1. {@link executeApply} loads a `ContractSpaceAggregate` via
18
+ * 1. {@link executeRun} loads a `ContractSpaceAggregate` via
19
19
  * {@link import('@prisma-next/migration-tools/aggregate').loadContractSpaceAggregate}
20
20
  * from the supplied descriptor set + on-disk on-disk artefacts.
21
21
  * 2. The aggregate planner runs with `callerPolicy.ignoreGraphFor`
@@ -68,7 +68,7 @@ export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extend
68
68
  export async function executeDbInit<TFamilyId extends string, TTargetId extends string>(
69
69
  options: ExecuteDbInitOptions<TFamilyId, TTargetId>,
70
70
  ): Promise<DbInitResult> {
71
- const result = await executeApply<TFamilyId, TTargetId>({
71
+ const result = await executeRun<TFamilyId, TTargetId>({
72
72
  driver: options.driver,
73
73
  familyInstance: options.familyInstance,
74
74
  contract: options.contract,
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Backs `db init` / `db update`. Strategy: introspect → planMigration; synth-for-app + graph-walk-extensions; plan-mode + orphan-marker preflight.
3
+ */
4
+
1
5
  import type { Contract } from '@prisma-next/contract/types';
2
6
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
3
7
  import type {
@@ -5,6 +9,7 @@ import type {
5
9
  ControlExtensionDescriptor,
6
10
  ControlFamilyInstance,
7
11
  MigrationOperationPolicy,
12
+ MigrationPlannerConflict,
8
13
  MigrationPlanOperation,
9
14
  OperationPreview,
10
15
  TargetMigrationsCapability,
@@ -32,14 +37,19 @@ import type {
32
37
  OnControlProgress,
33
38
  PerSpaceExecutionEntry,
34
39
  } from '../types';
35
- import { applyMigration, buildPerSpaceBreakdown, collectOrdered } from './apply';
36
40
  import { stripOperations } from './migration-helpers';
41
+ import {
42
+ buildPerSpaceBreakdown,
43
+ collectOrdered,
44
+ type OrderedResolution,
45
+ runMigration,
46
+ } from './run-migration';
37
47
 
38
48
  /**
39
- * Span IDs emitted via `onProgress` during the apply flow.
49
+ * Span IDs emitted via `onProgress` during the run flow.
40
50
  * Stable identifiers consumed by the structured-output renderer and by
41
51
  * tests asserting on span ids. The `apply` span itself is owned by
42
- * the {@link applyMigration} primitive — only the introspect / plan
52
+ * the {@link runMigration} primitive — only the introspect / plan
43
53
  * spans are emitted directly here.
44
54
  */
45
55
  const SPAN_IDS = {
@@ -48,13 +58,13 @@ const SPAN_IDS = {
48
58
  } as const;
49
59
 
50
60
  /**
51
- * Inputs shared by `db init` and `db update` apply flows.
61
+ * Inputs shared by `db init` and `db update` run flows.
52
62
  *
53
63
  * Accepts the already-validated app contract + descriptor list — the
54
64
  * loader gathers the rest from disk + descriptors. The CLI is the
55
65
  * descriptor-import boundary; everything downstream is descriptor-free.
56
66
  */
57
- export interface ExecuteApplyOptions<TFamilyId extends string, TTargetId extends string> {
67
+ export interface ExecuteRunOptions<TFamilyId extends string, TTargetId extends string> {
58
68
  readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
59
69
  readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;
60
70
  readonly contract: Contract;
@@ -92,8 +102,8 @@ export interface ExecuteApplyOptions<TFamilyId extends string, TTargetId extends
92
102
  * transaction across every space; failure on any space rolls back
93
103
  * every space's writes.
94
104
  */
95
- export async function executeApply<TFamilyId extends string, TTargetId extends string>(
96
- options: ExecuteApplyOptions<TFamilyId, TTargetId>,
105
+ export async function executeRun<TFamilyId extends string, TTargetId extends string>(
106
+ options: ExecuteRunOptions<TFamilyId, TTargetId>,
97
107
  ): Promise<DbInitResult | DbUpdateResult> {
98
108
  const {
99
109
  driver,
@@ -175,6 +185,7 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
175
185
  onProgress?.({ action, kind: 'spanEnd', spanId: SPAN_IDS.plan, outcome: 'ok' });
176
186
 
177
187
  const orderedResolutions = collectOrdered(planResult.value.applyOrder, planResult.value.perSpace);
188
+ const plannerWarnings = aggregatePlannerWarnings(orderedResolutions);
178
189
 
179
190
  // The destination's structural shape comes from the app's plan — its
180
191
  // `destination` is the storage hash users see in CLI output.
@@ -202,16 +213,17 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
202
213
  preview,
203
214
  perSpace,
204
215
  summary,
216
+ ...ifDefined('warnings', plannerWarnings),
205
217
  });
206
218
  }
207
219
 
208
- // 5. Apply mode: hand off to the shared `applyMigration` primitive.
220
+ // 5. Run mode: hand off to the shared `runMigration` primitive.
209
221
  // The runner-driving tail is identical for `db init` / `db update` /
210
222
  // `migrate` — only how each caller produces `perSpacePlans`
211
223
  // differs (synth + graph-walk via planMigration here; graph-walk
212
224
  // only for migrate). Each caller produces perSpacePlans differently;
213
- // this helper handles the shared apply tail.
214
- const applied = await applyMigration({
225
+ // this helper handles the shared run tail.
226
+ const applied = await runMigration({
215
227
  aggregate,
216
228
  perSpacePlans: planResult.value.perSpace,
217
229
  applyOrder: planResult.value.applyOrder,
@@ -228,6 +240,7 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
228
240
  summary: applied.failure.summary,
229
241
  ...ifDefined('why', applied.failure.why),
230
242
  meta: applied.failure.meta,
243
+ ...ifDefined('warnings', plannerWarnings),
231
244
  });
232
245
  }
233
246
 
@@ -246,9 +259,17 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
246
259
  operationsExecuted: applied.value.totalOpsExecuted,
247
260
  perSpace: applied.value.perSpace,
248
261
  summary,
262
+ ...ifDefined('warnings', plannerWarnings),
249
263
  });
250
264
  }
251
265
 
266
+ function aggregatePlannerWarnings(
267
+ orderedResolutions: readonly OrderedResolution[],
268
+ ): readonly MigrationPlannerConflict[] | undefined {
269
+ const warnings = orderedResolutions.flatMap((r) => r.entry.warnings ?? []);
270
+ return warnings.length > 0 ? warnings : undefined;
271
+ }
272
+
252
273
  /**
253
274
  * Compare the live `_prisma_marker` rows against the aggregate's
254
275
  * declared members. Any marker row whose `space` is not a member of
@@ -339,6 +360,7 @@ function wrapPlanResult(args: {
339
360
  readonly preview: OperationPreview | undefined;
340
361
  readonly perSpace: readonly PerSpaceExecutionEntry[];
341
362
  readonly summary: string;
363
+ readonly warnings?: readonly MigrationPlannerConflict[];
342
364
  }): DbInitResult | DbUpdateResult {
343
365
  const success: DbInitSuccess | DbUpdateSuccess = {
344
366
  mode: 'plan',
@@ -352,6 +374,7 @@ function wrapPlanResult(args: {
352
374
  },
353
375
  perSpace: args.perSpace,
354
376
  summary: args.summary,
377
+ ...ifDefined('warnings', args.warnings),
355
378
  };
356
379
  return ok(success);
357
380
  }
@@ -363,6 +386,7 @@ function wrapApplyResult(args: {
363
386
  readonly operationsExecuted: number;
364
387
  readonly perSpace: readonly PerSpaceExecutionEntry[];
365
388
  readonly summary: string;
389
+ readonly warnings?: readonly MigrationPlannerConflict[];
366
390
  }): DbInitResult | DbUpdateResult {
367
391
  const success: DbInitSuccess | DbUpdateSuccess = {
368
392
  mode: 'apply',
@@ -380,6 +404,7 @@ function wrapApplyResult(args: {
380
404
  : { storageHash: args.destination.storageHash },
381
405
  perSpace: args.perSpace,
382
406
  summary: args.summary,
407
+ ...ifDefined('warnings', args.warnings),
383
408
  };
384
409
  return ok(success);
385
410
  }
@@ -388,6 +413,7 @@ function buildRunnerFailure(args: {
388
413
  readonly summary: string;
389
414
  readonly why?: string;
390
415
  readonly meta: Record<string, unknown>;
416
+ readonly warnings?: readonly MigrationPlannerConflict[];
391
417
  }): DbInitResult | DbUpdateResult {
392
418
  const failure: DbInitFailure | DbUpdateFailure = {
393
419
  code: 'RUNNER_FAILED',
@@ -395,6 +421,7 @@ function buildRunnerFailure(args: {
395
421
  why: args.why,
396
422
  meta: args.meta,
397
423
  conflicts: undefined,
424
+ ...ifDefined('warnings', args.warnings),
398
425
  };
399
426
  return notOk(failure) as DbInitResult | DbUpdateResult;
400
427
  }
@@ -9,7 +9,7 @@ import type {
9
9
  import { ifDefined } from '@prisma-next/utils/defined';
10
10
  import { notOk } from '@prisma-next/utils/result';
11
11
  import type { DbUpdateResult, OnControlProgress } from '../types';
12
- import { executeApply } from './db-apply';
12
+ import { executeRun } from './db-run';
13
13
 
14
14
  const DB_UPDATE_POLICY = {
15
15
  allowedOperationClasses: ['additive', 'widening', 'destructive'] as const,
@@ -71,7 +71,7 @@ export async function executeDbUpdate<TFamilyId extends string, TTargetId extend
71
71
  const gate = await guardDestructiveChanges<TFamilyId, TTargetId>(sharedInputs);
72
72
  if (gate !== null) return gate;
73
73
  }
74
- return (await executeApply<TFamilyId, TTargetId>({
74
+ return (await executeRun<TFamilyId, TTargetId>({
75
75
  ...sharedInputs,
76
76
  mode: options.mode,
77
77
  })) as DbUpdateResult;
@@ -85,9 +85,9 @@ export async function executeDbUpdate<TFamilyId extends string, TTargetId extend
85
85
  * run.
86
86
  */
87
87
  async function guardDestructiveChanges<TFamilyId extends string, TTargetId extends string>(
88
- sharedInputs: Omit<Parameters<typeof executeApply<TFamilyId, TTargetId>>[0], 'mode'>,
88
+ sharedInputs: Omit<Parameters<typeof executeRun<TFamilyId, TTargetId>>[0], 'mode'>,
89
89
  ): Promise<DbUpdateResult | null> {
90
- const planResult = (await executeApply<TFamilyId, TTargetId>({
90
+ const planResult = (await executeRun<TFamilyId, TTargetId>({
91
91
  ...sharedInputs,
92
92
  mode: 'plan',
93
93
  })) as DbUpdateResult;
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Backs the `migrate` command. Strategy: graph-walk-all-members, replay-only (no introspect/synth/planner).
3
+ */
4
+
1
5
  import type { Contract } from '@prisma-next/contract/types';
2
6
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
3
7
  import type {
@@ -7,6 +11,7 @@ import type {
7
11
  TargetMigrationsCapability,
8
12
  } from '@prisma-next/framework-components/control';
9
13
  import {
14
+ buildSynthMigrationEdge,
10
15
  type ContractMarkerRecordLike,
11
16
  type ContractSpaceAggregate,
12
17
  type ContractSpaceMember,
@@ -24,14 +29,14 @@ import {
24
29
  buildContractSpaceAggregate,
25
30
  } from '../../utils/contract-space-aggregate-loader';
26
31
  import type {
27
- MigrationApplyFailure,
28
- MigrationApplyPathDecision,
29
- MigrationApplyResult,
30
- MigrationApplySuccess,
32
+ MigrateFailure,
33
+ MigratePathDecision,
34
+ MigrateResult,
35
+ MigrateSuccess,
31
36
  OnControlProgress,
32
37
  PerSpaceExecutionEntry,
33
38
  } from '../types';
34
- import { applyMigration, buildPerSpaceBreakdown } from './apply';
39
+ import { buildPerSpaceBreakdown, runMigration } from './run-migration';
35
40
 
36
41
  /**
37
42
  * Inputs for the aggregate-walking `migrate` control-api
@@ -42,7 +47,7 @@ import { applyMigration, buildPerSpaceBreakdown } from './apply';
42
47
  * is the single descriptor-free seam between the CLI and the
43
48
  * aggregate runtime.
44
49
  */
45
- export interface ExecuteMigrationApplyOptions<TFamilyId extends string, TTargetId extends string> {
50
+ export interface ExecuteMigrateOptions<TFamilyId extends string, TTargetId extends string> {
46
51
  readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
47
52
  readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;
48
53
  /** Already-validated app contract (the canonical "where we are heading" hash). */
@@ -95,16 +100,16 @@ export interface ExecuteMigrationApplyOptions<TFamilyId extends string, TTargetI
95
100
  * marker to `member.headRef.hash` (or `refHash` for the app
96
101
  * member when provided). Empty-graph members fail loudly — a
97
102
  * "never planned" space is a user-error condition for replay.
98
- * 4. Hand off to {@link applyMigration} (the runner-driving tail
103
+ * 4. Hand off to {@link runMigration} (the runner-driving tail
99
104
  * shared with `db init` / `db update`). Marker advancement is
100
105
  * inside the per-space transaction.
101
106
  *
102
107
  * Encodes the replay-only contract: every contract space must have an
103
108
  * authored migration graph on disk before this operation can advance it.
104
109
  */
105
- export async function executeMigrationApply<TFamilyId extends string, TTargetId extends string>(
106
- options: ExecuteMigrationApplyOptions<TFamilyId, TTargetId>,
107
- ): Promise<MigrationApplyResult> {
110
+ export async function executeMigrate<TFamilyId extends string, TTargetId extends string>(
111
+ options: ExecuteMigrateOptions<TFamilyId, TTargetId>,
112
+ ): Promise<MigrateResult> {
108
113
  const {
109
114
  driver,
110
115
  familyInstance,
@@ -276,7 +281,7 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
276
281
  );
277
282
  }
278
283
 
279
- const applied = await applyMigration({
284
+ const applied = await runMigration({
280
285
  aggregate,
281
286
  perSpacePlans,
282
287
  applyOrder,
@@ -285,12 +290,12 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
285
290
  migrations,
286
291
  frameworkComponents,
287
292
  policy: { allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'] },
288
- action: 'migrationApply',
293
+ action: 'migrate',
289
294
  ...ifDefined('onProgress', onProgress),
290
295
  });
291
296
 
292
297
  if (!applied.ok) {
293
- const failure: MigrationApplyFailure = {
298
+ const failure: MigrateFailure = {
294
299
  code: 'RUNNER_FAILED',
295
300
  summary: applied.failure.summary,
296
301
  why: applied.failure.why,
@@ -319,7 +324,7 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
319
324
  includeMarkers: true,
320
325
  });
321
326
  const totalMigrationsApplied = applied.value.orderedResolutions.reduce(
322
- (sum, r) => sum + (r.entry.migrationEdges?.length ?? 0),
327
+ (sum, r) => sum + r.entry.migrationEdges.length,
323
328
  0,
324
329
  );
325
330
  const summary = `Applied ${totalMigrationsApplied} migration(s) (${applied.value.totalOpsExecuted} operation(s)) across ${orderedAll.length} contract space(s)`;
@@ -361,7 +366,13 @@ function buildAtHeadResolution(args: {
361
366
  displayOps: [],
362
367
  destinationContract: member.contract(),
363
368
  strategy: 'graph-walk',
364
- migrationEdges: [],
369
+ migrationEdges: [
370
+ buildSynthMigrationEdge({
371
+ currentMarkerStorageHash: liveMarker?.storageHash,
372
+ destinationStorageHash: targetHash,
373
+ operationCount: 0,
374
+ }),
375
+ ],
365
376
  };
366
377
  }
367
378
 
@@ -389,9 +400,9 @@ interface BuildSuccessArgs {
389
400
  readonly summary: string;
390
401
  }
391
402
 
392
- function buildSuccess(args: BuildSuccessArgs): MigrationApplySuccess {
403
+ function buildSuccess(args: BuildSuccessArgs): MigrateSuccess {
393
404
  // The marker hash surfaced at the top level is the **app member's**
394
- // post-apply marker (the top-level `markerHash` field).
405
+ // post-migrate marker (the top-level `markerHash` field).
395
406
  // Per-space markers live on `perSpace[].marker.storageHash`.
396
407
  const appResolution = args.orderedResolutions.find(
397
408
  (r) => r.spaceId === args.aggregate.app.spaceId,
@@ -404,7 +415,7 @@ function buildSuccess(args: BuildSuccessArgs): MigrationApplySuccess {
404
415
  // JSON-shape consumers (e.g. `parsed.applied.length` in integration
405
416
  // tests). The aggregate per-space breakdown lives on `perSpace[]`.
406
417
  const applied = args.orderedResolutions.flatMap((r) => {
407
- const edges = r.entry.migrationEdges ?? [];
418
+ const edges = r.entry.migrationEdges;
408
419
  return edges.map((edge) => ({
409
420
  spaceId: r.spaceId,
410
421
  dirName: edge.dirName,
@@ -416,7 +427,7 @@ function buildSuccess(args: BuildSuccessArgs): MigrationApplySuccess {
416
427
  });
417
428
 
418
429
  const appPlan = appResolution?.entry;
419
- const pathDecision: MigrationApplyPathDecision | undefined = appPlan?.pathDecision
430
+ const pathDecision: MigratePathDecision | undefined = appPlan?.pathDecision
420
431
  ? {
421
432
  fromHash: appPlan.pathDecision.fromHash,
422
433
  toHash: appPlan.pathDecision.toHash,
@@ -455,10 +466,7 @@ function buildSuccess(args: BuildSuccessArgs): MigrationApplySuccess {
455
466
  *
456
467
  * @internal Exported for testing only.
457
468
  */
458
- export function buildNeverPlannedFailure(
459
- spaceId: string,
460
- targetHash: string,
461
- ): MigrationApplyFailure {
469
+ export function buildNeverPlannedFailure(spaceId: string, targetHash: string): MigrateFailure {
462
470
  return {
463
471
  code: 'MIGRATION_PATH_NOT_FOUND',
464
472
  summary: `No on-disk migrations for contract space "${spaceId}"`,
@@ -481,7 +489,7 @@ export function buildPathNotFoundFailure(
481
489
  spaceId: string,
482
490
  marker: ContractMarkerRecordLike | null,
483
491
  targetHash: string,
484
- ): MigrationApplyFailure {
492
+ ): MigrateFailure {
485
493
  const fromHash = marker?.storageHash ?? '<empty>';
486
494
  // The app-case phrasing names the user-visible condition (a
487
495
  // contract has been emitted that no on-disk migration reaches) so