@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
@@ -0,0 +1,119 @@
1
+ import type { Contract } from '@prisma-next/contract/types';
2
+ import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
3
+
4
+ type CapabilityMatrix = Record<string, Record<string, boolean>>;
5
+
6
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
7
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
8
+ }
9
+
10
+ function sortDeep(value: unknown): unknown {
11
+ if (Array.isArray(value)) {
12
+ return value.map(sortDeep);
13
+ }
14
+ if (!isPlainObject(value)) {
15
+ return value;
16
+ }
17
+ const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
18
+ const next: Record<string, unknown> = {};
19
+ for (const [key, child] of entries) {
20
+ next[key] = sortDeep(child);
21
+ }
22
+ return next;
23
+ }
24
+
25
+ function sortDeepTyped<T>(value: T): T {
26
+ return sortDeep(value) as T;
27
+ }
28
+
29
+ function extractCapabilityMatrix(value: unknown): CapabilityMatrix {
30
+ if (!isPlainObject(value)) return {};
31
+
32
+ const out: CapabilityMatrix = {};
33
+ for (const [namespace, maybeCaps] of Object.entries(value)) {
34
+ if (!isPlainObject(maybeCaps)) continue;
35
+ const caps: Record<string, boolean> = {};
36
+ for (const [key, flag] of Object.entries(maybeCaps)) {
37
+ if (typeof flag === 'boolean') {
38
+ caps[key] = flag;
39
+ }
40
+ }
41
+ if (Object.keys(caps).length > 0) {
42
+ out[namespace] = caps;
43
+ }
44
+ }
45
+
46
+ return out;
47
+ }
48
+
49
+ function mergeCapabilities(left: CapabilityMatrix, right: CapabilityMatrix): CapabilityMatrix {
50
+ const next: CapabilityMatrix = { ...left };
51
+ for (const [namespace, capabilities] of Object.entries(right)) {
52
+ next[namespace] = {
53
+ ...(left[namespace] ?? {}),
54
+ ...capabilities,
55
+ };
56
+ }
57
+ return next;
58
+ }
59
+
60
+ function extractExtensionPackMeta(
61
+ component: TargetBoundComponentDescriptor<string, string>,
62
+ ): Record<string, unknown> {
63
+ const { kind, id, version, capabilities, types } = component;
64
+ const base: Record<string, unknown> = {
65
+ kind,
66
+ id,
67
+ familyId: component.familyId,
68
+ targetId: component.targetId,
69
+ version,
70
+ };
71
+ if (capabilities) {
72
+ base['capabilities'] = capabilities;
73
+ }
74
+ if (types) {
75
+ if (types.codecTypes) {
76
+ const { controlPlaneHooks: _, codecInstances: _ci, ...cleanedCodecTypes } = types.codecTypes;
77
+ base['types'] = { ...types, codecTypes: cleanedCodecTypes };
78
+ } else {
79
+ base['types'] = types;
80
+ }
81
+ }
82
+ return base;
83
+ }
84
+
85
+ /**
86
+ * Enriches a raw contract with framework-derived metadata:
87
+ * capabilities from all component descriptors and extension pack metadata
88
+ * from extension descriptors. Produces deterministically sorted output.
89
+ */
90
+ export function enrichContract(
91
+ ir: Contract,
92
+ components: ReadonlyArray<TargetBoundComponentDescriptor<string, string>>,
93
+ ): Contract {
94
+ let mergedCapabilities = ir.capabilities;
95
+ const extensionPacksMeta: Record<string, unknown> = {};
96
+
97
+ for (const component of components) {
98
+ if (component.capabilities) {
99
+ mergedCapabilities = mergeCapabilities(
100
+ mergedCapabilities,
101
+ extractCapabilityMatrix(component.capabilities),
102
+ );
103
+ }
104
+ if (component.kind === 'extension') {
105
+ extensionPacksMeta[component.id] = extractExtensionPackMeta(component);
106
+ }
107
+ }
108
+
109
+ const extensionPacks =
110
+ Object.keys(extensionPacksMeta).length > 0
111
+ ? { ...ir.extensionPacks, ...extensionPacksMeta }
112
+ : ir.extensionPacks;
113
+
114
+ return {
115
+ ...ir,
116
+ capabilities: sortDeepTyped(mergedCapabilities),
117
+ extensionPacks: sortDeepTyped(extensionPacks),
118
+ };
119
+ }
@@ -0,0 +1,9 @@
1
+ export class ContractValidationError extends Error {
2
+ override readonly cause?: unknown;
3
+
4
+ constructor(message: string, cause?: unknown) {
5
+ super(message);
6
+ this.name = 'ContractValidationError';
7
+ this.cause = cause;
8
+ }
9
+ }
@@ -0,0 +1,174 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import type { Contract } from '@prisma-next/contract/types';
3
+ import { emit } from '@prisma-next/emitter';
4
+ import { createControlStack } from '@prisma-next/framework-components/control';
5
+ import { abortable } from '@prisma-next/utils/abortable';
6
+ import { ifDefined } from '@prisma-next/utils/defined';
7
+ import { dirname, isAbsolute, join, resolve } from 'pathe';
8
+ import { loadConfig } from '../../config-loader';
9
+ import { errorContractConfigMissing, errorRuntime } from '../../utils/cli-errors';
10
+ import { assertFrameworkComponentsCompatible } from '../../utils/framework-components';
11
+ import { enrichContract } from '../contract-enrichment';
12
+ import type { ContractEmitOptions, ContractEmitResult } from '../types';
13
+
14
+ interface ProviderFailureLike {
15
+ readonly summary: string;
16
+ readonly diagnostics: readonly unknown[];
17
+ readonly meta?: unknown;
18
+ }
19
+
20
+ function isRecord(value: unknown): value is Record<string, unknown> {
21
+ return typeof value === 'object' && value !== null;
22
+ }
23
+
24
+ function isAbortError(error: unknown): boolean {
25
+ return isRecord(error) && typeof error['name'] === 'string' && error['name'] === 'AbortError';
26
+ }
27
+
28
+ function isProviderFailureLike(value: unknown): value is ProviderFailureLike {
29
+ return (
30
+ isRecord(value) && typeof value['summary'] === 'string' && Array.isArray(value['diagnostics'])
31
+ );
32
+ }
33
+
34
+ /**
35
+ * Executes the contract emit operation.
36
+ *
37
+ * This is an offline operation that:
38
+ * 1. Loads the Prisma Next config from the specified path
39
+ * 2. Resolves the contract source from config
40
+ * 3. Creates a control plane stack and family instance
41
+ * 4. Emits contract artifacts (JSON and DTS)
42
+ * 5. Writes files to the paths specified in config
43
+ *
44
+ * Supports AbortSignal for cancellation, enabling "last change wins" behavior.
45
+ *
46
+ * @param options - Options including configPath and optional signal
47
+ * @returns File paths and hashes of emitted artifacts
48
+ * @throws If config loading fails, contract is invalid, or file I/O fails
49
+ * @throws signal.reason if cancelled via AbortSignal (typically DOMException with name 'AbortError')
50
+ */
51
+ export async function executeContractEmit(
52
+ options: ContractEmitOptions,
53
+ ): Promise<ContractEmitResult> {
54
+ const { configPath, signal = new AbortController().signal } = options;
55
+ const unlessAborted = abortable(signal);
56
+
57
+ // Load config using the existing config loader
58
+ const config = await unlessAborted(loadConfig(configPath));
59
+
60
+ // Validate contract config is present
61
+ if (!config.contract) {
62
+ throw errorContractConfigMissing({
63
+ why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',
64
+ });
65
+ }
66
+
67
+ const contractConfig = config.contract;
68
+
69
+ // Validate output path is present and ends with .json
70
+ if (!contractConfig.output) {
71
+ throw errorContractConfigMissing({
72
+ why: 'Contract config must have output path. This should not happen if defineConfig() was used.',
73
+ });
74
+ }
75
+ if (!contractConfig.output.endsWith('.json')) {
76
+ throw errorContractConfigMissing({
77
+ why: 'Contract config output path must end with .json (e.g., "src/prisma/contract.json")',
78
+ });
79
+ }
80
+
81
+ // Validate source exists and is callable
82
+ if (typeof contractConfig.source !== 'function') {
83
+ throw errorContractConfigMissing({
84
+ why: 'Contract config must include a valid source provider function',
85
+ });
86
+ }
87
+
88
+ // Normalize configPath and resolve artifact paths relative to config file directory
89
+ const normalizedConfigPath = resolve(configPath);
90
+ const configDir = dirname(normalizedConfigPath);
91
+ const outputJsonPath = isAbsolute(contractConfig.output)
92
+ ? contractConfig.output
93
+ : join(configDir, contractConfig.output);
94
+ // Colocate .d.ts with .json (contract.json → contract.d.ts)
95
+ const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;
96
+
97
+ const sourceContext = {
98
+ composedExtensionPacks: (config.extensionPacks ?? []).map((p) => p.id),
99
+ };
100
+
101
+ let providerResult: Awaited<ReturnType<typeof contractConfig.source>>;
102
+ try {
103
+ providerResult = await unlessAborted(contractConfig.source(sourceContext));
104
+ } catch (error) {
105
+ if (signal.aborted || isAbortError(error)) {
106
+ throw error;
107
+ }
108
+ throw errorRuntime('Failed to resolve contract source', {
109
+ why: error instanceof Error ? error.message : String(error),
110
+ fix: 'Ensure contract.source resolves to ok(Contract) or returns structured diagnostics.',
111
+ });
112
+ }
113
+
114
+ if (!isRecord(providerResult) || typeof providerResult.ok !== 'boolean') {
115
+ throw errorRuntime('Failed to resolve contract source', {
116
+ why: 'Contract source provider returned malformed result shape.',
117
+ fix: 'Ensure contract.source resolves to ok(Contract) or notOk({ summary, diagnostics }).',
118
+ });
119
+ }
120
+
121
+ if (providerResult.ok && !('value' in providerResult)) {
122
+ throw errorRuntime('Failed to resolve contract source', {
123
+ why: 'Contract source provider returned malformed success result: missing value.',
124
+ fix: 'Ensure contract.source success payload is ok(Contract).',
125
+ });
126
+ }
127
+
128
+ if (!providerResult.ok && !isProviderFailureLike(providerResult.failure)) {
129
+ throw errorRuntime('Failed to resolve contract source', {
130
+ why: 'Contract source provider returned malformed failure result: expected summary and diagnostics.',
131
+ fix: 'Ensure contract.source failure payload is notOk({ summary, diagnostics, meta? }).',
132
+ });
133
+ }
134
+
135
+ if (!providerResult.ok) {
136
+ throw errorRuntime('Failed to resolve contract source', {
137
+ why: providerResult.failure.summary,
138
+ fix: 'Fix contract source diagnostics and return ok(Contract).',
139
+ meta: {
140
+ diagnostics: providerResult.failure.diagnostics,
141
+ ...ifDefined('providerMeta', providerResult.failure.meta),
142
+ },
143
+ });
144
+ }
145
+
146
+ const stack = createControlStack(config);
147
+ const familyInstance = config.family.create(stack);
148
+
149
+ const rawComponents = [config.target, config.adapter, ...(config.extensionPacks ?? [])];
150
+ const frameworkComponents = assertFrameworkComponentsCompatible(
151
+ config.family.familyId,
152
+ config.target.targetId,
153
+ rawComponents,
154
+ );
155
+ const enrichedIR = enrichContract(providerResult.value as Contract, frameworkComponents);
156
+
157
+ familyInstance.validateContract(enrichedIR);
158
+ const emitResult = await unlessAborted(emit(enrichedIR, stack, config.family.emission));
159
+
160
+ // Create directory if needed and write files (both colocated)
161
+ await unlessAborted(mkdir(dirname(outputJsonPath), { recursive: true }));
162
+ await unlessAborted(writeFile(outputJsonPath, emitResult.contractJson, 'utf-8'));
163
+ await unlessAborted(writeFile(outputDtsPath, emitResult.contractDts, 'utf-8'));
164
+
165
+ return {
166
+ storageHash: emitResult.storageHash,
167
+ ...ifDefined('executionHash', emitResult.executionHash),
168
+ profileHash: emitResult.profileHash,
169
+ files: {
170
+ json: outputJsonPath,
171
+ dts: outputDtsPath,
172
+ },
173
+ };
174
+ }
@@ -1,29 +1,31 @@
1
- import type { TargetBoundComponentDescriptor } from '@prisma-next/contract/framework-components';
2
- import type { ContractIR } from '@prisma-next/contract/ir';
1
+ import type { Contract } from '@prisma-next/contract/types';
2
+ import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
3
3
  import type {
4
4
  ControlDriverInstance,
5
5
  ControlFamilyInstance,
6
6
  MigrationPlan,
7
7
  MigrationPlannerResult,
8
- MigrationPlanOperation,
9
8
  MigrationRunnerResult,
10
9
  TargetMigrationsCapability,
11
- } from '@prisma-next/core-control-plane/types';
10
+ } from '@prisma-next/framework-components/control';
11
+ import { ifDefined } from '@prisma-next/utils/defined';
12
12
  import { notOk, ok } from '@prisma-next/utils/result';
13
13
  import type { DbInitResult, DbInitSuccess, OnControlProgress } from '../types';
14
+ import { extractOperationStatements } from './extract-operation-statements';
15
+ import { createOperationCallbacks, stripOperations } from './migration-helpers';
14
16
 
15
17
  /**
16
18
  * Options for executing dbInit operation.
17
19
  */
18
20
  export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extends string> {
19
21
  readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;
20
- readonly familyInstance: ControlFamilyInstance<TFamilyId>;
21
- readonly contractIR: ContractIR;
22
+ readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;
23
+ readonly contract: Contract;
22
24
  readonly mode: 'plan' | 'apply';
23
25
  readonly migrations: TargetMigrationsCapability<
24
26
  TFamilyId,
25
27
  TTargetId,
26
- ControlFamilyInstance<TFamilyId>
28
+ ControlFamilyInstance<TFamilyId, unknown>
27
29
  >;
28
30
  readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
29
31
  /** Optional progress callback for observing operation progress */
@@ -43,7 +45,7 @@ export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extend
43
45
  export async function executeDbInit<TFamilyId extends string, TTargetId extends string>(
44
46
  options: ExecuteDbInitOptions<TFamilyId, TTargetId>,
45
47
  ): Promise<DbInitResult> {
46
- const { driver, familyInstance, contractIR, mode, migrations, frameworkComponents, onProgress } =
48
+ const { driver, familyInstance, contract, mode, migrations, frameworkComponents, onProgress } =
47
49
  options;
48
50
 
49
51
  // Create planner and runner from target migrations capability
@@ -78,7 +80,7 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
78
80
  label: 'Planning migration',
79
81
  });
80
82
  const plannerResult: MigrationPlannerResult = await planner.plan({
81
- contract: contractIR,
83
+ contract,
82
84
  schema: schemaIR,
83
85
  policy,
84
86
  frameworkComponents,
@@ -114,12 +116,12 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
114
116
  action: 'dbInit',
115
117
  kind: 'spanStart',
116
118
  spanId: checkMarkerSpanId,
117
- label: 'Checking contract marker',
119
+ label: 'Checking database signature',
118
120
  });
119
121
  const existingMarker = await familyInstance.readMarker({ driver });
120
122
  if (existingMarker) {
121
123
  const markerMatchesDestination =
122
- existingMarker.coreHash === migrationPlan.destination.coreHash &&
124
+ existingMarker.storageHash === migrationPlan.destination.storageHash &&
123
125
  (!migrationPlan.destination.profileHash ||
124
126
  existingMarker.profileHash === migrationPlan.destination.profileHash);
125
127
 
@@ -134,15 +136,23 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
134
136
  const result: DbInitSuccess = {
135
137
  mode,
136
138
  plan: { operations: [] },
137
- ...(mode === 'apply'
138
- ? {
139
- execution: { operationsPlanned: 0, operationsExecuted: 0 },
140
- marker: {
141
- coreHash: existingMarker.coreHash,
139
+ destination: {
140
+ storageHash: migrationPlan.destination.storageHash,
141
+ ...ifDefined('profileHash', migrationPlan.destination.profileHash),
142
+ },
143
+ ...ifDefined(
144
+ 'execution',
145
+ mode === 'apply' ? { operationsPlanned: 0, operationsExecuted: 0 } : undefined,
146
+ ),
147
+ ...ifDefined(
148
+ 'marker',
149
+ mode === 'apply'
150
+ ? {
151
+ storageHash: existingMarker.storageHash,
142
152
  profileHash: existingMarker.profileHash,
143
- },
144
- }
145
- : {}),
153
+ }
154
+ : undefined,
155
+ ),
146
156
  summary: 'Database already at target contract state',
147
157
  };
148
158
  return ok(result);
@@ -159,11 +169,11 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
159
169
  code: 'MARKER_ORIGIN_MISMATCH' as const,
160
170
  summary: 'Existing contract marker does not match plan destination',
161
171
  marker: {
162
- coreHash: existingMarker.coreHash,
172
+ storageHash: existingMarker.storageHash,
163
173
  profileHash: existingMarker.profileHash,
164
174
  },
165
175
  destination: {
166
- coreHash: migrationPlan.destination.coreHash,
176
+ storageHash: migrationPlan.destination.storageHash,
167
177
  profileHash: migrationPlan.destination.profileHash,
168
178
  },
169
179
  why: undefined,
@@ -181,9 +191,17 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
181
191
 
182
192
  // Plan mode - don't execute
183
193
  if (mode === 'plan') {
194
+ const planSql = extractOperationStatements(familyInstance.familyId, migrationPlan.operations);
184
195
  const result: DbInitSuccess = {
185
196
  mode: 'plan',
186
- plan: { operations: migrationPlan.operations },
197
+ plan: {
198
+ operations: stripOperations(migrationPlan.operations),
199
+ ...ifDefined('sql', planSql),
200
+ },
201
+ destination: {
202
+ storageHash: migrationPlan.destination.storageHash,
203
+ ...ifDefined('profileHash', migrationPlan.destination.profileHash),
204
+ },
187
205
  summary: `Planned ${migrationPlan.operations.length} operation(s)`,
188
206
  };
189
207
  return ok(result);
@@ -198,34 +216,14 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
198
216
  label: 'Applying migration plan',
199
217
  });
200
218
 
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;
219
+ const callbacks = createOperationCallbacks(onProgress, 'dbInit', applySpanId);
222
220
 
223
221
  const runnerResult: MigrationRunnerResult = await runner.execute({
224
222
  plan: migrationPlan,
225
223
  driver,
226
- destinationContract: contractIR,
224
+ destinationContract: contract,
227
225
  policy,
228
- ...(callbacks ? { callbacks } : {}),
226
+ ...ifDefined('callbacks', callbacks),
229
227
  // db init plans and applies back-to-back from a fresh introspection, so per-operation
230
228
  // pre/postchecks and the idempotency probe are usually redundant overhead. We still
231
229
  // enforce marker/origin compatibility and a full schema verification after apply.
@@ -264,18 +262,24 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
264
262
 
265
263
  const result: DbInitSuccess = {
266
264
  mode: 'apply',
267
- plan: { operations: migrationPlan.operations },
265
+ plan: {
266
+ operations: stripOperations(migrationPlan.operations),
267
+ },
268
+ destination: {
269
+ storageHash: migrationPlan.destination.storageHash,
270
+ ...ifDefined('profileHash', migrationPlan.destination.profileHash),
271
+ },
268
272
  execution: {
269
273
  operationsPlanned: execution.operationsPlanned,
270
274
  operationsExecuted: execution.operationsExecuted,
271
275
  },
272
276
  marker: migrationPlan.destination.profileHash
273
277
  ? {
274
- coreHash: migrationPlan.destination.coreHash,
278
+ storageHash: migrationPlan.destination.storageHash,
275
279
  profileHash: migrationPlan.destination.profileHash,
276
280
  }
277
- : { coreHash: migrationPlan.destination.coreHash },
278
- summary: `Applied ${execution.operationsExecuted} operation(s), marker written`,
281
+ : { storageHash: migrationPlan.destination.storageHash },
282
+ summary: `Applied ${execution.operationsExecuted} operation(s), database signed`,
279
283
  };
280
284
  return ok(result);
281
285
  }