@prisma-next/cli 0.1.0-pr.64.6 → 0.1.0-pr.65.2
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 +4 -5
- package/dist/{chunk-YDE4ILKH.js → chunk-TPVEV7KB.js} +33 -2
- package/dist/chunk-TPVEV7KB.js.map +1 -0
- package/dist/cli.js +67 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/db-init.js +9 -1
- package/dist/commands/db-init.js.map +1 -1
- package/dist/commands/db-introspect.js +12 -1
- package/dist/commands/db-introspect.js.map +1 -1
- package/dist/commands/db-schema-verify.js +9 -1
- package/dist/commands/db-schema-verify.js.map +1 -1
- package/dist/commands/db-sign.js +9 -1
- package/dist/commands/db-sign.js.map +1 -1
- package/dist/commands/db-verify.js +10 -0
- package/dist/commands/db-verify.js.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +1 -7
- package/dist/index.js.map +1 -1
- package/package.json +10 -14
- package/dist/chunk-W5YXBFPY.js +0 -96
- package/dist/chunk-W5YXBFPY.js.map +0 -1
- package/dist/chunk-YDE4ILKH.js.map +0 -1
- package/dist/pack-loading.d.ts +0 -6
- package/dist/pack-loading.js +0 -9
- package/dist/pack-loading.js.map +0 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ Provide a command-line interface that:
|
|
|
19
19
|
- **TS Contract Loading**: Bundle and load TypeScript contract files with import allowlist enforcement
|
|
20
20
|
- **CLI Command Interface**: Parse arguments and route to command handlers using commander
|
|
21
21
|
- **File I/O**: Read TS contracts, write emitted artifacts (`contract.json`, `contract.d.ts`)
|
|
22
|
-
- **Extension Pack
|
|
22
|
+
- **Extension Pack Descriptor Assembly**: Collect adapter and extension descriptors for emission
|
|
23
23
|
- **Help Output Formatting**: Custom styled help output with command trees and formatted descriptions
|
|
24
24
|
- **Config Management**: Load and validate `prisma-next.config.ts` files using Arktype validation
|
|
25
25
|
|
|
@@ -909,8 +909,8 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
|
|
|
909
909
|
- `schemaVerify(options)` - Verifies database schema against contract
|
|
910
910
|
- `introspect(options)` - Introspects database schema
|
|
911
911
|
|
|
912
|
-
###
|
|
913
|
-
- Families
|
|
912
|
+
### Descriptor Declarative Fields
|
|
913
|
+
- Families expose component descriptors (target, adapter, driver, extensions) with declarative metadata (`version`, `capabilities`, `types`, `operations`). CLI consumers import descriptors directly—there is no JSON manifest parsing step.
|
|
914
914
|
|
|
915
915
|
## Dependencies
|
|
916
916
|
|
|
@@ -982,7 +982,6 @@ The CLI package exports several subpaths for different use cases:
|
|
|
982
982
|
|
|
983
983
|
- **`@prisma-next/cli`** (main export): Exports `loadContractFromTs` and `createContractEmitCommand`
|
|
984
984
|
- **`@prisma-next/cli/config-types`**: Exports `defineConfig` and config types
|
|
985
|
-
- **`@prisma-next/cli/pack-loading`**: Exports `loadExtensionPacks` and `loadExtensionPackManifest`
|
|
986
985
|
- **`@prisma-next/cli/commands/db-init`**: Exports `createDbInitCommand`
|
|
987
986
|
- **`@prisma-next/cli/commands/db-introspect`**: Exports `createDbIntrospectCommand`
|
|
988
987
|
- **`@prisma-next/cli/commands/db-schema-verify`**: Exports `createDbSchemaVerifyCommand`
|
|
@@ -991,7 +990,7 @@ The CLI package exports several subpaths for different use cases:
|
|
|
991
990
|
- **`@prisma-next/cli/commands/contract-emit`**: Exports `createContractEmitCommand`
|
|
992
991
|
- **`@prisma-next/cli/config-loader`**: Exports `loadConfig` function
|
|
993
992
|
|
|
994
|
-
**Important**: `loadContractFromTs` is exported from the main package (`@prisma-next/cli`)
|
|
993
|
+
**Important**: `loadContractFromTs` is exported from the main package (`@prisma-next/cli`). See `.cursor/rules/cli-package-exports.mdc` for import patterns.
|
|
995
994
|
|
|
996
995
|
## Package Location
|
|
997
996
|
|
|
@@ -48,8 +48,39 @@ function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId,
|
|
|
48
48
|
}
|
|
49
49
|
return frameworkComponents;
|
|
50
50
|
}
|
|
51
|
+
function assertContractRequirementsSatisfied({
|
|
52
|
+
contract,
|
|
53
|
+
family,
|
|
54
|
+
target,
|
|
55
|
+
adapter,
|
|
56
|
+
extensions
|
|
57
|
+
}) {
|
|
58
|
+
if (contract.targetFamily !== family.familyId) {
|
|
59
|
+
throw errorConfigValidation("contract.targetFamily", {
|
|
60
|
+
why: `Contract was emitted for family '${contract.targetFamily}' but CLI config is wired to '${family.familyId}'.`
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (contract.target !== target.targetId) {
|
|
64
|
+
throw errorConfigValidation("contract.target", {
|
|
65
|
+
why: `Contract target '${contract.target}' does not match CLI target '${target.targetId}'.`
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const providedComponentIds = /* @__PURE__ */ new Set([target.id, adapter.id]);
|
|
69
|
+
for (const extension of extensions ?? []) {
|
|
70
|
+
providedComponentIds.add(extension.id);
|
|
71
|
+
}
|
|
72
|
+
const requiredPacks = contract.extensionPacks ? Object.keys(contract.extensionPacks) : [];
|
|
73
|
+
for (const packId of requiredPacks) {
|
|
74
|
+
if (!providedComponentIds.has(packId)) {
|
|
75
|
+
throw errorConfigValidation("contract.extensionPacks", {
|
|
76
|
+
why: `Contract requires extension pack '${packId}', but CLI config does not provide a matching descriptor.`
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
51
81
|
|
|
52
82
|
export {
|
|
53
|
-
assertFrameworkComponentsCompatible
|
|
83
|
+
assertFrameworkComponentsCompatible,
|
|
84
|
+
assertContractRequirementsSatisfied
|
|
54
85
|
};
|
|
55
|
-
//# sourceMappingURL=chunk-
|
|
86
|
+
//# sourceMappingURL=chunk-TPVEV7KB.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 type { ContractIR } from '@prisma-next/contract/ir';\nimport type {\n ControlAdapterDescriptor,\n ControlExtensionDescriptor,\n ControlFamilyDescriptor,\n ControlTargetDescriptor,\n} from '@prisma-next/core-control-plane/types';\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\nexport function assertContractRequirementsSatisfied<\n TFamilyId extends string,\n TTargetId extends string,\n>({\n contract,\n family,\n target,\n adapter,\n extensions,\n}: {\n readonly contract: Pick<ContractIR, 'targetFamily' | 'target' | 'extensionPacks'>;\n readonly family: ControlFamilyDescriptor<TFamilyId>;\n readonly target: ControlTargetDescriptor<TFamilyId, TTargetId>;\n readonly adapter: ControlAdapterDescriptor<TFamilyId, TTargetId>;\n readonly extensions?: readonly ControlExtensionDescriptor<TFamilyId, TTargetId>[];\n}): void {\n if (contract.targetFamily !== family.familyId) {\n throw errorConfigValidation('contract.targetFamily', {\n why: `Contract was emitted for family '${contract.targetFamily}' but CLI config is wired to '${family.familyId}'.`,\n });\n }\n\n if (contract.target !== target.targetId) {\n throw errorConfigValidation('contract.target', {\n why: `Contract target '${contract.target}' does not match CLI target '${target.targetId}'.`,\n });\n }\n\n const providedComponentIds = new Set<string>([target.id, adapter.id]);\n for (const extension of extensions ?? []) {\n providedComponentIds.add(extension.id);\n }\n\n const requiredPacks = contract.extensionPacks ? Object.keys(contract.extensionPacks) : [];\n for (const packId of requiredPacks) {\n if (!providedComponentIds.has(packId)) {\n throw errorConfigValidation('contract.extensionPacks', {\n why: `Contract requires extension pack '${packId}', but CLI config does not provide a matching descriptor.`,\n });\n }\n }\n}\n"],"mappings":";;;;;AA4CO,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;AAEO,SAAS,oCAGd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMS;AACP,MAAI,SAAS,iBAAiB,OAAO,UAAU;AAC7C,UAAM,sBAAsB,yBAAyB;AAAA,MACnD,KAAK,oCAAoC,SAAS,YAAY,iCAAiC,OAAO,QAAQ;AAAA,IAChH,CAAC;AAAA,EACH;AAEA,MAAI,SAAS,WAAW,OAAO,UAAU;AACvC,UAAM,sBAAsB,mBAAmB;AAAA,MAC7C,KAAK,oBAAoB,SAAS,MAAM,gCAAgC,OAAO,QAAQ;AAAA,IACzF,CAAC;AAAA,EACH;AAEA,QAAM,uBAAuB,oBAAI,IAAY,CAAC,OAAO,IAAI,QAAQ,EAAE,CAAC;AACpE,aAAW,aAAa,cAAc,CAAC,GAAG;AACxC,yBAAqB,IAAI,UAAU,EAAE;AAAA,EACvC;AAEA,QAAM,gBAAgB,SAAS,iBAAiB,OAAO,KAAK,SAAS,cAAc,IAAI,CAAC;AACxF,aAAW,UAAU,eAAe;AAClC,QAAI,CAAC,qBAAqB,IAAI,MAAM,GAAG;AACrC,YAAM,sBAAsB,2BAA2B;AAAA,QACrD,KAAK,qCAAqC,MAAM;AAAA,MAClD,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -1223,6 +1223,36 @@ function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId,
|
|
|
1223
1223
|
}
|
|
1224
1224
|
return frameworkComponents;
|
|
1225
1225
|
}
|
|
1226
|
+
function assertContractRequirementsSatisfied({
|
|
1227
|
+
contract,
|
|
1228
|
+
family,
|
|
1229
|
+
target,
|
|
1230
|
+
adapter,
|
|
1231
|
+
extensions
|
|
1232
|
+
}) {
|
|
1233
|
+
if (contract.targetFamily !== family.familyId) {
|
|
1234
|
+
throw errorConfigValidation("contract.targetFamily", {
|
|
1235
|
+
why: `Contract was emitted for family '${contract.targetFamily}' but CLI config is wired to '${family.familyId}'.`
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
if (contract.target !== target.targetId) {
|
|
1239
|
+
throw errorConfigValidation("contract.target", {
|
|
1240
|
+
why: `Contract target '${contract.target}' does not match CLI target '${target.targetId}'.`
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
const providedComponentIds = /* @__PURE__ */ new Set([target.id, adapter.id]);
|
|
1244
|
+
for (const extension of extensions ?? []) {
|
|
1245
|
+
providedComponentIds.add(extension.id);
|
|
1246
|
+
}
|
|
1247
|
+
const requiredPacks = contract.extensionPacks ? Object.keys(contract.extensionPacks) : [];
|
|
1248
|
+
for (const packId of requiredPacks) {
|
|
1249
|
+
if (!providedComponentIds.has(packId)) {
|
|
1250
|
+
throw errorConfigValidation("contract.extensionPacks", {
|
|
1251
|
+
why: `Contract requires extension pack '${packId}', but CLI config does not provide a matching descriptor.`
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1226
1256
|
|
|
1227
1257
|
// src/commands/db-init.ts
|
|
1228
1258
|
function createDbInitCommand() {
|
|
@@ -1318,6 +1348,13 @@ function createDbInitCommand() {
|
|
|
1318
1348
|
rawComponents
|
|
1319
1349
|
);
|
|
1320
1350
|
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
1351
|
+
assertContractRequirementsSatisfied({
|
|
1352
|
+
contract: contractIR,
|
|
1353
|
+
family: config.family,
|
|
1354
|
+
target: config.target,
|
|
1355
|
+
adapter: config.adapter,
|
|
1356
|
+
extensions: config.extensions ?? []
|
|
1357
|
+
});
|
|
1321
1358
|
const planner = migrations.createPlanner(familyInstance);
|
|
1322
1359
|
const runner = migrations.createRunner(familyInstance);
|
|
1323
1360
|
const schemaIR = await withSpinner(() => familyInstance.introspect({ driver }), {
|
|
@@ -1571,7 +1608,15 @@ function createDbIntrospectCommand() {
|
|
|
1571
1608
|
extensions: config.extensions ?? []
|
|
1572
1609
|
});
|
|
1573
1610
|
if (contractIR) {
|
|
1574
|
-
|
|
1611
|
+
const validatedContract = familyInstance.validateContractIR(contractIR);
|
|
1612
|
+
assertContractRequirementsSatisfied({
|
|
1613
|
+
contract: validatedContract,
|
|
1614
|
+
family: config.family,
|
|
1615
|
+
target: config.target,
|
|
1616
|
+
adapter: config.adapter,
|
|
1617
|
+
extensions: config.extensions ?? []
|
|
1618
|
+
});
|
|
1619
|
+
contractIR = validatedContract;
|
|
1575
1620
|
}
|
|
1576
1621
|
let schemaIR;
|
|
1577
1622
|
try {
|
|
@@ -1737,6 +1782,13 @@ function createDbSchemaVerifyCommand() {
|
|
|
1737
1782
|
rawComponents
|
|
1738
1783
|
);
|
|
1739
1784
|
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
1785
|
+
assertContractRequirementsSatisfied({
|
|
1786
|
+
contract: contractIR,
|
|
1787
|
+
family: config.family,
|
|
1788
|
+
target: config.target,
|
|
1789
|
+
adapter: config.adapter,
|
|
1790
|
+
extensions: config.extensions ?? []
|
|
1791
|
+
});
|
|
1740
1792
|
let schemaVerifyResult;
|
|
1741
1793
|
try {
|
|
1742
1794
|
schemaVerifyResult = await withSpinner(
|
|
@@ -1869,6 +1921,13 @@ function createDbSignCommand() {
|
|
|
1869
1921
|
rawComponents
|
|
1870
1922
|
);
|
|
1871
1923
|
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
1924
|
+
assertContractRequirementsSatisfied({
|
|
1925
|
+
contract: contractIR,
|
|
1926
|
+
family: config.family,
|
|
1927
|
+
target: config.target,
|
|
1928
|
+
adapter: config.adapter,
|
|
1929
|
+
extensions: config.extensions ?? []
|
|
1930
|
+
});
|
|
1872
1931
|
let schemaVerifyResult;
|
|
1873
1932
|
try {
|
|
1874
1933
|
schemaVerifyResult = await withSpinner(
|
|
@@ -2037,6 +2096,13 @@ function createDbVerifyCommand() {
|
|
|
2037
2096
|
extensions: config.extensions ?? []
|
|
2038
2097
|
});
|
|
2039
2098
|
const contractIR = familyInstance.validateContractIR(contractJson);
|
|
2099
|
+
assertContractRequirementsSatisfied({
|
|
2100
|
+
contract: contractIR,
|
|
2101
|
+
family: config.family,
|
|
2102
|
+
target: config.target,
|
|
2103
|
+
adapter: config.adapter,
|
|
2104
|
+
extensions: config.extensions ?? []
|
|
2105
|
+
});
|
|
2040
2106
|
let verifyResult;
|
|
2041
2107
|
try {
|
|
2042
2108
|
verifyResult = await withSpinner(
|