@prisma-next/cli 0.5.0-dev.8 → 0.5.0-dev.81

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 (186) hide show
  1. package/README.md +56 -21
  2. package/dist/cli-errors-B9OBbled.d.mts +3 -0
  3. package/dist/cli-errors-D3_sMh2K.mjs +33 -0
  4. package/dist/cli-errors-D3_sMh2K.mjs.map +1 -0
  5. package/dist/cli.mjs +16 -78
  6. package/dist/cli.mjs.map +1 -1
  7. package/dist/client-qVH-rEgd.mjs +1595 -0
  8. package/dist/client-qVH-rEgd.mjs.map +1 -0
  9. package/dist/{result-handler-Ba3zWQsI.mjs → command-helpers-BeZHkxV8.mjs} +70 -47
  10. package/dist/command-helpers-BeZHkxV8.mjs.map +1 -0
  11. package/dist/commands/contract-emit.d.mts.map +1 -1
  12. package/dist/commands/contract-emit.mjs +2 -4
  13. package/dist/commands/contract-infer.d.mts.map +1 -1
  14. package/dist/commands/contract-infer.mjs +2 -4
  15. package/dist/commands/db-init.d.mts.map +1 -1
  16. package/dist/commands/db-init.mjs +16 -13
  17. package/dist/commands/db-init.mjs.map +1 -1
  18. package/dist/commands/db-schema.d.mts.map +1 -1
  19. package/dist/commands/db-schema.mjs +6 -7
  20. package/dist/commands/db-schema.mjs.map +1 -1
  21. package/dist/commands/db-sign.d.mts.map +1 -1
  22. package/dist/commands/db-sign.mjs +9 -9
  23. package/dist/commands/db-sign.mjs.map +1 -1
  24. package/dist/commands/db-update.d.mts.map +1 -1
  25. package/dist/commands/db-update.mjs +15 -13
  26. package/dist/commands/db-update.mjs.map +1 -1
  27. package/dist/commands/db-verify.d.mts.map +1 -1
  28. package/dist/commands/db-verify.mjs +1 -321
  29. package/dist/commands/migration-apply.d.mts +28 -13
  30. package/dist/commands/migration-apply.d.mts.map +1 -1
  31. package/dist/commands/migration-apply.mjs +55 -151
  32. package/dist/commands/migration-apply.mjs.map +1 -1
  33. package/dist/commands/migration-new.d.mts +0 -1
  34. package/dist/commands/migration-new.d.mts.map +1 -1
  35. package/dist/commands/migration-new.mjs +34 -40
  36. package/dist/commands/migration-new.mjs.map +1 -1
  37. package/dist/commands/migration-plan.d.mts +33 -6
  38. package/dist/commands/migration-plan.d.mts.map +1 -1
  39. package/dist/commands/migration-plan.mjs +2 -348
  40. package/dist/commands/migration-ref.d.mts +1 -1
  41. package/dist/commands/migration-ref.d.mts.map +1 -1
  42. package/dist/commands/migration-ref.mjs +8 -12
  43. package/dist/commands/migration-ref.mjs.map +1 -1
  44. package/dist/commands/migration-show.d.mts +13 -7
  45. package/dist/commands/migration-show.d.mts.map +1 -1
  46. package/dist/commands/migration-show.mjs +35 -36
  47. package/dist/commands/migration-show.mjs.map +1 -1
  48. package/dist/commands/migration-status.d.mts +126 -5
  49. package/dist/commands/migration-status.d.mts.map +1 -1
  50. package/dist/commands/migration-status.mjs +2 -4
  51. package/dist/{config-loader-C25b63rJ.mjs → config-loader-B6sJjXTv.mjs} +3 -5
  52. package/dist/config-loader-B6sJjXTv.mjs.map +1 -0
  53. package/dist/config-loader.d.mts +0 -1
  54. package/dist/config-loader.d.mts.map +1 -1
  55. package/dist/config-loader.mjs +2 -3
  56. package/dist/contract-emit-9DBda5Ou.mjs +150 -0
  57. package/dist/contract-emit-9DBda5Ou.mjs.map +1 -0
  58. package/dist/contract-emit-B77TsJqf.mjs +327 -0
  59. package/dist/contract-emit-B77TsJqf.mjs.map +1 -0
  60. package/dist/{contract-enrichment-CAOELa-H.mjs → contract-enrichment-Dani0mMW.mjs} +4 -6
  61. package/dist/contract-enrichment-Dani0mMW.mjs.map +1 -0
  62. package/dist/{contract-infer-D9cC3rJm.mjs → contract-infer-BK9YFGEG.mjs} +13 -22
  63. package/dist/contract-infer-BK9YFGEG.mjs.map +1 -0
  64. package/dist/db-verify-C0y1PCO2.mjs +404 -0
  65. package/dist/db-verify-C0y1PCO2.mjs.map +1 -0
  66. package/dist/exports/config-types.mjs +1 -2
  67. package/dist/exports/control-api.d.mts +101 -586
  68. package/dist/exports/control-api.d.mts.map +1 -1
  69. package/dist/exports/control-api.mjs +4 -6
  70. package/dist/exports/index.d.mts.map +1 -1
  71. package/dist/exports/index.mjs +28 -30
  72. package/dist/exports/index.mjs.map +1 -1
  73. package/dist/exports/init-output.d.mts +2 -4
  74. package/dist/exports/init-output.d.mts.map +1 -1
  75. package/dist/exports/init-output.mjs +2 -3
  76. package/dist/extension-pack-inputs-C7xgE-vv.mjs +74 -0
  77. package/dist/extension-pack-inputs-C7xgE-vv.mjs.map +1 -0
  78. package/dist/{framework-components-Cr--XBKy.mjs → framework-components-ChqVUxR-.mjs} +3 -4
  79. package/dist/{framework-components-Cr--XBKy.mjs.map → framework-components-ChqVUxR-.mjs.map} +1 -1
  80. package/dist/global-flags-Icqpxk23.d.mts +12 -0
  81. package/dist/global-flags-Icqpxk23.d.mts.map +1 -0
  82. package/dist/helpers-eqdN8tH6.mjs +25 -0
  83. package/dist/helpers-eqdN8tH6.mjs.map +1 -0
  84. package/dist/{init-C5220SY9.mjs → init-CoDVPvQ4.mjs} +26 -35
  85. package/dist/init-CoDVPvQ4.mjs.map +1 -0
  86. package/dist/{inspect-live-schema-yrHAvG71.mjs → inspect-live-schema-CWYxGKlb.mjs} +10 -11
  87. package/dist/inspect-live-schema-CWYxGKlb.mjs.map +1 -0
  88. package/dist/migration-cli.d.mts +41 -12
  89. package/dist/migration-cli.d.mts.map +1 -1
  90. package/dist/migration-cli.mjs +309 -86
  91. package/dist/migration-cli.mjs.map +1 -1
  92. package/dist/{migration-command-scaffold-B3B09et6.mjs → migration-command-scaffold-B5dORFEv.mjs} +8 -9
  93. package/dist/migration-command-scaffold-B5dORFEv.mjs.map +1 -0
  94. package/dist/migration-plan-C6lVaHsO.mjs +554 -0
  95. package/dist/migration-plan-C6lVaHsO.mjs.map +1 -0
  96. package/dist/{migration-status-DUMiH8_G.mjs → migration-status-CZ-D5k7k.mjs} +272 -65
  97. package/dist/migration-status-CZ-D5k7k.mjs.map +1 -0
  98. package/dist/migrations-D_UJnpuW.mjs +216 -0
  99. package/dist/migrations-D_UJnpuW.mjs.map +1 -0
  100. package/dist/{output-BpcQrnnq.mjs → output-B16Kefzx.mjs} +9 -3
  101. package/dist/output-B16Kefzx.mjs.map +1 -0
  102. package/dist/{progress-adapter-DvQWB1nK.mjs → progress-adapter-DFfvZcYL.mjs} +2 -2
  103. package/dist/{progress-adapter-DvQWB1nK.mjs.map → progress-adapter-DFfvZcYL.mjs.map} +1 -1
  104. package/dist/result-handler-rmPVKIP2.mjs +25 -0
  105. package/dist/result-handler-rmPVKIP2.mjs.map +1 -0
  106. package/dist/rolldown-runtime-twds-ZHy.mjs +14 -0
  107. package/dist/{terminal-ui-C3ZLwQxK.mjs → terminal-ui-C_hFNbAn.mjs} +4 -28
  108. package/dist/terminal-ui-C_hFNbAn.mjs.map +1 -0
  109. package/dist/types-D7x-IFLO.d.mts +858 -0
  110. package/dist/types-D7x-IFLO.d.mts.map +1 -0
  111. package/dist/{verify-Bkycc-Tf.mjs → verify-CiwNWM9N.mjs} +3 -4
  112. package/dist/verify-CiwNWM9N.mjs.map +1 -0
  113. package/package.json +26 -24
  114. package/src/cli.ts +32 -6
  115. package/src/commands/contract-emit.ts +67 -163
  116. package/src/commands/contract-infer.ts +7 -20
  117. package/src/commands/db-init.ts +15 -3
  118. package/src/commands/db-update.ts +9 -4
  119. package/src/commands/db-verify.ts +47 -15
  120. package/src/commands/init/index.ts +1 -1
  121. package/src/commands/init/init.ts +2 -2
  122. package/src/commands/init/templates/code-templates.ts +12 -4
  123. package/src/commands/inspect-live-schema.ts +10 -5
  124. package/src/commands/migration-apply.ts +114 -212
  125. package/src/commands/migration-new.ts +42 -45
  126. package/src/commands/migration-plan.ts +212 -72
  127. package/src/commands/migration-ref.ts +8 -7
  128. package/src/commands/migration-show.ts +60 -41
  129. package/src/commands/migration-status.ts +483 -64
  130. package/src/config-path-validation.ts +0 -1
  131. package/src/control-api/client.ts +85 -5
  132. package/src/control-api/contract-enrichment.ts +6 -4
  133. package/src/control-api/operations/apply-aggregate.ts +290 -0
  134. package/src/control-api/operations/contract-emit.ts +198 -115
  135. package/src/control-api/operations/db-apply-aggregate.ts +397 -0
  136. package/src/control-api/operations/db-init.ts +51 -253
  137. package/src/control-api/operations/db-update.ts +66 -183
  138. package/src/control-api/operations/db-verify.ts +342 -0
  139. package/src/control-api/operations/migration-apply.ts +424 -131
  140. package/src/control-api/types.ts +280 -29
  141. package/src/exports/control-api.ts +15 -3
  142. package/src/load-ts-contract.ts +28 -26
  143. package/src/migration-cli.ts +445 -122
  144. package/src/utils/cli-errors.ts +49 -2
  145. package/src/utils/combine-schema-results.ts +84 -0
  146. package/src/utils/command-helpers.ts +69 -25
  147. package/src/utils/contract-space-aggregate-loader.ts +204 -0
  148. package/src/utils/contract-space-extension-migrations-pass.ts +120 -0
  149. package/src/utils/contract-space-migrate-pass.ts +156 -0
  150. package/src/utils/emit-queue.ts +26 -0
  151. package/src/utils/extension-pack-inputs.ts +170 -0
  152. package/src/utils/formatters/graph-migration-mapper.ts +7 -3
  153. package/src/utils/formatters/migrations.ts +197 -61
  154. package/src/utils/publish-contract-artifact-pair.ts +134 -0
  155. package/dist/cli-errors-BFYgBH3L.d.mts +0 -4
  156. package/dist/cli-errors-Cd79vmTH.mjs +0 -5
  157. package/dist/client-CrsnY58k.mjs +0 -997
  158. package/dist/client-CrsnY58k.mjs.map +0 -1
  159. package/dist/commands/db-verify.mjs.map +0 -1
  160. package/dist/commands/migration-plan.mjs.map +0 -1
  161. package/dist/config-loader-C25b63rJ.mjs.map +0 -1
  162. package/dist/contract-emit--feXyNd7.mjs +0 -4
  163. package/dist/contract-emit-NJ01hiiv.mjs +0 -195
  164. package/dist/contract-emit-NJ01hiiv.mjs.map +0 -1
  165. package/dist/contract-emit-V5SSitUT.mjs +0 -122
  166. package/dist/contract-emit-V5SSitUT.mjs.map +0 -1
  167. package/dist/contract-enrichment-CAOELa-H.mjs.map +0 -1
  168. package/dist/contract-infer-D9cC3rJm.mjs.map +0 -1
  169. package/dist/extract-operation-statements-DsFfxXVZ.mjs +0 -13
  170. package/dist/extract-operation-statements-DsFfxXVZ.mjs.map +0 -1
  171. package/dist/extract-sql-ddl-D9UbZDyz.mjs +0 -26
  172. package/dist/extract-sql-ddl-D9UbZDyz.mjs.map +0 -1
  173. package/dist/init-C5220SY9.mjs.map +0 -1
  174. package/dist/inspect-live-schema-yrHAvG71.mjs.map +0 -1
  175. package/dist/migration-command-scaffold-B3B09et6.mjs.map +0 -1
  176. package/dist/migration-status-DUMiH8_G.mjs.map +0 -1
  177. package/dist/migrations-Bo5WtTla.mjs +0 -153
  178. package/dist/migrations-Bo5WtTla.mjs.map +0 -1
  179. package/dist/output-BpcQrnnq.mjs.map +0 -1
  180. package/dist/result-handler-Ba3zWQsI.mjs.map +0 -1
  181. package/dist/terminal-ui-C3ZLwQxK.mjs.map +0 -1
  182. package/dist/validate-contract-deps-B_Cs29TL.mjs +0 -37
  183. package/dist/validate-contract-deps-B_Cs29TL.mjs.map +0 -1
  184. package/dist/verify-Bkycc-Tf.mjs.map +0 -1
  185. package/src/control-api/operations/extract-operation-statements.ts +0 -14
  186. package/src/control-api/operations/extract-sql-ddl.ts +0 -47
@@ -0,0 +1,156 @@
1
+ import {
2
+ detectSpaceContractDrift,
3
+ emitContractSpaceArtefacts,
4
+ readContractSpaceHeadRef,
5
+ type SpaceContractDriftResult,
6
+ } from '@prisma-next/migration-tools/spaces';
7
+
8
+ /**
9
+ * Minimal descriptor view consumed by the migrate-time per-space pass.
10
+ *
11
+ * The CLI receives descriptors typed against the SQL family (or any other
12
+ * family in the future); this helper only needs the structural shape of
13
+ * `contractSpace`, so it accepts an `unknown`-typed `contractJson` and
14
+ * a structurally-typed `headRef`. SQL-family callers pass the same
15
+ * `Contract<SqlStorage>` value through unchanged — `emitContractSpaceArtefacts`
16
+ * already serialises through `canonicalizeJson` and is framework-neutral.
17
+ *
18
+ * @see specs/framework-mechanism.spec.md § 3 — Per-space helper location.
19
+ */
20
+ export interface MigrateExtensionInput {
21
+ readonly id: string;
22
+ readonly contractSpace?: {
23
+ readonly contractJson: unknown;
24
+ readonly headRef: { readonly hash: string; readonly invariants: readonly string[] };
25
+ };
26
+ }
27
+
28
+ /**
29
+ * Inputs needed to compose the migrate-time per-space pass at the CLI
30
+ * surface — typically called once after the app-space migration package
31
+ * has been written, regardless of whether the app-space had structural
32
+ * changes (an extension bump alone should still re-pin its artefacts).
33
+ */
34
+ export interface ContractSpaceMigratePassInputs {
35
+ readonly migrationsDir: string;
36
+ readonly extensionPacks: ReadonlyArray<MigrateExtensionInput>;
37
+ }
38
+
39
+ export interface ContractSpaceMigratePassResult {
40
+ readonly drifts: readonly SpaceContractDriftResult[];
41
+ readonly emittedSpaceIds: readonly string[];
42
+ }
43
+
44
+ /**
45
+ * Run drift detection + on-disk artefact emission for every loaded
46
+ * extension space at `migrate` time.
47
+ *
48
+ * Per sub-spec § 3:
49
+ *
50
+ * - For each declared extension that exposes a `contractSpace`:
51
+ * - Read the on-disk head hash from `migrations/<spaceId>/refs/head.json`
52
+ * (returns `null` on first emit).
53
+ * - Compare against the descriptor's `headRef.hash` via
54
+ * `detectSpaceContractDrift`. The `kind` discriminant decides whether
55
+ * the user sees a warning (`drift`), a no-op silent emit (`firstEmit`,
56
+ * `noDrift`), or nothing at all.
57
+ * - Always re-emit the on-disk artefacts (`contract.json`, `contract.d.ts`,
58
+ * `refs/head.json`). The framework owns these files and the helper is
59
+ * idempotent.
60
+ *
61
+ * Drift warnings are returned to the caller for formatting (TerminalUI,
62
+ * structured-output envelope, etc.) — the helper does not print directly,
63
+ * keeping it framework-neutral and unit-testable.
64
+ *
65
+ * Extension migration packages (the descriptor's pre-canned `migrations`
66
+ * array → `migrations/<spaceId>/<dirName>/`) are intentionally not
67
+ * materialised here — that interaction will be wired in a follow-on round
68
+ * once the runner-side single-tx slice (sub-spec § 6) is in place.
69
+ * On-disk artefacts are sufficient to lock the drift-warning behaviour
70
+ * and the always-on re-emit AC for R2.
71
+ *
72
+ * @see specs/framework-mechanism.spec.md § 3 — Drift detection (T1.9).
73
+ */
74
+ export async function runContractSpaceMigratePass(
75
+ inputs: ContractSpaceMigratePassInputs,
76
+ ): Promise<ContractSpaceMigratePassResult> {
77
+ const drifts: SpaceContractDriftResult[] = [];
78
+ const emittedSpaceIds: string[] = [];
79
+
80
+ for (const pack of inputs.extensionPacks) {
81
+ if (pack.contractSpace === undefined) continue;
82
+ const { contractJson, headRef } = pack.contractSpace;
83
+
84
+ const onDiskHeadRef = await readContractSpaceHeadRef(inputs.migrationsDir, pack.id);
85
+ const drift = detectSpaceContractDrift(pack.id, {
86
+ descriptorHash: headRef.hash,
87
+ priorHeadHash: onDiskHeadRef?.hash ?? null,
88
+ });
89
+ drifts.push(drift);
90
+
91
+ await emitContractSpaceArtefacts(inputs.migrationsDir, pack.id, {
92
+ contract: contractJson,
93
+ contractDts: buildPlaceholderContractDts(pack.id),
94
+ headRef: { hash: headRef.hash, invariants: headRef.invariants },
95
+ });
96
+ emittedSpaceIds.push(pack.id);
97
+ }
98
+
99
+ return { drifts, emittedSpaceIds };
100
+ }
101
+
102
+ /**
103
+ * Format the user-facing drift warning for a single space. Callers
104
+ * funnel this through their preferred output channel (TerminalUI line,
105
+ * structured-output envelope `warnings[]`, etc.).
106
+ *
107
+ * Locks AM7 — drift warning surfaces the extension name and the diff
108
+ * direction (descriptor → on-disk head).
109
+ */
110
+ export function formatContractSpaceDriftWarning(drift: SpaceContractDriftResult): string {
111
+ if (drift.kind !== 'drift') {
112
+ throw new Error(`formatContractSpaceDriftWarning called with non-drift result: ${drift.kind}`);
113
+ }
114
+ return (
115
+ `Contract-space drift detected for "${drift.spaceId}": descriptor hash ` +
116
+ `${drift.descriptorHash} differs from on-disk head hash ${drift.priorHeadHash ?? '<none>'}. ` +
117
+ `The on-disk artefacts under migrations/${drift.spaceId}/ will be refreshed to match the descriptor.`
118
+ );
119
+ }
120
+
121
+ /**
122
+ * Placeholder `.d.ts` content for an extension space's on-disk mirror.
123
+ *
124
+ * Rendering a fully-typed `.d.ts` for an extension contract requires the
125
+ * SQL-family renderer with the codec / typemap registry threaded
126
+ * through; that integration is tracked under sub-spec Open Question 3
127
+ * (see `projects/extension-contract-spaces/specs/framework-mechanism.spec.md`).
128
+ *
129
+ * Until that ships, the on-disk `.d.ts` is a `@ts-nocheck` stub. The
130
+ * spec gap closing alongside the typed renderer is **AC2 / AC14**
131
+ * (byte-equivalence of per-space artefacts under `migrate`):
132
+ * a placeholder cannot be byte-equal to a fully-rendered `.d.ts` from
133
+ * the same descriptor, so AC2 / AC14 are PARTIAL today and become
134
+ * fully-PASS once OQ3 closes.
135
+ *
136
+ * Scheduled to close in **M3** (cipherstash editor tooling) — that's
137
+ * the milestone where the typed renderer gets its first real
138
+ * extension-space consumer and the byte-equivalence guarantee is
139
+ * practically required.
140
+ */
141
+ function buildPlaceholderContractDts(spaceId: string): string {
142
+ return [
143
+ '// @ts-nocheck',
144
+ '/**',
145
+ ` * Placeholder \`.d.ts\` for extension space "${spaceId}".`,
146
+ ' *',
147
+ ' * The framework re-emits this file on every `migrate` run alongside',
148
+ ' * `contract.json` and `refs/head.json`. A typed `.d.ts` rendering',
149
+ " * pass for extension contracts is tracked under the project's open",
150
+ ' * questions; until that ships, consumers should import',
151
+ ' * `contract.json` directly with `validateContract<…>(…)`.',
152
+ ' */',
153
+ 'export {};',
154
+ '',
155
+ ].join('\n');
156
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Per-output FIFO queue for `executeContractEmit`.
3
+ *
4
+ * Ensures that at most one emit (load → resolve source → emit bytes → publish)
5
+ * runs per output JSON path at a time. Concurrent calls for the same path
6
+ * line up behind the in-flight one and run in submission order; the user-visible
7
+ * outcome is "last submission wins on disk" without any supersession bookkeeping.
8
+ *
9
+ * Long-lived hosts (Vite dev server, watch CLIs) must call `disposeEmitQueue`
10
+ * when they stop publishing to a path, otherwise the module-global `Map`
11
+ * accumulates one entry per unique output path for the lifetime of the process.
12
+ */
13
+ const emitQueues = new Map<string, Promise<unknown>>();
14
+
15
+ export function queueEmitByOutput<T>(outputJsonPath: string, action: () => Promise<T>): Promise<T> {
16
+ const previous = emitQueues.get(outputJsonPath) ?? Promise.resolve();
17
+ // Continue regardless of the previous task's outcome — a failed emit must not
18
+ // block subsequent ones. The current task's outcome propagates via `next`.
19
+ const next = previous.then(action, action);
20
+ emitQueues.set(outputJsonPath, next);
21
+ return next;
22
+ }
23
+
24
+ export function disposeEmitQueue(outputJsonPath: string): void {
25
+ emitQueues.delete(outputJsonPath);
26
+ }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Single descriptor-import boundary for CLI consumers of `Config.extensionPacks`.
3
+ *
4
+ * Every CLI command / utility that reads an extension descriptor's
5
+ * `contractSpace` projection (loader, migrate-pass, extension-migrations
6
+ * pass, migration commands) goes through {@link toExtensionInputs}. The
7
+ * structural cast `pack as { contractSpace?: ... }` lives **only** here —
8
+ * downstream code consumes the canonical shape and maps it to its own
9
+ * narrower shape via the per-consumer adapters below.
10
+ *
11
+ * The CLI receives extension descriptors typed against the SQL family
12
+ * (or any other family in the future); this helper only depends on the
13
+ * structural shape of `contractSpace`. SQL-family callers pass the same
14
+ * `contractJson` / `headRef.hash` value through unchanged.
15
+ */
16
+ import type { DeclaredExtensionEntry } from '@prisma-next/migration-tools/aggregate';
17
+ import type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';
18
+ import type { MigrationOps } from '@prisma-next/migration-tools/package';
19
+ import type { ExtensionMigrationsExtensionInput } from './contract-space-extension-migrations-pass';
20
+ import type { MigrateExtensionInput } from './contract-space-migrate-pass';
21
+
22
+ /**
23
+ * In-memory authored migration package shipped by an extension descriptor.
24
+ * Mirrors the `MigrationPackage` shape from
25
+ * `@prisma-next/framework-components/control` minus `dirPath`; redeclared
26
+ * structurally here so the helper does not couple to the SQL family's
27
+ * `ExtensionMigrationPackage` type.
28
+ */
29
+ export interface DescriptorMigrationPackage {
30
+ readonly dirName: string;
31
+ readonly metadata: MigrationMetadata;
32
+ readonly ops: MigrationOps;
33
+ }
34
+
35
+ /**
36
+ * The most-general projection of a single declared extension pack
37
+ * needed by the CLI's descriptor-import boundary.
38
+ *
39
+ * - `id` / `targetId` are always present.
40
+ * - `contractSpace` is present only when the extension declares one.
41
+ * When present, it carries the canonical inputs every downstream
42
+ * consumer needs — `contractJson`, `headRef`, and the descriptor's
43
+ * pre-built migration packages.
44
+ */
45
+ export interface ExtensionPackInput {
46
+ readonly id: string;
47
+ readonly targetId: string;
48
+ readonly contractSpace?: {
49
+ readonly contractJson: unknown;
50
+ readonly headRef: {
51
+ readonly hash: string;
52
+ readonly invariants: readonly string[];
53
+ };
54
+ readonly migrations: readonly DescriptorMigrationPackage[];
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Structural shape we read off each `Config.extensionPacks` entry.
60
+ *
61
+ * The CLI is the descriptor-import boundary; `extensionPacks` is the only
62
+ * surface where the SQL-family-typed `ControlExtensionDescriptor` flows
63
+ * into framework-neutral helpers. The structural cast lives here, and
64
+ * here alone — every other CLI consumer reads the canonical
65
+ * {@link ExtensionPackInput} shape produced by {@link toExtensionInputs}.
66
+ */
67
+ type ExtensionPackLike = {
68
+ readonly id: string;
69
+ readonly targetId: string;
70
+ readonly contractSpace?: {
71
+ readonly contractJson: unknown;
72
+ readonly headRef: {
73
+ readonly hash: string;
74
+ readonly invariants: readonly string[];
75
+ };
76
+ readonly migrations?: readonly DescriptorMigrationPackage[];
77
+ };
78
+ };
79
+
80
+ /**
81
+ * Project the CLI's `Config.extensionPacks` array into the canonical
82
+ * {@link ExtensionPackInput} shape. The single `as ExtensionPackLike`
83
+ * structural cast in the CLI lives inside this function.
84
+ */
85
+ export function toExtensionInputs(
86
+ extensionPacks: ReadonlyArray<unknown>,
87
+ ): readonly ExtensionPackInput[] {
88
+ return extensionPacks.map((raw) => {
89
+ const pack = raw as ExtensionPackLike;
90
+ if (pack.contractSpace === undefined) {
91
+ return { id: pack.id, targetId: pack.targetId };
92
+ }
93
+ return {
94
+ id: pack.id,
95
+ targetId: pack.targetId,
96
+ contractSpace: {
97
+ contractJson: pack.contractSpace.contractJson,
98
+ headRef: pack.contractSpace.headRef,
99
+ migrations: pack.contractSpace.migrations ?? [],
100
+ },
101
+ };
102
+ });
103
+ }
104
+
105
+ // ---------------------------------------------------------------------------
106
+ // Per-consumer adapters: take the canonical `ExtensionPackInput[]` and
107
+ // project to whatever narrower shape the downstream primitive needs.
108
+ // ---------------------------------------------------------------------------
109
+
110
+ /**
111
+ * Aggregate-loader projection: surfaces `targetId` + `contractSpace.contractJson`
112
+ * to {@link import('./contract-space-aggregate-loader').buildContractSpaceAggregate}
113
+ * and a `hashByContractJson` map keyed by the same `contractJson` reference
114
+ * the loader hands to its hash callback.
115
+ */
116
+ export function toDeclaredExtensions(inputs: ReadonlyArray<ExtensionPackInput>): {
117
+ readonly entries: ReadonlyArray<DeclaredExtensionEntry>;
118
+ readonly hashByContractJson: Map<unknown, string>;
119
+ } {
120
+ const entries: DeclaredExtensionEntry[] = [];
121
+ const hashByContractJson = new Map<unknown, string>();
122
+ for (const pack of inputs) {
123
+ if (pack.contractSpace) {
124
+ entries.push({
125
+ id: pack.id,
126
+ targetId: pack.targetId,
127
+ contractSpace: { contractJson: pack.contractSpace.contractJson },
128
+ });
129
+ hashByContractJson.set(pack.contractSpace.contractJson, pack.contractSpace.headRef.hash);
130
+ } else {
131
+ entries.push({ id: pack.id, targetId: pack.targetId });
132
+ }
133
+ }
134
+ return { entries, hashByContractJson };
135
+ }
136
+
137
+ /** Migrate-time per-space pass projection. */
138
+ export function toMigratePassInputs(
139
+ inputs: ReadonlyArray<ExtensionPackInput>,
140
+ ): readonly MigrateExtensionInput[] {
141
+ return inputs.map((pack) =>
142
+ pack.contractSpace
143
+ ? {
144
+ id: pack.id,
145
+ contractSpace: {
146
+ contractJson: pack.contractSpace.contractJson,
147
+ headRef: pack.contractSpace.headRef,
148
+ },
149
+ }
150
+ : { id: pack.id },
151
+ );
152
+ }
153
+
154
+ /** Extension-migrations materialisation pass projection. */
155
+ export function toExtensionMigrationsInputs(
156
+ inputs: ReadonlyArray<ExtensionPackInput>,
157
+ ): readonly ExtensionMigrationsExtensionInput[] {
158
+ return inputs.map((pack) =>
159
+ pack.contractSpace
160
+ ? {
161
+ id: pack.id,
162
+ contractSpace: {
163
+ contractJson: pack.contractSpace.contractJson,
164
+ headRef: pack.contractSpace.headRef,
165
+ migrations: pack.contractSpace.migrations,
166
+ },
167
+ }
168
+ : { id: pack.id },
169
+ );
170
+ }
@@ -2,8 +2,8 @@
2
2
  * Maps MigrationGraph + status info to the generic graph renderer types.
3
3
  */
4
4
  import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
5
- import { findPath } from '@prisma-next/migration-tools/dag';
6
- import type { MigrationGraph } from '@prisma-next/migration-tools/types';
5
+ import type { MigrationGraph } from '@prisma-next/migration-tools/graph';
6
+ import { findPath } from '@prisma-next/migration-tools/migration-graph';
7
7
  import { ifDefined } from '@prisma-next/utils/defined';
8
8
 
9
9
  import type { StatusRef } from '../migration-types';
@@ -106,7 +106,11 @@ export function migrationGraphToRenderInput(input: MigrationGraphInput): Migrati
106
106
  for (const entry of entries) {
107
107
  const status = statusByDirName.get(entry.dirName);
108
108
  const icon = status ? STATUS_ICON[status] : '';
109
- const label = `${entry.dirName}${icon}`;
109
+ const invariantsSuffix =
110
+ entry.invariants.length > 0
111
+ ? ` provides [${entry.invariants.map((id) => JSON.stringify(id)).join(', ')}]`
112
+ : '';
113
+ const label = `${entry.dirName}${icon}${invariantsSuffix}`;
110
114
 
111
115
  edgeList.push({
112
116
  from: toShortId(entry.from),