@prisma-next/cli 0.3.0-dev.17 → 0.3.0-dev.18

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 (45) hide show
  1. package/dist/chunk-BO73VO4I.js +45 -0
  2. package/dist/chunk-BO73VO4I.js.map +1 -0
  3. package/dist/{chunk-VI2YETW7.js → chunk-MPSJAVF6.js} +4 -2
  4. package/dist/{chunk-U6QI3AZ3.js → chunk-RIONCN4I.js} +45 -6
  5. package/dist/chunk-RIONCN4I.js.map +1 -0
  6. package/dist/{chunk-74IELXRA.js → chunk-RPYY5SM7.js} +273 -19
  7. package/dist/chunk-RPYY5SM7.js.map +1 -0
  8. package/dist/cli.js +708 -551
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/contract-emit.js +2 -3
  11. package/dist/commands/db-init.js +5 -46
  12. package/dist/commands/db-init.js.map +1 -1
  13. package/dist/commands/db-introspect.d.ts.map +1 -1
  14. package/dist/commands/db-introspect.js +107 -133
  15. package/dist/commands/db-introspect.js.map +1 -1
  16. package/dist/commands/db-schema-verify.d.ts.map +1 -1
  17. package/dist/commands/db-schema-verify.js +119 -107
  18. package/dist/commands/db-schema-verify.js.map +1 -1
  19. package/dist/commands/db-sign.d.ts.map +1 -1
  20. package/dist/commands/db-sign.js +151 -150
  21. package/dist/commands/db-sign.js.map +1 -1
  22. package/dist/commands/db-verify.d.ts.map +1 -1
  23. package/dist/commands/db-verify.js +141 -116
  24. package/dist/commands/db-verify.js.map +1 -1
  25. package/dist/control-api/client.d.ts.map +1 -1
  26. package/dist/control-api/types.d.ts +41 -0
  27. package/dist/control-api/types.d.ts.map +1 -1
  28. package/dist/exports/control-api.js +2 -3
  29. package/dist/exports/index.js +2 -3
  30. package/dist/exports/index.js.map +1 -1
  31. package/package.json +10 -10
  32. package/src/commands/contract-emit.ts +1 -1
  33. package/src/commands/db-introspect.ts +151 -178
  34. package/src/commands/db-schema-verify.ts +150 -143
  35. package/src/commands/db-sign.ts +202 -196
  36. package/src/commands/db-verify.ts +179 -149
  37. package/src/control-api/client.ts +256 -22
  38. package/src/control-api/types.ts +42 -0
  39. package/dist/chunk-5MPKZYVI.js +0 -47
  40. package/dist/chunk-5MPKZYVI.js.map +0 -1
  41. package/dist/chunk-6EPKRATC.js +0 -91
  42. package/dist/chunk-6EPKRATC.js.map +0 -1
  43. package/dist/chunk-74IELXRA.js.map +0 -1
  44. package/dist/chunk-U6QI3AZ3.js.map +0 -1
  45. /package/dist/{chunk-VI2YETW7.js.map → chunk-MPSJAVF6.js.map} +0 -0
@@ -0,0 +1,45 @@
1
+ // src/utils/progress-adapter.ts
2
+ import ora from "ora";
3
+ function createProgressAdapter(options) {
4
+ const { flags } = options;
5
+ const shouldShowProgress = !flags.quiet && flags.json !== "object" && process.stdout.isTTY;
6
+ if (!shouldShowProgress) {
7
+ return () => {
8
+ };
9
+ }
10
+ const activeSpans = /* @__PURE__ */ new Map();
11
+ return (event) => {
12
+ if (event.kind === "spanStart") {
13
+ if (event.parentSpanId) {
14
+ console.log(` \u2192 ${event.label}...`);
15
+ return;
16
+ }
17
+ const spinner = ora({
18
+ text: event.label,
19
+ color: flags.color !== false ? "cyan" : false
20
+ }).start();
21
+ activeSpans.set(event.spanId, {
22
+ spinner,
23
+ startTime: Date.now()
24
+ });
25
+ } else if (event.kind === "spanEnd") {
26
+ const spanState = activeSpans.get(event.spanId);
27
+ if (spanState) {
28
+ const elapsed = Date.now() - spanState.startTime;
29
+ if (event.outcome === "error") {
30
+ spanState.spinner.fail(`${spanState.spinner.text} (failed)`);
31
+ } else if (event.outcome === "skipped") {
32
+ spanState.spinner.info(`${spanState.spinner.text} (skipped)`);
33
+ } else {
34
+ spanState.spinner.succeed(`${spanState.spinner.text} (${elapsed}ms)`);
35
+ }
36
+ activeSpans.delete(event.spanId);
37
+ }
38
+ }
39
+ };
40
+ }
41
+
42
+ export {
43
+ createProgressAdapter
44
+ };
45
+ //# sourceMappingURL=chunk-BO73VO4I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/progress-adapter.ts"],"sourcesContent":["import ora from 'ora';\nimport type { ControlProgressEvent, OnControlProgress } from '../control-api/types';\nimport type { GlobalFlags } from './global-flags';\n\n/**\n * Options for creating a progress adapter.\n */\ninterface ProgressAdapterOptions {\n /**\n * Global flags that control progress output behavior (quiet, json, color).\n */\n readonly flags: GlobalFlags;\n}\n\n/**\n * State for tracking active spans in the progress adapter.\n */\ninterface SpanState {\n readonly spinner: ReturnType<typeof ora>;\n readonly startTime: number;\n}\n\n/**\n * Creates a progress adapter that converts control-api progress events\n * into CLI spinner/progress output.\n *\n * The adapter:\n * - Starts/succeeds spinners for top-level span boundaries\n * - Prints per-operation lines for nested spans (e.g., migration operations under 'apply')\n * - Respects quiet/json/non-TTY flags (no-op in those cases)\n *\n * @param options - Progress adapter configuration\n * @returns An onProgress callback compatible with control-api operations\n */\nexport function createProgressAdapter(options: ProgressAdapterOptions): OnControlProgress {\n const { flags } = options;\n\n // Skip progress if quiet, JSON output, or non-TTY\n const shouldShowProgress = !flags.quiet && flags.json !== 'object' && process.stdout.isTTY;\n\n if (!shouldShowProgress) {\n // Return a no-op callback\n return () => {\n // No-op\n };\n }\n\n // Track active spans by spanId\n const activeSpans = new Map<string, SpanState>();\n\n return (event: ControlProgressEvent) => {\n if (event.kind === 'spanStart') {\n // Nested spans (with parentSpanId) are printed as lines, not spinners\n if (event.parentSpanId) {\n console.log(` → ${event.label}...`);\n return;\n }\n\n // Top-level spans get a spinner\n const spinner = ora({\n text: event.label,\n color: flags.color !== false ? 'cyan' : false,\n }).start();\n\n activeSpans.set(event.spanId, {\n spinner,\n startTime: Date.now(),\n });\n } else if (event.kind === 'spanEnd') {\n // Complete the spinner for this span (only top-level spans have spinners)\n const spanState = activeSpans.get(event.spanId);\n if (spanState) {\n const elapsed = Date.now() - spanState.startTime;\n if (event.outcome === 'error') {\n spanState.spinner.fail(`${spanState.spinner.text} (failed)`);\n } else if (event.outcome === 'skipped') {\n spanState.spinner.info(`${spanState.spinner.text} (skipped)`);\n } else {\n spanState.spinner.succeed(`${spanState.spinner.text} (${elapsed}ms)`);\n }\n activeSpans.delete(event.spanId);\n }\n // Nested span ends are no-ops (could log completion if needed)\n }\n };\n}\n"],"mappings":";AAAA,OAAO,SAAS;AAkCT,SAAS,sBAAsB,SAAoD;AACxF,QAAM,EAAE,MAAM,IAAI;AAGlB,QAAM,qBAAqB,CAAC,MAAM,SAAS,MAAM,SAAS,YAAY,QAAQ,OAAO;AAErF,MAAI,CAAC,oBAAoB;AAEvB,WAAO,MAAM;AAAA,IAEb;AAAA,EACF;AAGA,QAAM,cAAc,oBAAI,IAAuB;AAE/C,SAAO,CAAC,UAAgC;AACtC,QAAI,MAAM,SAAS,aAAa;AAE9B,UAAI,MAAM,cAAc;AACtB,gBAAQ,IAAI,YAAO,MAAM,KAAK,KAAK;AACnC;AAAA,MACF;AAGA,YAAM,UAAU,IAAI;AAAA,QAClB,MAAM,MAAM;AAAA,QACZ,OAAO,MAAM,UAAU,QAAQ,SAAS;AAAA,MAC1C,CAAC,EAAE,MAAM;AAET,kBAAY,IAAI,MAAM,QAAQ;AAAA,QAC5B;AAAA,QACA,WAAW,KAAK,IAAI;AAAA,MACtB,CAAC;AAAA,IACH,WAAW,MAAM,SAAS,WAAW;AAEnC,YAAM,YAAY,YAAY,IAAI,MAAM,MAAM;AAC9C,UAAI,WAAW;AACb,cAAM,UAAU,KAAK,IAAI,IAAI,UAAU;AACvC,YAAI,MAAM,YAAY,SAAS;AAC7B,oBAAU,QAAQ,KAAK,GAAG,UAAU,QAAQ,IAAI,WAAW;AAAA,QAC7D,WAAW,MAAM,YAAY,WAAW;AACtC,oBAAU,QAAQ,KAAK,GAAG,UAAU,QAAQ,IAAI,YAAY;AAAA,QAC9D,OAAO;AACL,oBAAU,QAAQ,QAAQ,GAAG,UAAU,QAAQ,IAAI,KAAK,OAAO,KAAK;AAAA,QACtE;AACA,oBAAY,OAAO,MAAM,MAAM;AAAA,MACjC;AAAA,IAEF;AAAA,EACF;AACF;","names":[]}
@@ -24,15 +24,17 @@ import {
24
24
  export {
25
25
  CliStructuredError,
26
26
  errorConfigValidation,
27
- errorContractMissingExtensionPacks,
28
27
  errorContractValidationFailed,
29
28
  errorDatabaseConnectionRequired,
30
29
  errorDriverRequired,
31
30
  errorFileNotFound,
31
+ errorHashMismatch,
32
32
  errorJsonFormatNotSupported,
33
+ errorMarkerMissing,
33
34
  errorMigrationPlanningFailed,
34
35
  errorRuntime,
35
36
  errorTargetMigrationNotSupported,
37
+ errorTargetMismatch,
36
38
  errorUnexpected
37
39
  };
38
- //# sourceMappingURL=chunk-VI2YETW7.js.map
40
+ //# sourceMappingURL=chunk-MPSJAVF6.js.map
@@ -1,7 +1,3 @@
1
- import {
2
- performAction,
3
- withSpinner
4
- } from "./chunk-5MPKZYVI.js";
5
1
  import {
6
2
  formatCommandHelp,
7
3
  formatEmitJson,
@@ -15,13 +11,56 @@ import {
15
11
  import {
16
12
  loadConfig
17
13
  } from "./chunk-HWYQOCAJ.js";
14
+ import {
15
+ CliStructuredError
16
+ } from "./chunk-MPSJAVF6.js";
18
17
 
19
18
  // src/commands/contract-emit.ts
20
19
  import { mkdirSync, writeFileSync } from "fs";
21
20
  import { dirname, relative, resolve } from "path";
22
21
  import { errorContractConfigMissing } from "@prisma-next/core-control-plane/errors";
23
- import { createControlPlaneStack } from "@prisma-next/core-control-plane/types";
22
+ import { createControlPlaneStack } from "@prisma-next/core-control-plane/stack";
24
23
  import { Command } from "commander";
24
+
25
+ // src/utils/action.ts
26
+ import { notOk, ok } from "@prisma-next/utils/result";
27
+ async function performAction(fn) {
28
+ try {
29
+ const value = await fn();
30
+ return ok(value);
31
+ } catch (error) {
32
+ if (error instanceof CliStructuredError) {
33
+ return notOk(error);
34
+ }
35
+ throw error;
36
+ }
37
+ }
38
+
39
+ // src/utils/spinner.ts
40
+ import ora from "ora";
41
+ async function withSpinner(operation, options) {
42
+ const { message, flags } = options;
43
+ const shouldShowSpinner = !flags.quiet && flags.json !== "object" && process.stdout.isTTY;
44
+ if (!shouldShowSpinner) {
45
+ return operation();
46
+ }
47
+ const startTime = Date.now();
48
+ const spinner = ora({
49
+ text: message,
50
+ color: flags.color !== false ? "cyan" : false
51
+ }).start();
52
+ try {
53
+ const result = await operation();
54
+ const elapsed = Date.now() - startTime;
55
+ spinner.succeed(`${message} (${elapsed}ms)`);
56
+ return result;
57
+ } catch (error) {
58
+ spinner.fail(`${message} failed: ${error instanceof Error ? error.message : String(error)}`);
59
+ throw error;
60
+ }
61
+ }
62
+
63
+ // src/commands/contract-emit.ts
25
64
  function createContractEmitCommand() {
26
65
  const command = new Command("emit");
27
66
  setCommandDescriptions(
@@ -130,4 +169,4 @@ function createContractEmitCommand() {
130
169
  export {
131
170
  createContractEmitCommand
132
171
  };
133
- //# sourceMappingURL=chunk-U6QI3AZ3.js.map
172
+ //# sourceMappingURL=chunk-RIONCN4I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/contract-emit.ts","../src/utils/action.ts","../src/utils/spinner.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, relative, resolve } from 'node:path';\nimport { errorContractConfigMissing } from '@prisma-next/core-control-plane/errors';\nimport { createControlPlaneStack } from '@prisma-next/core-control-plane/stack';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { performAction } from '../utils/action';\nimport { setCommandDescriptions } from '../utils/command-helpers';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport {\n formatCommandHelp,\n formatEmitJson,\n formatEmitOutput,\n formatStyledHeader,\n formatSuccessMessage,\n} from '../utils/output';\nimport { handleResult } from '../utils/result-handler';\nimport { withSpinner } from '../utils/spinner';\n\ninterface ContractEmitOptions {\n readonly config?: string;\n readonly json?: string | boolean;\n readonly quiet?: boolean;\n readonly q?: boolean;\n readonly verbose?: boolean;\n readonly v?: boolean;\n readonly vv?: boolean;\n readonly trace?: boolean;\n readonly timestamps?: boolean;\n readonly color?: boolean;\n readonly 'no-color'?: boolean;\n}\n\nexport function createContractEmitCommand(): Command {\n const command = new Command('emit');\n setCommandDescriptions(\n command,\n 'Write your contract to JSON and sign it',\n 'Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\\n' +\n 'contract.d.ts. The contract.json contains the canonical contract structure, and\\n' +\n 'contract.d.ts provides TypeScript types for type-safe query building.',\n );\n command\n .configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n })\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--json [format]', 'Output as JSON (object or ndjson)', false)\n .option('-q, --quiet', 'Quiet mode: errors only')\n .option('-v, --verbose', 'Verbose output: debug info, timings')\n .option('-vv, --trace', 'Trace output: deep internals, stack traces')\n .option('--timestamps', 'Add timestamps to output')\n .option('--color', 'Force color output')\n .option('--no-color', 'Disable color output')\n .action(async (options: ContractEmitOptions) => {\n const flags = parseGlobalFlags(options);\n\n const result = await performAction(async () => {\n // Load config\n const config = await loadConfig(options.config);\n\n // Resolve contract from config\n if (!config.contract) {\n throw errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ..., types: ... }',\n });\n }\n\n // Contract config is already normalized by defineConfig() with defaults applied\n const contractConfig = config.contract;\n\n // Resolve artifact paths from config (already normalized by defineConfig() with defaults)\n if (!contractConfig.output || !contractConfig.types) {\n throw errorContractConfigMissing({\n why: 'Contract config must have output and types paths. This should not happen if defineConfig() was used.',\n });\n }\n const outputJsonPath = resolve(contractConfig.output);\n const outputDtsPath = resolve(contractConfig.types);\n\n // Output header (only for human-readable output)\n if (flags.json !== 'object' && !flags.quiet) {\n // Normalize config path for display (match contract path format - no ./ prefix)\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n // Convert absolute paths to relative paths for display\n const contractPath = relative(process.cwd(), outputJsonPath);\n const typesPath = relative(process.cwd(), outputDtsPath);\n const header = formatStyledHeader({\n command: 'contract emit',\n description: 'Write your contract to JSON and sign it',\n url: 'https://pris.ly/contract-emit',\n details: [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n { label: 'types', value: typesPath },\n ],\n flags,\n });\n console.log(header);\n }\n\n const stack = createControlPlaneStack({\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks,\n });\n const familyInstance = config.family.create(stack);\n\n // Resolve contract source from config (user's config handles loading)\n let contractRaw: unknown;\n if (typeof contractConfig.source === 'function') {\n contractRaw = await contractConfig.source();\n } else {\n contractRaw = contractConfig.source;\n }\n\n // Call emitContract on family instance (handles stripping mappings and validation internally)\n const emitResult = await withSpinner(\n () => familyInstance.emitContract({ contractIR: contractRaw }),\n {\n message: 'Emitting contract...',\n flags,\n },\n );\n\n // Create directories if needed\n mkdirSync(dirname(outputJsonPath), { recursive: true });\n mkdirSync(dirname(outputDtsPath), { recursive: true });\n\n // Write the results to files\n writeFileSync(outputJsonPath, emitResult.contractJson, 'utf-8');\n writeFileSync(outputDtsPath, emitResult.contractDts, 'utf-8');\n\n // Add blank line after all async operations if spinners were shown\n if (!flags.quiet && flags.json !== 'object' && process.stdout.isTTY) {\n console.log('');\n }\n\n // Return result with file paths for output formatting\n return {\n coreHash: emitResult.coreHash,\n profileHash: emitResult.profileHash,\n outDir: dirname(outputJsonPath),\n files: {\n json: outputJsonPath,\n dts: outputDtsPath,\n },\n timings: {\n total: 0, // Timing is handled by emitContract internally if needed\n },\n };\n });\n\n // Handle result - formats output and returns exit code\n const exitCode = handleResult(result, flags, (emitResult) => {\n // Output based on flags\n if (flags.json === 'object') {\n // JSON output to stdout\n console.log(formatEmitJson(emitResult));\n } else {\n // Human-readable output to stdout\n const output = formatEmitOutput(emitResult, flags);\n if (output) {\n console.log(output);\n }\n // Output success message\n if (!flags.quiet) {\n console.log(formatSuccessMessage(flags));\n }\n }\n });\n process.exit(exitCode);\n });\n\n return command;\n}\n","import type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { CliStructuredError } from './cli-errors';\n\nexport type CliResult<T> = Result<T, CliStructuredError>;\n\n/**\n * Performs an async action and catches structured errors, returning a Result.\n * Only catches CliStructuredError instances - other errors are allowed to propagate (fail fast).\n * If the function throws a CliStructuredError, it's caught and converted to a NotOk result.\n */\nexport async function performAction<T>(fn: () => Promise<T>): Promise<CliResult<T>> {\n try {\n const value = await fn();\n return ok(value);\n } catch (error) {\n // Only catch structured errors - let other errors propagate (fail fast)\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n // Re-throw non-structured errors to fail fast\n throw error;\n }\n}\n\n/**\n * Wraps a synchronous function to catch structured errors and return a Result.\n * Only catches CliStructuredError instances - other errors are allowed to propagate (fail fast).\n * If the function throws a CliStructuredError, it's caught and converted to a NotOk result.\n */\nexport function wrapSync<T>(fn: () => T): CliResult<T> {\n try {\n const value = fn();\n return ok(value);\n } catch (error) {\n // Only catch structured errors - let other errors propagate (fail fast)\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n // Re-throw non-structured errors to fail fast\n throw error;\n }\n}\n","import ora from 'ora';\nimport type { GlobalFlags } from './global-flags';\n\n/**\n * Options for the withSpinner helper function.\n */\ninterface WithSpinnerOptions {\n /**\n * The message to display in the spinner.\n */\n readonly message: string;\n /**\n * Global flags that control spinner behavior (quiet, json, color).\n */\n readonly flags: GlobalFlags;\n}\n\n/**\n * Wraps an async operation with a spinner.\n *\n * The spinner respects:\n * - `flags.quiet`: No spinner if quiet mode is enabled\n * - `flags.json === 'object'`: No spinner if JSON output is enabled\n * - Non-TTY environments: No spinner if stdout is not a TTY\n *\n * @param operation - The async operation to execute\n * @param options - Spinner configuration options\n * @returns The result of the operation\n */\nexport async function withSpinner<T>(\n operation: () => Promise<T>,\n options: WithSpinnerOptions,\n): Promise<T> {\n const { message, flags } = options;\n\n // Skip spinner if quiet, JSON output, or non-TTY\n const shouldShowSpinner = !flags.quiet && flags.json !== 'object' && process.stdout.isTTY;\n\n if (!shouldShowSpinner) {\n // Just execute the operation without spinner\n return operation();\n }\n\n // Start spinner immediately\n const startTime = Date.now();\n const spinner = ora({\n text: message,\n color: flags.color !== false ? 'cyan' : false,\n }).start();\n\n try {\n // Execute the operation\n const result = await operation();\n\n // Mark spinner as succeeded\n const elapsed = Date.now() - startTime;\n spinner.succeed(`${message} (${elapsed}ms)`);\n\n return result;\n } catch (error) {\n // Mark spinner as failed\n spinner.fail(`${message} failed: ${error instanceof Error ? error.message : String(error)}`);\n\n // Re-throw the error\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,10 +1,60 @@
1
1
  import {
2
- assertFrameworkComponentsCompatible
3
- } from "./chunk-6EPKRATC.js";
2
+ errorConfigValidation
3
+ } from "./chunk-MPSJAVF6.js";
4
4
 
5
5
  // src/control-api/client.ts
6
6
  import { createControlPlaneStack } from "@prisma-next/core-control-plane/stack";
7
7
 
8
+ // src/utils/framework-components.ts
9
+ import {
10
+ checkContractComponentRequirements
11
+ } from "@prisma-next/contract/framework-components";
12
+ function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId, frameworkComponents) {
13
+ for (let i = 0; i < frameworkComponents.length; i++) {
14
+ const component = frameworkComponents[i];
15
+ if (typeof component !== "object" || component === null) {
16
+ throw errorConfigValidation("frameworkComponents[]", {
17
+ why: `Framework component at index ${i} must be an object`
18
+ });
19
+ }
20
+ const record = component;
21
+ if (!Object.hasOwn(record, "kind")) {
22
+ throw errorConfigValidation("frameworkComponents[].kind", {
23
+ why: `Framework component at index ${i} must have 'kind' property`
24
+ });
25
+ }
26
+ const kind = record["kind"];
27
+ if (kind !== "target" && kind !== "adapter" && kind !== "extension" && kind !== "driver") {
28
+ throw errorConfigValidation("frameworkComponents[].kind", {
29
+ why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')`
30
+ });
31
+ }
32
+ if (!Object.hasOwn(record, "familyId")) {
33
+ throw errorConfigValidation("frameworkComponents[].familyId", {
34
+ why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property`
35
+ });
36
+ }
37
+ const familyId = record["familyId"];
38
+ if (familyId !== expectedFamilyId) {
39
+ throw errorConfigValidation("frameworkComponents[].familyId", {
40
+ why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'`
41
+ });
42
+ }
43
+ if (!Object.hasOwn(record, "targetId")) {
44
+ throw errorConfigValidation("frameworkComponents[].targetId", {
45
+ why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property`
46
+ });
47
+ }
48
+ const targetId = record["targetId"];
49
+ if (targetId !== expectedTargetId) {
50
+ throw errorConfigValidation("frameworkComponents[].targetId", {
51
+ why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'`
52
+ });
53
+ }
54
+ }
55
+ return frameworkComponents;
56
+ }
57
+
8
58
  // src/control-api/operations/db-init.ts
9
59
  import { notOk, ok } from "@prisma-next/utils/result";
10
60
  async function executeDbInit(options) {
@@ -286,34 +336,182 @@ var ControlClientImpl = class {
286
336
  };
287
337
  }
288
338
  async verify(options) {
339
+ const { onProgress } = options;
340
+ if (options.connection !== void 0) {
341
+ onProgress?.({
342
+ action: "verify",
343
+ kind: "spanStart",
344
+ spanId: "connect",
345
+ label: "Connecting to database..."
346
+ });
347
+ try {
348
+ await this.connect(options.connection);
349
+ onProgress?.({
350
+ action: "verify",
351
+ kind: "spanEnd",
352
+ spanId: "connect",
353
+ outcome: "ok"
354
+ });
355
+ } catch (error) {
356
+ onProgress?.({
357
+ action: "verify",
358
+ kind: "spanEnd",
359
+ spanId: "connect",
360
+ outcome: "error"
361
+ });
362
+ throw error;
363
+ }
364
+ }
289
365
  const { driver, familyInstance } = await this.ensureConnected();
290
366
  const contractIR = familyInstance.validateContractIR(options.contractIR);
291
- return familyInstance.verify({
292
- driver,
293
- contractIR,
294
- expectedTargetId: this.options.target.targetId,
295
- contractPath: ""
367
+ onProgress?.({
368
+ action: "verify",
369
+ kind: "spanStart",
370
+ spanId: "verify",
371
+ label: "Verifying contract marker..."
296
372
  });
373
+ try {
374
+ const result = await familyInstance.verify({
375
+ driver,
376
+ contractIR,
377
+ expectedTargetId: this.options.target.targetId,
378
+ contractPath: ""
379
+ });
380
+ onProgress?.({
381
+ action: "verify",
382
+ kind: "spanEnd",
383
+ spanId: "verify",
384
+ outcome: result.ok ? "ok" : "error"
385
+ });
386
+ return result;
387
+ } catch (error) {
388
+ onProgress?.({
389
+ action: "verify",
390
+ kind: "spanEnd",
391
+ spanId: "verify",
392
+ outcome: "error"
393
+ });
394
+ throw error;
395
+ }
297
396
  }
298
397
  async schemaVerify(options) {
398
+ const { onProgress } = options;
399
+ if (options.connection !== void 0) {
400
+ onProgress?.({
401
+ action: "schemaVerify",
402
+ kind: "spanStart",
403
+ spanId: "connect",
404
+ label: "Connecting to database..."
405
+ });
406
+ try {
407
+ await this.connect(options.connection);
408
+ onProgress?.({
409
+ action: "schemaVerify",
410
+ kind: "spanEnd",
411
+ spanId: "connect",
412
+ outcome: "ok"
413
+ });
414
+ } catch (error) {
415
+ onProgress?.({
416
+ action: "schemaVerify",
417
+ kind: "spanEnd",
418
+ spanId: "connect",
419
+ outcome: "error"
420
+ });
421
+ throw error;
422
+ }
423
+ }
299
424
  const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
300
425
  const contractIR = familyInstance.validateContractIR(options.contractIR);
301
- return familyInstance.schemaVerify({
302
- driver,
303
- contractIR,
304
- strict: options.strict ?? false,
305
- contractPath: "",
306
- frameworkComponents
426
+ onProgress?.({
427
+ action: "schemaVerify",
428
+ kind: "spanStart",
429
+ spanId: "schemaVerify",
430
+ label: "Verifying database schema..."
307
431
  });
432
+ try {
433
+ const result = await familyInstance.schemaVerify({
434
+ driver,
435
+ contractIR,
436
+ strict: options.strict ?? false,
437
+ contractPath: "",
438
+ frameworkComponents
439
+ });
440
+ onProgress?.({
441
+ action: "schemaVerify",
442
+ kind: "spanEnd",
443
+ spanId: "schemaVerify",
444
+ outcome: result.ok ? "ok" : "error"
445
+ });
446
+ return result;
447
+ } catch (error) {
448
+ onProgress?.({
449
+ action: "schemaVerify",
450
+ kind: "spanEnd",
451
+ spanId: "schemaVerify",
452
+ outcome: "error"
453
+ });
454
+ throw error;
455
+ }
308
456
  }
309
457
  async sign(options) {
458
+ const { onProgress } = options;
459
+ if (options.connection !== void 0) {
460
+ onProgress?.({
461
+ action: "sign",
462
+ kind: "spanStart",
463
+ spanId: "connect",
464
+ label: "Connecting to database..."
465
+ });
466
+ try {
467
+ await this.connect(options.connection);
468
+ onProgress?.({
469
+ action: "sign",
470
+ kind: "spanEnd",
471
+ spanId: "connect",
472
+ outcome: "ok"
473
+ });
474
+ } catch (error) {
475
+ onProgress?.({
476
+ action: "sign",
477
+ kind: "spanEnd",
478
+ spanId: "connect",
479
+ outcome: "error"
480
+ });
481
+ throw error;
482
+ }
483
+ }
310
484
  const { driver, familyInstance } = await this.ensureConnected();
311
485
  const contractIR = familyInstance.validateContractIR(options.contractIR);
312
- return familyInstance.sign({
313
- driver,
314
- contractIR,
315
- contractPath: ""
486
+ onProgress?.({
487
+ action: "sign",
488
+ kind: "spanStart",
489
+ spanId: "sign",
490
+ label: "Signing database..."
316
491
  });
492
+ try {
493
+ const result = await familyInstance.sign({
494
+ driver,
495
+ contractIR,
496
+ contractPath: options.contractPath ?? "",
497
+ ...options.configPath ? { configPath: options.configPath } : {}
498
+ });
499
+ onProgress?.({
500
+ action: "sign",
501
+ kind: "spanEnd",
502
+ spanId: "sign",
503
+ outcome: "ok"
504
+ });
505
+ return result;
506
+ } catch (error) {
507
+ onProgress?.({
508
+ action: "sign",
509
+ kind: "spanEnd",
510
+ spanId: "sign",
511
+ outcome: "error"
512
+ });
513
+ throw error;
514
+ }
317
515
  }
318
516
  async dbInit(options) {
319
517
  const { onProgress } = options;
@@ -358,14 +556,70 @@ var ControlClientImpl = class {
358
556
  });
359
557
  }
360
558
  async introspect(options) {
559
+ const onProgress = options?.onProgress;
560
+ if (options?.connection !== void 0) {
561
+ onProgress?.({
562
+ action: "introspect",
563
+ kind: "spanStart",
564
+ spanId: "connect",
565
+ label: "Connecting to database..."
566
+ });
567
+ try {
568
+ await this.connect(options.connection);
569
+ onProgress?.({
570
+ action: "introspect",
571
+ kind: "spanEnd",
572
+ spanId: "connect",
573
+ outcome: "ok"
574
+ });
575
+ } catch (error) {
576
+ onProgress?.({
577
+ action: "introspect",
578
+ kind: "spanEnd",
579
+ spanId: "connect",
580
+ outcome: "error"
581
+ });
582
+ throw error;
583
+ }
584
+ }
361
585
  const { driver, familyInstance } = await this.ensureConnected();
362
586
  const _schema = options?.schema;
363
587
  void _schema;
364
- return familyInstance.introspect({ driver });
588
+ onProgress?.({
589
+ action: "introspect",
590
+ kind: "spanStart",
591
+ spanId: "introspect",
592
+ label: "Introspecting database schema..."
593
+ });
594
+ try {
595
+ const result = await familyInstance.introspect({ driver });
596
+ onProgress?.({
597
+ action: "introspect",
598
+ kind: "spanEnd",
599
+ spanId: "introspect",
600
+ outcome: "ok"
601
+ });
602
+ return result;
603
+ } catch (error) {
604
+ onProgress?.({
605
+ action: "introspect",
606
+ kind: "spanEnd",
607
+ spanId: "introspect",
608
+ outcome: "error"
609
+ });
610
+ throw error;
611
+ }
612
+ }
613
+ toSchemaView(schemaIR) {
614
+ this.init();
615
+ if (this.familyInstance?.toSchemaView) {
616
+ return this.familyInstance.toSchemaView(schemaIR);
617
+ }
618
+ return void 0;
365
619
  }
366
620
  };
367
621
 
368
622
  export {
369
623
  createControlClient
370
624
  };
371
- //# sourceMappingURL=chunk-74IELXRA.js.map
625
+ //# sourceMappingURL=chunk-RPYY5SM7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/control-api/client.ts","../src/utils/framework-components.ts","../src/control-api/operations/db-init.ts"],"sourcesContent":["import type { TargetBoundComponentDescriptor } from '@prisma-next/contract/framework-components';\nimport type { CoreSchemaView } from '@prisma-next/core-control-plane/schema-view';\nimport { createControlPlaneStack } from '@prisma-next/core-control-plane/stack';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n ControlPlaneStack,\n SignDatabaseResult,\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/core-control-plane/types';\nimport { assertFrameworkComponentsCompatible } from '../utils/framework-components';\nimport { executeDbInit } from './operations/db-init';\nimport type {\n ControlClient,\n ControlClientOptions,\n DbInitOptions,\n DbInitResult,\n IntrospectOptions,\n SchemaVerifyOptions,\n SignOptions,\n VerifyOptions,\n} from './types';\n\n/**\n * Creates a programmatic control client for Prisma Next operations.\n *\n * The client accepts framework component descriptors at creation time,\n * manages driver lifecycle via connect()/close(), and exposes domain\n * operations that delegate to the existing family instance methods.\n *\n * @see {@link ControlClient} for the client interface\n * @see README.md \"Programmatic Control API\" section for usage examples\n */\nexport function createControlClient(options: ControlClientOptions): ControlClient {\n return new ControlClientImpl(options);\n}\n\n/**\n * Implementation of ControlClient.\n * Manages initialization and connection state, delegates operations to family instance.\n */\nclass ControlClientImpl implements ControlClient {\n private readonly options: ControlClientOptions;\n private stack: ControlPlaneStack<string, string> | null = null;\n private driver: ControlDriverInstance<string, string> | null = null;\n private familyInstance: ControlFamilyInstance<string> | null = null;\n private frameworkComponents: ReadonlyArray<\n TargetBoundComponentDescriptor<string, string>\n > | null = null;\n private initialized = false;\n private readonly defaultConnection: unknown;\n\n constructor(options: ControlClientOptions) {\n this.options = options;\n this.defaultConnection = options.connection;\n }\n\n init(): void {\n if (this.initialized) {\n return; // Idempotent\n }\n\n // Create the control plane stack\n this.stack = createControlPlaneStack({\n target: this.options.target,\n adapter: this.options.adapter,\n driver: this.options.driver,\n extensionPacks: this.options.extensionPacks,\n });\n\n // Create family instance using the stack\n this.familyInstance = this.options.family.create(this.stack);\n\n // Validate and type-narrow framework components\n const rawComponents = [\n this.options.target,\n this.options.adapter,\n ...(this.options.extensionPacks ?? []),\n ];\n this.frameworkComponents = assertFrameworkComponentsCompatible(\n this.options.family.familyId,\n this.options.target.targetId,\n rawComponents,\n );\n\n this.initialized = true;\n }\n\n async connect(connection?: unknown): Promise<void> {\n // Auto-init if needed\n this.init();\n\n if (this.driver) {\n throw new Error('Already connected. Call close() before reconnecting.');\n }\n\n // Resolve connection: argument > default from options\n const resolvedConnection = connection ?? this.defaultConnection;\n if (resolvedConnection === undefined) {\n throw new Error(\n 'No connection provided. Pass a connection to connect() or provide a default connection when creating the client.',\n );\n }\n\n // Check for driver descriptor\n if (!this.stack?.driver) {\n throw new Error(\n 'Driver is not configured. Pass a driver descriptor when creating the control client to enable database operations.',\n );\n }\n\n // Create driver instance\n // Cast through any since connection type is driver-specific at runtime.\n // The driver descriptor is typed with any for TConnection in ControlClientOptions,\n // but createControlPlaneStack defaults it to string. We bridge this at runtime.\n // biome-ignore lint/suspicious/noExplicitAny: required for runtime connection type flexibility\n this.driver = await this.stack?.driver.create(resolvedConnection as any);\n }\n\n async close(): Promise<void> {\n if (this.driver) {\n await this.driver.close();\n this.driver = null;\n }\n }\n\n private async ensureConnected(): Promise<{\n driver: ControlDriverInstance<string, string>;\n familyInstance: ControlFamilyInstance<string>;\n frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<string, string>>;\n }> {\n // Auto-init if needed\n this.init();\n\n // Auto-connect if not connected and default connection is available\n if (!this.driver && this.defaultConnection !== undefined) {\n await this.connect(this.defaultConnection);\n }\n\n if (!this.driver || !this.familyInstance || !this.frameworkComponents) {\n throw new Error('Not connected. Call connect(connection) first.');\n }\n return {\n driver: this.driver,\n familyInstance: this.familyInstance,\n frameworkComponents: this.frameworkComponents,\n };\n }\n\n async verify(options: VerifyOptions): Promise<VerifyDatabaseResult> {\n const { onProgress } = options;\n\n // Connect with progress span if connection provided\n if (options.connection !== undefined) {\n onProgress?.({\n action: 'verify',\n kind: 'spanStart',\n spanId: 'connect',\n label: 'Connecting to database...',\n });\n try {\n await this.connect(options.connection);\n onProgress?.({\n action: 'verify',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'ok',\n });\n } catch (error) {\n onProgress?.({\n action: 'verify',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n const { driver, familyInstance } = await this.ensureConnected();\n\n // Validate contract using family instance\n const contractIR = familyInstance.validateContractIR(options.contractIR);\n\n // Emit verify span\n onProgress?.({\n action: 'verify',\n kind: 'spanStart',\n spanId: 'verify',\n label: 'Verifying contract marker...',\n });\n\n try {\n // Delegate to family instance verify method\n // Note: We pass empty strings for contractPath/configPath since the programmatic\n // API doesn't deal with file paths. The family instance accepts these as optional\n // metadata for error reporting.\n const result = await familyInstance.verify({\n driver,\n contractIR,\n expectedTargetId: this.options.target.targetId,\n contractPath: '',\n });\n\n onProgress?.({\n action: 'verify',\n kind: 'spanEnd',\n spanId: 'verify',\n outcome: result.ok ? 'ok' : 'error',\n });\n\n return result;\n } catch (error) {\n onProgress?.({\n action: 'verify',\n kind: 'spanEnd',\n spanId: 'verify',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n async schemaVerify(options: SchemaVerifyOptions): Promise<VerifyDatabaseSchemaResult> {\n const { onProgress } = options;\n\n // Connect with progress span if connection provided\n if (options.connection !== undefined) {\n onProgress?.({\n action: 'schemaVerify',\n kind: 'spanStart',\n spanId: 'connect',\n label: 'Connecting to database...',\n });\n try {\n await this.connect(options.connection);\n onProgress?.({\n action: 'schemaVerify',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'ok',\n });\n } catch (error) {\n onProgress?.({\n action: 'schemaVerify',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();\n\n // Validate contract using family instance\n const contractIR = familyInstance.validateContractIR(options.contractIR);\n\n // Emit schemaVerify span\n onProgress?.({\n action: 'schemaVerify',\n kind: 'spanStart',\n spanId: 'schemaVerify',\n label: 'Verifying database schema...',\n });\n\n try {\n // Delegate to family instance schemaVerify method\n const result = await familyInstance.schemaVerify({\n driver,\n contractIR,\n strict: options.strict ?? false,\n contractPath: '',\n frameworkComponents,\n });\n\n onProgress?.({\n action: 'schemaVerify',\n kind: 'spanEnd',\n spanId: 'schemaVerify',\n outcome: result.ok ? 'ok' : 'error',\n });\n\n return result;\n } catch (error) {\n onProgress?.({\n action: 'schemaVerify',\n kind: 'spanEnd',\n spanId: 'schemaVerify',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n async sign(options: SignOptions): Promise<SignDatabaseResult> {\n const { onProgress } = options;\n\n // Connect with progress span if connection provided\n if (options.connection !== undefined) {\n onProgress?.({\n action: 'sign',\n kind: 'spanStart',\n spanId: 'connect',\n label: 'Connecting to database...',\n });\n try {\n await this.connect(options.connection);\n onProgress?.({\n action: 'sign',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'ok',\n });\n } catch (error) {\n onProgress?.({\n action: 'sign',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n const { driver, familyInstance } = await this.ensureConnected();\n\n // Validate contract using family instance\n const contractIR = familyInstance.validateContractIR(options.contractIR);\n\n // Emit sign span\n onProgress?.({\n action: 'sign',\n kind: 'spanStart',\n spanId: 'sign',\n label: 'Signing database...',\n });\n\n try {\n // Delegate to family instance sign method\n const result = await familyInstance.sign({\n driver,\n contractIR,\n contractPath: options.contractPath ?? '',\n ...(options.configPath ? { configPath: options.configPath } : {}),\n });\n\n onProgress?.({\n action: 'sign',\n kind: 'spanEnd',\n spanId: 'sign',\n outcome: 'ok',\n });\n\n return result;\n } catch (error) {\n onProgress?.({\n action: 'sign',\n kind: 'spanEnd',\n spanId: 'sign',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n async dbInit(options: DbInitOptions): Promise<DbInitResult> {\n const { onProgress } = options;\n\n // Connect with progress span if connection provided\n if (options.connection !== undefined) {\n onProgress?.({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: 'connect',\n label: 'Connecting to database...',\n });\n try {\n await this.connect(options.connection);\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'ok',\n });\n } catch (error) {\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();\n\n // Check target supports migrations\n if (!this.options.target.migrations) {\n throw new Error(`Target \"${this.options.target.targetId}\" does not support migrations`);\n }\n\n // Validate contract using family instance\n const contractIR = familyInstance.validateContractIR(options.contractIR);\n\n // Delegate to extracted dbInit operation\n return executeDbInit({\n driver,\n familyInstance,\n contractIR,\n mode: options.mode,\n migrations: this.options.target.migrations,\n frameworkComponents,\n ...(onProgress ? { onProgress } : {}),\n });\n }\n\n async introspect(options?: IntrospectOptions): Promise<unknown> {\n const onProgress = options?.onProgress;\n\n // Connect with progress span if connection provided\n if (options?.connection !== undefined) {\n onProgress?.({\n action: 'introspect',\n kind: 'spanStart',\n spanId: 'connect',\n label: 'Connecting to database...',\n });\n try {\n await this.connect(options.connection);\n onProgress?.({\n action: 'introspect',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'ok',\n });\n } catch (error) {\n onProgress?.({\n action: 'introspect',\n kind: 'spanEnd',\n spanId: 'connect',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n const { driver, familyInstance } = await this.ensureConnected();\n\n // TODO: Pass schema option to familyInstance.introspect when schema filtering is implemented\n const _schema = options?.schema;\n void _schema;\n\n // Emit introspect span\n onProgress?.({\n action: 'introspect',\n kind: 'spanStart',\n spanId: 'introspect',\n label: 'Introspecting database schema...',\n });\n\n try {\n const result = await familyInstance.introspect({ driver });\n\n onProgress?.({\n action: 'introspect',\n kind: 'spanEnd',\n spanId: 'introspect',\n outcome: 'ok',\n });\n\n return result;\n } catch (error) {\n onProgress?.({\n action: 'introspect',\n kind: 'spanEnd',\n spanId: 'introspect',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n toSchemaView(schemaIR: unknown): CoreSchemaView | undefined {\n this.init();\n if (this.familyInstance?.toSchemaView) {\n return this.familyInstance.toSchemaView(schemaIR);\n }\n return undefined;\n }\n}\n","import {\n checkContractComponentRequirements,\n type TargetBoundComponentDescriptor,\n} from '@prisma-next/contract/framework-components';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport type { ControlPlaneStack } from '@prisma-next/core-control-plane/types';\nimport { errorConfigValidation, errorContractMissingExtensionPacks } from './cli-errors';\n\n/**\n * Asserts that all framework components are compatible with the expected family and target.\n *\n * This function validates that each component in the framework components array:\n * - Has kind 'target', 'adapter', 'extension', or 'driver'\n * - Has familyId matching expectedFamilyId\n * - Has targetId matching expectedTargetId\n *\n * This validation happens at the CLI composition boundary, before passing components\n * to typed planner/runner instances. It fills the gap between runtime validation\n * (via `validateConfig()`) and compile-time type enforcement.\n *\n * @param expectedFamilyId - The expected family ID (e.g., 'sql')\n * @param expectedTargetId - The expected target ID (e.g., 'postgres')\n * @param frameworkComponents - Array of framework components to validate\n * @returns The same array typed as TargetBoundComponentDescriptor\n * @throws CliStructuredError if any component is incompatible\n *\n * @example\n * ```ts\n * const config = await loadConfig();\n * const frameworkComponents = [config.target, config.adapter, ...(config.extensionPacks ?? [])];\n *\n * // Validate and type-narrow components before passing to planner\n * const typedComponents = assertFrameworkComponentsCompatible(\n * config.family.familyId,\n * config.target.targetId,\n * frameworkComponents\n * );\n *\n * const planner = target.migrations.createPlanner(familyInstance);\n * planner.plan({ contract, schema, policy, frameworkComponents: typedComponents });\n * ```\n */\nexport function assertFrameworkComponentsCompatible<\n TFamilyId extends string,\n TTargetId extends string,\n>(\n expectedFamilyId: TFamilyId,\n expectedTargetId: TTargetId,\n frameworkComponents: ReadonlyArray<unknown>,\n): ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>> {\n for (let i = 0; i < frameworkComponents.length; i++) {\n const component = frameworkComponents[i];\n\n // Check that component is an object\n if (typeof component !== 'object' || component === null) {\n throw errorConfigValidation('frameworkComponents[]', {\n why: `Framework component at index ${i} must be an object`,\n });\n }\n\n const record = component as Record<string, unknown>;\n\n // Check kind\n if (!Object.hasOwn(record, 'kind')) {\n throw errorConfigValidation('frameworkComponents[].kind', {\n why: `Framework component at index ${i} must have 'kind' property`,\n });\n }\n\n const kind = record['kind'];\n if (kind !== 'target' && kind !== 'adapter' && kind !== 'extension' && kind !== 'driver') {\n throw errorConfigValidation('frameworkComponents[].kind', {\n why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')`,\n });\n }\n\n // Check familyId\n if (!Object.hasOwn(record, 'familyId')) {\n throw errorConfigValidation('frameworkComponents[].familyId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property`,\n });\n }\n\n const familyId = record['familyId'];\n if (familyId !== expectedFamilyId) {\n throw errorConfigValidation('frameworkComponents[].familyId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'`,\n });\n }\n\n // Check targetId\n if (!Object.hasOwn(record, 'targetId')) {\n throw errorConfigValidation('frameworkComponents[].targetId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property`,\n });\n }\n\n const targetId = record['targetId'];\n if (targetId !== expectedTargetId) {\n throw errorConfigValidation('frameworkComponents[].targetId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'`,\n });\n }\n }\n\n // Type assertion is safe because we've validated all components above\n return frameworkComponents as ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n}\n\n/**\n * Validates that a contract is compatible with the configured target, adapter,\n * and extension packs. Throws on family/target mismatches or missing extension packs.\n *\n * This check ensures the emitted contract matches the CLI config before running\n * commands that depend on the contract (e.g., db verify, db sign).\n *\n * @param contract - The contract IR to validate (must include targetFamily, target, extensionPacks).\n * @param stack - The control plane stack (target, adapter, driver, extensionPacks).\n *\n * @throws {CliStructuredError} errorConfigValidation when contract.targetFamily or contract.target\n * doesn't match the configured family/target.\n * @throws {CliStructuredError} errorContractMissingExtensionPacks when the contract requires\n * extension packs that are not provided in the config (includes all missing packs in error.meta).\n *\n * @example\n * ```ts\n * import { assertContractRequirementsSatisfied } from './framework-components';\n *\n * const config = await loadConfig();\n * const contractIR = await loadContractJson(config.contract.output);\n * const stack = createControlPlaneStack({ target: config.target, adapter: config.adapter, ... });\n *\n * // Throws if contract is incompatible with config\n * assertContractRequirementsSatisfied({ contract: contractIR, stack });\n * ```\n */\nexport function assertContractRequirementsSatisfied<\n TFamilyId extends string,\n TTargetId extends string,\n>({\n contract,\n stack,\n}: {\n readonly contract: Pick<ContractIR, 'targetFamily' | 'target' | 'extensionPacks'>;\n readonly stack: ControlPlaneStack<TFamilyId, TTargetId>;\n}): void {\n const providedComponentIds = new Set<string>([stack.target.id, stack.adapter.id]);\n for (const extension of stack.extensionPacks) {\n providedComponentIds.add(extension.id);\n }\n\n const result = checkContractComponentRequirements({\n contract,\n expectedTargetFamily: stack.target.familyId,\n expectedTargetId: stack.target.targetId,\n providedComponentIds,\n });\n\n if (result.familyMismatch) {\n throw errorConfigValidation('contract.targetFamily', {\n why: `Contract was emitted for family '${result.familyMismatch.actual}' but CLI config is wired to '${result.familyMismatch.expected}'.`,\n });\n }\n\n if (result.targetMismatch) {\n throw errorConfigValidation('contract.target', {\n why: `Contract target '${result.targetMismatch.actual}' does not match CLI target '${result.targetMismatch.expected}'.`,\n });\n }\n\n if (result.missingExtensionPackIds.length > 0) {\n throw errorContractMissingExtensionPacks({\n missingExtensionPacks: result.missingExtensionPackIds,\n providedComponentIds: [...providedComponentIds],\n });\n }\n}\n","import type { TargetBoundComponentDescriptor } from '@prisma-next/contract/framework-components';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n MigrationPlan,\n MigrationPlannerResult,\n MigrationPlanOperation,\n MigrationRunnerResult,\n TargetMigrationsCapability,\n} from '@prisma-next/core-control-plane/types';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport type { DbInitResult, DbInitSuccess, OnControlProgress } from '../types';\n\n/**\n * Options for executing dbInit operation.\n */\nexport interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extends string> {\n readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;\n readonly familyInstance: ControlFamilyInstance<TFamilyId>;\n readonly contractIR: ContractIR;\n readonly mode: 'plan' | 'apply';\n readonly migrations: TargetMigrationsCapability<\n TFamilyId,\n TTargetId,\n ControlFamilyInstance<TFamilyId>\n >;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n /** Optional progress callback for observing operation progress */\n readonly onProgress?: OnControlProgress;\n}\n\n/**\n * Executes the dbInit operation.\n *\n * This is the core logic extracted from the CLI command, without any file I/O,\n * process.exit(), or console output. It uses the Result pattern to return\n * success or failure details.\n *\n * @param options - The options for executing dbInit\n * @returns Result with DbInitSuccess on success, DbInitFailure on failure\n */\nexport async function executeDbInit<TFamilyId extends string, TTargetId extends string>(\n options: ExecuteDbInitOptions<TFamilyId, TTargetId>,\n): Promise<DbInitResult> {\n const { driver, familyInstance, contractIR, mode, migrations, frameworkComponents, onProgress } =\n options;\n\n // Create planner and runner from target migrations capability\n const planner = migrations.createPlanner(familyInstance);\n const runner = migrations.createRunner(familyInstance);\n\n // Introspect live schema\n const introspectSpanId = 'introspect';\n onProgress?.({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: introspectSpanId,\n label: 'Introspecting database schema',\n });\n const schemaIR = await familyInstance.introspect({ driver });\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: introspectSpanId,\n outcome: 'ok',\n });\n\n // Policy for init mode (additive only)\n const policy = { allowedOperationClasses: ['additive'] as const };\n\n // Plan migration\n const planSpanId = 'plan';\n onProgress?.({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: planSpanId,\n label: 'Planning migration',\n });\n const plannerResult: MigrationPlannerResult = await planner.plan({\n contract: contractIR,\n schema: schemaIR,\n policy,\n frameworkComponents,\n });\n\n if (plannerResult.kind === 'failure') {\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: planSpanId,\n outcome: 'error',\n });\n return notOk({\n code: 'PLANNING_FAILED' as const,\n summary: 'Migration planning failed due to conflicts',\n conflicts: plannerResult.conflicts,\n why: undefined,\n meta: undefined,\n });\n }\n\n const migrationPlan: MigrationPlan = plannerResult.plan;\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: planSpanId,\n outcome: 'ok',\n });\n\n // Check for existing marker - handle idempotency and mismatch errors\n const checkMarkerSpanId = 'checkMarker';\n onProgress?.({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: checkMarkerSpanId,\n label: 'Checking contract marker',\n });\n const existingMarker = await familyInstance.readMarker({ driver });\n if (existingMarker) {\n const markerMatchesDestination =\n existingMarker.coreHash === migrationPlan.destination.coreHash &&\n (!migrationPlan.destination.profileHash ||\n existingMarker.profileHash === migrationPlan.destination.profileHash);\n\n if (markerMatchesDestination) {\n // Already at destination - return success with no operations\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: checkMarkerSpanId,\n outcome: 'skipped',\n });\n const result: DbInitSuccess = {\n mode,\n plan: { operations: [] },\n ...(mode === 'apply'\n ? {\n execution: { operationsPlanned: 0, operationsExecuted: 0 },\n marker: {\n coreHash: existingMarker.coreHash,\n profileHash: existingMarker.profileHash,\n },\n }\n : {}),\n summary: 'Database already at target contract state',\n };\n return ok(result);\n }\n\n // Marker exists but doesn't match destination - fail\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: checkMarkerSpanId,\n outcome: 'error',\n });\n return notOk({\n code: 'MARKER_ORIGIN_MISMATCH' as const,\n summary: 'Existing contract marker does not match plan destination',\n marker: {\n coreHash: existingMarker.coreHash,\n profileHash: existingMarker.profileHash,\n },\n destination: {\n coreHash: migrationPlan.destination.coreHash,\n profileHash: migrationPlan.destination.profileHash,\n },\n why: undefined,\n conflicts: undefined,\n meta: undefined,\n });\n }\n\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: checkMarkerSpanId,\n outcome: 'ok',\n });\n\n // Plan mode - don't execute\n if (mode === 'plan') {\n const result: DbInitSuccess = {\n mode: 'plan',\n plan: { operations: migrationPlan.operations },\n summary: `Planned ${migrationPlan.operations.length} operation(s)`,\n };\n return ok(result);\n }\n\n // Apply mode - execute runner\n const applySpanId = 'apply';\n onProgress?.({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: applySpanId,\n label: 'Applying migration plan',\n });\n\n const callbacks = onProgress\n ? {\n onOperationStart: (op: MigrationPlanOperation) => {\n onProgress({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: `operation:${op.id}`,\n parentSpanId: applySpanId,\n label: op.label,\n });\n },\n onOperationComplete: (op: MigrationPlanOperation) => {\n onProgress({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: `operation:${op.id}`,\n outcome: 'ok',\n });\n },\n }\n : undefined;\n\n const runnerResult: MigrationRunnerResult = await runner.execute({\n plan: migrationPlan,\n driver,\n destinationContract: contractIR,\n policy,\n ...(callbacks ? { callbacks } : {}),\n // db init plans and applies back-to-back from a fresh introspection, so per-operation\n // pre/postchecks and the idempotency probe are usually redundant overhead. We still\n // enforce marker/origin compatibility and a full schema verification after apply.\n executionChecks: {\n prechecks: false,\n postchecks: false,\n idempotencyChecks: false,\n },\n frameworkComponents,\n });\n\n if (!runnerResult.ok) {\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: applySpanId,\n outcome: 'error',\n });\n return notOk({\n code: 'RUNNER_FAILED' as const,\n summary: runnerResult.failure.summary,\n why: runnerResult.failure.why,\n meta: runnerResult.failure.meta,\n conflicts: undefined,\n });\n }\n\n const execution = runnerResult.value;\n\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: applySpanId,\n outcome: 'ok',\n });\n\n const result: DbInitSuccess = {\n mode: 'apply',\n plan: { operations: migrationPlan.operations },\n execution: {\n operationsPlanned: execution.operationsPlanned,\n operationsExecuted: execution.operationsExecuted,\n },\n marker: migrationPlan.destination.profileHash\n ? {\n coreHash: migrationPlan.destination.coreHash,\n profileHash: migrationPlan.destination.profileHash,\n }\n : { coreHash: migrationPlan.destination.coreHash },\n summary: `Applied ${execution.operationsExecuted} operation(s), marker written`,\n };\n return ok(result);\n}\n"],"mappings":"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","names":["result"]}