@prisma-next/cli 0.12.0 → 0.13.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/cli.mjs +180 -163
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-KgJorIvG.mjs → client-CJzuo5wX.mjs} +222 -107
- package/dist/client-CJzuo5wX.mjs.map +1 -0
- package/dist/{command-helpers-Bbw1GbwL.mjs → command-helpers-DGMvGBeX.mjs} +318 -25
- package/dist/command-helpers-DGMvGBeX.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.d.mts.map +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +4 -5
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.d.mts.map +1 -1
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +6 -6
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +10 -7
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.d.mts.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +37 -3
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +298 -12
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +55 -13
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +3 -2
- package/dist/commands/migration-graph.d.mts +17 -8
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +185 -2
- package/dist/commands/migration-graph.mjs.map +1 -0
- package/dist/commands/migration-list.d.mts +26 -27
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +2 -190
- package/dist/commands/migration-log.d.mts +9 -19
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +1 -137
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +6 -5
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +1 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +17 -21
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +24 -36
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +42 -144
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +3 -759
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +4 -4
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/commands/telemetry/index.d.mts +7 -0
- package/dist/commands/telemetry/index.d.mts.map +1 -0
- package/dist/commands/telemetry/index.mjs +2 -0
- package/dist/{config-loader-B6sJjXTv.mjs → config-loader-p9JMrekQ.mjs} +1 -1
- package/dist/{config-loader-B6sJjXTv.mjs.map → config-loader-p9JMrekQ.mjs.map} +1 -1
- package/dist/config-loader.mjs +1 -1
- package/dist/{contract-at-errors-BxP-TOMl.mjs → contract-at-errors-CFXsstzm.mjs} +2 -2
- package/dist/{contract-at-errors-BxP-TOMl.mjs.map → contract-at-errors-CFXsstzm.mjs.map} +1 -1
- package/dist/{contract-emit-DxcGl4Uq.mjs → contract-emit-B_qriF8B.mjs} +5 -5
- package/dist/{contract-emit-DxcGl4Uq.mjs.map → contract-emit-B_qriF8B.mjs.map} +1 -1
- package/dist/{contract-emit-D-4jrNve.mjs → contract-emit-C8HmtboH.mjs} +12 -7
- package/dist/contract-emit-C8HmtboH.mjs.map +1 -0
- package/dist/{contract-enrichment-a0V5Y_mL.mjs → contract-enrichment-gn9sWbPw.mjs} +1 -1
- package/dist/{contract-enrichment-a0V5Y_mL.mjs.map → contract-enrichment-gn9sWbPw.mjs.map} +1 -1
- package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-BYT_ra_U.mjs} +5 -5
- package/dist/contract-infer-BYT_ra_U.mjs.map +1 -0
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs → contract-space-aggregate-loader-ClI1KN6d.mjs} +5 -5
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs.map → contract-space-aggregate-loader-ClI1KN6d.mjs.map} +1 -1
- package/dist/{db-verify-v_vUKXTU.mjs → db-verify-C24FKhb7.mjs} +6 -6
- package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-C24FKhb7.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +5 -3
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts +1 -3
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{extension-pack-inputs-IDvjRCi3.mjs → extension-pack-inputs-1ySHqxKG.mjs} +1 -1
- package/dist/{extension-pack-inputs-IDvjRCi3.mjs.map → extension-pack-inputs-1ySHqxKG.mjs.map} +1 -1
- package/dist/{framework-components-fYXjz_in.mjs → framework-components-YVQHhPH7.mjs} +2 -2
- package/dist/{framework-components-fYXjz_in.mjs.map → framework-components-YVQHhPH7.mjs.map} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-BpoOYtNZ.d.mts} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-BpoOYtNZ.d.mts.map} +1 -1
- package/dist/{init-Cv9UzWL5.mjs → init-0HwB-Vh8.mjs} +5 -58
- package/dist/init-0HwB-Vh8.mjs.map +1 -0
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-DF6IwcDl.mjs} +7 -5
- package/dist/inspect-live-schema-DF6IwcDl.mjs.map +1 -0
- package/dist/migration-check-soB5uZEQ.mjs +573 -0
- package/dist/migration-check-soB5uZEQ.mjs.map +1 -0
- package/dist/migration-cli.mjs +1 -1
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-DA-Lhx6o.mjs} +5 -5
- package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-DA-Lhx6o.mjs.map} +1 -1
- package/dist/migration-graph-command-render-CEez7YUK.mjs +1960 -0
- package/dist/migration-graph-command-render-CEez7YUK.mjs.map +1 -0
- package/dist/migration-list-DlJJ_38Z.mjs +230 -0
- package/dist/migration-list-DlJJ_38Z.mjs.map +1 -0
- package/dist/migration-log-CG0qQAFm.mjs +222 -0
- package/dist/migration-log-CG0qQAFm.mjs.map +1 -0
- package/dist/migration-path-target-Ce6OZImp.mjs +38 -0
- package/dist/migration-path-target-Ce6OZImp.mjs.map +1 -0
- package/dist/{migration-plan-9DJ7q7_z.mjs → migration-plan-z5Ing-TD.mjs} +9 -8
- package/dist/migration-plan-z5Ing-TD.mjs.map +1 -0
- package/dist/migration-status-CgWSoI_g.mjs +446 -0
- package/dist/migration-status-CgWSoI_g.mjs.map +1 -0
- package/dist/{output-B60Gw5fu.mjs → output-mEQ74_nd.mjs} +1 -1
- package/dist/{output-B60Gw5fu.mjs.map → output-mEQ74_nd.mjs.map} +1 -1
- package/dist/{progress-adapter-C644QK8l.mjs → progress-adapter-CjAeTxY_.mjs} +1 -1
- package/dist/{progress-adapter-C644QK8l.mjs.map → progress-adapter-CjAeTxY_.mjs.map} +1 -1
- package/dist/{ref-advancement-DUZqsue6.mjs → ref-advancement-BkXlikCA.mjs} +1 -1
- package/dist/{ref-advancement-DUZqsue6.mjs.map → ref-advancement-BkXlikCA.mjs.map} +1 -1
- package/dist/schemas-CeGMYFYX.d.mts +191 -0
- package/dist/schemas-CeGMYFYX.d.mts.map +1 -0
- package/dist/schemas-KhXMzNA_.mjs +112 -0
- package/dist/schemas-KhXMzNA_.mjs.map +1 -0
- package/dist/telemetry-BIM4beEO.mjs +122 -0
- package/dist/telemetry-BIM4beEO.mjs.map +1 -0
- package/dist/{terminal-ui-5Y6mrg93.d.mts → terminal-ui-DGRNFWna.d.mts} +1 -1
- package/dist/terminal-ui-DGRNFWna.d.mts.map +1 -0
- package/dist/{types-Dt_SfqFm.d.mts → types-C_tYiJYx.d.mts} +53 -31
- package/dist/types-C_tYiJYx.d.mts.map +1 -0
- package/dist/{verify-DCA9Sldu.mjs → verify-DcOYZ1tH.mjs} +2 -2
- package/dist/{verify-DCA9Sldu.mjs.map → verify-DcOYZ1tH.mjs.map} +1 -1
- package/package.json +26 -22
- package/src/cli.ts +5 -0
- package/src/commands/contract-infer.ts +2 -2
- package/src/commands/db-update.ts +7 -1
- package/src/commands/init/index.ts +6 -35
- package/src/commands/init/init.ts +1 -14
- package/src/commands/init/inputs.ts +0 -75
- package/src/commands/inspect-live-schema.ts +10 -0
- package/src/commands/json/schemas.ts +195 -0
- package/src/commands/migrate.ts +527 -8
- package/src/commands/migration-check.ts +469 -134
- package/src/commands/migration-graph.ts +164 -91
- package/src/commands/migration-list.ts +72 -39
- package/src/commands/migration-log.ts +52 -102
- package/src/commands/migration-new.ts +2 -1
- package/src/commands/migration-plan.ts +2 -1
- package/src/commands/migration-show.ts +31 -66
- package/src/commands/migration-status-overlay.ts +61 -0
- package/src/commands/migration-status.ts +458 -1066
- package/src/commands/telemetry/index.ts +107 -0
- package/src/commands/telemetry/status.ts +67 -0
- package/src/control-api/client.ts +70 -9
- package/src/control-api/operations/contract-emit.ts +22 -2
- package/src/control-api/operations/db-init.ts +6 -3
- package/src/control-api/operations/{db-apply.ts → db-run.ts} +55 -14
- package/src/control-api/operations/db-update.ts +7 -4
- package/src/control-api/operations/db-verify.ts +15 -5
- package/src/control-api/operations/{migration-apply.ts → migrate.ts} +181 -80
- package/src/control-api/operations/{apply.ts → run-migration.ts} +33 -27
- package/src/control-api/types.ts +56 -29
- package/src/utils/cli-errors.ts +70 -2
- package/src/utils/formatters/errors.ts +11 -0
- package/src/utils/formatters/migration-graph-command-render.ts +239 -0
- package/src/utils/formatters/migration-graph-grid-layout.ts +1134 -0
- package/src/utils/formatters/migration-graph-labels.ts +408 -0
- package/src/utils/formatters/migration-graph-model.ts +103 -0
- package/src/utils/formatters/migration-graph-occlusion-render.ts +258 -0
- package/src/utils/formatters/migration-graph-rows.ts +128 -15
- package/src/utils/formatters/migration-graph-space-render.ts +188 -0
- package/src/utils/formatters/migration-list-data-column.ts +4 -91
- package/src/utils/formatters/migration-list-graph-topology.ts +72 -94
- package/src/utils/formatters/migration-list-render.ts +135 -71
- package/src/utils/formatters/migration-list-styler.ts +46 -5
- package/src/utils/formatters/migration-list-types.ts +5 -21
- package/src/utils/formatters/migration-log-table.ts +205 -0
- package/src/utils/formatters/migrations.ts +33 -11
- package/src/utils/global-flags.ts +35 -0
- package/src/utils/integrity-violation-to-check-failure.ts +28 -19
- package/src/utils/legend.ts +38 -0
- package/src/utils/migration-path-target.ts +60 -0
- package/src/utils/telemetry.ts +68 -32
- package/dist/client-KgJorIvG.mjs.map +0 -1
- package/dist/command-helpers-Bbw1GbwL.mjs.map +0 -1
- package/dist/commands/migration-list.mjs.map +0 -1
- package/dist/commands/migration-log.mjs.map +0 -1
- package/dist/commands/migration-status.mjs.map +0 -1
- package/dist/contract-emit-D-4jrNve.mjs.map +0 -1
- package/dist/contract-infer-D8uEbJuu.mjs.map +0 -1
- package/dist/graph-render-rFAqZujX.mjs +0 -1081
- package/dist/graph-render-rFAqZujX.mjs.map +0 -1
- package/dist/init-Cv9UzWL5.mjs.map +0 -1
- package/dist/inspect-live-schema-C6ohV_oQ.mjs.map +0 -1
- package/dist/migration-check-BiBJoYYW.mjs +0 -341
- package/dist/migration-check-BiBJoYYW.mjs.map +0 -1
- package/dist/migration-graph-D7DVUElV.mjs +0 -1232
- package/dist/migration-graph-D7DVUElV.mjs.map +0 -1
- package/dist/migration-list-styler-BRwF4-gy.mjs +0 -399
- package/dist/migration-list-styler-BRwF4-gy.mjs.map +0 -1
- package/dist/migration-plan-9DJ7q7_z.mjs.map +0 -1
- package/dist/migration-types-D2FW63pr.d.mts +0 -15
- package/dist/migration-types-D2FW63pr.d.mts.map +0 -1
- package/dist/migrations-Cv2jxNNK.mjs +0 -228
- package/dist/migrations-Cv2jxNNK.mjs.map +0 -1
- package/dist/terminal-ui-5Y6mrg93.d.mts.map +0 -1
- package/dist/types-Dt_SfqFm.d.mts.map +0 -1
- package/src/utils/formatters/graph-migration-mapper.ts +0 -235
- package/src/utils/formatters/graph-render.ts +0 -1323
- package/src/utils/formatters/graph-types.ts +0 -120
- package/src/utils/formatters/migration-graph-layout.ts +0 -1119
- package/src/utils/formatters/migration-graph-tree-render.ts +0 -459
|
@@ -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,7 +1,13 @@
|
|
|
1
|
-
import type {
|
|
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';
|
|
7
|
+
import type { AuthoringPslBlockDescriptorNamespace } from '@prisma-next/framework-components/authoring';
|
|
3
8
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
4
9
|
import type {
|
|
10
|
+
ControlAdapterInstance,
|
|
5
11
|
ControlDriverInstance,
|
|
6
12
|
ControlFamilyInstance,
|
|
7
13
|
ControlStack,
|
|
@@ -21,15 +27,17 @@ import {
|
|
|
21
27
|
hasSchemaView,
|
|
22
28
|
} from '@prisma-next/framework-components/control';
|
|
23
29
|
import type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';
|
|
30
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
24
31
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
25
32
|
import { notOk, ok } from '@prisma-next/utils/result';
|
|
33
|
+
import { toExtensionInputs } from '../utils/extension-pack-inputs';
|
|
26
34
|
import { assertFrameworkComponentsCompatible } from '../utils/framework-components';
|
|
27
35
|
import { enrichContract } from './contract-enrichment';
|
|
28
36
|
import { ContractValidationError } from './errors';
|
|
29
37
|
import { executeDbInit } from './operations/db-init';
|
|
30
38
|
import { executeDbUpdate } from './operations/db-update';
|
|
31
39
|
import { type ExecuteDbVerifyResult, executeDbVerify } from './operations/db-verify';
|
|
32
|
-
import {
|
|
40
|
+
import { executeMigrate } from './operations/migrate';
|
|
33
41
|
|
|
34
42
|
import type {
|
|
35
43
|
ControlActionName,
|
|
@@ -43,8 +51,8 @@ import type {
|
|
|
43
51
|
EmitOptions,
|
|
44
52
|
EmitResult,
|
|
45
53
|
IntrospectOptions,
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
MigrateOptions,
|
|
55
|
+
MigrateResult,
|
|
48
56
|
OnControlProgress,
|
|
49
57
|
SchemaVerifyOptions,
|
|
50
58
|
SignOptions,
|
|
@@ -149,6 +157,23 @@ class ControlClientImpl implements ControlClient {
|
|
|
149
157
|
}
|
|
150
158
|
}
|
|
151
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Construct the control adapter once for a migration operation and return
|
|
162
|
+
* it, mirroring how the runtime plane builds the execution adapter once in
|
|
163
|
+
* `createExecutionStack`. Only `dbInit` / `dbUpdate` need it (it lowers the
|
|
164
|
+
* planner's DDL); read-only operations never build it. The descriptor is
|
|
165
|
+
* optional on the stack — targets without migrations omit it.
|
|
166
|
+
*/
|
|
167
|
+
private buildControlAdapter(): ControlAdapterInstance<string, string> {
|
|
168
|
+
this.init();
|
|
169
|
+
if (!this.stack?.adapter) {
|
|
170
|
+
throw new Error(
|
|
171
|
+
`Target "${this.options.target.targetId}" requires an adapter for migrations`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
return this.stack.adapter.create(this.stack);
|
|
175
|
+
}
|
|
176
|
+
|
|
152
177
|
private async ensureConnected(): Promise<{
|
|
153
178
|
driver: ControlDriverInstance<string, string>;
|
|
154
179
|
familyInstance: ControlFamilyInstance<string, unknown>;
|
|
@@ -359,6 +384,8 @@ class ControlClientImpl implements ControlClient {
|
|
|
359
384
|
throw new Error(`Target "${this.options.target.targetId}" does not support migrations`);
|
|
360
385
|
}
|
|
361
386
|
|
|
387
|
+
const adapter = this.buildControlAdapter();
|
|
388
|
+
|
|
362
389
|
let contract: Contract;
|
|
363
390
|
try {
|
|
364
391
|
contract = familyInstance.deserializeContract(options.contract);
|
|
@@ -369,6 +396,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
369
396
|
|
|
370
397
|
return executeDbInit({
|
|
371
398
|
driver,
|
|
399
|
+
adapter,
|
|
372
400
|
familyInstance,
|
|
373
401
|
contract,
|
|
374
402
|
mode: options.mode,
|
|
@@ -390,6 +418,8 @@ class ControlClientImpl implements ControlClient {
|
|
|
390
418
|
throw new Error(`Target "${this.options.target.targetId}" does not support migrations`);
|
|
391
419
|
}
|
|
392
420
|
|
|
421
|
+
const adapter = this.buildControlAdapter();
|
|
422
|
+
|
|
393
423
|
let contract: Contract;
|
|
394
424
|
try {
|
|
395
425
|
contract = familyInstance.deserializeContract(options.contract);
|
|
@@ -400,6 +430,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
400
430
|
|
|
401
431
|
return executeDbUpdate({
|
|
402
432
|
driver,
|
|
433
|
+
adapter,
|
|
403
434
|
familyInstance,
|
|
404
435
|
contract,
|
|
405
436
|
mode: options.mode,
|
|
@@ -447,9 +478,15 @@ class ControlClientImpl implements ControlClient {
|
|
|
447
478
|
return familyInstance.readAllMarkers({ driver });
|
|
448
479
|
}
|
|
449
480
|
|
|
450
|
-
|
|
481
|
+
/** Reads the per-migration journal; omit `space` to return every space. */
|
|
482
|
+
async readLedger(space?: string): Promise<readonly LedgerEntryRecord[]> {
|
|
483
|
+
const { driver, familyInstance } = await this.ensureConnected();
|
|
484
|
+
return familyInstance.readLedger({ driver, ...ifDefined('space', space) });
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
async migrate(options: MigrateOptions): Promise<MigrateResult> {
|
|
451
488
|
const { onProgress } = options;
|
|
452
|
-
await this.connectWithProgress(options.connection, '
|
|
489
|
+
await this.connectWithProgress(options.connection, 'migrate', onProgress);
|
|
453
490
|
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
454
491
|
|
|
455
492
|
if (!hasMigrations(this.options.target)) {
|
|
@@ -464,7 +501,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
464
501
|
throw new ContractValidationError(message, error);
|
|
465
502
|
}
|
|
466
503
|
|
|
467
|
-
return
|
|
504
|
+
return executeMigrate({
|
|
468
505
|
driver,
|
|
469
506
|
familyInstance,
|
|
470
507
|
contract,
|
|
@@ -535,6 +572,11 @@ class ControlClientImpl implements ControlClient {
|
|
|
535
572
|
return undefined;
|
|
536
573
|
}
|
|
537
574
|
|
|
575
|
+
getPslBlockDescriptors(): AuthoringPslBlockDescriptorNamespace {
|
|
576
|
+
this.init();
|
|
577
|
+
return this.stack!.authoringContributions.pslBlockDescriptors;
|
|
578
|
+
}
|
|
579
|
+
|
|
538
580
|
toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview | undefined {
|
|
539
581
|
this.init();
|
|
540
582
|
if (this.familyInstance && hasOperationPreview(this.familyInstance)) {
|
|
@@ -564,8 +606,26 @@ class ControlClientImpl implements ControlClient {
|
|
|
564
606
|
|
|
565
607
|
try {
|
|
566
608
|
const stack = this.stack!;
|
|
609
|
+
const extensionInputs = toExtensionInputs(
|
|
610
|
+
blindCast<
|
|
611
|
+
readonly unknown[],
|
|
612
|
+
'toExtensionInputs accepts readonly unknown[] per its documented structural cast boundary'
|
|
613
|
+
>(stack.extensionPacks),
|
|
614
|
+
);
|
|
615
|
+
const composedExtensionContracts = new Map<string, Contract>(
|
|
616
|
+
extensionInputs
|
|
617
|
+
.filter((p) => p.contractSpace !== undefined)
|
|
618
|
+
.map((p) => [
|
|
619
|
+
p.id,
|
|
620
|
+
blindCast<
|
|
621
|
+
Contract,
|
|
622
|
+
'contractSpace.contractJson is the typed contract for this extension space'
|
|
623
|
+
>(p.contractSpace!.contractJson),
|
|
624
|
+
]),
|
|
625
|
+
);
|
|
567
626
|
const sourceContext = {
|
|
568
627
|
composedExtensionPacks: stack.extensionPacks.map((p) => p.id),
|
|
628
|
+
composedExtensionContracts,
|
|
569
629
|
scalarTypeDescriptors: stack.scalarTypeDescriptors,
|
|
570
630
|
authoringContributions: stack.authoringContributions,
|
|
571
631
|
codecLookup: stack.codecLookup,
|
|
@@ -644,8 +704,9 @@ class ControlClientImpl implements ControlClient {
|
|
|
644
704
|
this.frameworkComponents ?? [],
|
|
645
705
|
);
|
|
646
706
|
|
|
707
|
+
let deserializedContract: Contract;
|
|
647
708
|
try {
|
|
648
|
-
this.familyInstance.deserializeContract(enrichedIR);
|
|
709
|
+
deserializedContract = this.familyInstance.deserializeContract(enrichedIR);
|
|
649
710
|
} catch (error) {
|
|
650
711
|
onProgress?.({
|
|
651
712
|
action: 'emit',
|
|
@@ -663,7 +724,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
663
724
|
}
|
|
664
725
|
|
|
665
726
|
const result = await emitContractArtifacts(
|
|
666
|
-
|
|
727
|
+
deserializedContract,
|
|
667
728
|
this.stack!,
|
|
668
729
|
this.options.family.emission,
|
|
669
730
|
{
|
|
@@ -3,12 +3,14 @@ import type { Contract } from '@prisma-next/contract/types';
|
|
|
3
3
|
import { emit, getEmittedArtifactPaths } from '@prisma-next/emitter';
|
|
4
4
|
import { createControlStack } from '@prisma-next/framework-components/control';
|
|
5
5
|
import { abortable } from '@prisma-next/utils/abortable';
|
|
6
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
6
7
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
7
8
|
import type { JsonObject } from '@prisma-next/utils/json';
|
|
8
9
|
import { dirname, join } from 'pathe';
|
|
9
10
|
import { loadConfig } from '../../config-loader';
|
|
10
11
|
import { errorContractConfigMissing, errorRuntime } from '../../utils/cli-errors';
|
|
11
12
|
import { queueEmitByOutput } from '../../utils/emit-queue';
|
|
13
|
+
import { toExtensionInputs } from '../../utils/extension-pack-inputs';
|
|
12
14
|
import { assertFrameworkComponentsCompatible } from '../../utils/framework-components';
|
|
13
15
|
import { publishContractArtifactPair } from '../../utils/publish-contract-artifact-pair';
|
|
14
16
|
import { validateContractDeps } from '../../utils/validate-contract-deps';
|
|
@@ -194,8 +196,26 @@ export async function executeContractEmit(
|
|
|
194
196
|
return queueEmitByOutput(outputJsonPath, async () => {
|
|
195
197
|
const stack = createControlStack(config);
|
|
196
198
|
|
|
199
|
+
const extensionInputs = toExtensionInputs(
|
|
200
|
+
blindCast<
|
|
201
|
+
readonly unknown[],
|
|
202
|
+
'toExtensionInputs accepts readonly unknown[] per its documented structural cast boundary'
|
|
203
|
+
>(stack.extensionPacks),
|
|
204
|
+
);
|
|
205
|
+
const composedExtensionContracts = new Map<string, Contract>(
|
|
206
|
+
extensionInputs
|
|
207
|
+
.filter((p) => p.contractSpace !== undefined)
|
|
208
|
+
.map((p) => [
|
|
209
|
+
p.id,
|
|
210
|
+
blindCast<
|
|
211
|
+
Contract,
|
|
212
|
+
'contractSpace.contractJson is the typed contract for this extension space'
|
|
213
|
+
>(p.contractSpace!.contractJson),
|
|
214
|
+
]),
|
|
215
|
+
);
|
|
197
216
|
const sourceContext = {
|
|
198
217
|
composedExtensionPacks: stack.extensionPacks.map((p) => p.id),
|
|
218
|
+
composedExtensionContracts,
|
|
199
219
|
scalarTypeDescriptors: stack.scalarTypeDescriptors,
|
|
200
220
|
authoringContributions: stack.authoringContributions,
|
|
201
221
|
codecLookup: stack.codecLookup,
|
|
@@ -247,7 +267,7 @@ export async function executeContractEmit(
|
|
|
247
267
|
validatedContract.value as unknown as Contract,
|
|
248
268
|
frameworkComponents,
|
|
249
269
|
);
|
|
250
|
-
familyInstance.deserializeContract(enrichedIR);
|
|
270
|
+
const deserializedContract = familyInstance.deserializeContract(enrichedIR);
|
|
251
271
|
// Each target's descriptor ships a `contractSerializer` SPI; the
|
|
252
272
|
// framework canonicalizer threads its `serializeContract` so the
|
|
253
273
|
// on-disk JSON envelope is constructed by target-owned code
|
|
@@ -260,7 +280,7 @@ export async function executeContractEmit(
|
|
|
260
280
|
const serializeContract = (c: Contract): JsonObject =>
|
|
261
281
|
contractSerializer.serializeContract(c);
|
|
262
282
|
emitResult = await unlessAborted(
|
|
263
|
-
emit(
|
|
283
|
+
emit(deserializedContract, stack, config.family.emission, {
|
|
264
284
|
outputJsonPath,
|
|
265
285
|
serializeContract,
|
|
266
286
|
...ifDefined('shouldPreserveEmpty', contractSerializer.shouldPreserveEmpty),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
2
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
3
3
|
import type {
|
|
4
|
+
ControlAdapterInstance,
|
|
4
5
|
ControlDriverInstance,
|
|
5
6
|
ControlExtensionDescriptor,
|
|
6
7
|
ControlFamilyInstance,
|
|
@@ -8,14 +9,14 @@ import type {
|
|
|
8
9
|
} from '@prisma-next/framework-components/control';
|
|
9
10
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
10
11
|
import type { DbInitResult, OnControlProgress } from '../types';
|
|
11
|
-
import {
|
|
12
|
+
import { executeRun } from './db-run';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Options for executing the `db init` operation.
|
|
15
16
|
*
|
|
16
17
|
* `db init` runs the loader → planner → runner pipeline:
|
|
17
18
|
*
|
|
18
|
-
* 1. {@link
|
|
19
|
+
* 1. {@link executeRun} loads a `ContractSpaceAggregate` via
|
|
19
20
|
* {@link import('@prisma-next/migration-tools/aggregate').loadContractSpaceAggregate}
|
|
20
21
|
* from the supplied descriptor set + on-disk on-disk artefacts.
|
|
21
22
|
* 2. The aggregate planner runs with `callerPolicy.ignoreGraphFor`
|
|
@@ -29,6 +30,7 @@ import { executeApply } from './db-apply';
|
|
|
29
30
|
*/
|
|
30
31
|
export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extends string> {
|
|
31
32
|
readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
|
|
33
|
+
readonly adapter: ControlAdapterInstance<TFamilyId, TTargetId>;
|
|
32
34
|
readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;
|
|
33
35
|
readonly contract: Contract;
|
|
34
36
|
readonly mode: 'plan' | 'apply';
|
|
@@ -68,8 +70,9 @@ export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extend
|
|
|
68
70
|
export async function executeDbInit<TFamilyId extends string, TTargetId extends string>(
|
|
69
71
|
options: ExecuteDbInitOptions<TFamilyId, TTargetId>,
|
|
70
72
|
): Promise<DbInitResult> {
|
|
71
|
-
const result = await
|
|
73
|
+
const result = await executeRun<TFamilyId, TTargetId>({
|
|
72
74
|
driver: options.driver,
|
|
75
|
+
adapter: options.adapter,
|
|
73
76
|
familyInstance: options.familyInstance,
|
|
74
77
|
contract: options.contract,
|
|
75
78
|
mode: options.mode,
|
|
@@ -1,10 +1,16 @@
|
|
|
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 {
|
|
8
|
+
ControlAdapterInstance,
|
|
4
9
|
ControlDriverInstance,
|
|
5
10
|
ControlExtensionDescriptor,
|
|
6
11
|
ControlFamilyInstance,
|
|
7
12
|
MigrationOperationPolicy,
|
|
13
|
+
MigrationPlannerConflict,
|
|
8
14
|
MigrationPlanOperation,
|
|
9
15
|
OperationPreview,
|
|
10
16
|
TargetMigrationsCapability,
|
|
@@ -12,9 +18,11 @@ import type {
|
|
|
12
18
|
import { hasOperationPreview } from '@prisma-next/framework-components/control';
|
|
13
19
|
import {
|
|
14
20
|
type ContractSpaceAggregate,
|
|
21
|
+
collectAggregateNamespaces,
|
|
15
22
|
type PlannerError,
|
|
16
23
|
planMigration,
|
|
17
24
|
} from '@prisma-next/migration-tools/aggregate';
|
|
25
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
18
26
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
19
27
|
import { notOk, ok } from '@prisma-next/utils/result';
|
|
20
28
|
import { CliStructuredError } from '../../utils/cli-errors';
|
|
@@ -32,14 +40,19 @@ import type {
|
|
|
32
40
|
OnControlProgress,
|
|
33
41
|
PerSpaceExecutionEntry,
|
|
34
42
|
} from '../types';
|
|
35
|
-
import { applyMigration, buildPerSpaceBreakdown, collectOrdered } from './apply';
|
|
36
43
|
import { stripOperations } from './migration-helpers';
|
|
44
|
+
import {
|
|
45
|
+
buildPerSpaceBreakdown,
|
|
46
|
+
collectOrdered,
|
|
47
|
+
type OrderedResolution,
|
|
48
|
+
runMigration,
|
|
49
|
+
} from './run-migration';
|
|
37
50
|
|
|
38
51
|
/**
|
|
39
|
-
* Span IDs emitted via `onProgress` during the
|
|
52
|
+
* Span IDs emitted via `onProgress` during the run flow.
|
|
40
53
|
* Stable identifiers consumed by the structured-output renderer and by
|
|
41
54
|
* tests asserting on span ids. The `apply` span itself is owned by
|
|
42
|
-
* the {@link
|
|
55
|
+
* the {@link runMigration} primitive — only the introspect / plan
|
|
43
56
|
* spans are emitted directly here.
|
|
44
57
|
*/
|
|
45
58
|
const SPAN_IDS = {
|
|
@@ -48,14 +61,15 @@ const SPAN_IDS = {
|
|
|
48
61
|
} as const;
|
|
49
62
|
|
|
50
63
|
/**
|
|
51
|
-
* Inputs shared by `db init` and `db update`
|
|
64
|
+
* Inputs shared by `db init` and `db update` run flows.
|
|
52
65
|
*
|
|
53
66
|
* Accepts the already-validated app contract + descriptor list — the
|
|
54
67
|
* loader gathers the rest from disk + descriptors. The CLI is the
|
|
55
68
|
* descriptor-import boundary; everything downstream is descriptor-free.
|
|
56
69
|
*/
|
|
57
|
-
export interface
|
|
70
|
+
export interface ExecuteRunOptions<TFamilyId extends string, TTargetId extends string> {
|
|
58
71
|
readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
|
|
72
|
+
readonly adapter: ControlAdapterInstance<TFamilyId, TTargetId>;
|
|
59
73
|
readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;
|
|
60
74
|
readonly contract: Contract;
|
|
61
75
|
readonly mode: 'plan' | 'apply';
|
|
@@ -92,11 +106,12 @@ export interface ExecuteApplyOptions<TFamilyId extends string, TTargetId extends
|
|
|
92
106
|
* transaction across every space; failure on any space rolls back
|
|
93
107
|
* every space's writes.
|
|
94
108
|
*/
|
|
95
|
-
export async function
|
|
96
|
-
options:
|
|
109
|
+
export async function executeRun<TFamilyId extends string, TTargetId extends string>(
|
|
110
|
+
options: ExecuteRunOptions<TFamilyId, TTargetId>,
|
|
97
111
|
): Promise<DbInitResult | DbUpdateResult> {
|
|
98
112
|
const {
|
|
99
113
|
driver,
|
|
114
|
+
adapter,
|
|
100
115
|
familyInstance,
|
|
101
116
|
contract,
|
|
102
117
|
mode,
|
|
@@ -147,7 +162,10 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
|
|
|
147
162
|
spanId: SPAN_IDS.introspect,
|
|
148
163
|
label: 'Introspecting database schema',
|
|
149
164
|
});
|
|
150
|
-
const schemaIR = await familyInstance.introspect({
|
|
165
|
+
const schemaIR = await familyInstance.introspect({
|
|
166
|
+
driver,
|
|
167
|
+
contract: collectAggregateNamespaces(aggregate),
|
|
168
|
+
});
|
|
151
169
|
onProgress?.({ action, kind: 'spanEnd', spanId: SPAN_IDS.introspect, outcome: 'ok' });
|
|
152
170
|
|
|
153
171
|
// 3. Plan via aggregate planner. App is forced through synth (today's
|
|
@@ -162,7 +180,7 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
|
|
|
162
180
|
const planResult = await planMigration<TFamilyId, TTargetId>({
|
|
163
181
|
aggregate,
|
|
164
182
|
currentDBState: { markersBySpaceId: markerRows, schemaIntrospection: schemaIR },
|
|
165
|
-
|
|
183
|
+
adapter,
|
|
166
184
|
migrations,
|
|
167
185
|
frameworkComponents,
|
|
168
186
|
callerPolicy: { ignoreGraphFor: new Set([aggregate.app.spaceId]) },
|
|
@@ -175,6 +193,7 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
|
|
|
175
193
|
onProgress?.({ action, kind: 'spanEnd', spanId: SPAN_IDS.plan, outcome: 'ok' });
|
|
176
194
|
|
|
177
195
|
const orderedResolutions = collectOrdered(planResult.value.applyOrder, planResult.value.perSpace);
|
|
196
|
+
const plannerWarnings = aggregatePlannerWarnings(orderedResolutions);
|
|
178
197
|
|
|
179
198
|
// The destination's structural shape comes from the app's plan — its
|
|
180
199
|
// `destination` is the storage hash users see in CLI output.
|
|
@@ -202,16 +221,17 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
|
|
|
202
221
|
preview,
|
|
203
222
|
perSpace,
|
|
204
223
|
summary,
|
|
224
|
+
...ifDefined('warnings', plannerWarnings),
|
|
205
225
|
});
|
|
206
226
|
}
|
|
207
227
|
|
|
208
|
-
// 5.
|
|
228
|
+
// 5. Run mode: hand off to the shared `runMigration` primitive.
|
|
209
229
|
// The runner-driving tail is identical for `db init` / `db update` /
|
|
210
230
|
// `migrate` — only how each caller produces `perSpacePlans`
|
|
211
231
|
// differs (synth + graph-walk via planMigration here; graph-walk
|
|
212
232
|
// only for migrate). Each caller produces perSpacePlans differently;
|
|
213
|
-
// this helper handles the shared
|
|
214
|
-
const applied = await
|
|
233
|
+
// this helper handles the shared run tail.
|
|
234
|
+
const applied = await runMigration({
|
|
215
235
|
aggregate,
|
|
216
236
|
perSpacePlans: planResult.value.perSpace,
|
|
217
237
|
applyOrder: planResult.value.applyOrder,
|
|
@@ -228,6 +248,7 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
|
|
|
228
248
|
summary: applied.failure.summary,
|
|
229
249
|
...ifDefined('why', applied.failure.why),
|
|
230
250
|
meta: applied.failure.meta,
|
|
251
|
+
...ifDefined('warnings', plannerWarnings),
|
|
231
252
|
});
|
|
232
253
|
}
|
|
233
254
|
|
|
@@ -246,9 +267,17 @@ export async function executeApply<TFamilyId extends string, TTargetId extends s
|
|
|
246
267
|
operationsExecuted: applied.value.totalOpsExecuted,
|
|
247
268
|
perSpace: applied.value.perSpace,
|
|
248
269
|
summary,
|
|
270
|
+
...ifDefined('warnings', plannerWarnings),
|
|
249
271
|
});
|
|
250
272
|
}
|
|
251
273
|
|
|
274
|
+
function aggregatePlannerWarnings(
|
|
275
|
+
orderedResolutions: readonly OrderedResolution[],
|
|
276
|
+
): readonly MigrationPlannerConflict[] | undefined {
|
|
277
|
+
const warnings = orderedResolutions.flatMap((r) => r.entry.warnings ?? []);
|
|
278
|
+
return warnings.length > 0 ? warnings : undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
252
281
|
/**
|
|
253
282
|
* Compare the live `_prisma_marker` rows against the aggregate's
|
|
254
283
|
* declared members. Any marker row whose `space` is not a member of
|
|
@@ -307,7 +336,10 @@ function mapPlannerError(error: PlannerError): DbInitResult | DbUpdateResult {
|
|
|
307
336
|
why: undefined,
|
|
308
337
|
meta: undefined,
|
|
309
338
|
};
|
|
310
|
-
return
|
|
339
|
+
return blindCast<
|
|
340
|
+
DbInitResult | DbUpdateResult,
|
|
341
|
+
'notOk(failure) is shape-compatible with both DbInitResult and DbUpdateResult; the union is the return type of the surrounding function'
|
|
342
|
+
>(notOk(failure));
|
|
311
343
|
}
|
|
312
344
|
if (error.kind === 'extensionPathUnreachable') {
|
|
313
345
|
return buildRunnerFailure({
|
|
@@ -339,6 +371,7 @@ function wrapPlanResult(args: {
|
|
|
339
371
|
readonly preview: OperationPreview | undefined;
|
|
340
372
|
readonly perSpace: readonly PerSpaceExecutionEntry[];
|
|
341
373
|
readonly summary: string;
|
|
374
|
+
readonly warnings?: readonly MigrationPlannerConflict[];
|
|
342
375
|
}): DbInitResult | DbUpdateResult {
|
|
343
376
|
const success: DbInitSuccess | DbUpdateSuccess = {
|
|
344
377
|
mode: 'plan',
|
|
@@ -352,6 +385,7 @@ function wrapPlanResult(args: {
|
|
|
352
385
|
},
|
|
353
386
|
perSpace: args.perSpace,
|
|
354
387
|
summary: args.summary,
|
|
388
|
+
...ifDefined('warnings', args.warnings),
|
|
355
389
|
};
|
|
356
390
|
return ok(success);
|
|
357
391
|
}
|
|
@@ -363,6 +397,7 @@ function wrapApplyResult(args: {
|
|
|
363
397
|
readonly operationsExecuted: number;
|
|
364
398
|
readonly perSpace: readonly PerSpaceExecutionEntry[];
|
|
365
399
|
readonly summary: string;
|
|
400
|
+
readonly warnings?: readonly MigrationPlannerConflict[];
|
|
366
401
|
}): DbInitResult | DbUpdateResult {
|
|
367
402
|
const success: DbInitSuccess | DbUpdateSuccess = {
|
|
368
403
|
mode: 'apply',
|
|
@@ -380,6 +415,7 @@ function wrapApplyResult(args: {
|
|
|
380
415
|
: { storageHash: args.destination.storageHash },
|
|
381
416
|
perSpace: args.perSpace,
|
|
382
417
|
summary: args.summary,
|
|
418
|
+
...ifDefined('warnings', args.warnings),
|
|
383
419
|
};
|
|
384
420
|
return ok(success);
|
|
385
421
|
}
|
|
@@ -388,6 +424,7 @@ function buildRunnerFailure(args: {
|
|
|
388
424
|
readonly summary: string;
|
|
389
425
|
readonly why?: string;
|
|
390
426
|
readonly meta: Record<string, unknown>;
|
|
427
|
+
readonly warnings?: readonly MigrationPlannerConflict[];
|
|
391
428
|
}): DbInitResult | DbUpdateResult {
|
|
392
429
|
const failure: DbInitFailure | DbUpdateFailure = {
|
|
393
430
|
code: 'RUNNER_FAILED',
|
|
@@ -395,6 +432,10 @@ function buildRunnerFailure(args: {
|
|
|
395
432
|
why: args.why,
|
|
396
433
|
meta: args.meta,
|
|
397
434
|
conflicts: undefined,
|
|
435
|
+
...ifDefined('warnings', args.warnings),
|
|
398
436
|
};
|
|
399
|
-
return
|
|
437
|
+
return blindCast<
|
|
438
|
+
DbInitResult | DbUpdateResult,
|
|
439
|
+
'notOk(failure) is shape-compatible with both DbInitResult and DbUpdateResult; the union is the return type of the surrounding function'
|
|
440
|
+
>(notOk(failure));
|
|
400
441
|
}
|