@prisma-next/cli 0.16.0-dev.20 → 0.16.0-dev.22
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 +13 -13
- package/dist/cli.mjs +11 -11
- package/dist/{client-DeJvLD2h.mjs → client-CMusjGV5.mjs} +23 -23
- package/dist/client-CMusjGV5.mjs.map +1 -0
- package/dist/command-helpers-CVn3U9Uz.mjs.map +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.mjs +2 -2
- package/dist/commands/db-schema.mjs +1 -1
- package/dist/commands/db-sign.mjs +3 -3
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.mjs +3 -3
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +1 -1
- package/dist/commands/migrate.mjs +7 -7
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +1 -1
- package/dist/commands/migration-check.mjs +1 -1
- package/dist/commands/migration-graph.d.mts +1 -1
- package/dist/commands/migration-graph.mjs +2 -2
- package/dist/commands/migration-list.d.mts +1 -1
- package/dist/commands/migration-list.mjs +1 -1
- package/dist/commands/migration-log.d.mts +1 -1
- package/dist/commands/migration-log.mjs +1 -1
- package/dist/commands/migration-new.mjs +3 -3
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.mjs +2 -2
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +1 -1
- package/dist/commands/migration-status.mjs +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.mjs +1 -1
- package/dist/{contract-emit-DJ8SRI7L.mjs → contract-emit-CfIbTnsR.mjs} +5 -5
- package/dist/{contract-emit-DJ8SRI7L.mjs.map → contract-emit-CfIbTnsR.mjs.map} +1 -1
- package/dist/{contract-emit-BMJiefhy.mjs → contract-emit-PaY3qRdN.mjs} +2 -2
- package/dist/{contract-emit-BMJiefhy.mjs.map → contract-emit-PaY3qRdN.mjs.map} +1 -1
- package/dist/{contract-enrichment-gn9sWbPw.mjs → contract-enrichment-JUhLv-BX.mjs} +8 -8
- package/dist/{contract-enrichment-gn9sWbPw.mjs.map → contract-enrichment-JUhLv-BX.mjs.map} +1 -1
- package/dist/{contract-infer-_tstfy3k.mjs → contract-infer-DCju2fTk.mjs} +2 -2
- package/dist/{contract-infer-_tstfy3k.mjs.map → contract-infer-DCju2fTk.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-hPVymNLw.mjs → contract-space-aggregate-loader-B6E9LGa6.mjs} +13 -13
- package/dist/contract-space-aggregate-loader-B6E9LGa6.mjs.map +1 -0
- package/dist/{db-verify-3WM8y323.mjs → db-verify-B_dKu6Yp.mjs} +3 -3
- package/dist/db-verify-B_dKu6Yp.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +4 -4
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.mjs +2 -2
- package/dist/{format-CFLZv_zU.mjs → format-cCyDfmRE.mjs} +3 -3
- package/dist/format-cCyDfmRE.mjs.map +1 -0
- package/dist/{framework-components-VMQJbAwl.mjs → framework-components-DUN-TYDg.mjs} +2 -2
- package/dist/framework-components-DUN-TYDg.mjs.map +1 -0
- package/dist/{init-XycYREvA.mjs → init-C9U3ffHH.mjs} +2 -2
- package/dist/{init-XycYREvA.mjs.map → init-C9U3ffHH.mjs.map} +1 -1
- package/dist/{inspect-live-schema-xS6VqjHE.mjs → inspect-live-schema-DHXE7skX.mjs} +3 -3
- package/dist/{inspect-live-schema-xS6VqjHE.mjs.map → inspect-live-schema-DHXE7skX.mjs.map} +1 -1
- package/dist/{migration-check-C_4gozCn.mjs → migration-check-W5XEx4d-.mjs} +6 -6
- package/dist/migration-check-W5XEx4d-.mjs.map +1 -0
- package/dist/{migration-command-scaffold-D9JkLq_M.mjs → migration-command-scaffold-hI5cnoGe.mjs} +3 -3
- package/dist/{migration-command-scaffold-D9JkLq_M.mjs.map → migration-command-scaffold-hI5cnoGe.mjs.map} +1 -1
- package/dist/{migration-list-BwEwRv25.mjs → migration-list-ClkEaoL8.mjs} +2 -2
- package/dist/{migration-list-BwEwRv25.mjs.map → migration-list-ClkEaoL8.mjs.map} +1 -1
- package/dist/{migration-log-C3RMIsUI.mjs → migration-log-CjafbZ2Z.mjs} +3 -3
- package/dist/{migration-log-C3RMIsUI.mjs.map → migration-log-CjafbZ2Z.mjs.map} +1 -1
- package/dist/{migration-plan-BzxmK_do.mjs → migration-plan-Pc4hCF1H.mjs} +9 -9
- package/dist/migration-plan-Pc4hCF1H.mjs.map +1 -0
- package/dist/{migration-status-ChQKA6Jf.mjs → migration-status-CqAdRzs8.mjs} +5 -5
- package/dist/migration-status-CqAdRzs8.mjs.map +1 -0
- package/dist/{types-D4r_HI9-.d.mts → types-DgXprE3w.d.mts} +3 -3
- package/dist/types-DgXprE3w.d.mts.map +1 -0
- package/package.json +21 -21
- package/src/commands/db-sign.ts +1 -1
- package/src/commands/db-verify.ts +1 -1
- package/src/commands/format.ts +1 -1
- package/src/commands/inspect-live-schema.ts +1 -1
- package/src/commands/migrate.ts +4 -4
- package/src/commands/migration-check.ts +1 -1
- package/src/commands/migration-log.ts +1 -1
- package/src/commands/migration-new.ts +1 -1
- package/src/commands/migration-plan.ts +5 -5
- package/src/commands/migration-show.ts +1 -1
- package/src/commands/migration-status.ts +1 -1
- package/src/control-api/client.ts +7 -7
- package/src/control-api/contract-enrichment.ts +7 -7
- package/src/control-api/operations/contract-emit.ts +2 -2
- package/src/control-api/operations/db-init.ts +3 -3
- package/src/control-api/operations/db-run.ts +6 -6
- package/src/control-api/operations/db-update.ts +2 -2
- package/src/control-api/operations/db-verify.ts +4 -4
- package/src/control-api/operations/format.ts +1 -1
- package/src/control-api/operations/migrate.ts +3 -3
- package/src/control-api/types.ts +1 -1
- package/src/utils/cli-errors.ts +2 -2
- package/src/utils/contract-space-aggregate-loader.ts +8 -8
- package/src/utils/contract-space-seed-phase.ts +3 -3
- package/src/utils/extension-pack-inputs.ts +8 -8
- package/src/utils/framework-components.ts +9 -9
- package/src/utils/integrity-violation-to-check-failure.ts +3 -3
- package/src/utils/migration-command-scaffold.ts +1 -1
- package/dist/client-DeJvLD2h.mjs.map +0 -1
- package/dist/contract-space-aggregate-loader-hPVymNLw.mjs.map +0 -1
- package/dist/db-verify-3WM8y323.mjs.map +0 -1
- package/dist/format-CFLZv_zU.mjs.map +0 -1
- package/dist/framework-components-VMQJbAwl.mjs.map +0 -1
- package/dist/migration-check-C_4gozCn.mjs.map +0 -1
- package/dist/migration-plan-BzxmK_do.mjs.map +0 -1
- package/dist/migration-status-ChQKA6Jf.mjs.map +0 -1
- package/dist/types-D4r_HI9-.d.mts.map +0 -1
|
@@ -65,21 +65,21 @@ export function enrichContract(
|
|
|
65
65
|
): Contract {
|
|
66
66
|
const mergedCapabilities = mergeCapabilityMatrices(ir.capabilities, components);
|
|
67
67
|
|
|
68
|
-
const
|
|
68
|
+
const extensionsMeta: Record<string, unknown> = {};
|
|
69
69
|
for (const component of components) {
|
|
70
70
|
if (component.kind === 'extension') {
|
|
71
|
-
|
|
71
|
+
extensionsMeta[component.id] = extractExtensionPackMeta(component);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const
|
|
76
|
-
Object.keys(
|
|
77
|
-
? { ...ir.
|
|
78
|
-
: ir.
|
|
75
|
+
const extensions =
|
|
76
|
+
Object.keys(extensionsMeta).length > 0
|
|
77
|
+
? { ...ir.extensions, ...extensionsMeta }
|
|
78
|
+
: ir.extensions;
|
|
79
79
|
|
|
80
80
|
return {
|
|
81
81
|
...ir,
|
|
82
82
|
capabilities: sortDeepTyped(mergedCapabilities),
|
|
83
|
-
|
|
83
|
+
extensions: sortDeepTyped(extensions),
|
|
84
84
|
};
|
|
85
85
|
}
|
|
@@ -195,7 +195,7 @@ export async function executeContractEmit(
|
|
|
195
195
|
const stack = createControlStack(config);
|
|
196
196
|
|
|
197
197
|
const sourceContext = {
|
|
198
|
-
|
|
198
|
+
composedExtensions: stack.extensions.map((p) => p.id),
|
|
199
199
|
composedExtensionContracts: stack.extensionContracts,
|
|
200
200
|
authoringContributions: stack.authoringContributions,
|
|
201
201
|
codecLookup: stack.codecLookup,
|
|
@@ -230,7 +230,7 @@ export async function executeContractEmit(
|
|
|
230
230
|
let emitResult: Awaited<ReturnType<typeof emit>>;
|
|
231
231
|
try {
|
|
232
232
|
const familyInstance = config.family.create(stack);
|
|
233
|
-
const rawComponents = [config.target, config.adapter, ...(config.
|
|
233
|
+
const rawComponents = [config.target, config.adapter, ...(config.extensions ?? [])];
|
|
234
234
|
const frameworkComponents = assertFrameworkComponentsCompatible(
|
|
235
235
|
config.family.familyId,
|
|
236
236
|
config.target.targetId,
|
|
@@ -25,7 +25,7 @@ import { executeRun } from './db-run';
|
|
|
25
25
|
* 3. The runner's `execute` applies the per-space plans
|
|
26
26
|
* inside one outer transaction.
|
|
27
27
|
*
|
|
28
|
-
* `
|
|
28
|
+
* `extensions` mirrors `Config.extensions` (descriptor list).
|
|
29
29
|
* The loader (sub-spec § Loader) is the sole descriptor-import boundary.
|
|
30
30
|
*/
|
|
31
31
|
export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extends string> {
|
|
@@ -55,7 +55,7 @@ export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extend
|
|
|
55
55
|
* routes through the same loader → planner → runner pipeline with no
|
|
56
56
|
* extension spaces in the aggregate.
|
|
57
57
|
*/
|
|
58
|
-
readonly
|
|
58
|
+
readonly extensions?: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
59
59
|
/** Optional progress callback for observing operation progress */
|
|
60
60
|
readonly onProgress?: OnControlProgress;
|
|
61
61
|
}
|
|
@@ -80,7 +80,7 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
|
|
|
80
80
|
frameworkComponents: options.frameworkComponents,
|
|
81
81
|
migrationsDir: options.migrationsDir,
|
|
82
82
|
targetId: options.targetId,
|
|
83
|
-
|
|
83
|
+
extensions: options.extensions ?? [],
|
|
84
84
|
policy: { allowedOperationClasses: ['additive'] },
|
|
85
85
|
action: 'dbInit',
|
|
86
86
|
...ifDefined('onProgress', options.onProgress),
|
|
@@ -80,7 +80,7 @@ export interface ExecuteRunOptions<TFamilyId extends string, TTargetId extends s
|
|
|
80
80
|
>;
|
|
81
81
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
82
82
|
readonly migrationsDir: string;
|
|
83
|
-
readonly
|
|
83
|
+
readonly extensions: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
84
84
|
readonly targetId: TTargetId;
|
|
85
85
|
readonly policy: MigrationOperationPolicy;
|
|
86
86
|
readonly action: 'dbInit' | 'dbUpdate';
|
|
@@ -119,7 +119,7 @@ export async function executeRun<TFamilyId extends string, TTargetId extends str
|
|
|
119
119
|
migrations,
|
|
120
120
|
frameworkComponents,
|
|
121
121
|
migrationsDir,
|
|
122
|
-
|
|
122
|
+
extensions,
|
|
123
123
|
targetId,
|
|
124
124
|
policy,
|
|
125
125
|
action,
|
|
@@ -131,7 +131,7 @@ export async function executeRun<TFamilyId extends string, TTargetId extends str
|
|
|
131
131
|
targetId,
|
|
132
132
|
migrationsDir,
|
|
133
133
|
appContract: contract,
|
|
134
|
-
|
|
134
|
+
extensions,
|
|
135
135
|
deserializeContract: (json) => familyInstance.deserializeContract(json),
|
|
136
136
|
};
|
|
137
137
|
const loaded = await buildContractSpaceAggregate(loadInputs);
|
|
@@ -283,7 +283,7 @@ function aggregatePlannerWarnings(
|
|
|
283
283
|
* Compare the live `_prisma_marker` rows against the aggregate's
|
|
284
284
|
* declared contract spaces. Any marker row whose `space` is not a space of
|
|
285
285
|
* the aggregate is an "orphan" — typically a marker left behind by
|
|
286
|
-
* an extension that was removed from `
|
|
286
|
+
* an extension that was removed from `extensions` without first
|
|
287
287
|
* cleaning up its on-disk migrations / database tables.
|
|
288
288
|
*
|
|
289
289
|
* Returns a {@link CliStructuredError} envelope (code
|
|
@@ -319,8 +319,8 @@ function detectOrphanMarkers(
|
|
|
319
319
|
.map((s) => `"${s}"`)
|
|
320
320
|
.join(
|
|
321
321
|
', ',
|
|
322
|
-
)}) that are not declared in the project's \`
|
|
323
|
-
fix: 'Either re-declare the missing extension(s) in `
|
|
322
|
+
)}) that are not declared in the project's \`extensions\`. The aggregate pipeline refuses to advance markers it cannot account for.`,
|
|
323
|
+
fix: 'Either re-declare the missing extension(s) in `extensions` (so the aggregate owns them again), or remove the orphan marker row(s) from `_prisma_marker` once you have confirmed the corresponding tables can be safely retired.',
|
|
324
324
|
docsUrl: 'https://pris.ly/contract-spaces',
|
|
325
325
|
meta: {
|
|
326
326
|
violations: orphans.map((spaceId) => ({ kind: 'orphanMarker', spaceId })),
|
|
@@ -40,7 +40,7 @@ export interface ExecuteDbUpdateOptions<TFamilyId extends string, TTargetId exte
|
|
|
40
40
|
readonly acceptDataLoss?: boolean;
|
|
41
41
|
readonly migrationsDir: string;
|
|
42
42
|
readonly targetId: TTargetId;
|
|
43
|
-
readonly
|
|
43
|
+
readonly extensions?: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
44
44
|
readonly onProgress?: OnControlProgress;
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -65,7 +65,7 @@ export async function executeDbUpdate<TFamilyId extends string, TTargetId extend
|
|
|
65
65
|
frameworkComponents: options.frameworkComponents,
|
|
66
66
|
migrationsDir: options.migrationsDir,
|
|
67
67
|
targetId: options.targetId,
|
|
68
|
-
|
|
68
|
+
extensions: options.extensions ?? [],
|
|
69
69
|
policy: DB_UPDATE_POLICY,
|
|
70
70
|
action: 'dbUpdate' as const,
|
|
71
71
|
...ifDefined('onProgress', options.onProgress),
|
|
@@ -50,7 +50,7 @@ export interface ExecuteDbVerifyOptions<TFamilyId extends string, TTargetId exte
|
|
|
50
50
|
readonly contract: Contract;
|
|
51
51
|
readonly migrationsDir: string;
|
|
52
52
|
readonly targetId: TTargetId;
|
|
53
|
-
readonly
|
|
53
|
+
readonly extensions: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
54
54
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
55
55
|
readonly mode: 'strict' | 'lenient';
|
|
56
56
|
readonly skipSchema: boolean;
|
|
@@ -149,7 +149,7 @@ function buildLoadInputs<TFamilyId extends string, TTargetId extends string>(
|
|
|
149
149
|
targetId: options.targetId,
|
|
150
150
|
migrationsDir: options.migrationsDir,
|
|
151
151
|
appContract: options.contract,
|
|
152
|
-
|
|
152
|
+
extensions: options.extensions,
|
|
153
153
|
deserializeContract: (json) => options.familyInstance.deserializeContract(json),
|
|
154
154
|
};
|
|
155
155
|
}
|
|
@@ -349,7 +349,7 @@ function mapMarkerCheckFailures(
|
|
|
349
349
|
violations.push({
|
|
350
350
|
kind: 'orphanMarker',
|
|
351
351
|
spaceId: orphan.spaceId,
|
|
352
|
-
remediation: `Add the corresponding extension to \`
|
|
352
|
+
remediation: `Add the corresponding extension to \`extensions\` in \`prisma-next.config.ts\`, or delete the orphan marker row for "${orphan.spaceId}".`,
|
|
353
353
|
});
|
|
354
354
|
}
|
|
355
355
|
if (violations.length === 0) return null;
|
|
@@ -359,7 +359,7 @@ function mapMarkerCheckFailures(
|
|
|
359
359
|
? 'Contract-space verifier found a violation'
|
|
360
360
|
: `Contract-space verifier found violations (${violations.length})`;
|
|
361
361
|
return new CliStructuredError('MIGRATION.CONTRACT_SPACE_VIOLATION', summary, {
|
|
362
|
-
why: `The on-disk \`migrations/\` directory, the \`
|
|
362
|
+
why: `The on-disk \`migrations/\` directory, the \`extensions\` declaration, and the live database marker rows are not in agreement.\n${lines.join('\n')}`,
|
|
363
363
|
fix: violations[0]?.remediation ?? 'Review and reconcile the violations listed above.',
|
|
364
364
|
docsUrl: 'https://pris.ly/contract-spaces',
|
|
365
365
|
meta: { violations },
|
|
@@ -60,7 +60,7 @@ export interface ExecuteMigrateOptions<TFamilyId extends string, TTargetId exten
|
|
|
60
60
|
>;
|
|
61
61
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
62
62
|
readonly migrationsDir: string;
|
|
63
|
-
readonly
|
|
63
|
+
readonly extensions: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
64
64
|
readonly targetId: TTargetId;
|
|
65
65
|
/**
|
|
66
66
|
* Optional app-space ref override. When provided, the app space's
|
|
@@ -122,7 +122,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
122
122
|
migrations,
|
|
123
123
|
frameworkComponents,
|
|
124
124
|
migrationsDir,
|
|
125
|
-
|
|
125
|
+
extensions,
|
|
126
126
|
targetId,
|
|
127
127
|
refHash,
|
|
128
128
|
refInvariants,
|
|
@@ -134,7 +134,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
134
134
|
targetId,
|
|
135
135
|
migrationsDir,
|
|
136
136
|
appContract: contract,
|
|
137
|
-
|
|
137
|
+
extensions,
|
|
138
138
|
deserializeContract: (json) => familyInstance.deserializeContract(json),
|
|
139
139
|
};
|
|
140
140
|
const loaded = await buildContractSpaceAggregate(loadInputs);
|
package/src/control-api/types.ts
CHANGED
|
@@ -52,7 +52,7 @@ export interface ControlClientOptions {
|
|
|
52
52
|
// biome-ignore lint/suspicious/noExplicitAny: required for contravariance in driver.create()
|
|
53
53
|
readonly driver?: ControlDriverDescriptor<any, any, any, any>;
|
|
54
54
|
// biome-ignore lint/suspicious/noExplicitAny: required for contravariance in extension.create()
|
|
55
|
-
readonly
|
|
55
|
+
readonly extensions?: ReadonlyArray<ControlExtensionDescriptor<any, any, any>>;
|
|
56
56
|
/**
|
|
57
57
|
* Optional default connection for auto-connect.
|
|
58
58
|
* When provided, operations will auto-connect if not already connected.
|
package/src/utils/cli-errors.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
errorConfigFileNotFound,
|
|
11
11
|
errorConfigValidation,
|
|
12
12
|
errorContractConfigMissing,
|
|
13
|
-
|
|
13
|
+
errorContractMissingExtensions,
|
|
14
14
|
errorContractValidationFailed,
|
|
15
15
|
errorDatabaseConnectionRequired,
|
|
16
16
|
errorDriverRequired,
|
|
@@ -54,7 +54,7 @@ export {
|
|
|
54
54
|
errorConfigFileNotFound,
|
|
55
55
|
errorConfigValidation,
|
|
56
56
|
errorContractConfigMissing,
|
|
57
|
-
|
|
57
|
+
errorContractMissingExtensions,
|
|
58
58
|
errorContractValidationFailed,
|
|
59
59
|
errorDatabaseConnectionRequired,
|
|
60
60
|
errorDriverRequired,
|
|
@@ -114,8 +114,8 @@ export function mapIntegrityViolations(
|
|
|
114
114
|
? 'Contract-space layout violation detected'
|
|
115
115
|
: `Contract-space layout violations detected (${layout.length})`;
|
|
116
116
|
return new CliStructuredError('MIGRATION.CONTRACT_SPACE_LAYOUT_VIOLATION', summary, {
|
|
117
|
-
why: `The on-disk \`migrations/\` directory and your \`
|
|
118
|
-
fix: 'Declare the extension in `
|
|
117
|
+
why: `The on-disk \`migrations/\` directory and your \`extensions\` declaration are not in agreement.\n${lines.join('\n')}`,
|
|
118
|
+
fix: 'Declare the extension in `extensions` and re-emit its contract-space artefacts, or remove the orphan `migrations/<space>` directory.',
|
|
119
119
|
docsUrl: CONTRACT_SPACES_DOCS_URL,
|
|
120
120
|
meta: { violations: layout },
|
|
121
121
|
});
|
|
@@ -177,14 +177,14 @@ export interface BuildAggregateInputs<TFamilyId extends string, TTargetId extend
|
|
|
177
177
|
readonly targetId: TTargetId;
|
|
178
178
|
readonly migrationsDir: string;
|
|
179
179
|
readonly appContract: Contract;
|
|
180
|
-
readonly
|
|
180
|
+
readonly extensions: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
181
181
|
readonly deserializeContract: (contractJson: unknown) => Contract;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
function declaredExtensionsFromInputs(
|
|
185
|
-
|
|
185
|
+
extensions: BuildAggregateInputs<string, string>['extensions'],
|
|
186
186
|
): readonly DeclaredExtensionEntry[] {
|
|
187
|
-
return toDeclaredExtensionsFromRaw(
|
|
187
|
+
return toDeclaredExtensionsFromRaw(extensions as ReadonlyArray<unknown>);
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
/**
|
|
@@ -195,7 +195,7 @@ export function refuseDeclaredExtensionTargetMismatch<
|
|
|
195
195
|
TFamilyId extends string,
|
|
196
196
|
TTargetId extends string,
|
|
197
197
|
>(inputs: BuildAggregateInputs<TFamilyId, TTargetId>): CliStructuredError | null {
|
|
198
|
-
for (const declared of declaredExtensionsFromInputs(inputs.
|
|
198
|
+
for (const declared of declaredExtensionsFromInputs(inputs.extensions)) {
|
|
199
199
|
if (declared.targetId !== inputs.targetId) {
|
|
200
200
|
return targetMismatchError(declared.id, inputs.targetId, declared.targetId);
|
|
201
201
|
}
|
|
@@ -271,7 +271,7 @@ export async function buildContractSpaceAggregate<
|
|
|
271
271
|
>(
|
|
272
272
|
inputs: BuildAggregateInputs<TFamilyId, TTargetId>,
|
|
273
273
|
): Promise<Result<ContractSpaceAggregate, CliStructuredError>> {
|
|
274
|
-
const declaredExtensions = declaredExtensionsFromInputs(inputs.
|
|
274
|
+
const declaredExtensions = declaredExtensionsFromInputs(inputs.extensions);
|
|
275
275
|
const loaded = await loadContractSpaceAggregateForCli(inputs);
|
|
276
276
|
if (!loaded.ok) {
|
|
277
277
|
return loaded;
|
|
@@ -375,7 +375,7 @@ export async function buildReadAggregate(
|
|
|
375
375
|
targetId: config.target.id,
|
|
376
376
|
migrationsDir: options.migrationsDir,
|
|
377
377
|
appContract: appContractForLoad,
|
|
378
|
-
|
|
378
|
+
extensions: config.extensions ?? [],
|
|
379
379
|
deserializeContract,
|
|
380
380
|
});
|
|
381
381
|
if (!loaded.ok) {
|
|
@@ -39,7 +39,7 @@ export interface SeedPhaseExtensionInput {
|
|
|
39
39
|
|
|
40
40
|
export interface ContractSpaceSeedPhaseInputs {
|
|
41
41
|
readonly migrationsDir: string;
|
|
42
|
-
readonly
|
|
42
|
+
readonly extensions: ReadonlyArray<SeedPhaseExtensionInput>;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -98,7 +98,7 @@ export interface ContractSpaceSeedPhaseResult {
|
|
|
98
98
|
export async function runContractSpaceSeedPhase(
|
|
99
99
|
inputs: ContractSpaceSeedPhaseInputs,
|
|
100
100
|
): Promise<ContractSpaceSeedPhaseResult> {
|
|
101
|
-
const planInputs = inputs.
|
|
101
|
+
const planInputs = inputs.extensions
|
|
102
102
|
.filter(
|
|
103
103
|
(
|
|
104
104
|
pack,
|
|
@@ -134,7 +134,7 @@ export async function runContractSpaceSeedPhase(
|
|
|
134
134
|
string,
|
|
135
135
|
NonNullable<SeedPhaseExtensionInput['contractSpace']>
|
|
136
136
|
>();
|
|
137
|
-
for (const pack of inputs.
|
|
137
|
+
for (const pack of inputs.extensions) {
|
|
138
138
|
if (pack.contractSpace !== undefined) descriptorBySpace.set(pack.id, pack.contractSpace);
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Single descriptor-import boundary for CLI consumers of `Config.
|
|
2
|
+
* Single descriptor-import boundary for CLI consumers of `Config.extensions`.
|
|
3
3
|
*
|
|
4
4
|
* Every CLI command / utility that reads an extension descriptor's
|
|
5
5
|
* `contractSpace` projection (loader, migrate-pass, extension-migrations
|
|
@@ -54,9 +54,9 @@ export interface ExtensionPackInput {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* Structural shape we read off each `Config.
|
|
57
|
+
* Structural shape we read off each `Config.extensions` entry.
|
|
58
58
|
*
|
|
59
|
-
* The CLI is the descriptor-import boundary; `
|
|
59
|
+
* The CLI is the descriptor-import boundary; `extensions` is the only
|
|
60
60
|
* surface where the SQL-family-typed `ControlExtensionDescriptor` flows
|
|
61
61
|
* into framework-neutral helpers. The structural cast lives here, and
|
|
62
62
|
* here alone — every other CLI consumer reads the canonical
|
|
@@ -76,14 +76,14 @@ type ExtensionPackLike = {
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
|
-
* Project the CLI's `Config.
|
|
79
|
+
* Project the CLI's `Config.extensions` array into the canonical
|
|
80
80
|
* {@link ExtensionPackInput} shape. The single `as ExtensionPackLike`
|
|
81
81
|
* structural cast in the CLI lives inside this function.
|
|
82
82
|
*/
|
|
83
83
|
export function toExtensionInputs(
|
|
84
|
-
|
|
84
|
+
extensions: ReadonlyArray<unknown>,
|
|
85
85
|
): readonly ExtensionPackInput[] {
|
|
86
|
-
return
|
|
86
|
+
return extensions.map((raw) => {
|
|
87
87
|
const pack = raw as ExtensionPackLike;
|
|
88
88
|
if (pack.contractSpace === undefined) {
|
|
89
89
|
return { id: pack.id, targetId: pack.targetId };
|
|
@@ -147,10 +147,10 @@ export function toDeclaredExtensions(
|
|
|
147
147
|
* always reads the contract from on-disk artefacts instead.
|
|
148
148
|
*/
|
|
149
149
|
export function toDeclaredExtensionsFromRaw(
|
|
150
|
-
|
|
150
|
+
extensions: ReadonlyArray<unknown>,
|
|
151
151
|
): readonly DeclaredExtensionEntry[] {
|
|
152
152
|
const entries: DeclaredExtensionEntry[] = [];
|
|
153
|
-
for (const raw of
|
|
153
|
+
for (const raw of extensions) {
|
|
154
154
|
if (typeof raw !== 'object' || raw === null) continue;
|
|
155
155
|
const descriptor = Object.getOwnPropertyDescriptor(raw, 'contractSpace');
|
|
156
156
|
if (descriptor === undefined) continue;
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
type TargetBoundComponentDescriptor,
|
|
5
5
|
} from '@prisma-next/framework-components/components';
|
|
6
6
|
import type { ControlStack } from '@prisma-next/framework-components/control';
|
|
7
|
-
import { errorConfigValidation,
|
|
7
|
+
import { errorConfigValidation, errorContractMissingExtensions } from './cli-errors';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Asserts that all framework components are compatible with the expected family and target.
|
|
@@ -27,7 +27,7 @@ import { errorConfigValidation, errorContractMissingExtensionPacks } from './cli
|
|
|
27
27
|
* @example
|
|
28
28
|
* ```ts
|
|
29
29
|
* const config = await loadConfig();
|
|
30
|
-
* const frameworkComponents = [config.target, config.adapter, ...(config.
|
|
30
|
+
* const frameworkComponents = [config.target, config.adapter, ...(config.extensions ?? [])];
|
|
31
31
|
*
|
|
32
32
|
* // Validate and type-narrow components before passing to planner
|
|
33
33
|
* const typedComponents = assertFrameworkComponentsCompatible(
|
|
@@ -114,12 +114,12 @@ export function assertFrameworkComponentsCompatible<
|
|
|
114
114
|
* This check ensures the emitted contract matches the CLI config before running
|
|
115
115
|
* commands that depend on the contract (e.g., db verify, db sign).
|
|
116
116
|
*
|
|
117
|
-
* @param contract - The contract to validate (must include targetFamily, target,
|
|
118
|
-
* @param stack - The control plane stack (target, adapter, driver,
|
|
117
|
+
* @param contract - The contract to validate (must include targetFamily, target, extensions).
|
|
118
|
+
* @param stack - The control plane stack (target, adapter, driver, extensions).
|
|
119
119
|
*
|
|
120
120
|
* @throws {CliStructuredError} errorConfigValidation when contract.targetFamily or contract.target
|
|
121
121
|
* doesn't match the configured family/target.
|
|
122
|
-
* @throws {CliStructuredError}
|
|
122
|
+
* @throws {CliStructuredError} errorContractMissingExtensions when the contract requires
|
|
123
123
|
* extension packs that are not provided in the config (includes all missing packs in error.meta).
|
|
124
124
|
*
|
|
125
125
|
* @example
|
|
@@ -141,14 +141,14 @@ export function assertContractRequirementsSatisfied<
|
|
|
141
141
|
contract,
|
|
142
142
|
stack,
|
|
143
143
|
}: {
|
|
144
|
-
readonly contract: Pick<Contract, 'targetFamily' | 'target' | '
|
|
144
|
+
readonly contract: Pick<Contract, 'targetFamily' | 'target' | 'extensions'>;
|
|
145
145
|
readonly stack: ControlStack<TFamilyId, TTargetId>;
|
|
146
146
|
}): void {
|
|
147
147
|
const providedComponentIds = new Set<string>([
|
|
148
148
|
stack.target.id,
|
|
149
149
|
...(stack.adapter ? [stack.adapter.id] : []),
|
|
150
150
|
]);
|
|
151
|
-
for (const extension of stack.
|
|
151
|
+
for (const extension of stack.extensions) {
|
|
152
152
|
providedComponentIds.add(extension.id);
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -172,8 +172,8 @@ export function assertContractRequirementsSatisfied<
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
if (result.missingExtensionPackIds.length > 0) {
|
|
175
|
-
throw
|
|
176
|
-
|
|
175
|
+
throw errorContractMissingExtensions({
|
|
176
|
+
missingExtensions: result.missingExtensionPackIds,
|
|
177
177
|
providedComponentIds: [...providedComponentIds],
|
|
178
178
|
});
|
|
179
179
|
}
|
|
@@ -69,15 +69,15 @@ export function integrityViolationToCheckFailure(
|
|
|
69
69
|
code: 'MIGRATION.CHECK_ORPHAN_SPACE_DIR',
|
|
70
70
|
where: spaceRelative(violation.spaceId),
|
|
71
71
|
why: `Contract-space directory "${violation.spaceId}" exists on disk but no extension declares it.`,
|
|
72
|
-
fix: 'Remove the orphan directory, or declare the extension in `
|
|
72
|
+
fix: 'Remove the orphan directory, or declare the extension in `extensions`.',
|
|
73
73
|
};
|
|
74
74
|
case 'declaredButUnmigrated':
|
|
75
75
|
return {
|
|
76
76
|
space: violation.spaceId,
|
|
77
77
|
code: 'MIGRATION.CHECK_DECLARED_BUT_UNMIGRATED',
|
|
78
78
|
where: spaceRelative(violation.spaceId),
|
|
79
|
-
why: `Extension "${violation.spaceId}" is declared in \`
|
|
80
|
-
fix: 'Re-emit the extension contract-space artefacts with `prisma-next contract emit` and migration planning, or remove the extension from `
|
|
79
|
+
why: `Extension "${violation.spaceId}" is declared in \`extensions\` but has no on-disk migrations directory.`,
|
|
80
|
+
fix: 'Re-emit the extension contract-space artefacts with `prisma-next contract emit` and migration planning, or remove the extension from `extensions` if it is unused.',
|
|
81
81
|
};
|
|
82
82
|
case 'headRefMissing':
|
|
83
83
|
return {
|
|
@@ -154,7 +154,7 @@ export async function prepareMigrationContext(
|
|
|
154
154
|
target: config.target,
|
|
155
155
|
adapter: config.adapter,
|
|
156
156
|
driver: config.driver,
|
|
157
|
-
|
|
157
|
+
extensions: config.extensions ?? [],
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
// Create progress adapter
|