@prisma-next/cli 0.3.0-dev.45 → 0.3.0-dev.52
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/README.md +20 -34
- package/dist/cli.mjs +2 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-Lm9Q6aQM.mjs → client-BSZKpZTF.mjs} +26 -9
- package/dist/{client-Lm9Q6aQM.mjs.map → client-BSZKpZTF.mjs.map} +1 -1
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +26 -19
- package/dist/commands/contract-emit.mjs.map +1 -1
- package/dist/commands/db-init.mjs +3 -3
- package/dist/commands/db-introspect.mjs +3 -3
- package/dist/commands/db-schema-verify.mjs +3 -3
- package/dist/commands/db-sign.mjs +3 -3
- package/dist/commands/db-verify.mjs +3 -3
- package/dist/{config-loader-CnnWuluc.mjs → config-loader-BJ8HsEdA.mjs} +2 -2
- package/dist/{config-loader-CnnWuluc.mjs.map → config-loader-BJ8HsEdA.mjs.map} +1 -1
- package/dist/config-loader.mjs +1 -1
- package/dist/exports/control-api.d.mts +5 -23
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +44 -7
- package/dist/exports/control-api.mjs.map +1 -1
- package/dist/exports/index.mjs +3 -1
- package/dist/exports/index.mjs.map +1 -1
- package/package.json +10 -10
- package/src/commands/contract-emit.ts +32 -16
- package/src/control-api/client.ts +28 -9
- package/src/control-api/operations/contract-emit.ts +72 -14
- package/src/control-api/types.ts +7 -25
- package/src/exports/control-api.ts +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-emit.mjs","names":["exhaustive: never","config: Awaited<ReturnType<typeof loadConfig>>","errorUnexpected","source: EmitContractSource"],"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 { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { EmitContractSource, EmitFailure } from '../control-api/types';\nimport { CliStructuredError, errorRuntime, errorUnexpected } from '../utils/cli-errors';\nimport { setCommandDescriptions } from '../utils/command-helpers';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport {\n type EmitContractResult,\n formatCommandHelp,\n formatEmitJson,\n formatEmitOutput,\n formatStyledHeader,\n formatSuccessMessage,\n} from '../utils/output';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport { handleResult } from '../utils/result-handler';\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\n/**\n * Maps an EmitFailure to a CliStructuredError for consistent error handling.\n */\nfunction mapEmitFailure(failure: EmitFailure): CliStructuredError {\n if (failure.code === 'CONTRACT_SOURCE_INVALID') {\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Contract source is invalid',\n fix: 'Check your contract source configuration in prisma-next.config.ts',\n });\n }\n\n if (failure.code === 'EMIT_FAILED') {\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Failed to emit contract',\n fix: 'Check your contract configuration and ensure the source is valid',\n });\n }\n\n // Exhaustive check - TypeScript will error if a new code is added but not handled\n const exhaustive: never = failure.code;\n throw new Error(`Unhandled EmitFailure code: ${exhaustive}`);\n}\n\n/**\n * Executes the contract emit command and returns a structured Result.\n */\nasync function executeContractEmitCommand(\n options: ContractEmitOptions,\n flags: GlobalFlags,\n startTime: number,\n): Promise<Result<EmitContractResult, CliStructuredError>> {\n // Load config\n let config: Awaited<ReturnType<typeof loadConfig>>;\n try {\n config = await loadConfig(options.config);\n } catch (error) {\n // Convert thrown CliStructuredError to Result\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: 'Failed to load config',\n }),\n );\n }\n\n // Resolve contract from config\n if (!config.contract) {\n return notOk(\n errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ..., types: ... }',\n }),\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) {\n return notOk(\n errorContractConfigMissing({\n why: 'Contract config must have output path. This should not happen if defineConfig() was used.',\n }),\n );\n }\n if (!contractConfig.output.endsWith('.json')) {\n return notOk(\n errorContractConfigMissing({\n why: 'Contract config output path must end with .json (e.g., \"src/prisma/contract.json\")',\n }),\n );\n }\n const outputJsonPath = resolve(contractConfig.output);\n // Colocate .d.ts with .json (contract.json → contract.d.ts)\n const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;\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 // Create control client (no driver needed for emit)\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ flags });\n\n try {\n // Convert user config source to discriminated union\n // Type assertion is safe: we check typeof to determine if it's a function\n const source: EmitContractSource =\n typeof contractConfig.source === 'function'\n ? { kind: 'loader', load: contractConfig.source as () => unknown | Promise<unknown> }\n : { kind: 'value', value: contractConfig.source };\n\n // Call emit with progress callback\n const result = await client.emit({\n contractConfig: {\n source,\n output: outputJsonPath,\n },\n onProgress,\n });\n\n // Handle failures by mapping to CLI structured error\n if (!result.ok) {\n return notOk(mapEmitFailure(result.failure));\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, result.value.contractJson, 'utf-8');\n writeFileSync(outputDtsPath, result.value.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 // Convert success result to CLI output format\n const emitResult: EmitContractResult = {\n storageHash: result.value.storageHash,\n ...(result.value.executionHash ? { executionHash: result.value.executionHash } : {}),\n profileHash: result.value.profileHash,\n outDir: dirname(outputJsonPath),\n files: {\n json: outputJsonPath,\n dts: outputDtsPath,\n },\n timings: { total: Date.now() - startTime },\n };\n\n return ok(emitResult);\n } catch (error) {\n // Use static type guard to work across module boundaries\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n // Wrap unexpected errors\n return notOk(\n errorUnexpected('Unexpected error during contract emit', {\n why: error instanceof Error ? error.message : String(error),\n }),\n );\n } finally {\n await client.close();\n }\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 const startTime = Date.now();\n\n const result = await executeContractEmitCommand(options, flags, startTime);\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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"}
|
|
1
|
+
{"version":3,"file":"contract-emit.mjs","names":["exhaustive: never","config: Awaited<ReturnType<typeof loadConfig>>","errorUnexpected"],"sources":["../../src/commands/contract-emit.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { errorContractConfigMissing } from '@prisma-next/core-control-plane/errors';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { dirname, isAbsolute, join, relative, resolve } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { EmitFailure } from '../control-api/types';\nimport { CliStructuredError, errorRuntime, errorUnexpected } from '../utils/cli-errors';\nimport { setCommandDescriptions } from '../utils/command-helpers';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport {\n type EmitContractResult,\n formatCommandHelp,\n formatEmitJson,\n formatEmitOutput,\n formatStyledHeader,\n formatSuccessMessage,\n} from '../utils/output';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport { handleResult } from '../utils/result-handler';\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\nfunction mapDiagnosticsToIssues(\n failure: EmitFailure,\n): ReadonlyArray<{ kind: string; message: string }> {\n const diagnostics = failure.diagnostics?.diagnostics ?? [];\n return diagnostics.map((diagnostic) => {\n const location =\n diagnostic.sourceId && diagnostic.span\n ? ` (${diagnostic.sourceId}:${diagnostic.span.start.line}:${diagnostic.span.start.column})`\n : diagnostic.sourceId\n ? ` (${diagnostic.sourceId})`\n : '';\n return {\n kind: diagnostic.code,\n message: `${diagnostic.message}${location}`,\n };\n });\n}\n\n/**\n * Maps an EmitFailure to a CliStructuredError for consistent error handling.\n */\nfunction mapEmitFailure(failure: EmitFailure): CliStructuredError {\n if (failure.code === 'CONTRACT_SOURCE_INVALID') {\n const issues = mapDiagnosticsToIssues(failure);\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Contract source provider failed',\n fix: 'Check your contract source provider in prisma-next.config.ts and ensure it returns Result<ContractIR, Diagnostics>',\n ...(issues.length > 0 ? { meta: { issues } } : {}),\n });\n }\n\n if (failure.code === 'EMIT_FAILED') {\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Failed to emit contract',\n fix: 'Check your contract configuration and ensure the source is valid',\n });\n }\n\n // Exhaustive check - TypeScript will error if a new code is added but not handled\n const exhaustive: never = failure.code;\n throw new Error(`Unhandled EmitFailure code: ${exhaustive}`);\n}\n\n/**\n * Executes the contract emit command and returns a structured Result.\n */\nasync function executeContractEmitCommand(\n options: ContractEmitOptions,\n flags: GlobalFlags,\n startTime: number,\n): Promise<Result<EmitContractResult, CliStructuredError>> {\n // Load config\n let config: Awaited<ReturnType<typeof loadConfig>>;\n try {\n config = await loadConfig(options.config);\n } catch (error) {\n // Convert thrown CliStructuredError to Result\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: 'Failed to load config',\n }),\n );\n }\n\n // Resolve contract from config\n if (!config.contract) {\n return notOk(\n errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',\n }),\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) {\n return notOk(\n errorContractConfigMissing({\n why: 'Contract config must have output path. This should not happen if defineConfig() was used.',\n }),\n );\n }\n if (!contractConfig.output.endsWith('.json')) {\n return notOk(\n errorContractConfigMissing({\n why: 'Contract config output path must end with .json (e.g., \"src/prisma/contract.json\")',\n }),\n );\n }\n const configDir = options.config ? dirname(resolve(options.config)) : process.cwd();\n const outputJsonPath = isAbsolute(contractConfig.output)\n ? contractConfig.output\n : join(configDir, contractConfig.output);\n // Colocate .d.ts with .json (contract.json → contract.d.ts)\n const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;\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: 'Emit your contract artifacts',\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 // Create control client (no driver needed for emit)\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ flags });\n\n try {\n // Call emit with progress callback\n const result = await client.emit({\n contractConfig: {\n sourceProvider: contractConfig.source,\n output: outputJsonPath,\n },\n onProgress,\n });\n\n // Handle failures by mapping to CLI structured error\n if (!result.ok) {\n return notOk(mapEmitFailure(result.failure));\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, result.value.contractJson, 'utf-8');\n writeFileSync(outputDtsPath, result.value.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 // Convert success result to CLI output format\n const emitResult: EmitContractResult = {\n storageHash: result.value.storageHash,\n ...(result.value.executionHash ? { executionHash: result.value.executionHash } : {}),\n profileHash: result.value.profileHash,\n outDir: dirname(outputJsonPath),\n files: {\n json: outputJsonPath,\n dts: outputDtsPath,\n },\n timings: { total: Date.now() - startTime },\n };\n\n return ok(emitResult);\n } catch (error) {\n // Use static type guard to work across module boundaries\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n // Wrap unexpected errors\n return notOk(\n errorUnexpected('Unexpected error during contract emit', {\n why: error instanceof Error ? error.message : String(error),\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createContractEmitCommand(): Command {\n const command = new Command('emit');\n setCommandDescriptions(\n command,\n 'Emit your contract artifacts',\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 const startTime = Date.now();\n\n const result = await executeContractEmitCommand(options, flags, startTime);\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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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as loadConfig } from "../config-loader-
|
|
2
|
-
import { a as errorDatabaseConnectionRequired, d as errorMigrationPlanningFailed, f as errorRuntime, h as errorUnexpected, i as errorContractValidationFailed, l as errorJsonFormatNotSupported, n as CliStructuredError, o as errorDriverRequired, p as errorTargetMigrationNotSupported, s as errorFileNotFound, t as createControlClient } from "../client-
|
|
1
|
+
import { t as loadConfig } from "../config-loader-BJ8HsEdA.mjs";
|
|
2
|
+
import { a as errorDatabaseConnectionRequired, d as errorMigrationPlanningFailed, f as errorRuntime, h as errorUnexpected, i as errorContractValidationFailed, l as errorJsonFormatNotSupported, n as CliStructuredError, o as errorDriverRequired, p as errorTargetMigrationNotSupported, s as errorFileNotFound, t as createControlClient } from "../client-BSZKpZTF.mjs";
|
|
3
3
|
import { a as formatDbInitJson, b as parseGlobalFlags, g as formatStyledHeader, i as formatDbInitApplyOutput, n as createProgressAdapter, o as formatDbInitPlanOutput, r as formatCommandHelp, t as handleResult, x as setCommandDescriptions } from "../result-handler-BZPY7HX4.mjs";
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { relative, resolve } from "node:path";
|
|
6
5
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
6
|
+
import { relative, resolve } from "node:path";
|
|
7
7
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
8
8
|
import { readFile } from "node:fs/promises";
|
|
9
9
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as loadConfig } from "../config-loader-
|
|
2
|
-
import { a as errorDatabaseConnectionRequired, h as errorUnexpected, l as errorJsonFormatNotSupported, n as CliStructuredError, o as errorDriverRequired, t as createControlClient } from "../client-
|
|
1
|
+
import { t as loadConfig } from "../config-loader-BJ8HsEdA.mjs";
|
|
2
|
+
import { a as errorDatabaseConnectionRequired, h as errorUnexpected, l as errorJsonFormatNotSupported, n as CliStructuredError, o as errorDriverRequired, t as createControlClient } from "../client-BSZKpZTF.mjs";
|
|
3
3
|
import { b as parseGlobalFlags, g as formatStyledHeader, l as formatIntrospectJson, n as createProgressAdapter, r as formatCommandHelp, t as handleResult, u as formatIntrospectOutput, x as setCommandDescriptions } from "../result-handler-BZPY7HX4.mjs";
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { relative, resolve } from "node:path";
|
|
6
5
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
6
|
+
import { relative, resolve } from "node:path";
|
|
7
7
|
|
|
8
8
|
//#region src/commands/db-introspect.ts
|
|
9
9
|
/**
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as loadConfig } from "../config-loader-
|
|
2
|
-
import { a as errorDatabaseConnectionRequired, h as errorUnexpected, i as errorContractValidationFailed, l as errorJsonFormatNotSupported, n as CliStructuredError, o as errorDriverRequired, s as errorFileNotFound, t as createControlClient } from "../client-
|
|
1
|
+
import { t as loadConfig } from "../config-loader-BJ8HsEdA.mjs";
|
|
2
|
+
import { a as errorDatabaseConnectionRequired, h as errorUnexpected, i as errorContractValidationFailed, l as errorJsonFormatNotSupported, n as CliStructuredError, o as errorDriverRequired, s as errorFileNotFound, t as createControlClient } from "../client-BSZKpZTF.mjs";
|
|
3
3
|
import { b as parseGlobalFlags, f as formatSchemaVerifyJson, g as formatStyledHeader, n as createProgressAdapter, p as formatSchemaVerifyOutput, r as formatCommandHelp, t as handleResult, x as setCommandDescriptions } from "../result-handler-BZPY7HX4.mjs";
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { relative, resolve } from "node:path";
|
|
6
5
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
6
|
+
import { relative, resolve } from "node:path";
|
|
7
7
|
import { readFile } from "node:fs/promises";
|
|
8
8
|
|
|
9
9
|
//#region src/commands/db-schema-verify.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as loadConfig } from "../config-loader-
|
|
2
|
-
import { a as errorDatabaseConnectionRequired, h as errorUnexpected, i as errorContractValidationFailed, l as errorJsonFormatNotSupported, n as CliStructuredError, o as errorDriverRequired, s as errorFileNotFound, t as createControlClient } from "../client-
|
|
1
|
+
import { t as loadConfig } from "../config-loader-BJ8HsEdA.mjs";
|
|
2
|
+
import { a as errorDatabaseConnectionRequired, h as errorUnexpected, i as errorContractValidationFailed, l as errorJsonFormatNotSupported, n as CliStructuredError, o as errorDriverRequired, s as errorFileNotFound, t as createControlClient } from "../client-BSZKpZTF.mjs";
|
|
3
3
|
import { b as parseGlobalFlags, f as formatSchemaVerifyJson, g as formatStyledHeader, h as formatSignOutput, m as formatSignJson, n as createProgressAdapter, p as formatSchemaVerifyOutput, r as formatCommandHelp, t as handleResult, x as setCommandDescriptions } from "../result-handler-BZPY7HX4.mjs";
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { relative, resolve } from "node:path";
|
|
6
5
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
6
|
+
import { relative, resolve } from "node:path";
|
|
7
7
|
import { readFile } from "node:fs/promises";
|
|
8
8
|
|
|
9
9
|
//#region src/commands/db-sign.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as loadConfig } from "../config-loader-
|
|
2
|
-
import { a as errorDatabaseConnectionRequired, c as errorHashMismatch, f as errorRuntime, h as errorUnexpected, i as errorContractValidationFailed, l as errorJsonFormatNotSupported, m as errorTargetMismatch, n as CliStructuredError, o as errorDriverRequired, s as errorFileNotFound, t as createControlClient, u as errorMarkerMissing } from "../client-
|
|
1
|
+
import { t as loadConfig } from "../config-loader-BJ8HsEdA.mjs";
|
|
2
|
+
import { a as errorDatabaseConnectionRequired, c as errorHashMismatch, f as errorRuntime, h as errorUnexpected, i as errorContractValidationFailed, l as errorJsonFormatNotSupported, m as errorTargetMismatch, n as CliStructuredError, o as errorDriverRequired, s as errorFileNotFound, t as createControlClient, u as errorMarkerMissing } from "../client-BSZKpZTF.mjs";
|
|
3
3
|
import { b as parseGlobalFlags, g as formatStyledHeader, n as createProgressAdapter, r as formatCommandHelp, t as handleResult, v as formatVerifyJson, x as setCommandDescriptions, y as formatVerifyOutput } from "../result-handler-BZPY7HX4.mjs";
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { relative, resolve } from "node:path";
|
|
6
5
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
6
|
+
import { relative, resolve } from "node:path";
|
|
7
7
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
8
8
|
import { readFile } from "node:fs/promises";
|
|
9
9
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { dirname, resolve } from "node:path";
|
|
2
1
|
import { errorConfigFileNotFound, errorUnexpected } from "@prisma-next/core-control-plane/errors";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { validateConfig } from "@prisma-next/core-control-plane/config-validation";
|
|
4
4
|
import { loadConfig } from "c12";
|
|
5
5
|
|
|
@@ -39,4 +39,4 @@ async function loadConfig$1(configPath) {
|
|
|
39
39
|
|
|
40
40
|
//#endregion
|
|
41
41
|
export { loadConfig$1 as t };
|
|
42
|
-
//# sourceMappingURL=config-loader-
|
|
42
|
+
//# sourceMappingURL=config-loader-BJ8HsEdA.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-loader-
|
|
1
|
+
{"version":3,"file":"config-loader-BJ8HsEdA.mjs","names":["loadConfig","loadConfigC12"],"sources":["../src/config-loader.ts"],"sourcesContent":["import { dirname, resolve } from 'node:path';\nimport type { PrismaNextConfig } from '@prisma-next/core-control-plane/config-types';\nimport { validateConfig } from '@prisma-next/core-control-plane/config-validation';\nimport { errorConfigFileNotFound, errorUnexpected } from '@prisma-next/core-control-plane/errors';\nimport { loadConfig as loadConfigC12 } from 'c12';\n\n/**\n * Loads the Prisma Next config from a TypeScript file.\n * Supports both default export and named export.\n * Uses c12 to automatically handle TypeScript compilation and config file discovery.\n *\n * @param configPath - Optional path to config file. Defaults to `./prisma-next.config.ts` in current directory.\n * @returns The loaded config object.\n * @throws Error if config file doesn't exist or is invalid.\n */\nexport async function loadConfig(configPath?: string): Promise<PrismaNextConfig> {\n try {\n const cwd = process.cwd();\n // Resolve config path to absolute path and set cwd to config directory when path is provided\n const resolvedConfigPath = configPath ? resolve(cwd, configPath) : undefined;\n const configCwd = resolvedConfigPath ? dirname(resolvedConfigPath) : cwd;\n\n const result = await loadConfigC12<PrismaNextConfig>({\n name: 'prisma-next',\n ...(resolvedConfigPath ? { configFile: resolvedConfigPath } : {}),\n cwd: configCwd,\n });\n\n // When a specific config file was requested, verify it was actually loaded\n // (c12 falls back to searching by name if the specified file doesn't exist)\n if (resolvedConfigPath && result.configFile !== resolvedConfigPath) {\n throw errorConfigFileNotFound(resolvedConfigPath);\n }\n\n // Check if config is missing or empty (c12 may return empty object when file doesn't exist)\n if (!result.config || Object.keys(result.config).length === 0) {\n // Use c12's configFile if available, otherwise use explicit configPath, otherwise omit path\n const displayPath = result.configFile || resolvedConfigPath || configPath;\n throw errorConfigFileNotFound(displayPath);\n }\n\n // Validate config structure\n validateConfig(result.config);\n\n return result.config;\n } catch (error) {\n // Re-throw structured errors as-is\n if (\n error instanceof Error &&\n 'code' in error &&\n typeof (error as { code: string }).code === 'string'\n ) {\n throw error;\n }\n\n if (error instanceof Error) {\n // Check for file not found errors\n if (\n error.message.includes('not found') ||\n error.message.includes('Cannot find') ||\n error.message.includes('ENOENT')\n ) {\n // Use resolved path if available, otherwise use original configPath\n const displayPath = configPath ? resolve(process.cwd(), configPath) : undefined;\n throw errorConfigFileNotFound(displayPath, {\n why: error.message,\n });\n }\n // For other errors, wrap in unexpected error\n throw errorUnexpected(error.message, {\n why: `Failed to load config: ${error.message}`,\n });\n }\n throw errorUnexpected(String(error));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,eAAsBA,aAAW,YAAgD;AAC/E,KAAI;EACF,MAAM,MAAM,QAAQ,KAAK;EAEzB,MAAM,qBAAqB,aAAa,QAAQ,KAAK,WAAW,GAAG;EACnE,MAAM,YAAY,qBAAqB,QAAQ,mBAAmB,GAAG;EAErE,MAAM,SAAS,MAAMC,WAAgC;GACnD,MAAM;GACN,GAAI,qBAAqB,EAAE,YAAY,oBAAoB,GAAG,EAAE;GAChE,KAAK;GACN,CAAC;AAIF,MAAI,sBAAsB,OAAO,eAAe,mBAC9C,OAAM,wBAAwB,mBAAmB;AAInD,MAAI,CAAC,OAAO,UAAU,OAAO,KAAK,OAAO,OAAO,CAAC,WAAW,EAG1D,OAAM,wBADc,OAAO,cAAc,sBAAsB,WACrB;AAI5C,iBAAe,OAAO,OAAO;AAE7B,SAAO,OAAO;UACP,OAAO;AAEd,MACE,iBAAiB,SACjB,UAAU,SACV,OAAQ,MAA2B,SAAS,SAE5C,OAAM;AAGR,MAAI,iBAAiB,OAAO;AAE1B,OACE,MAAM,QAAQ,SAAS,YAAY,IACnC,MAAM,QAAQ,SAAS,cAAc,IACrC,MAAM,QAAQ,SAAS,SAAS,CAIhC,OAAM,wBADc,aAAa,QAAQ,QAAQ,KAAK,EAAE,WAAW,GAAG,QAC3B,EACzC,KAAK,MAAM,SACZ,CAAC;AAGJ,SAAM,gBAAgB,MAAM,SAAS,EACnC,KAAK,0BAA0B,MAAM,WACtC,CAAC;;AAEJ,QAAM,gBAAgB,OAAO,MAAM,CAAC"}
|
package/dist/config-loader.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Result } from "@prisma-next/utils/result";
|
|
2
|
+
import { ContractSourceDiagnostics, ContractSourceProvider } from "@prisma-next/core-control-plane/config-types";
|
|
2
3
|
import { ControlAdapterDescriptor, ControlDriverDescriptor, ControlExtensionDescriptor, ControlFamilyDescriptor, ControlPlaneStack, ControlTargetDescriptor, MigrationPlannerConflict, SignDatabaseResult, SignDatabaseResult as SignDatabaseResult$1, VerifyDatabaseResult, VerifyDatabaseResult as VerifyDatabaseResult$1, VerifyDatabaseSchemaResult, VerifyDatabaseSchemaResult as VerifyDatabaseSchemaResult$1 } from "@prisma-next/core-control-plane/types";
|
|
3
4
|
import { CoreSchemaView } from "@prisma-next/core-control-plane/schema-view";
|
|
4
5
|
|
|
@@ -161,34 +162,14 @@ interface IntrospectOptions {
|
|
|
161
162
|
/** Optional progress callback for observing operation progress */
|
|
162
163
|
readonly onProgress?: OnControlProgress;
|
|
163
164
|
}
|
|
164
|
-
/**
|
|
165
|
-
* Contract source as a raw value (any JSON-serializable value).
|
|
166
|
-
*/
|
|
167
|
-
interface ContractSourceValue {
|
|
168
|
-
readonly kind: 'value';
|
|
169
|
-
readonly value: unknown;
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Contract source as a lazy loader function.
|
|
173
|
-
*/
|
|
174
|
-
interface ContractSourceLoader {
|
|
175
|
-
readonly kind: 'loader';
|
|
176
|
-
readonly load: () => unknown | Promise<unknown>;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Discriminated union for contract source.
|
|
180
|
-
* Use `kind` to determine how to resolve the contract.
|
|
181
|
-
*/
|
|
182
|
-
type EmitContractSource = ContractSourceValue | ContractSourceLoader;
|
|
183
165
|
/**
|
|
184
166
|
* Contract configuration for emit operation.
|
|
185
167
|
*/
|
|
186
168
|
interface EmitContractConfig {
|
|
187
169
|
/**
|
|
188
|
-
* Contract source
|
|
189
|
-
* Switch on `source.kind` to determine how to resolve.
|
|
170
|
+
* Contract source provider.
|
|
190
171
|
*/
|
|
191
|
-
readonly
|
|
172
|
+
readonly sourceProvider: ContractSourceProvider;
|
|
192
173
|
/**
|
|
193
174
|
* Output path for contract.json.
|
|
194
175
|
* The .d.ts types file will be colocated (e.g., contract.json → contract.d.ts).
|
|
@@ -283,6 +264,7 @@ interface EmitFailure {
|
|
|
283
264
|
readonly summary: string;
|
|
284
265
|
readonly why: string | undefined;
|
|
285
266
|
readonly meta: Record<string, unknown> | undefined;
|
|
267
|
+
readonly diagnostics?: ContractSourceDiagnostics;
|
|
286
268
|
}
|
|
287
269
|
/**
|
|
288
270
|
* Result type for emit operation.
|
|
@@ -447,5 +429,5 @@ declare function createControlClient(options: ControlClientOptions): ControlClie
|
|
|
447
429
|
*/
|
|
448
430
|
declare function executeContractEmit(options: ContractEmitOptions): Promise<ContractEmitResult>;
|
|
449
431
|
//#endregion
|
|
450
|
-
export { type ContractEmitOptions, type ContractEmitResult, type
|
|
432
|
+
export { type ContractEmitOptions, type ContractEmitResult, type ControlActionName, type ControlClient, type ControlClientOptions, type ControlPlaneStack, type ControlProgressEvent, type DbInitFailure, type DbInitFailureCode, type DbInitOptions, type DbInitResult, type DbInitSuccess, type EmitContractConfig, type EmitFailure, type EmitFailureCode, type EmitOptions, type EmitResult, type EmitSuccess, type IntrospectOptions, type OnControlProgress, type SchemaVerifyOptions, type SignDatabaseResult, type SignOptions, type VerifyDatabaseResult, type VerifyDatabaseSchemaResult, type VerifyOptions, createControlClient, executeContractEmit };
|
|
451
433
|
//# sourceMappingURL=control-api.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-api.d.mts","names":[],"sources":["../../src/control-api/types.ts","../../src/control-api/client.ts","../../src/control-api/operations/contract-emit.ts"],"sourcesContent":[],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"control-api.d.mts","names":[],"sources":["../../src/control-api/types.ts","../../src/control-api/client.ts","../../src/control-api/operations/contract-emit.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import { t as loadConfig } from "../config-loader-
|
|
2
|
-
import { r as errorContractConfigMissing, t as createControlClient } from "../client-
|
|
1
|
+
import { t as loadConfig } from "../config-loader-BJ8HsEdA.mjs";
|
|
2
|
+
import { f as errorRuntime, r as errorContractConfigMissing, t as createControlClient } from "../client-BSZKpZTF.mjs";
|
|
3
|
+
import { dirname, isAbsolute, join, resolve } from "pathe";
|
|
3
4
|
import { createControlPlaneStack } from "@prisma-next/core-control-plane/stack";
|
|
4
5
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
5
6
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
6
7
|
import { abortable } from "@prisma-next/utils/abortable";
|
|
7
|
-
import { dirname, isAbsolute, join, resolve } from "pathe";
|
|
8
8
|
|
|
9
9
|
//#region src/control-api/operations/contract-emit.ts
|
|
10
|
+
function isRecord(value) {
|
|
11
|
+
return typeof value === "object" && value !== null;
|
|
12
|
+
}
|
|
13
|
+
function isAbortError(error) {
|
|
14
|
+
return isRecord(error) && typeof error["name"] === "string" && error["name"] === "AbortError";
|
|
15
|
+
}
|
|
16
|
+
function isProviderFailureLike(value) {
|
|
17
|
+
return isRecord(value) && typeof value["summary"] === "string" && Array.isArray(value["diagnostics"]);
|
|
18
|
+
}
|
|
10
19
|
/**
|
|
11
20
|
* Executes the contract emit operation.
|
|
12
21
|
*
|
|
@@ -32,14 +41,42 @@ async function executeContractEmit(options) {
|
|
|
32
41
|
const contractConfig = config.contract;
|
|
33
42
|
if (!contractConfig.output) throw errorContractConfigMissing({ why: "Contract config must have output path. This should not happen if defineConfig() was used." });
|
|
34
43
|
if (!contractConfig.output.endsWith(".json")) throw errorContractConfigMissing({ why: "Contract config output path must end with .json (e.g., \"src/prisma/contract.json\")" });
|
|
35
|
-
if (
|
|
44
|
+
if (typeof contractConfig.source !== "function") throw errorContractConfigMissing({ why: "Contract config must include a valid source provider function" });
|
|
36
45
|
const configDir = dirname(resolve(configPath));
|
|
37
46
|
const outputJsonPath = isAbsolute(contractConfig.output) ? contractConfig.output : join(configDir, contractConfig.output);
|
|
38
47
|
const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;
|
|
48
|
+
let providerResult;
|
|
49
|
+
try {
|
|
50
|
+
providerResult = await unlessAborted(contractConfig.source());
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (signal.aborted || isAbortError(error)) throw error;
|
|
53
|
+
throw errorRuntime("Failed to resolve contract source", {
|
|
54
|
+
why: error instanceof Error ? error.message : String(error),
|
|
55
|
+
fix: "Ensure contract.source resolves to ok(contractIR) or returns structured diagnostics."
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (!isRecord(providerResult) || typeof providerResult.ok !== "boolean") throw errorRuntime("Failed to resolve contract source", {
|
|
59
|
+
why: "Contract source provider returned malformed result shape.",
|
|
60
|
+
fix: "Ensure contract.source resolves to ok(contractIR) or notOk({ summary, diagnostics })."
|
|
61
|
+
});
|
|
62
|
+
if (providerResult.ok && !("value" in providerResult)) throw errorRuntime("Failed to resolve contract source", {
|
|
63
|
+
why: "Contract source provider returned malformed success result: missing value.",
|
|
64
|
+
fix: "Ensure contract.source success payload is ok(contractIR)."
|
|
65
|
+
});
|
|
66
|
+
if (!providerResult.ok && !isProviderFailureLike(providerResult.failure)) throw errorRuntime("Failed to resolve contract source", {
|
|
67
|
+
why: "Contract source provider returned malformed failure result: expected summary and diagnostics.",
|
|
68
|
+
fix: "Ensure contract.source failure payload is notOk({ summary, diagnostics, meta? })."
|
|
69
|
+
});
|
|
70
|
+
if (!providerResult.ok) throw errorRuntime("Failed to resolve contract source", {
|
|
71
|
+
why: providerResult.failure.summary,
|
|
72
|
+
fix: "Fix contract source diagnostics and return ok(contractIR).",
|
|
73
|
+
meta: {
|
|
74
|
+
diagnostics: providerResult.failure.diagnostics,
|
|
75
|
+
...ifDefined("providerMeta", providerResult.failure.meta)
|
|
76
|
+
}
|
|
77
|
+
});
|
|
39
78
|
const stack = createControlPlaneStack(config);
|
|
40
|
-
const
|
|
41
|
-
const contractRaw = typeof contractConfig.source === "function" ? await unlessAborted(contractConfig.source()) : contractConfig.source;
|
|
42
|
-
const emitResult = await unlessAborted(familyInstance.emitContract({ contractIR: contractRaw }));
|
|
79
|
+
const emitResult = await unlessAborted(config.family.create(stack).emitContract({ contractIR: providerResult.value }));
|
|
43
80
|
await unlessAborted(mkdir(dirname(outputJsonPath), { recursive: true }));
|
|
44
81
|
await unlessAborted(writeFile(outputJsonPath, emitResult.contractJson, "utf-8"));
|
|
45
82
|
await unlessAborted(writeFile(outputDtsPath, emitResult.contractDts, "utf-8"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-api.mjs","names":[],"sources":["../../src/control-api/operations/contract-emit.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { createControlPlaneStack } from '@prisma-next/core-control-plane/stack';\nimport { abortable } from '@prisma-next/utils/abortable';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { dirname, isAbsolute, join, resolve } from 'pathe';\nimport { loadConfig } from '../../config-loader';\nimport { errorContractConfigMissing } from '../../utils/cli-errors';\nimport type { ContractEmitOptions, ContractEmitResult } from '../types';\n\n/**\n * Executes the contract emit operation.\n *\n * This is an offline operation that:\n * 1. Loads the Prisma Next config from the specified path\n * 2. Resolves the contract source from config\n * 3. Creates a control plane stack and family instance\n * 4. Emits contract artifacts (JSON and DTS)\n * 5. Writes files to the paths specified in config\n *\n * Supports AbortSignal for cancellation, enabling \"last change wins\" behavior.\n *\n * @param options - Options including configPath and optional signal\n * @returns File paths and hashes of emitted artifacts\n * @throws If config loading fails, contract is invalid, or file I/O fails\n * @throws signal.reason if cancelled via AbortSignal (typically DOMException with name 'AbortError')\n */\nexport async function executeContractEmit(\n options: ContractEmitOptions,\n): Promise<ContractEmitResult> {\n const { configPath, signal = new AbortController().signal } = options;\n const unlessAborted = abortable(signal);\n\n // Load config using the existing config loader\n const config = await unlessAborted(loadConfig(configPath));\n\n // Validate contract config is present\n if (!config.contract) {\n throw errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',\n });\n }\n\n const contractConfig = config.contract;\n\n // Validate output path is present and ends with .json\n if (!contractConfig.output) {\n throw errorContractConfigMissing({\n why: 'Contract config must have output path. This should not happen if defineConfig() was used.',\n });\n }\n if (!contractConfig.output.endsWith('.json')) {\n throw errorContractConfigMissing({\n why: 'Contract config output path must end with .json (e.g., \"src/prisma/contract.json\")',\n });\n }\n\n // Validate source
|
|
1
|
+
{"version":3,"file":"control-api.mjs","names":["providerResult: Awaited<ReturnType<typeof contractConfig.source>>"],"sources":["../../src/control-api/operations/contract-emit.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport { createControlPlaneStack } from '@prisma-next/core-control-plane/stack';\nimport { abortable } from '@prisma-next/utils/abortable';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { dirname, isAbsolute, join, resolve } from 'pathe';\nimport { loadConfig } from '../../config-loader';\nimport { errorContractConfigMissing, errorRuntime } from '../../utils/cli-errors';\nimport type { ContractEmitOptions, ContractEmitResult } from '../types';\n\ninterface ProviderFailureLike {\n readonly summary: string;\n readonly diagnostics: readonly unknown[];\n readonly meta?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isAbortError(error: unknown): boolean {\n return isRecord(error) && typeof error['name'] === 'string' && error['name'] === 'AbortError';\n}\n\nfunction isProviderFailureLike(value: unknown): value is ProviderFailureLike {\n return (\n isRecord(value) && typeof value['summary'] === 'string' && Array.isArray(value['diagnostics'])\n );\n}\n\n/**\n * Executes the contract emit operation.\n *\n * This is an offline operation that:\n * 1. Loads the Prisma Next config from the specified path\n * 2. Resolves the contract source from config\n * 3. Creates a control plane stack and family instance\n * 4. Emits contract artifacts (JSON and DTS)\n * 5. Writes files to the paths specified in config\n *\n * Supports AbortSignal for cancellation, enabling \"last change wins\" behavior.\n *\n * @param options - Options including configPath and optional signal\n * @returns File paths and hashes of emitted artifacts\n * @throws If config loading fails, contract is invalid, or file I/O fails\n * @throws signal.reason if cancelled via AbortSignal (typically DOMException with name 'AbortError')\n */\nexport async function executeContractEmit(\n options: ContractEmitOptions,\n): Promise<ContractEmitResult> {\n const { configPath, signal = new AbortController().signal } = options;\n const unlessAborted = abortable(signal);\n\n // Load config using the existing config loader\n const config = await unlessAborted(loadConfig(configPath));\n\n // Validate contract config is present\n if (!config.contract) {\n throw errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',\n });\n }\n\n const contractConfig = config.contract;\n\n // Validate output path is present and ends with .json\n if (!contractConfig.output) {\n throw errorContractConfigMissing({\n why: 'Contract config must have output path. This should not happen if defineConfig() was used.',\n });\n }\n if (!contractConfig.output.endsWith('.json')) {\n throw errorContractConfigMissing({\n why: 'Contract config output path must end with .json (e.g., \"src/prisma/contract.json\")',\n });\n }\n\n // Validate source exists and is callable\n if (typeof contractConfig.source !== 'function') {\n throw errorContractConfigMissing({\n why: 'Contract config must include a valid source provider function',\n });\n }\n\n // Normalize configPath and resolve artifact paths relative to config file directory\n const normalizedConfigPath = resolve(configPath);\n const configDir = dirname(normalizedConfigPath);\n const outputJsonPath = isAbsolute(contractConfig.output)\n ? contractConfig.output\n : join(configDir, contractConfig.output);\n // Colocate .d.ts with .json (contract.json → contract.d.ts)\n const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;\n\n let providerResult: Awaited<ReturnType<typeof contractConfig.source>>;\n try {\n providerResult = await unlessAborted(contractConfig.source());\n } catch (error) {\n if (signal.aborted || isAbortError(error)) {\n throw error;\n }\n throw errorRuntime('Failed to resolve contract source', {\n why: error instanceof Error ? error.message : String(error),\n fix: 'Ensure contract.source resolves to ok(contractIR) or returns structured diagnostics.',\n });\n }\n\n if (!isRecord(providerResult) || typeof providerResult.ok !== 'boolean') {\n throw errorRuntime('Failed to resolve contract source', {\n why: 'Contract source provider returned malformed result shape.',\n fix: 'Ensure contract.source resolves to ok(contractIR) or notOk({ summary, diagnostics }).',\n });\n }\n\n if (providerResult.ok && !('value' in providerResult)) {\n throw errorRuntime('Failed to resolve contract source', {\n why: 'Contract source provider returned malformed success result: missing value.',\n fix: 'Ensure contract.source success payload is ok(contractIR).',\n });\n }\n\n if (!providerResult.ok && !isProviderFailureLike(providerResult.failure)) {\n throw errorRuntime('Failed to resolve contract source', {\n why: 'Contract source provider returned malformed failure result: expected summary and diagnostics.',\n fix: 'Ensure contract.source failure payload is notOk({ summary, diagnostics, meta? }).',\n });\n }\n\n if (!providerResult.ok) {\n throw errorRuntime('Failed to resolve contract source', {\n why: providerResult.failure.summary,\n fix: 'Fix contract source diagnostics and return ok(contractIR).',\n meta: {\n diagnostics: providerResult.failure.diagnostics,\n ...ifDefined('providerMeta', providerResult.failure.meta),\n },\n });\n }\n\n // Create control plane stack from config\n const stack = createControlPlaneStack(config);\n const familyInstance = config.family.create(stack);\n\n // Emit contract via family instance\n const emitResult = await unlessAborted(\n familyInstance.emitContract({ contractIR: providerResult.value }),\n );\n\n // Create directory if needed and write files (both colocated)\n await unlessAborted(mkdir(dirname(outputJsonPath), { recursive: true }));\n await unlessAborted(writeFile(outputJsonPath, emitResult.contractJson, 'utf-8'));\n await unlessAborted(writeFile(outputDtsPath, emitResult.contractDts, 'utf-8'));\n\n return {\n storageHash: emitResult.storageHash,\n ...ifDefined('executionHash', emitResult.executionHash),\n profileHash: emitResult.profileHash,\n files: {\n json: outputJsonPath,\n dts: outputDtsPath,\n },\n };\n}\n"],"mappings":";;;;;;;;;AAeA,SAAS,SAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU;;AAGhD,SAAS,aAAa,OAAyB;AAC7C,QAAO,SAAS,MAAM,IAAI,OAAO,MAAM,YAAY,YAAY,MAAM,YAAY;;AAGnF,SAAS,sBAAsB,OAA8C;AAC3E,QACE,SAAS,MAAM,IAAI,OAAO,MAAM,eAAe,YAAY,MAAM,QAAQ,MAAM,eAAe;;;;;;;;;;;;;;;;;;;AAqBlG,eAAsB,oBACpB,SAC6B;CAC7B,MAAM,EAAE,YAAY,SAAS,IAAI,iBAAiB,CAAC,WAAW;CAC9D,MAAM,gBAAgB,UAAU,OAAO;CAGvC,MAAM,SAAS,MAAM,cAAc,WAAW,WAAW,CAAC;AAG1D,KAAI,CAAC,OAAO,SACV,OAAM,2BAA2B,EAC/B,KAAK,0GACN,CAAC;CAGJ,MAAM,iBAAiB,OAAO;AAG9B,KAAI,CAAC,eAAe,OAClB,OAAM,2BAA2B,EAC/B,KAAK,6FACN,CAAC;AAEJ,KAAI,CAAC,eAAe,OAAO,SAAS,QAAQ,CAC1C,OAAM,2BAA2B,EAC/B,KAAK,wFACN,CAAC;AAIJ,KAAI,OAAO,eAAe,WAAW,WACnC,OAAM,2BAA2B,EAC/B,KAAK,iEACN,CAAC;CAKJ,MAAM,YAAY,QADW,QAAQ,WAAW,CACD;CAC/C,MAAM,iBAAiB,WAAW,eAAe,OAAO,GACpD,eAAe,SACf,KAAK,WAAW,eAAe,OAAO;CAE1C,MAAM,gBAAgB,GAAG,eAAe,MAAM,GAAG,GAAG,CAAC;CAErD,IAAIA;AACJ,KAAI;AACF,mBAAiB,MAAM,cAAc,eAAe,QAAQ,CAAC;UACtD,OAAO;AACd,MAAI,OAAO,WAAW,aAAa,MAAM,CACvC,OAAM;AAER,QAAM,aAAa,qCAAqC;GACtD,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;GAC3D,KAAK;GACN,CAAC;;AAGJ,KAAI,CAAC,SAAS,eAAe,IAAI,OAAO,eAAe,OAAO,UAC5D,OAAM,aAAa,qCAAqC;EACtD,KAAK;EACL,KAAK;EACN,CAAC;AAGJ,KAAI,eAAe,MAAM,EAAE,WAAW,gBACpC,OAAM,aAAa,qCAAqC;EACtD,KAAK;EACL,KAAK;EACN,CAAC;AAGJ,KAAI,CAAC,eAAe,MAAM,CAAC,sBAAsB,eAAe,QAAQ,CACtE,OAAM,aAAa,qCAAqC;EACtD,KAAK;EACL,KAAK;EACN,CAAC;AAGJ,KAAI,CAAC,eAAe,GAClB,OAAM,aAAa,qCAAqC;EACtD,KAAK,eAAe,QAAQ;EAC5B,KAAK;EACL,MAAM;GACJ,aAAa,eAAe,QAAQ;GACpC,GAAG,UAAU,gBAAgB,eAAe,QAAQ,KAAK;GAC1D;EACF,CAAC;CAIJ,MAAM,QAAQ,wBAAwB,OAAO;CAI7C,MAAM,aAAa,MAAM,cAHF,OAAO,OAAO,OAAO,MAAM,CAIjC,aAAa,EAAE,YAAY,eAAe,OAAO,CAAC,CAClE;AAGD,OAAM,cAAc,MAAM,QAAQ,eAAe,EAAE,EAAE,WAAW,MAAM,CAAC,CAAC;AACxE,OAAM,cAAc,UAAU,gBAAgB,WAAW,cAAc,QAAQ,CAAC;AAChF,OAAM,cAAc,UAAU,eAAe,WAAW,aAAa,QAAQ,CAAC;AAE9E,QAAO;EACL,aAAa,WAAW;EACxB,GAAG,UAAU,iBAAiB,WAAW,cAAc;EACvD,aAAa,WAAW;EACxB,OAAO;GACL,MAAM;GACN,KAAK;GACN;EACF"}
|
package/dist/exports/index.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import "../config-loader-
|
|
1
|
+
import "../config-loader-BJ8HsEdA.mjs";
|
|
2
|
+
import "../client-BSZKpZTF.mjs";
|
|
3
|
+
import "../result-handler-BZPY7HX4.mjs";
|
|
2
4
|
import { createContractEmitCommand } from "../commands/contract-emit.mjs";
|
|
3
5
|
import { existsSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
6
|
import { join } from "node:path";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["value","disallowedImports: string[]","contract: unknown"],"sources":["../../src/load-ts-contract.ts"],"sourcesContent":["import { existsSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport type { Plugin } from 'esbuild';\nimport { build } from 'esbuild';\n\nexport interface LoadTsContractOptions {\n readonly allowlist?: ReadonlyArray<string>;\n}\n\nconst DEFAULT_ALLOWLIST = ['@prisma-next/*'];\n\nfunction isAllowedImport(importPath: string, allowlist: ReadonlyArray<string>): boolean {\n for (const pattern of allowlist) {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n if (importPath === prefix || importPath.startsWith(`${prefix}/`)) {\n return true;\n }\n } else if (importPath === pattern) {\n return true;\n }\n }\n return false;\n}\n\nfunction validatePurity(value: unknown): void {\n if (typeof value !== 'object' || value === null) {\n return;\n }\n\n const path = new WeakSet();\n\n function check(value: unknown): void {\n if (value === null || typeof value !== 'object') {\n return;\n }\n\n if (path.has(value)) {\n throw new Error('Contract export contains circular references');\n }\n path.add(value);\n\n try {\n for (const key in value) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (descriptor && (descriptor.get || descriptor.set)) {\n throw new Error(`Contract export contains getter/setter at key \"${key}\"`);\n }\n if (descriptor && typeof descriptor.value === 'function') {\n throw new Error(`Contract export contains function at key \"${key}\"`);\n }\n check((value as Record<string, unknown>)[key]);\n }\n } finally {\n path.delete(value);\n }\n }\n\n try {\n check(value);\n JSON.stringify(value);\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('getter') || error.message.includes('circular')) {\n throw error;\n }\n throw new Error(`Contract export is not JSON-serializable: ${error.message}`);\n }\n throw new Error('Contract export is not JSON-serializable');\n }\n}\n\nfunction createImportAllowlistPlugin(allowlist: ReadonlyArray<string>, entryPath: string): Plugin {\n return {\n name: 'import-allowlist',\n setup(build) {\n build.onResolve({ filter: /.*/ }, (args) => {\n if (args.kind === 'entry-point') {\n return undefined;\n }\n if (args.path.startsWith('.') || args.path.startsWith('/')) {\n return undefined;\n }\n const isFromEntryPoint = args.importer === entryPath || args.importer === '<stdin>';\n if (isFromEntryPoint && !isAllowedImport(args.path, allowlist)) {\n return {\n path: args.path,\n external: true,\n };\n }\n return undefined;\n });\n },\n };\n}\n\n/**\n * Loads a contract from a TypeScript file and returns it as ContractIR.\n *\n * **Responsibility: Parsing Only**\n * This function loads and parses a TypeScript contract file. It does NOT normalize the contract.\n * The contract should already be normalized if it was built using the contract builder.\n *\n * Normalization must happen in the contract builder when the contract is created.\n * This function only validates that the contract is JSON-serializable and returns it as-is.\n *\n * @param entryPath - Path to the TypeScript contract file\n * @param options - Optional configuration (import allowlist)\n * @returns The contract as ContractIR (should already be normalized)\n * @throws Error if the contract cannot be loaded or is not JSON-serializable\n */\nexport async function loadContractFromTs(\n entryPath: string,\n options?: LoadTsContractOptions,\n): Promise<ContractIR> {\n const allowlist = options?.allowlist ?? DEFAULT_ALLOWLIST;\n\n if (!existsSync(entryPath)) {\n throw new Error(`Contract file not found: ${entryPath}`);\n }\n\n const tempFile = join(\n tmpdir(),\n `prisma-next-contract-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`,\n );\n\n try {\n const result = await build({\n entryPoints: [entryPath],\n bundle: true,\n format: 'esm',\n platform: 'node',\n target: 'es2022',\n outfile: tempFile,\n write: false,\n metafile: true,\n plugins: [createImportAllowlistPlugin(allowlist, entryPath)],\n logLevel: 'error',\n });\n\n if (result.errors.length > 0) {\n const errorMessages = result.errors.map((e: { text: string }) => e.text).join('\\n');\n throw new Error(`Failed to bundle contract file: ${errorMessages}`);\n }\n\n if (!result.outputFiles || result.outputFiles.length === 0) {\n throw new Error('No output files generated from bundling');\n }\n\n const disallowedImports: string[] = [];\n if (result.metafile) {\n const inputs = result.metafile.inputs;\n for (const [, inputData] of Object.entries(inputs)) {\n const imports =\n (inputData as { imports?: Array<{ path: string; external?: boolean }> }).imports || [];\n for (const imp of imports) {\n if (\n imp.external &&\n !imp.path.startsWith('.') &&\n !imp.path.startsWith('/') &&\n !isAllowedImport(imp.path, allowlist)\n ) {\n disallowedImports.push(imp.path);\n }\n }\n }\n }\n\n if (disallowedImports.length > 0) {\n throw new Error(\n `Disallowed imports detected. Only imports matching the allowlist are permitted:\\n Allowlist: ${allowlist.join(', ')}\\n Disallowed imports: ${disallowedImports.join(', ')}\\n\\nOnly @prisma-next/* packages are allowed in contract files.`,\n );\n }\n\n const bundleContent = result.outputFiles[0]?.text;\n if (bundleContent === undefined) {\n throw new Error('Bundle content is undefined');\n }\n writeFileSync(tempFile, bundleContent, 'utf-8');\n\n const module = (await import(`file://${tempFile}`)) as {\n default?: unknown;\n contract?: unknown;\n };\n unlinkSync(tempFile);\n\n let contract: unknown;\n\n if (module.default !== undefined) {\n contract = module.default;\n } else if (module.contract !== undefined) {\n contract = module.contract;\n } else {\n throw new Error(\n `Contract file must export a contract as default export or named export 'contract'. Found exports: ${Object.keys(module as Record<string, unknown>).join(', ') || 'none'}`,\n );\n }\n\n if (typeof contract !== 'object' || contract === null) {\n throw new Error(`Contract export must be an object, got ${typeof contract}`);\n }\n\n validatePurity(contract);\n\n return contract as ContractIR;\n } catch (error) {\n try {\n if (tempFile) {\n unlinkSync(tempFile);\n }\n } catch {\n // Ignore cleanup errors\n }\n\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Failed to load contract from ${entryPath}: ${String(error)}`);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["value","disallowedImports: string[]","contract: unknown"],"sources":["../../src/load-ts-contract.ts"],"sourcesContent":["import { existsSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { ContractIR } from '@prisma-next/contract/ir';\nimport type { Plugin } from 'esbuild';\nimport { build } from 'esbuild';\n\nexport interface LoadTsContractOptions {\n readonly allowlist?: ReadonlyArray<string>;\n}\n\nconst DEFAULT_ALLOWLIST = ['@prisma-next/*'];\n\nfunction isAllowedImport(importPath: string, allowlist: ReadonlyArray<string>): boolean {\n for (const pattern of allowlist) {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n if (importPath === prefix || importPath.startsWith(`${prefix}/`)) {\n return true;\n }\n } else if (importPath === pattern) {\n return true;\n }\n }\n return false;\n}\n\nfunction validatePurity(value: unknown): void {\n if (typeof value !== 'object' || value === null) {\n return;\n }\n\n const path = new WeakSet();\n\n function check(value: unknown): void {\n if (value === null || typeof value !== 'object') {\n return;\n }\n\n if (path.has(value)) {\n throw new Error('Contract export contains circular references');\n }\n path.add(value);\n\n try {\n for (const key in value) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (descriptor && (descriptor.get || descriptor.set)) {\n throw new Error(`Contract export contains getter/setter at key \"${key}\"`);\n }\n if (descriptor && typeof descriptor.value === 'function') {\n throw new Error(`Contract export contains function at key \"${key}\"`);\n }\n check((value as Record<string, unknown>)[key]);\n }\n } finally {\n path.delete(value);\n }\n }\n\n try {\n check(value);\n JSON.stringify(value);\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('getter') || error.message.includes('circular')) {\n throw error;\n }\n throw new Error(`Contract export is not JSON-serializable: ${error.message}`);\n }\n throw new Error('Contract export is not JSON-serializable');\n }\n}\n\nfunction createImportAllowlistPlugin(allowlist: ReadonlyArray<string>, entryPath: string): Plugin {\n return {\n name: 'import-allowlist',\n setup(build) {\n build.onResolve({ filter: /.*/ }, (args) => {\n if (args.kind === 'entry-point') {\n return undefined;\n }\n if (args.path.startsWith('.') || args.path.startsWith('/')) {\n return undefined;\n }\n const isFromEntryPoint = args.importer === entryPath || args.importer === '<stdin>';\n if (isFromEntryPoint && !isAllowedImport(args.path, allowlist)) {\n return {\n path: args.path,\n external: true,\n };\n }\n return undefined;\n });\n },\n };\n}\n\n/**\n * Loads a contract from a TypeScript file and returns it as ContractIR.\n *\n * **Responsibility: Parsing Only**\n * This function loads and parses a TypeScript contract file. It does NOT normalize the contract.\n * The contract should already be normalized if it was built using the contract builder.\n *\n * Normalization must happen in the contract builder when the contract is created.\n * This function only validates that the contract is JSON-serializable and returns it as-is.\n *\n * @param entryPath - Path to the TypeScript contract file\n * @param options - Optional configuration (import allowlist)\n * @returns The contract as ContractIR (should already be normalized)\n * @throws Error if the contract cannot be loaded or is not JSON-serializable\n */\nexport async function loadContractFromTs(\n entryPath: string,\n options?: LoadTsContractOptions,\n): Promise<ContractIR> {\n const allowlist = options?.allowlist ?? DEFAULT_ALLOWLIST;\n\n if (!existsSync(entryPath)) {\n throw new Error(`Contract file not found: ${entryPath}`);\n }\n\n const tempFile = join(\n tmpdir(),\n `prisma-next-contract-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`,\n );\n\n try {\n const result = await build({\n entryPoints: [entryPath],\n bundle: true,\n format: 'esm',\n platform: 'node',\n target: 'es2022',\n outfile: tempFile,\n write: false,\n metafile: true,\n plugins: [createImportAllowlistPlugin(allowlist, entryPath)],\n logLevel: 'error',\n });\n\n if (result.errors.length > 0) {\n const errorMessages = result.errors.map((e: { text: string }) => e.text).join('\\n');\n throw new Error(`Failed to bundle contract file: ${errorMessages}`);\n }\n\n if (!result.outputFiles || result.outputFiles.length === 0) {\n throw new Error('No output files generated from bundling');\n }\n\n const disallowedImports: string[] = [];\n if (result.metafile) {\n const inputs = result.metafile.inputs;\n for (const [, inputData] of Object.entries(inputs)) {\n const imports =\n (inputData as { imports?: Array<{ path: string; external?: boolean }> }).imports || [];\n for (const imp of imports) {\n if (\n imp.external &&\n !imp.path.startsWith('.') &&\n !imp.path.startsWith('/') &&\n !isAllowedImport(imp.path, allowlist)\n ) {\n disallowedImports.push(imp.path);\n }\n }\n }\n }\n\n if (disallowedImports.length > 0) {\n throw new Error(\n `Disallowed imports detected. Only imports matching the allowlist are permitted:\\n Allowlist: ${allowlist.join(', ')}\\n Disallowed imports: ${disallowedImports.join(', ')}\\n\\nOnly @prisma-next/* packages are allowed in contract files.`,\n );\n }\n\n const bundleContent = result.outputFiles[0]?.text;\n if (bundleContent === undefined) {\n throw new Error('Bundle content is undefined');\n }\n writeFileSync(tempFile, bundleContent, 'utf-8');\n\n const module = (await import(`file://${tempFile}`)) as {\n default?: unknown;\n contract?: unknown;\n };\n unlinkSync(tempFile);\n\n let contract: unknown;\n\n if (module.default !== undefined) {\n contract = module.default;\n } else if (module.contract !== undefined) {\n contract = module.contract;\n } else {\n throw new Error(\n `Contract file must export a contract as default export or named export 'contract'. Found exports: ${Object.keys(module as Record<string, unknown>).join(', ') || 'none'}`,\n );\n }\n\n if (typeof contract !== 'object' || contract === null) {\n throw new Error(`Contract export must be an object, got ${typeof contract}`);\n }\n\n validatePurity(contract);\n\n return contract as ContractIR;\n } catch (error) {\n try {\n if (tempFile) {\n unlinkSync(tempFile);\n }\n } catch {\n // Ignore cleanup errors\n }\n\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Failed to load contract from ${entryPath}: ${String(error)}`);\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/cli",
|
|
3
|
-
"version": "0.3.0-dev.
|
|
3
|
+
"version": "0.3.0-dev.52",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"files": [
|
|
@@ -21,21 +21,21 @@
|
|
|
21
21
|
"string-width": "^7.2.0",
|
|
22
22
|
"strip-ansi": "^7.1.2",
|
|
23
23
|
"wrap-ansi": "^9.0.2",
|
|
24
|
-
"@prisma-next/contract": "0.3.0-dev.
|
|
25
|
-
"@prisma-next/
|
|
26
|
-
"@prisma-next/
|
|
27
|
-
"@prisma-next/utils": "0.3.0-dev.
|
|
24
|
+
"@prisma-next/contract": "0.3.0-dev.52",
|
|
25
|
+
"@prisma-next/core-control-plane": "0.3.0-dev.52",
|
|
26
|
+
"@prisma-next/emitter": "0.3.0-dev.52",
|
|
27
|
+
"@prisma-next/utils": "0.3.0-dev.52"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "24.10.4",
|
|
31
31
|
"tsdown": "0.18.4",
|
|
32
32
|
"typescript": "5.9.3",
|
|
33
33
|
"vitest": "4.0.17",
|
|
34
|
-
"@prisma-next/sql-contract": "0.3.0-dev.
|
|
35
|
-
"@prisma-next/sql-contract-emitter": "0.3.0-dev.
|
|
36
|
-
"@prisma-next/sql-contract-ts": "0.3.0-dev.
|
|
37
|
-
"@prisma-next/sql-operations": "0.3.0-dev.
|
|
38
|
-
"@prisma-next/sql-runtime": "0.3.0-dev.
|
|
34
|
+
"@prisma-next/sql-contract": "0.3.0-dev.52",
|
|
35
|
+
"@prisma-next/sql-contract-emitter": "0.3.0-dev.52",
|
|
36
|
+
"@prisma-next/sql-contract-ts": "0.3.0-dev.52",
|
|
37
|
+
"@prisma-next/sql-operations": "0.3.0-dev.52",
|
|
38
|
+
"@prisma-next/sql-runtime": "0.3.0-dev.52",
|
|
39
39
|
"@prisma-next/test-utils": "0.0.1",
|
|
40
40
|
"@prisma-next/tsconfig": "0.0.0",
|
|
41
41
|
"@prisma-next/tsdown": "0.0.0"
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, relative, resolve } from 'node:path';
|
|
3
2
|
import { errorContractConfigMissing } from '@prisma-next/core-control-plane/errors';
|
|
4
3
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
5
4
|
import { Command } from 'commander';
|
|
5
|
+
import { dirname, isAbsolute, join, relative, resolve } from 'pathe';
|
|
6
6
|
import { loadConfig } from '../config-loader';
|
|
7
7
|
import { createControlClient } from '../control-api/client';
|
|
8
|
-
import type {
|
|
8
|
+
import type { EmitFailure } from '../control-api/types';
|
|
9
9
|
import { CliStructuredError, errorRuntime, errorUnexpected } from '../utils/cli-errors';
|
|
10
10
|
import { setCommandDescriptions } from '../utils/command-helpers';
|
|
11
11
|
import { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';
|
|
@@ -34,14 +34,34 @@ interface ContractEmitOptions {
|
|
|
34
34
|
readonly 'no-color'?: boolean;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
function mapDiagnosticsToIssues(
|
|
38
|
+
failure: EmitFailure,
|
|
39
|
+
): ReadonlyArray<{ kind: string; message: string }> {
|
|
40
|
+
const diagnostics = failure.diagnostics?.diagnostics ?? [];
|
|
41
|
+
return diagnostics.map((diagnostic) => {
|
|
42
|
+
const location =
|
|
43
|
+
diagnostic.sourceId && diagnostic.span
|
|
44
|
+
? ` (${diagnostic.sourceId}:${diagnostic.span.start.line}:${diagnostic.span.start.column})`
|
|
45
|
+
: diagnostic.sourceId
|
|
46
|
+
? ` (${diagnostic.sourceId})`
|
|
47
|
+
: '';
|
|
48
|
+
return {
|
|
49
|
+
kind: diagnostic.code,
|
|
50
|
+
message: `${diagnostic.message}${location}`,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
37
55
|
/**
|
|
38
56
|
* Maps an EmitFailure to a CliStructuredError for consistent error handling.
|
|
39
57
|
*/
|
|
40
58
|
function mapEmitFailure(failure: EmitFailure): CliStructuredError {
|
|
41
59
|
if (failure.code === 'CONTRACT_SOURCE_INVALID') {
|
|
60
|
+
const issues = mapDiagnosticsToIssues(failure);
|
|
42
61
|
return errorRuntime(failure.summary, {
|
|
43
|
-
why: failure.why ?? 'Contract source
|
|
44
|
-
fix: 'Check your contract source
|
|
62
|
+
why: failure.why ?? 'Contract source provider failed',
|
|
63
|
+
fix: 'Check your contract source provider in prisma-next.config.ts and ensure it returns Result<ContractIR, Diagnostics>',
|
|
64
|
+
...(issues.length > 0 ? { meta: { issues } } : {}),
|
|
45
65
|
});
|
|
46
66
|
}
|
|
47
67
|
|
|
@@ -85,7 +105,7 @@ async function executeContractEmitCommand(
|
|
|
85
105
|
if (!config.contract) {
|
|
86
106
|
return notOk(
|
|
87
107
|
errorContractConfigMissing({
|
|
88
|
-
why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output:
|
|
108
|
+
why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',
|
|
89
109
|
}),
|
|
90
110
|
);
|
|
91
111
|
}
|
|
@@ -108,7 +128,10 @@ async function executeContractEmitCommand(
|
|
|
108
128
|
}),
|
|
109
129
|
);
|
|
110
130
|
}
|
|
111
|
-
const
|
|
131
|
+
const configDir = options.config ? dirname(resolve(options.config)) : process.cwd();
|
|
132
|
+
const outputJsonPath = isAbsolute(contractConfig.output)
|
|
133
|
+
? contractConfig.output
|
|
134
|
+
: join(configDir, contractConfig.output);
|
|
112
135
|
// Colocate .d.ts with .json (contract.json → contract.d.ts)
|
|
113
136
|
const outputDtsPath = `${outputJsonPath.slice(0, -5)}.d.ts`;
|
|
114
137
|
|
|
@@ -123,7 +146,7 @@ async function executeContractEmitCommand(
|
|
|
123
146
|
const typesPath = relative(process.cwd(), outputDtsPath);
|
|
124
147
|
const header = formatStyledHeader({
|
|
125
148
|
command: 'contract emit',
|
|
126
|
-
description: '
|
|
149
|
+
description: 'Emit your contract artifacts',
|
|
127
150
|
url: 'https://pris.ly/contract-emit',
|
|
128
151
|
details: [
|
|
129
152
|
{ label: 'config', value: configPath },
|
|
@@ -147,17 +170,10 @@ async function executeContractEmitCommand(
|
|
|
147
170
|
const onProgress = createProgressAdapter({ flags });
|
|
148
171
|
|
|
149
172
|
try {
|
|
150
|
-
// Convert user config source to discriminated union
|
|
151
|
-
// Type assertion is safe: we check typeof to determine if it's a function
|
|
152
|
-
const source: EmitContractSource =
|
|
153
|
-
typeof contractConfig.source === 'function'
|
|
154
|
-
? { kind: 'loader', load: contractConfig.source as () => unknown | Promise<unknown> }
|
|
155
|
-
: { kind: 'value', value: contractConfig.source };
|
|
156
|
-
|
|
157
173
|
// Call emit with progress callback
|
|
158
174
|
const result = await client.emit({
|
|
159
175
|
contractConfig: {
|
|
160
|
-
source,
|
|
176
|
+
sourceProvider: contractConfig.source,
|
|
161
177
|
output: outputJsonPath,
|
|
162
178
|
},
|
|
163
179
|
onProgress,
|
|
@@ -216,7 +232,7 @@ export function createContractEmitCommand(): Command {
|
|
|
216
232
|
const command = new Command('emit');
|
|
217
233
|
setCommandDescriptions(
|
|
218
234
|
command,
|
|
219
|
-
'
|
|
235
|
+
'Emit your contract artifacts',
|
|
220
236
|
'Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\n' +
|
|
221
237
|
'contract.d.ts. The contract.json contains the canonical contract structure, and\n' +
|
|
222
238
|
'contract.d.ts provides TypeScript types for type-safe query building.',
|