@prisma-next/cli 0.1.0-pr.49.4 → 0.1.0-pr.49.5
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 +14 -13
- package/dist/{chunk-4W62XWA4.js → chunk-VWAVGWUP.js} +2 -2
- package/dist/chunk-VWAVGWUP.js.map +1 -0
- package/dist/chunk-YDE4ILKH.js +55 -0
- package/dist/chunk-YDE4ILKH.js.map +1 -0
- package/dist/{chunk-JLA4BH74.js → chunk-ZKEJZ3NU.js} +2 -1
- package/dist/cli.js +99 -38
- package/dist/cli.js.map +1 -1
- package/dist/commands/contract-emit.js +2 -2
- package/dist/commands/db-init.js +16 -6
- package/dist/commands/db-init.js.map +1 -1
- package/dist/commands/db-introspect.js +6 -8
- package/dist/commands/db-introspect.js.map +1 -1
- package/dist/commands/db-schema-verify.js +14 -5
- package/dist/commands/db-schema-verify.js.map +1 -1
- package/dist/commands/db-sign.js +25 -20
- package/dist/commands/db-sign.js.map +1 -1
- package/dist/commands/db-verify.js +3 -4
- package/dist/commands/db-verify.js.map +1 -1
- package/dist/index.js +2 -2
- package/package.json +11 -11
- package/dist/chunk-4W62XWA4.js.map +0 -1
- /package/dist/{chunk-JLA4BH74.js.map → chunk-ZKEJZ3NU.js.map} +0 -0
package/README.md
CHANGED
|
@@ -221,20 +221,21 @@ Failure:
|
|
|
221
221
|
|
|
222
222
|
**Family Requirements:**
|
|
223
223
|
|
|
224
|
-
The family must provide a `create()` method in the family descriptor that returns a `
|
|
224
|
+
The family must provide a `create()` method in the family descriptor that returns a `ControlFamilyInstance` with a `verify()` method:
|
|
225
225
|
|
|
226
226
|
```typescript
|
|
227
|
-
interface
|
|
227
|
+
interface ControlFamilyDescriptor {
|
|
228
228
|
create(options: {
|
|
229
|
-
target:
|
|
230
|
-
adapter:
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
target: ControlTargetDescriptor;
|
|
230
|
+
adapter: ControlAdapterDescriptor;
|
|
231
|
+
driver: ControlDriverDescriptor;
|
|
232
|
+
extensions: ControlExtensionDescriptor[];
|
|
233
|
+
}): ControlFamilyInstance;
|
|
233
234
|
}
|
|
234
235
|
|
|
235
|
-
interface
|
|
236
|
+
interface ControlFamilyInstance {
|
|
236
237
|
verify(options: {
|
|
237
|
-
driver:
|
|
238
|
+
driver: ControlDriverInstance;
|
|
238
239
|
contractIR: ContractIR;
|
|
239
240
|
expectedTargetId: string;
|
|
240
241
|
contractPath: string;
|
|
@@ -377,11 +378,11 @@ sql schema (tables: 2)
|
|
|
377
378
|
**Family Requirements:**
|
|
378
379
|
|
|
379
380
|
The family must provide:
|
|
380
|
-
1. A `create()` method in the family descriptor that returns a `
|
|
381
|
-
2. An optional `toSchemaView()` method on the `
|
|
381
|
+
1. A `create()` method in the family descriptor that returns a `ControlFamilyInstance` with an `introspect()` method
|
|
382
|
+
2. An optional `toSchemaView()` method on the `ControlFamilyInstance` to project family-specific schema IR into `CoreSchemaView`
|
|
382
383
|
|
|
383
384
|
```typescript
|
|
384
|
-
interface
|
|
385
|
+
interface ControlFamilyInstance {
|
|
385
386
|
introspect(options: {
|
|
386
387
|
driver: ControlDriverInstance;
|
|
387
388
|
contractIR?: ContractIR;
|
|
@@ -583,10 +584,10 @@ The `db sign` command is idempotent and safe to run multiple times:
|
|
|
583
584
|
- Safe to run in CI/deployment pipelines
|
|
584
585
|
|
|
585
586
|
**Family Requirements:**
|
|
586
|
-
The family must provide a `create()` method in the family descriptor that returns a `
|
|
587
|
+
The family must provide a `create()` method in the family descriptor that returns a `ControlFamilyInstance` with `schemaVerify()` and `sign()` methods:
|
|
587
588
|
|
|
588
589
|
```typescript
|
|
589
|
-
interface
|
|
590
|
+
interface ControlFamilyInstance {
|
|
590
591
|
schemaVerify(options: {
|
|
591
592
|
driver: ControlDriverInstance;
|
|
592
593
|
contractIR: ContractIR;
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
performAction,
|
|
10
10
|
setCommandDescriptions,
|
|
11
11
|
withSpinner
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZKEJZ3NU.js";
|
|
13
13
|
import {
|
|
14
14
|
loadConfig
|
|
15
15
|
} from "./chunk-HWYQOCAJ.js";
|
|
@@ -131,4 +131,4 @@ function createContractEmitCommand() {
|
|
|
131
131
|
export {
|
|
132
132
|
createContractEmitCommand
|
|
133
133
|
};
|
|
134
|
-
//# sourceMappingURL=chunk-
|
|
134
|
+
//# sourceMappingURL=chunk-VWAVGWUP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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 { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\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 { performAction } from '../utils/result';\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 // Create family instance (assembles operation registry, type imports, extension IDs)\n // Note: emit command doesn't need driver, but ControlFamilyDescriptor.create() requires it\n // We'll need to provide a minimal driver descriptor or make driver optional for emit\n // For now, we'll require driver to be present in config even for emit\n if (!config.driver) {\n throw errorContractConfigMissing({\n why: 'Config.driver is required. Even though emit does not use the driver, it is required by ControlFamilyDescriptor.create()',\n });\n }\n const familyInstance = config.family.create({\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensions: config.extensions ?? [],\n });\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":";;;;;;;;;;;;;;;;;AAAA,SAAS,WAAW,qBAAqB;AACzC,SAAS,SAAS,UAAU,eAAe;AAC3C,SAAS,kCAAkC;AAC3C,SAAS,eAAe;AA6BjB,SAAS,4BAAqC;AACnD,QAAM,UAAU,IAAI,QAAQ,MAAM;AAClC;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EAGF;AACA,UACG,cAAc;AAAA,IACb,YAAY,CAAC,QAAQ;AACnB,YAAM,QAAQ,iBAAiB,CAAC,CAAC;AACjC,aAAO,kBAAkB,EAAE,SAAS,KAAK,MAAM,CAAC;AAAA,IAClD;AAAA,EACF,CAAC,EACA,OAAO,mBAAmB,+BAA+B,EACzD,OAAO,mBAAmB,qCAAqC,KAAK,EACpE,OAAO,eAAe,yBAAyB,EAC/C,OAAO,iBAAiB,qCAAqC,EAC7D,OAAO,gBAAgB,4CAA4C,EACnE,OAAO,gBAAgB,0BAA0B,EACjD,OAAO,WAAW,oBAAoB,EACtC,OAAO,cAAc,sBAAsB,EAC3C,OAAO,OAAO,YAAiC;AAC9C,UAAM,QAAQ,iBAAiB,OAAO;AAEtC,UAAM,SAAS,MAAM,cAAc,YAAY;AAE7C,YAAM,SAAS,MAAM,WAAW,QAAQ,MAAM;AAG9C,UAAI,CAAC,OAAO,UAAU;AACpB,cAAM,2BAA2B;AAAA,UAC/B,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AAGA,YAAM,iBAAiB,OAAO;AAG9B,UAAI,CAAC,eAAe,UAAU,CAAC,eAAe,OAAO;AACnD,cAAM,2BAA2B;AAAA,UAC/B,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AACA,YAAM,iBAAiB,QAAQ,eAAe,MAAM;AACpD,YAAM,gBAAgB,QAAQ,eAAe,KAAK;AAGlD,UAAI,MAAM,SAAS,YAAY,CAAC,MAAM,OAAO;AAE3C,cAAM,aAAa,QAAQ,SACvB,SAAS,QAAQ,IAAI,GAAG,QAAQ,QAAQ,MAAM,CAAC,IAC/C;AAEJ,cAAM,eAAe,SAAS,QAAQ,IAAI,GAAG,cAAc;AAC3D,cAAM,YAAY,SAAS,QAAQ,IAAI,GAAG,aAAa;AACvD,cAAM,SAAS,mBAAmB;AAAA,UAChC,SAAS;AAAA,UACT,aAAa;AAAA,UACb,KAAK;AAAA,UACL,SAAS;AAAA,YACP,EAAE,OAAO,UAAU,OAAO,WAAW;AAAA,YACrC,EAAE,OAAO,YAAY,OAAO,aAAa;AAAA,YACzC,EAAE,OAAO,SAAS,OAAO,UAAU;AAAA,UACrC;AAAA,UACA;AAAA,QACF,CAAC;AACD,gBAAQ,IAAI,MAAM;AAAA,MACpB;AAMA,UAAI,CAAC,OAAO,QAAQ;AAClB,cAAM,2BAA2B;AAAA,UAC/B,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AACA,YAAM,iBAAiB,OAAO,OAAO,OAAO;AAAA,QAC1C,QAAQ,OAAO;AAAA,QACf,SAAS,OAAO;AAAA,QAChB,QAAQ,OAAO;AAAA,QACf,YAAY,OAAO,cAAc,CAAC;AAAA,MACpC,CAAC;AAGD,UAAI;AACJ,UAAI,OAAO,eAAe,WAAW,YAAY;AAC/C,sBAAc,MAAM,eAAe,OAAO;AAAA,MAC5C,OAAO;AACL,sBAAc,eAAe;AAAA,MAC/B;AAGA,YAAM,aAAa,MAAM;AAAA,QACvB,MAAM,eAAe,aAAa,EAAE,YAAY,YAAY,CAAC;AAAA,QAC7D;AAAA,UACE,SAAS;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAGA,gBAAU,QAAQ,cAAc,GAAG,EAAE,WAAW,KAAK,CAAC;AACtD,gBAAU,QAAQ,aAAa,GAAG,EAAE,WAAW,KAAK,CAAC;AAGrD,oBAAc,gBAAgB,WAAW,cAAc,OAAO;AAC9D,oBAAc,eAAe,WAAW,aAAa,OAAO;AAG5D,UAAI,CAAC,MAAM,SAAS,MAAM,SAAS,YAAY,QAAQ,OAAO,OAAO;AACnE,gBAAQ,IAAI,EAAE;AAAA,MAChB;AAGA,aAAO;AAAA,QACL,UAAU,WAAW;AAAA,QACrB,aAAa,WAAW;AAAA,QACxB,QAAQ,QAAQ,cAAc;AAAA,QAC9B,OAAO;AAAA,UACL,MAAM;AAAA,UACN,KAAK;AAAA,QACP;AAAA,QACA,SAAS;AAAA,UACP,OAAO;AAAA;AAAA,QACT;AAAA,MACF;AAAA,IACF,CAAC;AAGD,UAAM,WAAW,aAAa,QAAQ,OAAO,CAAC,eAAe;AAE3D,UAAI,MAAM,SAAS,UAAU;AAE3B,gBAAQ,IAAI,eAAe,UAAU,CAAC;AAAA,MACxC,OAAO;AAEL,cAAM,SAAS,iBAAiB,YAAY,KAAK;AACjD,YAAI,QAAQ;AACV,kBAAQ,IAAI,MAAM;AAAA,QACpB;AAEA,YAAI,CAAC,MAAM,OAAO;AAChB,kBAAQ,IAAI,qBAAqB,KAAK,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,QAAQ;AAAA,EACvB,CAAC;AAEH,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
errorConfigValidation
|
|
3
|
+
} from "./chunk-ZKEJZ3NU.js";
|
|
4
|
+
|
|
5
|
+
// src/utils/framework-components.ts
|
|
6
|
+
function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId, frameworkComponents) {
|
|
7
|
+
for (let i = 0; i < frameworkComponents.length; i++) {
|
|
8
|
+
const component = frameworkComponents[i];
|
|
9
|
+
if (typeof component !== "object" || component === null) {
|
|
10
|
+
throw errorConfigValidation("frameworkComponents[]", {
|
|
11
|
+
why: `Framework component at index ${i} must be an object`
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const record = component;
|
|
15
|
+
if (!Object.hasOwn(record, "kind")) {
|
|
16
|
+
throw errorConfigValidation("frameworkComponents[].kind", {
|
|
17
|
+
why: `Framework component at index ${i} must have 'kind' property`
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
const kind = record["kind"];
|
|
21
|
+
if (kind !== "target" && kind !== "adapter" && kind !== "extension" && kind !== "driver") {
|
|
22
|
+
throw errorConfigValidation("frameworkComponents[].kind", {
|
|
23
|
+
why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')`
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (!Object.hasOwn(record, "familyId")) {
|
|
27
|
+
throw errorConfigValidation("frameworkComponents[].familyId", {
|
|
28
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property`
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const familyId = record["familyId"];
|
|
32
|
+
if (familyId !== expectedFamilyId) {
|
|
33
|
+
throw errorConfigValidation("frameworkComponents[].familyId", {
|
|
34
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'`
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
if (!Object.hasOwn(record, "targetId")) {
|
|
38
|
+
throw errorConfigValidation("frameworkComponents[].targetId", {
|
|
39
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property`
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const targetId = record["targetId"];
|
|
43
|
+
if (targetId !== expectedTargetId) {
|
|
44
|
+
throw errorConfigValidation("frameworkComponents[].targetId", {
|
|
45
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'`
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return frameworkComponents;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
assertFrameworkComponentsCompatible
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=chunk-YDE4ILKH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/framework-components.ts"],"sourcesContent":["import type { TargetBoundComponentDescriptor } from '@prisma-next/contract/framework-components';\nimport { errorConfigValidation } 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.extensions ?? [])];\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"],"mappings":";;;;;AAqCO,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;","names":[]}
|
|
@@ -961,6 +961,7 @@ export {
|
|
|
961
961
|
formatStyledHeader,
|
|
962
962
|
formatSuccessMessage,
|
|
963
963
|
formatCommandHelp,
|
|
964
|
+
errorConfigValidation,
|
|
964
965
|
errorDatabaseUrlRequired,
|
|
965
966
|
errorDriverRequired,
|
|
966
967
|
errorFileNotFound,
|
|
@@ -972,4 +973,4 @@ export {
|
|
|
972
973
|
handleResult,
|
|
973
974
|
withSpinner
|
|
974
975
|
};
|
|
975
|
-
//# sourceMappingURL=chunk-
|
|
976
|
+
//# sourceMappingURL=chunk-ZKEJZ3NU.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1176,6 +1176,55 @@ function createContractEmitCommand() {
|
|
|
1176
1176
|
import { readFile } from "fs/promises";
|
|
1177
1177
|
import { relative as relative3, resolve as resolve3 } from "path";
|
|
1178
1178
|
import { Command as Command2 } from "commander";
|
|
1179
|
+
|
|
1180
|
+
// src/utils/framework-components.ts
|
|
1181
|
+
function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId, frameworkComponents) {
|
|
1182
|
+
for (let i = 0; i < frameworkComponents.length; i++) {
|
|
1183
|
+
const component = frameworkComponents[i];
|
|
1184
|
+
if (typeof component !== "object" || component === null) {
|
|
1185
|
+
throw errorConfigValidation("frameworkComponents[]", {
|
|
1186
|
+
why: `Framework component at index ${i} must be an object`
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
const record = component;
|
|
1190
|
+
if (!Object.hasOwn(record, "kind")) {
|
|
1191
|
+
throw errorConfigValidation("frameworkComponents[].kind", {
|
|
1192
|
+
why: `Framework component at index ${i} must have 'kind' property`
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
const kind = record["kind"];
|
|
1196
|
+
if (kind !== "target" && kind !== "adapter" && kind !== "extension" && kind !== "driver") {
|
|
1197
|
+
throw errorConfigValidation("frameworkComponents[].kind", {
|
|
1198
|
+
why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')`
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
if (!Object.hasOwn(record, "familyId")) {
|
|
1202
|
+
throw errorConfigValidation("frameworkComponents[].familyId", {
|
|
1203
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property`
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
const familyId = record["familyId"];
|
|
1207
|
+
if (familyId !== expectedFamilyId) {
|
|
1208
|
+
throw errorConfigValidation("frameworkComponents[].familyId", {
|
|
1209
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'`
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
if (!Object.hasOwn(record, "targetId")) {
|
|
1213
|
+
throw errorConfigValidation("frameworkComponents[].targetId", {
|
|
1214
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property`
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
const targetId = record["targetId"];
|
|
1218
|
+
if (targetId !== expectedTargetId) {
|
|
1219
|
+
throw errorConfigValidation("frameworkComponents[].targetId", {
|
|
1220
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'`
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return frameworkComponents;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// src/commands/db-init.ts
|
|
1179
1228
|
function createDbInitCommand() {
|
|
1180
1229
|
const command = new Command2("init");
|
|
1181
1230
|
setCommandDescriptions(
|
|
@@ -1262,11 +1311,16 @@ function createDbInitCommand() {
|
|
|
1262
1311
|
driver: driverDescriptor,
|
|
1263
1312
|
extensions: config.extensions ?? []
|
|
1264
1313
|
});
|
|
1265
|
-
const
|
|
1266
|
-
const
|
|
1314
|
+
const rawComponents = [config.target, config.adapter, ...config.extensions ?? []];
|
|
1315
|
+
const frameworkComponents = assertFrameworkComponentsCompatible(
|
|
1316
|
+
config.family.familyId,
|
|
1317
|
+
config.target.targetId,
|
|
1318
|
+
rawComponents
|
|
1319
|
+
);
|
|
1320
|
+
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
1267
1321
|
const planner = migrations.createPlanner(familyInstance);
|
|
1268
1322
|
const runner = migrations.createRunner(familyInstance);
|
|
1269
|
-
const schemaIR = await withSpinner(() =>
|
|
1323
|
+
const schemaIR = await withSpinner(() => familyInstance.introspect({ driver }), {
|
|
1270
1324
|
message: "Introspecting database schema...",
|
|
1271
1325
|
flags
|
|
1272
1326
|
});
|
|
@@ -1275,7 +1329,8 @@ function createDbInitCommand() {
|
|
|
1275
1329
|
async () => planner.plan({
|
|
1276
1330
|
contract: contractIR,
|
|
1277
1331
|
schema: schemaIR,
|
|
1278
|
-
policy
|
|
1332
|
+
policy,
|
|
1333
|
+
frameworkComponents
|
|
1279
1334
|
}),
|
|
1280
1335
|
{
|
|
1281
1336
|
message: "Planning migration...",
|
|
@@ -1319,7 +1374,8 @@ function createDbInitCommand() {
|
|
|
1319
1374
|
driver,
|
|
1320
1375
|
destinationContract: contractIR,
|
|
1321
1376
|
policy,
|
|
1322
|
-
callbacks
|
|
1377
|
+
callbacks,
|
|
1378
|
+
frameworkComponents
|
|
1323
1379
|
}),
|
|
1324
1380
|
{
|
|
1325
1381
|
message: "Applying migration plan...",
|
|
@@ -1409,8 +1465,7 @@ function createDbIntrospectCommand() {
|
|
|
1409
1465
|
const contractPath = resolve4(config.contract.output);
|
|
1410
1466
|
try {
|
|
1411
1467
|
const contractJsonContent = await readFile2(contractPath, "utf-8");
|
|
1412
|
-
|
|
1413
|
-
contractIR = contractJson;
|
|
1468
|
+
contractIR = JSON.parse(contractJsonContent);
|
|
1414
1469
|
} catch (error) {
|
|
1415
1470
|
if (error instanceof Error && error.code !== "ENOENT") {
|
|
1416
1471
|
throw errorUnexpected3(error.message, {
|
|
@@ -1458,14 +1513,13 @@ function createDbIntrospectCommand() {
|
|
|
1458
1513
|
driver: driverDescriptor,
|
|
1459
1514
|
extensions: config.extensions ?? []
|
|
1460
1515
|
});
|
|
1461
|
-
const typedFamilyInstance = familyInstance;
|
|
1462
1516
|
if (contractIR) {
|
|
1463
|
-
contractIR =
|
|
1517
|
+
contractIR = familyInstance.validateContractIR(contractIR);
|
|
1464
1518
|
}
|
|
1465
1519
|
let schemaIR;
|
|
1466
1520
|
try {
|
|
1467
1521
|
schemaIR = await withSpinner(
|
|
1468
|
-
() =>
|
|
1522
|
+
() => familyInstance.introspect({
|
|
1469
1523
|
driver,
|
|
1470
1524
|
contractIR
|
|
1471
1525
|
}),
|
|
@@ -1480,9 +1534,9 @@ function createDbIntrospectCommand() {
|
|
|
1480
1534
|
});
|
|
1481
1535
|
}
|
|
1482
1536
|
let schemaView;
|
|
1483
|
-
if (
|
|
1537
|
+
if (familyInstance.toSchemaView) {
|
|
1484
1538
|
try {
|
|
1485
|
-
schemaView =
|
|
1539
|
+
schemaView = familyInstance.toSchemaView(schemaIR);
|
|
1486
1540
|
} catch (error) {
|
|
1487
1541
|
if (flags.verbose) {
|
|
1488
1542
|
console.error(
|
|
@@ -1619,17 +1673,23 @@ function createDbSchemaVerifyCommand() {
|
|
|
1619
1673
|
driver: driverDescriptor,
|
|
1620
1674
|
extensions: config.extensions ?? []
|
|
1621
1675
|
});
|
|
1622
|
-
const
|
|
1623
|
-
const
|
|
1676
|
+
const rawComponents = [config.target, config.adapter, ...config.extensions ?? []];
|
|
1677
|
+
const frameworkComponents = assertFrameworkComponentsCompatible(
|
|
1678
|
+
config.family.familyId,
|
|
1679
|
+
config.target.targetId,
|
|
1680
|
+
rawComponents
|
|
1681
|
+
);
|
|
1682
|
+
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
1624
1683
|
let schemaVerifyResult;
|
|
1625
1684
|
try {
|
|
1626
1685
|
schemaVerifyResult = await withSpinner(
|
|
1627
|
-
() =>
|
|
1686
|
+
() => familyInstance.schemaVerify({
|
|
1628
1687
|
driver,
|
|
1629
1688
|
contractIR,
|
|
1630
1689
|
strict: options.strict ?? false,
|
|
1631
1690
|
contractPath: contractPathAbsolute,
|
|
1632
|
-
configPath
|
|
1691
|
+
configPath,
|
|
1692
|
+
frameworkComponents
|
|
1633
1693
|
}),
|
|
1634
1694
|
{
|
|
1635
1695
|
message: "Verifying database schema...",
|
|
@@ -1745,20 +1805,24 @@ function createDbSignCommand() {
|
|
|
1745
1805
|
driver: driverDescriptor,
|
|
1746
1806
|
extensions: config.extensions ?? []
|
|
1747
1807
|
});
|
|
1748
|
-
const
|
|
1749
|
-
const
|
|
1808
|
+
const rawComponents = [config.target, config.adapter, ...config.extensions ?? []];
|
|
1809
|
+
const frameworkComponents = assertFrameworkComponentsCompatible(
|
|
1810
|
+
config.family.familyId,
|
|
1811
|
+
config.target.targetId,
|
|
1812
|
+
rawComponents
|
|
1813
|
+
);
|
|
1814
|
+
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
1750
1815
|
let schemaVerifyResult;
|
|
1751
1816
|
try {
|
|
1752
1817
|
schemaVerifyResult = await withSpinner(
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
},
|
|
1818
|
+
() => familyInstance.schemaVerify({
|
|
1819
|
+
driver,
|
|
1820
|
+
contractIR,
|
|
1821
|
+
strict: false,
|
|
1822
|
+
contractPath: contractPathAbsolute,
|
|
1823
|
+
configPath,
|
|
1824
|
+
frameworkComponents
|
|
1825
|
+
}),
|
|
1762
1826
|
{
|
|
1763
1827
|
message: "Verifying database satisfies contract",
|
|
1764
1828
|
flags
|
|
@@ -1775,14 +1839,12 @@ function createDbSignCommand() {
|
|
|
1775
1839
|
let signResult;
|
|
1776
1840
|
try {
|
|
1777
1841
|
signResult = await withSpinner(
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
});
|
|
1785
|
-
},
|
|
1842
|
+
() => familyInstance.sign({
|
|
1843
|
+
driver,
|
|
1844
|
+
contractIR,
|
|
1845
|
+
contractPath: contractPathAbsolute,
|
|
1846
|
+
configPath
|
|
1847
|
+
}),
|
|
1786
1848
|
{
|
|
1787
1849
|
message: "Signing database...",
|
|
1788
1850
|
flags
|
|
@@ -1917,12 +1979,11 @@ function createDbVerifyCommand() {
|
|
|
1917
1979
|
driver: driverDescriptor,
|
|
1918
1980
|
extensions: config.extensions ?? []
|
|
1919
1981
|
});
|
|
1920
|
-
const
|
|
1921
|
-
const contractIR = typedFamilyInstance.validateContractIR(contractJson);
|
|
1982
|
+
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
1922
1983
|
let verifyResult;
|
|
1923
1984
|
try {
|
|
1924
1985
|
verifyResult = await withSpinner(
|
|
1925
|
-
() =>
|
|
1986
|
+
() => familyInstance.verify({
|
|
1926
1987
|
driver,
|
|
1927
1988
|
contractIR,
|
|
1928
1989
|
expectedTargetId: config.target.targetId,
|