@prisma-next/cli 0.3.0-pr.77.3 → 0.3.0-pr.78.1
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.
- package/dist/{chunk-QUPBU4KV.js → chunk-464LNZCE.js} +8 -5
- package/dist/chunk-464LNZCE.js.map +1 -0
- package/dist/{chunk-CVNWLFXO.js → chunk-ZKYEJROM.js} +9 -6
- package/dist/chunk-ZKYEJROM.js.map +1 -0
- package/dist/cli.js +60 -34
- package/dist/cli.js.map +1 -1
- package/dist/commands/contract-emit.d.ts.map +1 -1
- package/dist/commands/contract-emit.js +1 -1
- package/dist/commands/db-init.d.ts.map +1 -1
- package/dist/commands/db-init.js +10 -6
- package/dist/commands/db-init.js.map +1 -1
- package/dist/commands/db-introspect.d.ts.map +1 -1
- package/dist/commands/db-introspect.js +10 -6
- package/dist/commands/db-introspect.js.map +1 -1
- package/dist/commands/db-schema-verify.d.ts.map +1 -1
- package/dist/commands/db-schema-verify.js +10 -6
- package/dist/commands/db-schema-verify.js.map +1 -1
- package/dist/commands/db-sign.d.ts.map +1 -1
- package/dist/commands/db-sign.js +10 -6
- package/dist/commands/db-sign.js.map +1 -1
- package/dist/commands/db-verify.d.ts.map +1 -1
- package/dist/commands/db-verify.js +10 -6
- package/dist/commands/db-verify.js.map +1 -1
- package/dist/exports/index.js +1 -1
- package/dist/utils/framework-components.d.ts +18 -7
- package/dist/utils/framework-components.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/commands/contract-emit.ts +11 -4
- package/src/commands/db-init.ts +9 -5
- package/src/commands/db-introspect.ts +9 -5
- package/src/commands/db-schema-verify.ts +9 -5
- package/src/commands/db-sign.ts +9 -5
- package/src/commands/db-verify.ts +9 -5
- package/src/utils/framework-components.ts +30 -11
- package/dist/chunk-CVNWLFXO.js.map +0 -1
- package/dist/chunk-QUPBU4KV.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/db-verify.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport {\n errorDatabaseUrlRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorHashMismatch,\n errorMarkerMissing,\n errorRuntime,\n errorTargetMismatch,\n errorUnexpected,\n} from '@prisma-next/core-control-plane/errors';\nimport type { VerifyDatabaseResult } from '@prisma-next/core-control-plane/types';\nimport { createControlPlaneStack } from '@prisma-next/core-control-plane/types';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { performAction } from '../utils/action';\nimport { setCommandDescriptions } from '../utils/command-helpers';\nimport { assertContractRequirementsSatisfied } from '../utils/framework-components';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport {\n formatCommandHelp,\n formatStyledHeader,\n formatVerifyJson,\n formatVerifyOutput,\n} from '../utils/output';\nimport { handleResult } from '../utils/result-handler';\nimport { withSpinner } from '../utils/spinner';\n\ninterface DbVerifyOptions {\n readonly db?: string;\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 createDbVerifyCommand(): Command {\n const command = new Command('verify');\n setCommandDescriptions(\n command,\n 'Check whether the database has been signed with your contract',\n 'Verifies that your database schema matches the emitted contract. Checks table structures,\\n' +\n 'column types, constraints, and codec coverage. Reports any mismatches or missing codecs.',\n );\n command\n .configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n })\n .option('--db <url>', 'Database connection string')\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: DbVerifyOptions) => {\n const flags = parseGlobalFlags(options);\n\n const result = await performAction(async () => {\n // Load config (file I/O)\n const config = await loadConfig(options.config);\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 const contractPathAbsolute = config.contract?.output\n ? resolve(config.contract.output)\n : resolve('src/prisma/contract.json');\n // Convert to relative path for display\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n // Output header (only for human-readable output)\n if (flags.json !== 'object' && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n ];\n if (options.db) {\n details.push({ label: 'database', value: options.db });\n }\n const header = formatStyledHeader({\n command: 'db verify',\n description: 'Check whether the database has been signed with your contract',\n url: 'https://pris.ly/db-verify',\n details,\n flags,\n });\n console.log(header);\n }\n\n // Load contract file (file I/O)\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n throw errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n });\n }\n throw errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n const contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;\n\n // Resolve database URL\n const dbUrl = options.db ?? config.db?.url;\n if (!dbUrl) {\n throw errorDatabaseUrlRequired();\n }\n\n // Check for driver\n if (!config.driver) {\n throw errorDriverRequired();\n }\n\n // Store driver descriptor after null check\n const driverDescriptor = config.driver;\n\n // Create driver\n const driver = await withSpinner(() => driverDescriptor.create(dbUrl), {\n message: 'Connecting to database...',\n flags,\n });\n\n try {\n // Create family instance\n const stack = createControlPlaneStack({\n target: config.target,\n adapter: config.adapter,\n driver: driverDescriptor,\n extensionPacks: config.extensionPacks,\n });\n const familyInstance = config.family.create(stack);\n\n // Validate contract using instance validator\n const contractIR = familyInstance.validateContractIR(contractJson) as ContractIR;\n assertContractRequirementsSatisfied({ contract: contractIR, stack });\n\n // Call family instance verify method\n let verifyResult: VerifyDatabaseResult;\n try {\n verifyResult = await withSpinner(\n () =>\n familyInstance.verify({\n driver,\n contractIR,\n expectedTargetId: config.target.targetId,\n contractPath: contractPathAbsolute,\n configPath,\n }),\n {\n message: 'Verifying database schema...',\n flags,\n },\n );\n } catch (error) {\n // Wrap errors from verify() in structured error\n throw errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to verify database: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n\n // If verification failed, throw structured error\n if (!verifyResult.ok && verifyResult.code) {\n if (verifyResult.code === 'PN-RTM-3001') {\n throw errorMarkerMissing();\n }\n if (verifyResult.code === 'PN-RTM-3002') {\n throw errorHashMismatch({\n expected: verifyResult.contract.coreHash,\n ...(verifyResult.marker?.coreHash ? { actual: verifyResult.marker.coreHash } : {}),\n });\n }\n if (verifyResult.code === 'PN-RTM-3003') {\n throw errorTargetMismatch(\n verifyResult.target.expected,\n verifyResult.target.actual ?? 'unknown',\n );\n }\n throw errorRuntime(verifyResult.summary);\n }\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 verifyResult;\n } finally {\n // Ensure driver connection is closed\n await driver.close();\n }\n });\n\n // Handle result - formats output and returns exit code\n const exitCode = handleResult(result, flags, (verifyResult) => {\n // Output based on flags\n if (flags.json === 'object') {\n // JSON output to stdout\n console.log(formatVerifyJson(verifyResult));\n } else {\n // Human-readable output to stdout\n const output = formatVerifyOutput(verifyResult, flags);\n if (output) {\n console.log(output);\n }\n }\n });\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/commands/db-verify.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport {\n errorDatabaseUrlRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorHashMismatch,\n errorMarkerMissing,\n errorRuntime,\n errorTargetMismatch,\n errorUnexpected,\n} from '@prisma-next/core-control-plane/errors';\nimport type { VerifyDatabaseResult } from '@prisma-next/core-control-plane/types';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { performAction } from '../utils/action';\nimport { setCommandDescriptions } from '../utils/command-helpers';\nimport { assertContractRequirementsSatisfied } from '../utils/framework-components';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport {\n formatCommandHelp,\n formatStyledHeader,\n formatVerifyJson,\n formatVerifyOutput,\n} from '../utils/output';\nimport { handleResult } from '../utils/result-handler';\nimport { withSpinner } from '../utils/spinner';\n\ninterface DbVerifyOptions {\n readonly db?: string;\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 createDbVerifyCommand(): Command {\n const command = new Command('verify');\n setCommandDescriptions(\n command,\n 'Check whether the database has been signed with your contract',\n 'Verifies that your database schema matches the emitted contract. Checks table structures,\\n' +\n 'column types, constraints, and codec coverage. Reports any mismatches or missing codecs.',\n );\n command\n .configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n })\n .option('--db <url>', 'Database connection string')\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: DbVerifyOptions) => {\n const flags = parseGlobalFlags(options);\n\n const result = await performAction(async () => {\n // Load config (file I/O)\n const config = await loadConfig(options.config);\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 const contractPathAbsolute = config.contract?.output\n ? resolve(config.contract.output)\n : resolve('src/prisma/contract.json');\n // Convert to relative path for display\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n // Output header (only for human-readable output)\n if (flags.json !== 'object' && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n ];\n if (options.db) {\n details.push({ label: 'database', value: options.db });\n }\n const header = formatStyledHeader({\n command: 'db verify',\n description: 'Check whether the database has been signed with your contract',\n url: 'https://pris.ly/db-verify',\n details,\n flags,\n });\n console.log(header);\n }\n\n // Load contract file (file I/O)\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n throw errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n });\n }\n throw errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n const contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;\n\n // Resolve database URL\n const dbUrl = options.db ?? config.db?.url;\n if (!dbUrl) {\n throw errorDatabaseUrlRequired();\n }\n\n // Check for driver\n if (!config.driver) {\n throw errorDriverRequired();\n }\n\n // Store driver descriptor after null check\n const driverDescriptor = config.driver;\n\n // Create driver\n const driver = await withSpinner(() => driverDescriptor.create(dbUrl), {\n message: 'Connecting to database...',\n flags,\n });\n\n try {\n // Create family instance\n const familyInstance = config.family.create({\n target: config.target,\n adapter: config.adapter,\n driver: driverDescriptor,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Validate contract using instance validator\n const contractIR = familyInstance.validateContractIR(contractJson) as ContractIR;\n assertContractRequirementsSatisfied({\n contract: contractIR,\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n extensionPacks: config.extensionPacks,\n });\n\n // Call family instance verify method\n let verifyResult: VerifyDatabaseResult;\n try {\n verifyResult = await withSpinner(\n () =>\n familyInstance.verify({\n driver,\n contractIR,\n expectedTargetId: config.target.targetId,\n contractPath: contractPathAbsolute,\n configPath,\n }),\n {\n message: 'Verifying database schema...',\n flags,\n },\n );\n } catch (error) {\n // Wrap errors from verify() in structured error\n throw errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to verify database: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n\n // If verification failed, throw structured error\n if (!verifyResult.ok && verifyResult.code) {\n if (verifyResult.code === 'PN-RTM-3001') {\n throw errorMarkerMissing();\n }\n if (verifyResult.code === 'PN-RTM-3002') {\n throw errorHashMismatch({\n expected: verifyResult.contract.coreHash,\n ...(verifyResult.marker?.coreHash ? { actual: verifyResult.marker.coreHash } : {}),\n });\n }\n if (verifyResult.code === 'PN-RTM-3003') {\n throw errorTargetMismatch(\n verifyResult.target.expected,\n verifyResult.target.actual ?? 'unknown',\n );\n }\n throw errorRuntime(verifyResult.summary);\n }\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 verifyResult;\n } finally {\n // Ensure driver connection is closed\n await driver.close();\n }\n });\n\n // Handle result - formats output and returns exit code\n const exitCode = handleResult(result, flags, (verifyResult) => {\n // Output based on flags\n if (flags.json === 'object') {\n // JSON output to stdout\n console.log(formatVerifyJson(verifyResult));\n } else {\n // Human-readable output to stdout\n const output = formatVerifyOutput(verifyResult, flags);\n if (output) {\n console.log(output);\n }\n }\n });\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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","names":[]}
|
package/dist/exports/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type TargetBoundComponentDescriptor } from '@prisma-next/contract/framework-components';
|
|
2
2
|
import type { ContractIR } from '@prisma-next/contract/ir';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ControlAdapterDescriptor, ControlExtensionDescriptor, ControlFamilyDescriptor, ControlTargetDescriptor } from '@prisma-next/core-control-plane/types';
|
|
4
4
|
/**
|
|
5
5
|
* Asserts that all framework components are compatible with the expected family and target.
|
|
6
6
|
*
|
|
@@ -37,14 +37,17 @@ import type { ControlPlaneStack } from '@prisma-next/core-control-plane/types';
|
|
|
37
37
|
*/
|
|
38
38
|
export declare function assertFrameworkComponentsCompatible<TFamilyId extends string, TTargetId extends string>(expectedFamilyId: TFamilyId, expectedTargetId: TTargetId, frameworkComponents: ReadonlyArray<unknown>): ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
39
39
|
/**
|
|
40
|
-
* Validates that a contract is compatible with the configured target, adapter,
|
|
40
|
+
* Validates that a contract is compatible with the configured family, target, adapter,
|
|
41
41
|
* and extension packs. Throws on family/target mismatches or missing extension packs.
|
|
42
42
|
*
|
|
43
43
|
* This check ensures the emitted contract matches the CLI config before running
|
|
44
44
|
* commands that depend on the contract (e.g., db verify, db sign).
|
|
45
45
|
*
|
|
46
46
|
* @param contract - The contract IR to validate (must include targetFamily, target, extensionPacks).
|
|
47
|
-
* @param
|
|
47
|
+
* @param family - The configured family descriptor.
|
|
48
|
+
* @param target - The configured target descriptor.
|
|
49
|
+
* @param adapter - The configured adapter descriptor.
|
|
50
|
+
* @param extensionPacks - Optional array of extension descriptors provided by the config.
|
|
48
51
|
*
|
|
49
52
|
* @throws {CliStructuredError} errorConfigValidation when contract.targetFamily or contract.target
|
|
50
53
|
* doesn't match the configured family/target.
|
|
@@ -57,14 +60,22 @@ export declare function assertFrameworkComponentsCompatible<TFamilyId extends st
|
|
|
57
60
|
*
|
|
58
61
|
* const config = await loadConfig();
|
|
59
62
|
* const contractIR = await loadContractJson(config.contract.output);
|
|
60
|
-
* const stack = createControlPlaneStack({ target: config.target, adapter: config.adapter, ... });
|
|
61
63
|
*
|
|
62
64
|
* // Throws if contract is incompatible with config
|
|
63
|
-
* assertContractRequirementsSatisfied({
|
|
65
|
+
* assertContractRequirementsSatisfied({
|
|
66
|
+
* contract: contractIR,
|
|
67
|
+
* family: config.family,
|
|
68
|
+
* target: config.target,
|
|
69
|
+
* adapter: config.adapter,
|
|
70
|
+
* extensionPacks: config.extensionPacks,
|
|
71
|
+
* });
|
|
64
72
|
* ```
|
|
65
73
|
*/
|
|
66
|
-
export declare function assertContractRequirementsSatisfied<TFamilyId extends string, TTargetId extends string>({ contract,
|
|
74
|
+
export declare function assertContractRequirementsSatisfied<TFamilyId extends string, TTargetId extends string>({ contract, family, target, adapter, extensionPacks, }: {
|
|
67
75
|
readonly contract: Pick<ContractIR, 'targetFamily' | 'target' | 'extensionPacks'>;
|
|
68
|
-
readonly
|
|
76
|
+
readonly family: ControlFamilyDescriptor<TFamilyId>;
|
|
77
|
+
readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;
|
|
78
|
+
readonly adapter: ControlAdapterDescriptor<TFamilyId, TTargetId>;
|
|
79
|
+
readonly extensionPacks?: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[] | undefined;
|
|
69
80
|
}): void;
|
|
70
81
|
//# sourceMappingURL=framework-components.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-components.d.ts","sourceRoot":"","sources":["../../src/utils/framework-components.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,8BAA8B,EACpC,MAAM,4CAA4C,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"framework-components.d.ts","sourceRoot":"","sources":["../../src/utils/framework-components.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,8BAA8B,EACpC,MAAM,4CAA4C,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,uCAAuC,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,mCAAmC,CACjD,SAAS,SAAS,MAAM,EACxB,SAAS,SAAS,MAAM,EAExB,gBAAgB,EAAE,SAAS,EAC3B,gBAAgB,EAAE,SAAS,EAC3B,mBAAmB,EAAE,aAAa,CAAC,OAAO,CAAC,GAC1C,aAAa,CAAC,8BAA8B,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CA0DrE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,mCAAmC,CACjD,SAAS,SAAS,MAAM,EACxB,SAAS,SAAS,MAAM,EACxB,EACA,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,cAAc,GACf,EAAE;IACD,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,GAAG,QAAQ,GAAG,gBAAgB,CAAC,CAAC;IAClF,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC,SAAS,CAAC,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/D,QAAQ,CAAC,OAAO,EAAE,wBAAwB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACjE,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,0BAA0B,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,GAAG,SAAS,CAAC;CACnG,GAAG,IAAI,CA+BP"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/cli",
|
|
3
|
-
"version": "0.3.0-pr.
|
|
3
|
+
"version": "0.3.0-pr.78.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"files": [
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"string-width": "^7.2.0",
|
|
21
21
|
"strip-ansi": "^7.1.2",
|
|
22
22
|
"wrap-ansi": "^9.0.2",
|
|
23
|
-
"@prisma-next/contract": "0.3.0-pr.
|
|
24
|
-
"@prisma-next/
|
|
25
|
-
"@prisma-next/
|
|
26
|
-
"@prisma-next/utils": "0.3.0-pr.
|
|
23
|
+
"@prisma-next/contract": "0.3.0-pr.78.1",
|
|
24
|
+
"@prisma-next/core-control-plane": "0.3.0-pr.78.1",
|
|
25
|
+
"@prisma-next/emitter": "0.3.0-pr.78.1",
|
|
26
|
+
"@prisma-next/utils": "0.3.0-pr.78.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "24.10.4",
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"tsup": "8.5.1",
|
|
32
32
|
"typescript": "5.9.3",
|
|
33
33
|
"vitest": "4.0.16",
|
|
34
|
-
"@prisma-next/sql-contract
|
|
35
|
-
"@prisma-next/sql-contract-
|
|
36
|
-
"@prisma-next/sql-
|
|
37
|
-
"@prisma-next/sql-
|
|
38
|
-
"@prisma-next/sql-
|
|
34
|
+
"@prisma-next/sql-contract": "0.3.0-pr.78.1",
|
|
35
|
+
"@prisma-next/sql-contract-emitter": "0.3.0-pr.78.1",
|
|
36
|
+
"@prisma-next/sql-contract-ts": "0.3.0-pr.78.1",
|
|
37
|
+
"@prisma-next/sql-operations": "0.3.0-pr.78.1",
|
|
38
|
+
"@prisma-next/sql-runtime": "0.3.0-pr.78.1",
|
|
39
39
|
"@prisma-next/test-utils": "0.0.1"
|
|
40
40
|
},
|
|
41
41
|
"exports": {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, relative, resolve } from 'node:path';
|
|
3
3
|
import { errorContractConfigMissing } from '@prisma-next/core-control-plane/errors';
|
|
4
|
-
import { createControlPlaneStack } from '@prisma-next/core-control-plane/types';
|
|
5
4
|
import { Command } from 'commander';
|
|
6
5
|
import { loadConfig } from '../config-loader';
|
|
7
6
|
import { performAction } from '../utils/action';
|
|
@@ -104,13 +103,21 @@ export function createContractEmitCommand(): Command {
|
|
|
104
103
|
console.log(header);
|
|
105
104
|
}
|
|
106
105
|
|
|
107
|
-
|
|
106
|
+
// Create family instance (assembles operation registry, type imports, extension IDs)
|
|
107
|
+
// Note: emit command doesn't need driver, but ControlFamilyDescriptor.create() requires it
|
|
108
|
+
// We'll need to provide a minimal driver descriptor or make driver optional for emit
|
|
109
|
+
// For now, we'll require driver to be present in config even for emit
|
|
110
|
+
if (!config.driver) {
|
|
111
|
+
throw errorContractConfigMissing({
|
|
112
|
+
why: 'Config.driver is required. Even though emit does not use the driver, it is required by ControlFamilyDescriptor.create()',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const familyInstance = config.family.create({
|
|
108
116
|
target: config.target,
|
|
109
117
|
adapter: config.adapter,
|
|
110
118
|
driver: config.driver,
|
|
111
|
-
extensionPacks: config.extensionPacks,
|
|
119
|
+
extensionPacks: config.extensionPacks ?? [],
|
|
112
120
|
});
|
|
113
|
-
const familyInstance = config.family.create(stack);
|
|
114
121
|
|
|
115
122
|
// Resolve contract source from config (user's config handles loading)
|
|
116
123
|
let contractRaw: unknown;
|
package/src/commands/db-init.ts
CHANGED
|
@@ -6,7 +6,6 @@ import type {
|
|
|
6
6
|
MigrationPlanOperation,
|
|
7
7
|
MigrationRunnerResult,
|
|
8
8
|
} from '@prisma-next/core-control-plane/types';
|
|
9
|
-
import { createControlPlaneStack } from '@prisma-next/core-control-plane/types';
|
|
10
9
|
import { redactDatabaseUrl } from '@prisma-next/utils/redact-db-url';
|
|
11
10
|
import { Command } from 'commander';
|
|
12
11
|
import { loadConfig } from '../config-loader';
|
|
@@ -199,13 +198,12 @@ export function createDbInitCommand(): Command {
|
|
|
199
198
|
|
|
200
199
|
try {
|
|
201
200
|
// Create family instance
|
|
202
|
-
const
|
|
201
|
+
const familyInstance = config.family.create({
|
|
203
202
|
target: config.target,
|
|
204
203
|
adapter: config.adapter,
|
|
205
204
|
driver: driverDescriptor,
|
|
206
|
-
extensionPacks: config.extensionPacks,
|
|
205
|
+
extensionPacks: config.extensionPacks ?? [],
|
|
207
206
|
});
|
|
208
|
-
const familyInstance = config.family.create(stack);
|
|
209
207
|
const rawComponents = [config.target, config.adapter, ...(config.extensionPacks ?? [])];
|
|
210
208
|
const frameworkComponents = assertFrameworkComponentsCompatible(
|
|
211
209
|
config.family.familyId,
|
|
@@ -215,7 +213,13 @@ export function createDbInitCommand(): Command {
|
|
|
215
213
|
|
|
216
214
|
// Validate contract
|
|
217
215
|
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
218
|
-
assertContractRequirementsSatisfied({
|
|
216
|
+
assertContractRequirementsSatisfied({
|
|
217
|
+
contract: contractIR,
|
|
218
|
+
family: config.family,
|
|
219
|
+
target: config.target,
|
|
220
|
+
adapter: config.adapter,
|
|
221
|
+
extensionPacks: config.extensionPacks,
|
|
222
|
+
});
|
|
219
223
|
|
|
220
224
|
// Create planner and runner from target migrations capability
|
|
221
225
|
const planner = migrations.createPlanner(familyInstance);
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
} from '@prisma-next/core-control-plane/errors';
|
|
9
9
|
import type { CoreSchemaView } from '@prisma-next/core-control-plane/schema-view';
|
|
10
10
|
import type { IntrospectSchemaResult } from '@prisma-next/core-control-plane/types';
|
|
11
|
-
import { createControlPlaneStack } from '@prisma-next/core-control-plane/types';
|
|
12
11
|
import { Command } from 'commander';
|
|
13
12
|
import { loadConfig } from '../config-loader';
|
|
14
13
|
import { performAction } from '../utils/action';
|
|
@@ -140,18 +139,23 @@ export function createDbIntrospectCommand(): Command {
|
|
|
140
139
|
|
|
141
140
|
try {
|
|
142
141
|
// Create family instance
|
|
143
|
-
const
|
|
142
|
+
const familyInstance = config.family.create({
|
|
144
143
|
target: config.target,
|
|
145
144
|
adapter: config.adapter,
|
|
146
145
|
driver: driverDescriptor,
|
|
147
|
-
extensionPacks: config.extensionPacks,
|
|
146
|
+
extensionPacks: config.extensionPacks ?? [],
|
|
148
147
|
});
|
|
149
|
-
const familyInstance = config.family.create(stack);
|
|
150
148
|
|
|
151
149
|
// Validate contract IR if we loaded it
|
|
152
150
|
if (contractIR) {
|
|
153
151
|
const validatedContract = familyInstance.validateContractIR(contractIR);
|
|
154
|
-
assertContractRequirementsSatisfied({
|
|
152
|
+
assertContractRequirementsSatisfied({
|
|
153
|
+
contract: validatedContract,
|
|
154
|
+
family: config.family,
|
|
155
|
+
target: config.target,
|
|
156
|
+
adapter: config.adapter,
|
|
157
|
+
extensionPacks: config.extensionPacks,
|
|
158
|
+
});
|
|
155
159
|
contractIR = validatedContract;
|
|
156
160
|
}
|
|
157
161
|
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
errorUnexpected,
|
|
10
10
|
} from '@prisma-next/core-control-plane/errors';
|
|
11
11
|
import type { VerifyDatabaseSchemaResult } from '@prisma-next/core-control-plane/types';
|
|
12
|
-
import { createControlPlaneStack } from '@prisma-next/core-control-plane/types';
|
|
13
12
|
import { Command } from 'commander';
|
|
14
13
|
import { loadConfig } from '../config-loader';
|
|
15
14
|
import { performAction } from '../utils/action';
|
|
@@ -130,19 +129,24 @@ export function createDbSchemaVerifyCommand(): Command {
|
|
|
130
129
|
const driverDescriptor = config.driver;
|
|
131
130
|
|
|
132
131
|
// Create family instance (needed for contract validation)
|
|
133
|
-
const
|
|
132
|
+
const familyInstance = config.family.create({
|
|
134
133
|
target: config.target,
|
|
135
134
|
adapter: config.adapter,
|
|
136
135
|
driver: driverDescriptor,
|
|
137
|
-
extensionPacks: config.extensionPacks,
|
|
136
|
+
extensionPacks: config.extensionPacks ?? [],
|
|
138
137
|
});
|
|
139
|
-
const familyInstance = config.family.create(stack);
|
|
140
138
|
|
|
141
139
|
// Validate contract using instance validator
|
|
142
140
|
const contractIR = familyInstance.validateContractIR(contractJson) as ContractIR;
|
|
143
141
|
|
|
144
142
|
// Validate contract requirements fail-fast before connecting to database
|
|
145
|
-
assertContractRequirementsSatisfied({
|
|
143
|
+
assertContractRequirementsSatisfied({
|
|
144
|
+
contract: contractIR,
|
|
145
|
+
family: config.family,
|
|
146
|
+
target: config.target,
|
|
147
|
+
adapter: config.adapter,
|
|
148
|
+
extensionPacks: config.extensionPacks,
|
|
149
|
+
});
|
|
146
150
|
|
|
147
151
|
// Resolve database URL
|
|
148
152
|
const dbUrl = options.db ?? config.db?.url;
|
package/src/commands/db-sign.ts
CHANGED
|
@@ -11,7 +11,6 @@ import type {
|
|
|
11
11
|
SignDatabaseResult,
|
|
12
12
|
VerifyDatabaseSchemaResult,
|
|
13
13
|
} from '@prisma-next/core-control-plane/types';
|
|
14
|
-
import { createControlPlaneStack } from '@prisma-next/core-control-plane/types';
|
|
15
14
|
import { Command } from 'commander';
|
|
16
15
|
import { loadConfig } from '../config-loader';
|
|
17
16
|
import { performAction } from '../utils/action';
|
|
@@ -139,17 +138,22 @@ export function createDbSignCommand(): Command {
|
|
|
139
138
|
const driverDescriptor = config.driver;
|
|
140
139
|
|
|
141
140
|
// Create family instance (needed for contract validation - no DB connection required)
|
|
142
|
-
const
|
|
141
|
+
const familyInstance = config.family.create({
|
|
143
142
|
target: config.target,
|
|
144
143
|
adapter: config.adapter,
|
|
145
144
|
driver: driverDescriptor,
|
|
146
|
-
extensionPacks: config.extensionPacks,
|
|
145
|
+
extensionPacks: config.extensionPacks ?? [],
|
|
147
146
|
});
|
|
148
|
-
const familyInstance = config.family.create(stack);
|
|
149
147
|
|
|
150
148
|
// Validate contract using instance validator (fail-fast before DB connection)
|
|
151
149
|
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
152
|
-
assertContractRequirementsSatisfied({
|
|
150
|
+
assertContractRequirementsSatisfied({
|
|
151
|
+
contract: contractIR,
|
|
152
|
+
family: config.family,
|
|
153
|
+
target: config.target,
|
|
154
|
+
adapter: config.adapter,
|
|
155
|
+
extensionPacks: config.extensionPacks,
|
|
156
|
+
});
|
|
153
157
|
|
|
154
158
|
const rawComponents = [config.target, config.adapter, ...(config.extensionPacks ?? [])];
|
|
155
159
|
const frameworkComponents = assertFrameworkComponentsCompatible(
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
errorUnexpected,
|
|
13
13
|
} from '@prisma-next/core-control-plane/errors';
|
|
14
14
|
import type { VerifyDatabaseResult } from '@prisma-next/core-control-plane/types';
|
|
15
|
-
import { createControlPlaneStack } from '@prisma-next/core-control-plane/types';
|
|
16
15
|
import { Command } from 'commander';
|
|
17
16
|
import { loadConfig } from '../config-loader';
|
|
18
17
|
import { performAction } from '../utils/action';
|
|
@@ -140,17 +139,22 @@ export function createDbVerifyCommand(): Command {
|
|
|
140
139
|
|
|
141
140
|
try {
|
|
142
141
|
// Create family instance
|
|
143
|
-
const
|
|
142
|
+
const familyInstance = config.family.create({
|
|
144
143
|
target: config.target,
|
|
145
144
|
adapter: config.adapter,
|
|
146
145
|
driver: driverDescriptor,
|
|
147
|
-
extensionPacks: config.extensionPacks,
|
|
146
|
+
extensionPacks: config.extensionPacks ?? [],
|
|
148
147
|
});
|
|
149
|
-
const familyInstance = config.family.create(stack);
|
|
150
148
|
|
|
151
149
|
// Validate contract using instance validator
|
|
152
150
|
const contractIR = familyInstance.validateContractIR(contractJson) as ContractIR;
|
|
153
|
-
assertContractRequirementsSatisfied({
|
|
151
|
+
assertContractRequirementsSatisfied({
|
|
152
|
+
contract: contractIR,
|
|
153
|
+
family: config.family,
|
|
154
|
+
target: config.target,
|
|
155
|
+
adapter: config.adapter,
|
|
156
|
+
extensionPacks: config.extensionPacks,
|
|
157
|
+
});
|
|
154
158
|
|
|
155
159
|
// Call family instance verify method
|
|
156
160
|
let verifyResult: VerifyDatabaseResult;
|
|
@@ -3,7 +3,12 @@ import {
|
|
|
3
3
|
type TargetBoundComponentDescriptor,
|
|
4
4
|
} from '@prisma-next/contract/framework-components';
|
|
5
5
|
import type { ContractIR } from '@prisma-next/contract/ir';
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
ControlAdapterDescriptor,
|
|
8
|
+
ControlExtensionDescriptor,
|
|
9
|
+
ControlFamilyDescriptor,
|
|
10
|
+
ControlTargetDescriptor,
|
|
11
|
+
} from '@prisma-next/core-control-plane/types';
|
|
7
12
|
import { errorConfigValidation, errorContractMissingExtensionPacks } from './cli-errors';
|
|
8
13
|
|
|
9
14
|
/**
|
|
@@ -108,14 +113,17 @@ export function assertFrameworkComponentsCompatible<
|
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
/**
|
|
111
|
-
* Validates that a contract is compatible with the configured target, adapter,
|
|
116
|
+
* Validates that a contract is compatible with the configured family, target, adapter,
|
|
112
117
|
* and extension packs. Throws on family/target mismatches or missing extension packs.
|
|
113
118
|
*
|
|
114
119
|
* This check ensures the emitted contract matches the CLI config before running
|
|
115
120
|
* commands that depend on the contract (e.g., db verify, db sign).
|
|
116
121
|
*
|
|
117
122
|
* @param contract - The contract IR to validate (must include targetFamily, target, extensionPacks).
|
|
118
|
-
* @param
|
|
123
|
+
* @param family - The configured family descriptor.
|
|
124
|
+
* @param target - The configured target descriptor.
|
|
125
|
+
* @param adapter - The configured adapter descriptor.
|
|
126
|
+
* @param extensionPacks - Optional array of extension descriptors provided by the config.
|
|
119
127
|
*
|
|
120
128
|
* @throws {CliStructuredError} errorConfigValidation when contract.targetFamily or contract.target
|
|
121
129
|
* doesn't match the configured family/target.
|
|
@@ -128,10 +136,15 @@ export function assertFrameworkComponentsCompatible<
|
|
|
128
136
|
*
|
|
129
137
|
* const config = await loadConfig();
|
|
130
138
|
* const contractIR = await loadContractJson(config.contract.output);
|
|
131
|
-
* const stack = createControlPlaneStack({ target: config.target, adapter: config.adapter, ... });
|
|
132
139
|
*
|
|
133
140
|
* // Throws if contract is incompatible with config
|
|
134
|
-
* assertContractRequirementsSatisfied({
|
|
141
|
+
* assertContractRequirementsSatisfied({
|
|
142
|
+
* contract: contractIR,
|
|
143
|
+
* family: config.family,
|
|
144
|
+
* target: config.target,
|
|
145
|
+
* adapter: config.adapter,
|
|
146
|
+
* extensionPacks: config.extensionPacks,
|
|
147
|
+
* });
|
|
135
148
|
* ```
|
|
136
149
|
*/
|
|
137
150
|
export function assertContractRequirementsSatisfied<
|
|
@@ -139,20 +152,26 @@ export function assertContractRequirementsSatisfied<
|
|
|
139
152
|
TTargetId extends string,
|
|
140
153
|
>({
|
|
141
154
|
contract,
|
|
142
|
-
|
|
155
|
+
family,
|
|
156
|
+
target,
|
|
157
|
+
adapter,
|
|
158
|
+
extensionPacks,
|
|
143
159
|
}: {
|
|
144
160
|
readonly contract: Pick<ContractIR, 'targetFamily' | 'target' | 'extensionPacks'>;
|
|
145
|
-
readonly
|
|
161
|
+
readonly family: ControlFamilyDescriptor<TFamilyId>;
|
|
162
|
+
readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;
|
|
163
|
+
readonly adapter: ControlAdapterDescriptor<TFamilyId, TTargetId>;
|
|
164
|
+
readonly extensionPacks?: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[] | undefined;
|
|
146
165
|
}): void {
|
|
147
|
-
const providedComponentIds = new Set<string>([
|
|
148
|
-
for (const extension of
|
|
166
|
+
const providedComponentIds = new Set<string>([target.id, adapter.id]);
|
|
167
|
+
for (const extension of extensionPacks ?? []) {
|
|
149
168
|
providedComponentIds.add(extension.id);
|
|
150
169
|
}
|
|
151
170
|
|
|
152
171
|
const result = checkContractComponentRequirements({
|
|
153
172
|
contract,
|
|
154
|
-
expectedTargetFamily:
|
|
155
|
-
expectedTargetId:
|
|
173
|
+
expectedTargetFamily: family.familyId,
|
|
174
|
+
expectedTargetId: target.targetId,
|
|
156
175
|
providedComponentIds,
|
|
157
176
|
});
|
|
158
177
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/framework-components.ts"],"sourcesContent":["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"],"mappings":";;;;;;AAAA;AAAA,EACE;AAAA,OAEK;AAuCA,SAAS,oCAId,kBACA,kBACA,qBACqE;AACrE,WAAS,IAAI,GAAG,IAAI,oBAAoB,QAAQ,KAAK;AACnD,UAAM,YAAY,oBAAoB,CAAC;AAGvC,QAAI,OAAO,cAAc,YAAY,cAAc,MAAM;AACvD,YAAM,sBAAsB,yBAAyB;AAAA,QACnD,KAAK,gCAAgC,CAAC;AAAA,MACxC,CAAC;AAAA,IACH;AAEA,UAAM,SAAS;AAGf,QAAI,CAAC,OAAO,OAAO,QAAQ,MAAM,GAAG;AAClC,YAAM,sBAAsB,8BAA8B;AAAA,QACxD,KAAK,gCAAgC,CAAC;AAAA,MACxC,CAAC;AAAA,IACH;AAEA,UAAM,OAAO,OAAO,MAAM;AAC1B,QAAI,SAAS,YAAY,SAAS,aAAa,SAAS,eAAe,SAAS,UAAU;AACxF,YAAM,sBAAsB,8BAA8B;AAAA,QACxD,KAAK,gCAAgC,CAAC,sBAAsB,OAAO,IAAI,CAAC;AAAA,MAC1E,CAAC;AAAA,IACH;AAGA,QAAI,CAAC,OAAO,OAAO,QAAQ,UAAU,GAAG;AACtC,YAAM,sBAAsB,kCAAkC;AAAA,QAC5D,KAAK,gCAAgC,CAAC,WAAW,OAAO,IAAI,CAAC;AAAA,MAC/D,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,OAAO,UAAU;AAClC,QAAI,aAAa,kBAAkB;AACjC,YAAM,sBAAsB,kCAAkC;AAAA,QAC5D,KAAK,gCAAgC,CAAC,WAAW,OAAO,IAAI,CAAC,mBAAmB,OAAO,QAAQ,CAAC,mBAAmB,gBAAgB;AAAA,MACrI,CAAC;AAAA,IACH;AAGA,QAAI,CAAC,OAAO,OAAO,QAAQ,UAAU,GAAG;AACtC,YAAM,sBAAsB,kCAAkC;AAAA,QAC5D,KAAK,gCAAgC,CAAC,WAAW,OAAO,IAAI,CAAC;AAAA,MAC/D,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,OAAO,UAAU;AAClC,QAAI,aAAa,kBAAkB;AACjC,YAAM,sBAAsB,kCAAkC;AAAA,QAC5D,KAAK,gCAAgC,CAAC,WAAW,OAAO,IAAI,CAAC,mBAAmB,OAAO,QAAQ,CAAC,mBAAmB,gBAAgB;AAAA,MACrI,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO;AACT;AA6BO,SAAS,oCAGd;AAAA,EACA;AAAA,EACA;AACF,GAGS;AACP,QAAM,uBAAuB,oBAAI,IAAY,CAAC,MAAM,OAAO,IAAI,MAAM,QAAQ,EAAE,CAAC;AAChF,aAAW,aAAa,MAAM,gBAAgB;AAC5C,yBAAqB,IAAI,UAAU,EAAE;AAAA,EACvC;AAEA,QAAM,SAAS,mCAAmC;AAAA,IAChD;AAAA,IACA,sBAAsB,MAAM,OAAO;AAAA,IACnC,kBAAkB,MAAM,OAAO;AAAA,IAC/B;AAAA,EACF,CAAC;AAED,MAAI,OAAO,gBAAgB;AACzB,UAAM,sBAAsB,yBAAyB;AAAA,MACnD,KAAK,oCAAoC,OAAO,eAAe,MAAM,iCAAiC,OAAO,eAAe,QAAQ;AAAA,IACtI,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,gBAAgB;AACzB,UAAM,sBAAsB,mBAAmB;AAAA,MAC7C,KAAK,oBAAoB,OAAO,eAAe,MAAM,gCAAgC,OAAO,eAAe,QAAQ;AAAA,IACrH,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,wBAAwB,SAAS,GAAG;AAC7C,UAAM,mCAAmC;AAAA,MACvC,uBAAuB,OAAO;AAAA,MAC9B,sBAAsB,CAAC,GAAG,oBAAoB;AAAA,IAChD,CAAC;AAAA,EACH;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/contract-emit.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/types';\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"],"mappings":"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","names":[]}
|