@prisma-next/cli 0.3.0-dev.16 → 0.3.0-dev.162

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 (242) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +381 -128
  3. package/dist/cli-errors-BDCYR5ap.mjs +4 -0
  4. package/dist/cli-errors-Dzs7Oxz7.d.mts +3 -0
  5. package/dist/cli.d.mts +1 -0
  6. package/dist/cli.js +1 -2671
  7. package/dist/cli.mjs +245 -0
  8. package/dist/cli.mjs.map +1 -0
  9. package/dist/client-yYtotiSX.mjs +1063 -0
  10. package/dist/client-yYtotiSX.mjs.map +1 -0
  11. package/dist/commands/contract-emit.d.mts +7 -0
  12. package/dist/commands/contract-emit.d.mts.map +1 -0
  13. package/dist/commands/contract-emit.mjs +8 -0
  14. package/dist/commands/contract-infer.d.mts +7 -0
  15. package/dist/commands/contract-infer.d.mts.map +1 -0
  16. package/dist/commands/contract-infer.mjs +9 -0
  17. package/dist/commands/db-init.d.mts +7 -0
  18. package/dist/commands/db-init.d.mts.map +1 -0
  19. package/dist/commands/db-init.mjs +125 -0
  20. package/dist/commands/db-init.mjs.map +1 -0
  21. package/dist/commands/db-schema.d.mts +7 -0
  22. package/dist/commands/db-schema.d.mts.map +1 -0
  23. package/dist/commands/db-schema.mjs +55 -0
  24. package/dist/commands/db-schema.mjs.map +1 -0
  25. package/dist/commands/db-sign.d.mts +7 -0
  26. package/dist/commands/db-sign.d.mts.map +1 -0
  27. package/dist/commands/db-sign.mjs +136 -0
  28. package/dist/commands/db-sign.mjs.map +1 -0
  29. package/dist/commands/db-update.d.mts +7 -0
  30. package/dist/commands/db-update.d.mts.map +1 -0
  31. package/dist/commands/db-update.mjs +122 -0
  32. package/dist/commands/db-update.mjs.map +1 -0
  33. package/dist/commands/db-verify.d.mts +7 -0
  34. package/dist/commands/db-verify.d.mts.map +1 -0
  35. package/dist/commands/db-verify.mjs +322 -0
  36. package/dist/commands/db-verify.mjs.map +1 -0
  37. package/dist/commands/migration-apply.d.mts +36 -0
  38. package/dist/commands/migration-apply.d.mts.map +1 -0
  39. package/dist/commands/migration-apply.mjs +244 -0
  40. package/dist/commands/migration-apply.mjs.map +1 -0
  41. package/dist/commands/migration-new.d.mts +8 -0
  42. package/dist/commands/migration-new.d.mts.map +1 -0
  43. package/dist/commands/migration-new.mjs +151 -0
  44. package/dist/commands/migration-new.mjs.map +1 -0
  45. package/dist/commands/migration-plan.d.mts +47 -0
  46. package/dist/commands/migration-plan.d.mts.map +1 -0
  47. package/dist/commands/migration-plan.mjs +312 -0
  48. package/dist/commands/migration-plan.mjs.map +1 -0
  49. package/dist/commands/migration-ref.d.mts +43 -0
  50. package/dist/commands/migration-ref.d.mts.map +1 -0
  51. package/dist/commands/migration-ref.mjs +194 -0
  52. package/dist/commands/migration-ref.mjs.map +1 -0
  53. package/dist/commands/migration-show.d.mts +28 -0
  54. package/dist/commands/migration-show.d.mts.map +1 -0
  55. package/dist/commands/migration-show.mjs +139 -0
  56. package/dist/commands/migration-show.mjs.map +1 -0
  57. package/dist/commands/migration-status.d.mts +86 -0
  58. package/dist/commands/migration-status.d.mts.map +1 -0
  59. package/dist/commands/migration-status.mjs +8 -0
  60. package/dist/commands/migration-verify.d.mts +16 -0
  61. package/dist/commands/migration-verify.d.mts.map +1 -0
  62. package/dist/commands/migration-verify.mjs +109 -0
  63. package/dist/commands/migration-verify.mjs.map +1 -0
  64. package/dist/config-loader-C4VXKl8f.mjs +43 -0
  65. package/dist/config-loader-C4VXKl8f.mjs.map +1 -0
  66. package/dist/{config-loader.d.ts → config-loader.d.mts} +8 -3
  67. package/dist/config-loader.d.mts.map +1 -0
  68. package/dist/config-loader.mjs +3 -0
  69. package/dist/contract-emit-Bk_eEDKu.mjs +187 -0
  70. package/dist/contract-emit-Bk_eEDKu.mjs.map +1 -0
  71. package/dist/contract-infer-suMDmFSG.mjs +89 -0
  72. package/dist/contract-infer-suMDmFSG.mjs.map +1 -0
  73. package/dist/exports/config-types.d.mts +2 -0
  74. package/dist/exports/config-types.mjs +3 -0
  75. package/dist/exports/control-api.d.mts +624 -0
  76. package/dist/exports/control-api.d.mts.map +1 -0
  77. package/dist/exports/control-api.mjs +109 -0
  78. package/dist/exports/control-api.mjs.map +1 -0
  79. package/dist/{load-ts-contract.d.ts → exports/index.d.mts} +12 -7
  80. package/dist/exports/index.d.mts.map +1 -0
  81. package/dist/exports/index.mjs +141 -0
  82. package/dist/exports/index.mjs.map +1 -0
  83. package/dist/extract-operation-statements-BVlb3jxp.mjs +13 -0
  84. package/dist/extract-operation-statements-BVlb3jxp.mjs.map +1 -0
  85. package/dist/extract-sql-ddl-6EVSOThm.mjs +26 -0
  86. package/dist/extract-sql-ddl-6EVSOThm.mjs.map +1 -0
  87. package/dist/framework-components-BAsliT4V.mjs +59 -0
  88. package/dist/framework-components-BAsliT4V.mjs.map +1 -0
  89. package/dist/inspect-live-schema-HMutsJYh.mjs +91 -0
  90. package/dist/inspect-live-schema-HMutsJYh.mjs.map +1 -0
  91. package/dist/migration-command-scaffold-Dg7CKKCg.mjs +105 -0
  92. package/dist/migration-command-scaffold-Dg7CKKCg.mjs.map +1 -0
  93. package/dist/migration-status-BqfVmC0w.mjs +1582 -0
  94. package/dist/migration-status-BqfVmC0w.mjs.map +1 -0
  95. package/dist/migrations-Bv8oeiY_.mjs +173 -0
  96. package/dist/migrations-Bv8oeiY_.mjs.map +1 -0
  97. package/dist/progress-adapter-D4x8SbJa.mjs +43 -0
  98. package/dist/progress-adapter-D4x8SbJa.mjs.map +1 -0
  99. package/dist/terminal-ui-N5tR-ob5.mjs +967 -0
  100. package/dist/terminal-ui-N5tR-ob5.mjs.map +1 -0
  101. package/dist/verify-WARh5TjK.mjs +385 -0
  102. package/dist/verify-WARh5TjK.mjs.map +1 -0
  103. package/package.json +88 -42
  104. package/src/cli.ts +113 -58
  105. package/src/commands/contract-emit.ts +237 -144
  106. package/src/commands/contract-infer-paths.ts +32 -0
  107. package/src/commands/contract-infer.ts +143 -0
  108. package/src/commands/db-init.ts +97 -219
  109. package/src/commands/db-schema.ts +77 -0
  110. package/src/commands/db-sign.ts +208 -229
  111. package/src/commands/db-update.ts +236 -0
  112. package/src/commands/db-verify.ts +504 -184
  113. package/src/commands/inspect-live-schema.ts +170 -0
  114. package/src/commands/migration-apply.ts +427 -0
  115. package/src/commands/migration-new.ts +260 -0
  116. package/src/commands/migration-plan.ts +519 -0
  117. package/src/commands/migration-ref.ts +305 -0
  118. package/src/commands/migration-show.ts +246 -0
  119. package/src/commands/migration-status.ts +864 -0
  120. package/src/commands/migration-verify.ts +180 -0
  121. package/src/config-loader.ts +13 -3
  122. package/src/control-api/client.ts +424 -72
  123. package/src/control-api/contract-enrichment.ts +119 -0
  124. package/src/control-api/errors.ts +9 -0
  125. package/src/control-api/operations/contract-emit.ts +174 -0
  126. package/src/control-api/operations/db-init.ts +53 -49
  127. package/src/control-api/operations/db-update.ts +220 -0
  128. package/src/control-api/operations/extract-operation-statements.ts +14 -0
  129. package/src/control-api/operations/extract-sql-ddl.ts +47 -0
  130. package/src/control-api/operations/migration-apply.ts +191 -0
  131. package/src/control-api/operations/migration-helpers.ts +49 -0
  132. package/src/control-api/types.ts +388 -18
  133. package/src/exports/config-types.ts +4 -3
  134. package/src/exports/control-api.ts +21 -2
  135. package/src/load-ts-contract.ts +30 -19
  136. package/src/utils/cli-errors.ts +14 -8
  137. package/src/utils/command-helpers.ts +302 -3
  138. package/src/utils/formatters/emit.ts +67 -0
  139. package/src/utils/formatters/errors.ts +82 -0
  140. package/src/utils/formatters/graph-migration-mapper.ts +240 -0
  141. package/src/utils/formatters/graph-render.ts +1323 -0
  142. package/src/utils/formatters/graph-types.ts +120 -0
  143. package/src/utils/formatters/help.ts +380 -0
  144. package/src/utils/formatters/helpers.ts +28 -0
  145. package/src/utils/formatters/migrations.ts +346 -0
  146. package/src/utils/formatters/styled.ts +212 -0
  147. package/src/utils/formatters/verify.ts +621 -0
  148. package/src/utils/framework-components.ts +13 -10
  149. package/src/utils/global-flags.ts +41 -23
  150. package/src/utils/migration-command-scaffold.ts +184 -0
  151. package/src/utils/migration-types.ts +12 -0
  152. package/src/utils/progress-adapter.ts +18 -29
  153. package/src/utils/result-handler.ts +12 -13
  154. package/src/utils/shutdown.ts +92 -0
  155. package/src/utils/suggest-command.ts +31 -0
  156. package/src/utils/terminal-ui.ts +276 -0
  157. package/dist/chunk-5MPKZYVI.js +0 -47
  158. package/dist/chunk-5MPKZYVI.js.map +0 -1
  159. package/dist/chunk-6EPKRATC.js +0 -91
  160. package/dist/chunk-6EPKRATC.js.map +0 -1
  161. package/dist/chunk-74IELXRA.js +0 -371
  162. package/dist/chunk-74IELXRA.js.map +0 -1
  163. package/dist/chunk-HWYQOCAJ.js +0 -47
  164. package/dist/chunk-HWYQOCAJ.js.map +0 -1
  165. package/dist/chunk-U6QI3AZ3.js +0 -133
  166. package/dist/chunk-U6QI3AZ3.js.map +0 -1
  167. package/dist/chunk-VI2YETW7.js +0 -38
  168. package/dist/chunk-VI2YETW7.js.map +0 -1
  169. package/dist/chunk-ZG5T6OB5.js +0 -923
  170. package/dist/chunk-ZG5T6OB5.js.map +0 -1
  171. package/dist/cli.d.ts +0 -2
  172. package/dist/cli.d.ts.map +0 -1
  173. package/dist/cli.js.map +0 -1
  174. package/dist/commands/contract-emit.d.ts +0 -3
  175. package/dist/commands/contract-emit.d.ts.map +0 -1
  176. package/dist/commands/contract-emit.js +0 -11
  177. package/dist/commands/contract-emit.js.map +0 -1
  178. package/dist/commands/db-init.d.ts +0 -3
  179. package/dist/commands/db-init.d.ts.map +0 -1
  180. package/dist/commands/db-init.js +0 -302
  181. package/dist/commands/db-init.js.map +0 -1
  182. package/dist/commands/db-introspect.d.ts +0 -3
  183. package/dist/commands/db-introspect.d.ts.map +0 -1
  184. package/dist/commands/db-introspect.js +0 -185
  185. package/dist/commands/db-introspect.js.map +0 -1
  186. package/dist/commands/db-schema-verify.d.ts +0 -3
  187. package/dist/commands/db-schema-verify.d.ts.map +0 -1
  188. package/dist/commands/db-schema-verify.js +0 -163
  189. package/dist/commands/db-schema-verify.js.map +0 -1
  190. package/dist/commands/db-sign.d.ts +0 -3
  191. package/dist/commands/db-sign.d.ts.map +0 -1
  192. package/dist/commands/db-sign.js +0 -198
  193. package/dist/commands/db-sign.js.map +0 -1
  194. package/dist/commands/db-verify.d.ts +0 -3
  195. package/dist/commands/db-verify.d.ts.map +0 -1
  196. package/dist/commands/db-verify.js +0 -172
  197. package/dist/commands/db-verify.js.map +0 -1
  198. package/dist/config-loader.d.ts.map +0 -1
  199. package/dist/config-loader.js +0 -7
  200. package/dist/config-loader.js.map +0 -1
  201. package/dist/control-api/client.d.ts +0 -13
  202. package/dist/control-api/client.d.ts.map +0 -1
  203. package/dist/control-api/operations/db-init.d.ts +0 -29
  204. package/dist/control-api/operations/db-init.d.ts.map +0 -1
  205. package/dist/control-api/types.d.ts +0 -256
  206. package/dist/control-api/types.d.ts.map +0 -1
  207. package/dist/exports/config-types.d.ts +0 -3
  208. package/dist/exports/config-types.d.ts.map +0 -1
  209. package/dist/exports/config-types.js +0 -6
  210. package/dist/exports/config-types.js.map +0 -1
  211. package/dist/exports/control-api.d.ts +0 -13
  212. package/dist/exports/control-api.d.ts.map +0 -1
  213. package/dist/exports/control-api.js +0 -9
  214. package/dist/exports/control-api.js.map +0 -1
  215. package/dist/exports/index.d.ts +0 -4
  216. package/dist/exports/index.d.ts.map +0 -1
  217. package/dist/exports/index.js +0 -177
  218. package/dist/exports/index.js.map +0 -1
  219. package/dist/load-ts-contract.d.ts.map +0 -1
  220. package/dist/utils/action.d.ts +0 -16
  221. package/dist/utils/action.d.ts.map +0 -1
  222. package/dist/utils/cli-errors.d.ts +0 -7
  223. package/dist/utils/cli-errors.d.ts.map +0 -1
  224. package/dist/utils/command-helpers.d.ts +0 -12
  225. package/dist/utils/command-helpers.d.ts.map +0 -1
  226. package/dist/utils/framework-components.d.ts +0 -70
  227. package/dist/utils/framework-components.d.ts.map +0 -1
  228. package/dist/utils/global-flags.d.ts +0 -25
  229. package/dist/utils/global-flags.d.ts.map +0 -1
  230. package/dist/utils/output.d.ts +0 -142
  231. package/dist/utils/output.d.ts.map +0 -1
  232. package/dist/utils/progress-adapter.d.ts +0 -26
  233. package/dist/utils/progress-adapter.d.ts.map +0 -1
  234. package/dist/utils/result-handler.d.ts +0 -15
  235. package/dist/utils/result-handler.d.ts.map +0 -1
  236. package/dist/utils/spinner.d.ts +0 -29
  237. package/dist/utils/spinner.d.ts.map +0 -1
  238. package/src/commands/db-introspect.ts +0 -254
  239. package/src/commands/db-schema-verify.ts +0 -231
  240. package/src/utils/action.ts +0 -43
  241. package/src/utils/output.ts +0 -1471
  242. package/src/utils/spinner.ts +0 -67
@@ -1,50 +1,37 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { relative, resolve } from 'node:path';
1
+ import { ifDefined } from '@prisma-next/utils/defined';
3
2
  import { notOk, ok, type Result } from '@prisma-next/utils/result';
4
3
  import { Command } from 'commander';
5
- import { loadConfig } from '../config-loader';
6
- import { createControlClient } from '../control-api/client';
4
+ import { ContractValidationError } from '../control-api/errors';
7
5
  import type { DbInitFailure } from '../control-api/types';
8
6
  import {
9
7
  CliStructuredError,
10
8
  errorContractValidationFailed,
11
- errorDatabaseConnectionRequired,
12
- errorDriverRequired,
13
- errorFileNotFound,
14
- errorJsonFormatNotSupported,
15
9
  errorMigrationPlanningFailed,
10
+ errorRunnerFailed,
16
11
  errorRuntime,
17
- errorTargetMigrationNotSupported,
18
12
  errorUnexpected,
19
13
  } from '../utils/cli-errors';
20
- import { setCommandDescriptions } from '../utils/command-helpers';
14
+ import type { MigrationCommandOptions } from '../utils/command-helpers';
15
+ import {
16
+ sanitizeErrorMessage,
17
+ setCommandDescriptions,
18
+ setCommandExamples,
19
+ } from '../utils/command-helpers';
20
+ import {
21
+ formatMigrationApplyOutput,
22
+ formatMigrationJson,
23
+ formatMigrationPlanOutput,
24
+ type MigrationCommandResult,
25
+ } from '../utils/formatters/migrations';
21
26
  import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
22
27
  import {
23
- type DbInitResult,
24
- formatCommandHelp,
25
- formatDbInitApplyOutput,
26
- formatDbInitJson,
27
- formatDbInitPlanOutput,
28
- formatStyledHeader,
29
- } from '../utils/output';
30
- import { createProgressAdapter } from '../utils/progress-adapter';
28
+ addMigrationCommandOptions,
29
+ prepareMigrationContext,
30
+ } from '../utils/migration-command-scaffold';
31
31
  import { handleResult } from '../utils/result-handler';
32
+ import { TerminalUI } from '../utils/terminal-ui';
32
33
 
33
- interface DbInitOptions {
34
- readonly db?: string;
35
- readonly config?: string;
36
- readonly plan?: boolean;
37
- readonly json?: string | boolean;
38
- readonly quiet?: boolean;
39
- readonly q?: boolean;
40
- readonly verbose?: boolean;
41
- readonly v?: boolean;
42
- readonly vv?: boolean;
43
- readonly trace?: boolean;
44
- readonly timestamps?: boolean;
45
- readonly color?: boolean;
46
- readonly 'no-color'?: boolean;
47
- }
34
+ type DbInitOptions = MigrationCommandOptions;
48
35
 
49
36
  /**
50
37
  * Maps a DbInitFailure to a CliStructuredError for consistent error handling.
@@ -57,12 +44,12 @@ function mapDbInitFailure(failure: DbInitFailure): CliStructuredError {
57
44
  if (failure.code === 'MARKER_ORIGIN_MISMATCH') {
58
45
  const mismatchParts: string[] = [];
59
46
  if (
60
- failure.marker?.coreHash !== failure.destination?.coreHash &&
61
- failure.marker?.coreHash &&
62
- failure.destination?.coreHash
47
+ failure.marker?.storageHash !== failure.destination?.storageHash &&
48
+ failure.marker?.storageHash &&
49
+ failure.destination?.storageHash
63
50
  ) {
64
51
  mismatchParts.push(
65
- `coreHash (marker: ${failure.marker.coreHash}, destination: ${failure.destination.coreHash})`,
52
+ `storageHash (marker: ${failure.marker.storageHash}, destination: ${failure.destination.storageHash})`,
66
53
  );
67
54
  }
68
55
  if (
@@ -76,33 +63,28 @@ function mapDbInitFailure(failure: DbInitFailure): CliStructuredError {
76
63
  }
77
64
 
78
65
  return errorRuntime(
79
- `Existing contract marker does not match plan destination.${mismatchParts.length > 0 ? ` Mismatch in ${mismatchParts.join(' and ')}.` : ''}`,
66
+ `Existing database signature does not match plan destination.${mismatchParts.length > 0 ? ` Mismatch in ${mismatchParts.join(' and ')}.` : ''}`,
80
67
  {
81
- why: 'Database has an existing contract marker that does not match the target contract',
68
+ why: 'Database has an existing signature (marker) that does not match the target contract',
82
69
  fix: 'If bootstrapping, drop/reset the database then re-run `prisma-next db init`; otherwise reconcile schema/marker using your migration workflow',
83
70
  meta: {
84
71
  code: 'MARKER_ORIGIN_MISMATCH',
85
- ...(failure.marker?.coreHash ? { markerCoreHash: failure.marker.coreHash } : {}),
86
- ...(failure.destination?.coreHash
87
- ? { destinationCoreHash: failure.destination.coreHash }
88
- : {}),
89
- ...(failure.marker?.profileHash ? { markerProfileHash: failure.marker.profileHash } : {}),
90
- ...(failure.destination?.profileHash
91
- ? { destinationProfileHash: failure.destination.profileHash }
92
- : {}),
72
+ ...ifDefined('markerStorageHash', failure.marker?.storageHash),
73
+ ...ifDefined('destinationStorageHash', failure.destination?.storageHash),
74
+ ...ifDefined('markerProfileHash', failure.marker?.profileHash),
75
+ ...ifDefined('destinationProfileHash', failure.destination?.profileHash),
93
76
  },
94
77
  },
95
78
  );
96
79
  }
97
80
 
98
81
  if (failure.code === 'RUNNER_FAILED') {
99
- return errorRuntime(failure.summary, {
82
+ return errorRunnerFailed(failure.summary, {
100
83
  why: failure.why ?? 'Migration runner failed',
101
84
  fix: 'Fix the schema mismatch (db init is additive-only), or drop/reset the database and re-run `prisma-next db init`',
102
- meta: {
103
- code: 'RUNNER_FAILED',
104
- ...(failure.meta ?? {}),
105
- },
85
+ ...(failure.meta
86
+ ? { meta: { code: 'RUNNER_FAILED', ...failure.meta } }
87
+ : { meta: { code: 'RUNNER_FAILED' } }),
106
88
  });
107
89
  }
108
90
 
@@ -117,114 +99,25 @@ function mapDbInitFailure(failure: DbInitFailure): CliStructuredError {
117
99
  async function executeDbInitCommand(
118
100
  options: DbInitOptions,
119
101
  flags: GlobalFlags,
102
+ ui: TerminalUI,
120
103
  startTime: number,
121
- ): Promise<Result<DbInitResult, CliStructuredError>> {
122
- // Load config
123
- const config = await loadConfig(options.config);
124
- const configPath = options.config
125
- ? relative(process.cwd(), resolve(options.config))
126
- : 'prisma-next.config.ts';
127
- const contractPathAbsolute = config.contract?.output
128
- ? resolve(config.contract.output)
129
- : resolve('src/prisma/contract.json');
130
- const contractPath = relative(process.cwd(), contractPathAbsolute);
131
-
132
- // Output header
133
- if (flags.json !== 'object' && !flags.quiet) {
134
- const details: Array<{ label: string; value: string }> = [
135
- { label: 'config', value: configPath },
136
- { label: 'contract', value: contractPath },
137
- ];
138
- if (options.db) {
139
- details.push({ label: 'database', value: options.db });
140
- }
141
- if (options.plan) {
142
- details.push({ label: 'mode', value: 'plan (dry run)' });
143
- }
144
- const header = formatStyledHeader({
145
- command: 'db init',
146
- description: 'Bootstrap a database to match the current contract',
147
- url: 'https://pris.ly/db-init',
148
- details,
149
- flags,
150
- });
151
- console.log(header);
152
- }
153
-
154
- // Load contract file
155
- let contractJsonContent: string;
156
- try {
157
- contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');
158
- } catch (error) {
159
- if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {
160
- return notOk(
161
- errorFileNotFound(contractPathAbsolute, {
162
- why: `Contract file not found at ${contractPathAbsolute}`,
163
- fix: `Run \`prisma-next contract emit\` to generate ${contractPath}, or update \`config.contract.output\` in ${configPath}`,
164
- }),
165
- );
166
- }
167
- return notOk(
168
- errorUnexpected(error instanceof Error ? error.message : String(error), {
169
- why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,
170
- }),
171
- );
172
- }
173
-
174
- let contractJson: Record<string, unknown>;
175
- try {
176
- contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;
177
- } catch (error) {
178
- return notOk(
179
- errorContractValidationFailed(
180
- `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,
181
- { where: { path: contractPathAbsolute } },
182
- ),
183
- );
184
- }
185
-
186
- // Resolve database connection (--db flag or config.db.connection)
187
- const dbConnection = options.db ?? config.db?.connection;
188
- if (!dbConnection) {
189
- return notOk(
190
- errorDatabaseConnectionRequired({
191
- why: `Database connection is required for db init (set db.connection in ${configPath}, or pass --db <url>)`,
192
- }),
193
- );
194
- }
195
-
196
- // Check for driver
197
- if (!config.driver) {
198
- return notOk(errorDriverRequired({ why: 'Config.driver is required for db init' }));
199
- }
200
-
201
- // Check target supports migrations via the migrations capability
202
- if (!config.target.migrations) {
203
- return notOk(
204
- errorTargetMigrationNotSupported({
205
- why: `Target "${config.target.id}" does not support migrations`,
206
- }),
207
- );
208
- }
209
-
210
- // Create control client
211
- const client = createControlClient({
212
- family: config.family,
213
- target: config.target,
214
- adapter: config.adapter,
215
- driver: config.driver,
216
- extensionPacks: config.extensionPacks ?? [],
104
+ ): Promise<Result<MigrationCommandResult, CliStructuredError>> {
105
+ // Prepare shared migration context (config, contract, connection, client)
106
+ const ctxResult = await prepareMigrationContext(options, flags, ui, {
107
+ commandName: 'db init',
108
+ description: 'Bootstrap a database to match the current contract',
109
+ url: 'https://pris.ly/db-init',
217
110
  });
218
-
219
- // Create progress adapter
220
- const onProgress = createProgressAdapter({ flags });
111
+ if (!ctxResult.ok) {
112
+ return ctxResult;
113
+ }
114
+ const { client, contractJson, dbConnection, onProgress, contractPathAbsolute } = ctxResult.value;
221
115
 
222
116
  try {
223
117
  // Call dbInit with connection and progress callback
224
- // Connection happens inside dbInit with a 'connect' progress span
225
118
  const result = await client.dbInit({
226
- contractIR: contractJson,
227
- mode: options.plan ? 'plan' : 'apply',
119
+ contract: contractJson,
120
+ mode: options.dryRun ? 'plan' : 'apply',
228
121
  connection: dbConnection,
229
122
  onProgress,
230
123
  });
@@ -235,15 +128,14 @@ async function executeDbInitCommand(
235
128
  }
236
129
 
237
130
  // Convert success result to CLI output format
238
- const profileHash = result.value.marker?.profileHash;
239
- const dbInitResult: DbInitResult = {
131
+ const dbInitResult: MigrationCommandResult = {
240
132
  ok: true,
241
133
  mode: result.value.mode,
242
134
  plan: {
243
- targetId: config.target.targetId,
135
+ targetId: ctxResult.value.config.target.targetId,
244
136
  destination: {
245
- coreHash: result.value.marker?.coreHash ?? '',
246
- ...(profileHash ? { profileHash } : {}),
137
+ storageHash: result.value.destination.storageHash,
138
+ ...ifDefined('profileHash', result.value.destination.profileHash),
247
139
  },
248
140
  operations: result.value.plan.operations.map((op) => ({
249
141
  id: op.id,
@@ -262,10 +154,8 @@ async function executeDbInitCommand(
262
154
  ...(result.value.marker
263
155
  ? {
264
156
  marker: {
265
- coreHash: result.value.marker.coreHash,
266
- ...(result.value.marker.profileHash
267
- ? { profileHash: result.value.marker.profileHash }
268
- : {}),
157
+ storageHash: result.value.marker.storageHash,
158
+ ...ifDefined('profileHash', result.value.marker.profileHash),
269
159
  },
270
160
  }
271
161
  : {}),
@@ -276,15 +166,26 @@ async function executeDbInitCommand(
276
166
  return ok(dbInitResult);
277
167
  } catch (error) {
278
168
  // Driver already throws CliStructuredError for connection failures
279
- // Use static type guard to work across module boundaries
280
169
  if (CliStructuredError.is(error)) {
281
170
  return notOk(error);
282
171
  }
283
172
 
284
- // Wrap unexpected errors
173
+ if (error instanceof ContractValidationError) {
174
+ return notOk(
175
+ errorContractValidationFailed(`Contract validation failed: ${error.message}`, {
176
+ where: { path: contractPathAbsolute },
177
+ }),
178
+ );
179
+ }
180
+
181
+ const rawMessage = error instanceof Error ? error.message : String(error);
182
+ const safeMessage = sanitizeErrorMessage(
183
+ rawMessage,
184
+ typeof dbConnection === 'string' ? dbConnection : undefined,
185
+ );
285
186
  return notOk(
286
- errorUnexpected(error instanceof Error ? error.message : String(error), {
287
- why: `Unexpected error during db init: ${error instanceof Error ? error.message : String(error)}`,
187
+ errorUnexpected(safeMessage, {
188
+ why: `Unexpected error during db init: ${safeMessage}`,
288
189
  }),
289
190
  );
290
191
  } finally {
@@ -296,65 +197,42 @@ export function createDbInitCommand(): Command {
296
197
  const command = new Command('init');
297
198
  setCommandDescriptions(
298
199
  command,
299
- 'Bootstrap a database to match the current contract and write the contract marker',
200
+ 'Bootstrap a database to match the current contract and sign it',
300
201
  'Initializes a database to match your emitted contract using additive-only operations.\n' +
301
202
  'Creates any missing tables, columns, indexes, and constraints defined in your contract.\n' +
302
203
  'Leaves existing compatible structures in place, surfaces conflicts when destructive changes\n' +
303
- 'would be required, and writes a contract marker to track the database state. Use --plan to\n' +
204
+ 'would be required, and signs the database to track contract state. Use --dry-run to\n' +
304
205
  'preview changes without applying.',
305
206
  );
306
- command
307
- .configureHelp({
308
- formatHelp: (cmd) => {
309
- const flags = parseGlobalFlags({});
310
- return formatCommandHelp({ command: cmd, flags });
311
- },
312
- })
313
- .option('--db <url>', 'Database connection string')
314
- .option('--config <path>', 'Path to prisma-next.config.ts')
315
- .option('--plan', 'Preview planned operations without applying', false)
316
- .option('--json [format]', 'Output as JSON (object)', false)
317
- .option('-q, --quiet', 'Quiet mode: errors only')
318
- .option('-v, --verbose', 'Verbose output: debug info, timings')
319
- .option('-vv, --trace', 'Trace output: deep internals, stack traces')
320
- .option('--timestamps', 'Add timestamps to output')
321
- .option('--color', 'Force color output')
322
- .option('--no-color', 'Disable color output')
323
- .action(async (options: DbInitOptions) => {
324
- const flags = parseGlobalFlags(options);
325
- const startTime = Date.now();
326
-
327
- // Validate JSON format option
328
- if (flags.json === 'ndjson') {
329
- const result = notOk(
330
- errorJsonFormatNotSupported({
331
- command: 'db init',
332
- format: 'ndjson',
333
- supportedFormats: ['object'],
334
- }),
335
- );
336
- const exitCode = handleResult(result, flags);
337
- process.exit(exitCode);
338
- }
339
-
340
- const result = await executeDbInitCommand(options, flags, startTime);
341
-
342
- const exitCode = handleResult(result, flags, (dbInitResult) => {
343
- if (flags.json === 'object') {
344
- console.log(formatDbInitJson(dbInitResult));
345
- } else {
346
- const output =
347
- dbInitResult.mode === 'plan'
348
- ? formatDbInitPlanOutput(dbInitResult, flags)
349
- : formatDbInitApplyOutput(dbInitResult, flags);
350
- if (output) {
351
- console.log(output);
352
- }
207
+ setCommandExamples(command, [
208
+ 'prisma-next db init --db $DATABASE_URL',
209
+ 'prisma-next db init --db $DATABASE_URL --dry-run',
210
+ ]);
211
+ addMigrationCommandOptions(command);
212
+ command.action(async (options: DbInitOptions) => {
213
+ const flags = parseGlobalFlags(options);
214
+ const startTime = Date.now();
215
+
216
+ const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
217
+
218
+ const result = await executeDbInitCommand(options, flags, ui, startTime);
219
+
220
+ const exitCode = handleResult(result, flags, ui, (dbInitResult) => {
221
+ if (flags.json) {
222
+ ui.output(formatMigrationJson(dbInitResult));
223
+ } else {
224
+ const output =
225
+ dbInitResult.mode === 'plan'
226
+ ? formatMigrationPlanOutput(dbInitResult, flags)
227
+ : formatMigrationApplyOutput(dbInitResult, flags);
228
+ if (output) {
229
+ ui.log(output);
353
230
  }
354
- });
355
-
356
- process.exit(exitCode);
231
+ }
357
232
  });
358
233
 
234
+ process.exit(exitCode);
235
+ });
236
+
359
237
  return command;
360
238
  }
@@ -0,0 +1,77 @@
1
+ import type { IntrospectSchemaResult } from '@prisma-next/framework-components/control';
2
+ import { Command } from 'commander';
3
+ import {
4
+ addGlobalOptions,
5
+ setCommandDescriptions,
6
+ setCommandExamples,
7
+ } from '../utils/command-helpers';
8
+ import { formatIntrospectJson, formatIntrospectOutput } from '../utils/formatters/verify';
9
+ import { parseGlobalFlags } from '../utils/global-flags';
10
+ import { handleResult } from '../utils/result-handler';
11
+ import { TerminalUI } from '../utils/terminal-ui';
12
+ import {
13
+ type InspectLiveSchemaOptions,
14
+ type InspectLiveSchemaResult,
15
+ inspectLiveSchema,
16
+ } from './inspect-live-schema';
17
+
18
+ function toIntrospectSchemaResult(
19
+ result: InspectLiveSchemaResult,
20
+ ): IntrospectSchemaResult<unknown> {
21
+ return {
22
+ ok: true,
23
+ summary: 'Schema read successfully',
24
+ target: result.target,
25
+ schema: result.schema,
26
+ meta: result.meta,
27
+ timings: result.timings,
28
+ };
29
+ }
30
+
31
+ export function createDbSchemaCommand(): Command {
32
+ const command = new Command('schema');
33
+ setCommandDescriptions(
34
+ command,
35
+ 'Inspect the live database schema',
36
+ 'Reads the live database schema and prints it as a tree by default or as JSON with\n' +
37
+ '--json. This command is always read-only and never writes files. To save machine-\n' +
38
+ 'readable output, use shell redirection, for example `prisma-next db schema --json > schema.json`.',
39
+ );
40
+ setCommandExamples(command, [
41
+ 'prisma-next db schema --db $DATABASE_URL',
42
+ 'prisma-next db schema --db $DATABASE_URL --json',
43
+ 'prisma-next db schema --db $DATABASE_URL --json > schema.json',
44
+ ]);
45
+ addGlobalOptions(command)
46
+ .option('--db <url>', 'Database connection string')
47
+ .option('--config <path>', 'Path to prisma-next.config.ts')
48
+ .action(async (options: InspectLiveSchemaOptions) => {
49
+ const flags = parseGlobalFlags(options);
50
+ const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
51
+ const startTime = Date.now();
52
+
53
+ const result = await inspectLiveSchema(options, flags, ui, startTime, {
54
+ commandName: 'db schema',
55
+ description: 'Inspect the live database schema',
56
+ url: 'https://pris.ly/db-schema',
57
+ });
58
+
59
+ const exitCode = handleResult(result, flags, ui, (value) => {
60
+ const introspectResult = toIntrospectSchemaResult(value);
61
+
62
+ if (flags.json) {
63
+ ui.output(formatIntrospectJson(introspectResult));
64
+ return;
65
+ }
66
+
67
+ const output = formatIntrospectOutput(introspectResult, value.schemaView, flags);
68
+ if (output) {
69
+ ui.log(output);
70
+ }
71
+ });
72
+
73
+ process.exit(exitCode);
74
+ });
75
+
76
+ return command;
77
+ }