@prisma-next/cli 0.3.0-dev.3 → 0.3.0-dev.30

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 (101) hide show
  1. package/README.md +111 -27
  2. package/dist/{chunk-BZMBKEEQ.js → chunk-AGOTG4L3.js} +44 -76
  3. package/dist/chunk-AGOTG4L3.js.map +1 -0
  4. package/dist/chunk-HLLI4YL7.js +180 -0
  5. package/dist/chunk-HLLI4YL7.js.map +1 -0
  6. package/dist/chunk-VG2R7DGF.js +735 -0
  7. package/dist/chunk-VG2R7DGF.js.map +1 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +1502 -968
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/contract-emit.d.ts +2 -4
  13. package/dist/commands/contract-emit.d.ts.map +1 -0
  14. package/dist/commands/contract-emit.js +3 -2
  15. package/dist/commands/db-init.d.ts +2 -4
  16. package/dist/commands/db-init.d.ts.map +1 -0
  17. package/dist/commands/db-init.js +205 -289
  18. package/dist/commands/db-init.js.map +1 -1
  19. package/dist/commands/db-introspect.d.ts +2 -4
  20. package/dist/commands/db-introspect.d.ts.map +1 -0
  21. package/dist/commands/db-introspect.js +108 -143
  22. package/dist/commands/db-introspect.js.map +1 -1
  23. package/dist/commands/db-schema-verify.d.ts +2 -4
  24. package/dist/commands/db-schema-verify.d.ts.map +1 -0
  25. package/dist/commands/db-schema-verify.js +120 -113
  26. package/dist/commands/db-schema-verify.js.map +1 -1
  27. package/dist/commands/db-sign.d.ts +2 -4
  28. package/dist/commands/db-sign.d.ts.map +1 -0
  29. package/dist/commands/db-sign.js +152 -156
  30. package/dist/commands/db-sign.js.map +1 -1
  31. package/dist/commands/db-verify.d.ts +2 -4
  32. package/dist/commands/db-verify.d.ts.map +1 -0
  33. package/dist/commands/db-verify.js +142 -122
  34. package/dist/commands/db-verify.js.map +1 -1
  35. package/dist/config-loader.d.ts +3 -5
  36. package/dist/config-loader.d.ts.map +1 -0
  37. package/dist/control-api/client.d.ts +13 -0
  38. package/dist/control-api/client.d.ts.map +1 -0
  39. package/dist/control-api/operations/db-init.d.ts +29 -0
  40. package/dist/control-api/operations/db-init.d.ts.map +1 -0
  41. package/dist/control-api/types.d.ts +387 -0
  42. package/dist/control-api/types.d.ts.map +1 -0
  43. package/dist/exports/config-types.d.ts +3 -0
  44. package/dist/exports/config-types.d.ts.map +1 -0
  45. package/dist/exports/config-types.js.map +1 -0
  46. package/dist/exports/control-api.d.ts +13 -0
  47. package/dist/exports/control-api.d.ts.map +1 -0
  48. package/dist/exports/control-api.js +7 -0
  49. package/dist/exports/control-api.js.map +1 -0
  50. package/dist/exports/index.d.ts +4 -0
  51. package/dist/exports/index.d.ts.map +1 -0
  52. package/dist/{index.js → exports/index.js} +4 -3
  53. package/dist/exports/index.js.map +1 -0
  54. package/dist/{index.d.ts → load-ts-contract.d.ts} +4 -8
  55. package/dist/load-ts-contract.d.ts.map +1 -0
  56. package/dist/utils/cli-errors.d.ts +7 -0
  57. package/dist/utils/cli-errors.d.ts.map +1 -0
  58. package/dist/utils/command-helpers.d.ts +12 -0
  59. package/dist/utils/command-helpers.d.ts.map +1 -0
  60. package/dist/utils/framework-components.d.ts +70 -0
  61. package/dist/utils/framework-components.d.ts.map +1 -0
  62. package/dist/utils/global-flags.d.ts +25 -0
  63. package/dist/utils/global-flags.d.ts.map +1 -0
  64. package/dist/utils/output.d.ts +142 -0
  65. package/dist/utils/output.d.ts.map +1 -0
  66. package/dist/utils/progress-adapter.d.ts +26 -0
  67. package/dist/utils/progress-adapter.d.ts.map +1 -0
  68. package/dist/utils/result-handler.d.ts +15 -0
  69. package/dist/utils/result-handler.d.ts.map +1 -0
  70. package/package.json +30 -26
  71. package/src/cli.ts +260 -0
  72. package/src/commands/contract-emit.ts +259 -0
  73. package/src/commands/db-init.ts +360 -0
  74. package/src/commands/db-introspect.ts +227 -0
  75. package/src/commands/db-schema-verify.ts +238 -0
  76. package/src/commands/db-sign.ts +279 -0
  77. package/src/commands/db-verify.ts +258 -0
  78. package/src/config-loader.ts +76 -0
  79. package/src/control-api/client.ts +589 -0
  80. package/src/control-api/operations/db-init.ts +281 -0
  81. package/src/control-api/types.ts +461 -0
  82. package/src/exports/config-types.ts +6 -0
  83. package/src/exports/control-api.ts +46 -0
  84. package/src/exports/index.ts +4 -0
  85. package/src/load-ts-contract.ts +217 -0
  86. package/src/utils/cli-errors.ts +26 -0
  87. package/src/utils/command-helpers.ts +26 -0
  88. package/src/utils/framework-components.ts +177 -0
  89. package/src/utils/global-flags.ts +75 -0
  90. package/src/utils/output.ts +1471 -0
  91. package/src/utils/progress-adapter.ts +86 -0
  92. package/src/utils/result-handler.ts +44 -0
  93. package/dist/chunk-464LNZCE.js +0 -134
  94. package/dist/chunk-464LNZCE.js.map +0 -1
  95. package/dist/chunk-BZMBKEEQ.js.map +0 -1
  96. package/dist/chunk-ZKYEJROM.js +0 -94
  97. package/dist/chunk-ZKYEJROM.js.map +0 -1
  98. package/dist/config-types.d.ts +0 -1
  99. package/dist/config-types.js.map +0 -1
  100. package/dist/index.js.map +0 -1
  101. /package/dist/{config-types.js → exports/config-types.js} +0 -0
@@ -0,0 +1,281 @@
1
+ import type { TargetBoundComponentDescriptor } from '@prisma-next/contract/framework-components';
2
+ import type { ContractIR } from '@prisma-next/contract/ir';
3
+ import type {
4
+ ControlDriverInstance,
5
+ ControlFamilyInstance,
6
+ MigrationPlan,
7
+ MigrationPlannerResult,
8
+ MigrationPlanOperation,
9
+ MigrationRunnerResult,
10
+ TargetMigrationsCapability,
11
+ } from '@prisma-next/core-control-plane/types';
12
+ import { notOk, ok } from '@prisma-next/utils/result';
13
+ import type { DbInitResult, DbInitSuccess, OnControlProgress } from '../types';
14
+
15
+ /**
16
+ * Options for executing dbInit operation.
17
+ */
18
+ export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extends string> {
19
+ readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
20
+ readonly familyInstance: ControlFamilyInstance<TFamilyId>;
21
+ readonly contractIR: ContractIR;
22
+ readonly mode: 'plan' | 'apply';
23
+ readonly migrations: TargetMigrationsCapability<
24
+ TFamilyId,
25
+ TTargetId,
26
+ ControlFamilyInstance<TFamilyId>
27
+ >;
28
+ readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
29
+ /** Optional progress callback for observing operation progress */
30
+ readonly onProgress?: OnControlProgress;
31
+ }
32
+
33
+ /**
34
+ * Executes the dbInit operation.
35
+ *
36
+ * This is the core logic extracted from the CLI command, without any file I/O,
37
+ * process.exit(), or console output. It uses the Result pattern to return
38
+ * success or failure details.
39
+ *
40
+ * @param options - The options for executing dbInit
41
+ * @returns Result with DbInitSuccess on success, DbInitFailure on failure
42
+ */
43
+ export async function executeDbInit<TFamilyId extends string, TTargetId extends string>(
44
+ options: ExecuteDbInitOptions<TFamilyId, TTargetId>,
45
+ ): Promise<DbInitResult> {
46
+ const { driver, familyInstance, contractIR, mode, migrations, frameworkComponents, onProgress } =
47
+ options;
48
+
49
+ // Create planner and runner from target migrations capability
50
+ const planner = migrations.createPlanner(familyInstance);
51
+ const runner = migrations.createRunner(familyInstance);
52
+
53
+ // Introspect live schema
54
+ const introspectSpanId = 'introspect';
55
+ onProgress?.({
56
+ action: 'dbInit',
57
+ kind: 'spanStart',
58
+ spanId: introspectSpanId,
59
+ label: 'Introspecting database schema',
60
+ });
61
+ const schemaIR = await familyInstance.introspect({ driver });
62
+ onProgress?.({
63
+ action: 'dbInit',
64
+ kind: 'spanEnd',
65
+ spanId: introspectSpanId,
66
+ outcome: 'ok',
67
+ });
68
+
69
+ // Policy for init mode (additive only)
70
+ const policy = { allowedOperationClasses: ['additive'] as const };
71
+
72
+ // Plan migration
73
+ const planSpanId = 'plan';
74
+ onProgress?.({
75
+ action: 'dbInit',
76
+ kind: 'spanStart',
77
+ spanId: planSpanId,
78
+ label: 'Planning migration',
79
+ });
80
+ const plannerResult: MigrationPlannerResult = await planner.plan({
81
+ contract: contractIR,
82
+ schema: schemaIR,
83
+ policy,
84
+ frameworkComponents,
85
+ });
86
+
87
+ if (plannerResult.kind === 'failure') {
88
+ onProgress?.({
89
+ action: 'dbInit',
90
+ kind: 'spanEnd',
91
+ spanId: planSpanId,
92
+ outcome: 'error',
93
+ });
94
+ return notOk({
95
+ code: 'PLANNING_FAILED' as const,
96
+ summary: 'Migration planning failed due to conflicts',
97
+ conflicts: plannerResult.conflicts,
98
+ why: undefined,
99
+ meta: undefined,
100
+ });
101
+ }
102
+
103
+ const migrationPlan: MigrationPlan = plannerResult.plan;
104
+ onProgress?.({
105
+ action: 'dbInit',
106
+ kind: 'spanEnd',
107
+ spanId: planSpanId,
108
+ outcome: 'ok',
109
+ });
110
+
111
+ // Check for existing marker - handle idempotency and mismatch errors
112
+ const checkMarkerSpanId = 'checkMarker';
113
+ onProgress?.({
114
+ action: 'dbInit',
115
+ kind: 'spanStart',
116
+ spanId: checkMarkerSpanId,
117
+ label: 'Checking contract marker',
118
+ });
119
+ const existingMarker = await familyInstance.readMarker({ driver });
120
+ if (existingMarker) {
121
+ const markerMatchesDestination =
122
+ existingMarker.coreHash === migrationPlan.destination.coreHash &&
123
+ (!migrationPlan.destination.profileHash ||
124
+ existingMarker.profileHash === migrationPlan.destination.profileHash);
125
+
126
+ if (markerMatchesDestination) {
127
+ // Already at destination - return success with no operations
128
+ onProgress?.({
129
+ action: 'dbInit',
130
+ kind: 'spanEnd',
131
+ spanId: checkMarkerSpanId,
132
+ outcome: 'skipped',
133
+ });
134
+ const result: DbInitSuccess = {
135
+ mode,
136
+ plan: { operations: [] },
137
+ ...(mode === 'apply'
138
+ ? {
139
+ execution: { operationsPlanned: 0, operationsExecuted: 0 },
140
+ marker: {
141
+ coreHash: existingMarker.coreHash,
142
+ profileHash: existingMarker.profileHash,
143
+ },
144
+ }
145
+ : {}),
146
+ summary: 'Database already at target contract state',
147
+ };
148
+ return ok(result);
149
+ }
150
+
151
+ // Marker exists but doesn't match destination - fail
152
+ onProgress?.({
153
+ action: 'dbInit',
154
+ kind: 'spanEnd',
155
+ spanId: checkMarkerSpanId,
156
+ outcome: 'error',
157
+ });
158
+ return notOk({
159
+ code: 'MARKER_ORIGIN_MISMATCH' as const,
160
+ summary: 'Existing contract marker does not match plan destination',
161
+ marker: {
162
+ coreHash: existingMarker.coreHash,
163
+ profileHash: existingMarker.profileHash,
164
+ },
165
+ destination: {
166
+ coreHash: migrationPlan.destination.coreHash,
167
+ profileHash: migrationPlan.destination.profileHash,
168
+ },
169
+ why: undefined,
170
+ conflicts: undefined,
171
+ meta: undefined,
172
+ });
173
+ }
174
+
175
+ onProgress?.({
176
+ action: 'dbInit',
177
+ kind: 'spanEnd',
178
+ spanId: checkMarkerSpanId,
179
+ outcome: 'ok',
180
+ });
181
+
182
+ // Plan mode - don't execute
183
+ if (mode === 'plan') {
184
+ const result: DbInitSuccess = {
185
+ mode: 'plan',
186
+ plan: { operations: migrationPlan.operations },
187
+ summary: `Planned ${migrationPlan.operations.length} operation(s)`,
188
+ };
189
+ return ok(result);
190
+ }
191
+
192
+ // Apply mode - execute runner
193
+ const applySpanId = 'apply';
194
+ onProgress?.({
195
+ action: 'dbInit',
196
+ kind: 'spanStart',
197
+ spanId: applySpanId,
198
+ label: 'Applying migration plan',
199
+ });
200
+
201
+ const callbacks = onProgress
202
+ ? {
203
+ onOperationStart: (op: MigrationPlanOperation) => {
204
+ onProgress({
205
+ action: 'dbInit',
206
+ kind: 'spanStart',
207
+ spanId: `operation:${op.id}`,
208
+ parentSpanId: applySpanId,
209
+ label: op.label,
210
+ });
211
+ },
212
+ onOperationComplete: (op: MigrationPlanOperation) => {
213
+ onProgress({
214
+ action: 'dbInit',
215
+ kind: 'spanEnd',
216
+ spanId: `operation:${op.id}`,
217
+ outcome: 'ok',
218
+ });
219
+ },
220
+ }
221
+ : undefined;
222
+
223
+ const runnerResult: MigrationRunnerResult = await runner.execute({
224
+ plan: migrationPlan,
225
+ driver,
226
+ destinationContract: contractIR,
227
+ policy,
228
+ ...(callbacks ? { callbacks } : {}),
229
+ // db init plans and applies back-to-back from a fresh introspection, so per-operation
230
+ // pre/postchecks and the idempotency probe are usually redundant overhead. We still
231
+ // enforce marker/origin compatibility and a full schema verification after apply.
232
+ executionChecks: {
233
+ prechecks: false,
234
+ postchecks: false,
235
+ idempotencyChecks: false,
236
+ },
237
+ frameworkComponents,
238
+ });
239
+
240
+ if (!runnerResult.ok) {
241
+ onProgress?.({
242
+ action: 'dbInit',
243
+ kind: 'spanEnd',
244
+ spanId: applySpanId,
245
+ outcome: 'error',
246
+ });
247
+ return notOk({
248
+ code: 'RUNNER_FAILED' as const,
249
+ summary: runnerResult.failure.summary,
250
+ why: runnerResult.failure.why,
251
+ meta: runnerResult.failure.meta,
252
+ conflicts: undefined,
253
+ });
254
+ }
255
+
256
+ const execution = runnerResult.value;
257
+
258
+ onProgress?.({
259
+ action: 'dbInit',
260
+ kind: 'spanEnd',
261
+ spanId: applySpanId,
262
+ outcome: 'ok',
263
+ });
264
+
265
+ const result: DbInitSuccess = {
266
+ mode: 'apply',
267
+ plan: { operations: migrationPlan.operations },
268
+ execution: {
269
+ operationsPlanned: execution.operationsPlanned,
270
+ operationsExecuted: execution.operationsExecuted,
271
+ },
272
+ marker: migrationPlan.destination.profileHash
273
+ ? {
274
+ coreHash: migrationPlan.destination.coreHash,
275
+ profileHash: migrationPlan.destination.profileHash,
276
+ }
277
+ : { coreHash: migrationPlan.destination.coreHash },
278
+ summary: `Applied ${execution.operationsExecuted} operation(s), marker written`,
279
+ };
280
+ return ok(result);
281
+ }