@prisma-next/cli 0.5.0-dev.67 → 0.5.0-dev.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +8 -8
- package/dist/cli.mjs.map +1 -1
- package/dist/client-0ZX24FXF.mjs +1398 -0
- package/dist/client-0ZX24FXF.mjs.map +1 -0
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +7 -5
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +2 -2
- package/dist/commands/db-sign.mjs +2 -2
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +7 -5
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.d.mts.map +1 -1
- package/dist/commands/db-verify.mjs +1 -320
- package/dist/commands/migration-apply.mjs +11 -11
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.mjs +5 -5
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -344
- package/dist/commands/migration-ref.d.mts +1 -1
- package/dist/commands/migration-ref.mjs +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +8 -7
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.mjs +1 -1
- package/dist/{contract-emit-B0nGrDtk.mjs → contract-emit-DkMqO7f2.mjs} +2 -2
- package/dist/{contract-emit-B0nGrDtk.mjs.map → contract-emit-DkMqO7f2.mjs.map} +1 -1
- package/dist/{contract-infer-BjMJaOOa.mjs → contract-infer-BDKAE0B0.mjs} +3 -3
- package/dist/{contract-infer-BjMJaOOa.mjs.map → contract-infer-BDKAE0B0.mjs.map} +1 -1
- package/dist/db-verify-B4TdDKOI.mjs +403 -0
- package/dist/db-verify-B4TdDKOI.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +201 -3
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +17 -17
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{init-C3qdc0Sh.mjs → init-Deo7U8_U.mjs} +2 -2
- package/dist/{init-C3qdc0Sh.mjs.map → init-Deo7U8_U.mjs.map} +1 -1
- package/dist/{inspect-live-schema-33rxnu0K.mjs → inspect-live-schema-BAgQMYpD.mjs} +3 -3
- package/dist/{inspect-live-schema-33rxnu0K.mjs.map → inspect-live-schema-BAgQMYpD.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-DQo4R0XT.mjs → migration-command-scaffold-B8J702Uh.mjs} +3 -3
- package/dist/{migration-command-scaffold-DQo4R0XT.mjs.map → migration-command-scaffold-B8J702Uh.mjs.map} +1 -1
- package/dist/migration-plan-BcKNnTM7.mjs +530 -0
- package/dist/migration-plan-BcKNnTM7.mjs.map +1 -0
- package/dist/{migration-status-C_2FSkbf.mjs → migration-status-CjwB2of-.mjs} +6 -6
- package/dist/{migration-status-C_2FSkbf.mjs.map → migration-status-CjwB2of-.mjs.map} +1 -1
- package/dist/{output-BTgnZ5c_.mjs → output-DnjfCC_u.mjs} +1 -1
- package/dist/{output-BTgnZ5c_.mjs.map → output-DnjfCC_u.mjs.map} +1 -1
- package/dist/{result-handler-C0QeiqKO.mjs → result-handler-DWb1rFS-.mjs} +18 -3
- package/dist/result-handler-DWb1rFS-.mjs.map +1 -0
- package/package.json +15 -15
- package/src/commands/db-init.ts +13 -3
- package/src/commands/db-update.ts +7 -3
- package/src/commands/db-verify.ts +47 -15
- package/src/commands/init/index.ts +1 -1
- package/src/commands/init/init.ts +2 -2
- package/src/commands/migration-apply.ts +9 -9
- package/src/commands/migration-new.ts +4 -4
- package/src/commands/migration-plan.ts +66 -9
- package/src/commands/migration-show.ts +7 -5
- package/src/commands/migration-status.ts +3 -3
- package/src/control-api/client.ts +42 -0
- package/src/control-api/operations/db-apply-aggregate.ts +446 -0
- package/src/control-api/operations/db-init.ts +51 -258
- package/src/control-api/operations/db-update.ts +66 -188
- package/src/control-api/operations/db-verify.ts +342 -0
- package/src/control-api/types.ts +56 -0
- package/src/exports/control-api.ts +13 -2
- package/src/load-ts-contract.ts +28 -26
- package/src/utils/combine-schema-results.ts +84 -0
- package/src/utils/command-helpers.ts +24 -2
- package/src/utils/contract-space-aggregate-loader.ts +236 -0
- package/src/utils/contract-space-extension-migrations-pass.ts +120 -0
- package/src/utils/contract-space-migrate-pass.ts +156 -0
- package/dist/client-CW1hcUtM.mjs +0 -1025
- package/dist/client-CW1hcUtM.mjs.map +0 -1
- package/dist/commands/db-verify.mjs.map +0 -1
- package/dist/commands/migration-plan.mjs.map +0 -1
- package/dist/result-handler-C0QeiqKO.mjs.map +0 -1
- /package/dist/{cli-errors-BWn943z2.d.mts → cli-errors-QH8kf-C2.d.mts} +0 -0
|
@@ -43,6 +43,15 @@ import {
|
|
|
43
43
|
setCommandDescriptions,
|
|
44
44
|
setCommandExamples,
|
|
45
45
|
} from '../utils/command-helpers';
|
|
46
|
+
import {
|
|
47
|
+
type ExtensionMigrationsExtensionInput,
|
|
48
|
+
runContractSpaceExtensionMigrationsPass,
|
|
49
|
+
} from '../utils/contract-space-extension-migrations-pass';
|
|
50
|
+
import {
|
|
51
|
+
formatContractSpaceDriftWarning,
|
|
52
|
+
type MigrateExtensionInput,
|
|
53
|
+
runContractSpaceMigratePass,
|
|
54
|
+
} from '../utils/contract-space-migrate-pass';
|
|
46
55
|
import { formatStyledHeader } from '../utils/formatters/styled';
|
|
47
56
|
import { assertFrameworkComponentsCompatible } from '../utils/framework-components';
|
|
48
57
|
import type { CommonCommandOptions } from '../utils/global-flags';
|
|
@@ -92,10 +101,8 @@ async function executeMigrationPlanCommand(
|
|
|
92
101
|
startTime: number,
|
|
93
102
|
): Promise<Result<MigrationPlanResult, CliStructuredError>> {
|
|
94
103
|
const config = await loadConfig(options.config);
|
|
95
|
-
const { configPath, migrationsDir,
|
|
96
|
-
options.config,
|
|
97
|
-
config,
|
|
98
|
-
);
|
|
104
|
+
const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative } =
|
|
105
|
+
resolveMigrationPaths(options.config, config);
|
|
99
106
|
|
|
100
107
|
const contractPathAbsolute = resolveContractPath(config);
|
|
101
108
|
const contractPath = relative(process.cwd(), contractPathAbsolute);
|
|
@@ -104,7 +111,7 @@ async function executeMigrationPlanCommand(
|
|
|
104
111
|
const details: Array<{ label: string; value: string }> = [
|
|
105
112
|
{ label: 'config', value: configPath },
|
|
106
113
|
{ label: 'contract', value: contractPath },
|
|
107
|
-
{ label: 'migrations', value:
|
|
114
|
+
{ label: 'migrations', value: appMigrationsRelative },
|
|
108
115
|
];
|
|
109
116
|
if (options.from) {
|
|
110
117
|
details.push({ label: 'from', value: options.from });
|
|
@@ -170,7 +177,7 @@ async function executeMigrationPlanCommand(
|
|
|
170
177
|
let fromContractSourceDir: string | null = null;
|
|
171
178
|
|
|
172
179
|
try {
|
|
173
|
-
const { bundles, graph } = await loadMigrationPackages(
|
|
180
|
+
const { bundles, graph } = await loadMigrationPackages(appMigrationsDir);
|
|
174
181
|
|
|
175
182
|
if (options.from) {
|
|
176
183
|
const resolved = resolveBundleByPrefix(bundles, options.from);
|
|
@@ -179,11 +186,11 @@ async function executeMigrationPlanCommand(
|
|
|
179
186
|
return notOk(
|
|
180
187
|
f.reason === 'ambiguous'
|
|
181
188
|
? errorRuntime('Multiple matching migrations found', {
|
|
182
|
-
why: `Prefix "${options.from}" matches ${f.count} migrations in ${
|
|
189
|
+
why: `Prefix "${options.from}" matches ${f.count} migrations in ${appMigrationsRelative}`,
|
|
183
190
|
fix: 'Provide a longer prefix to disambiguate, or omit --from to use the latest migration target.',
|
|
184
191
|
})
|
|
185
192
|
: errorRuntime('Starting contract not found', {
|
|
186
|
-
why: `No migration with to hash matching "${options.from}" exists in ${
|
|
193
|
+
why: `No migration with to hash matching "${options.from}" exists in ${appMigrationsRelative}`,
|
|
187
194
|
fix: 'Check that the --from hash matches a known migration target hash, or omit --from to use the latest migration target.',
|
|
188
195
|
}),
|
|
189
196
|
);
|
|
@@ -220,6 +227,56 @@ async function executeMigrationPlanCommand(
|
|
|
220
227
|
);
|
|
221
228
|
}
|
|
222
229
|
|
|
230
|
+
// Per-space migrate pass: drift detection + on-disk artefact emission for
|
|
231
|
+
// every loaded extension that exposes a `contractSpace`. Runs *before*
|
|
232
|
+
// the app-space no-op check so that an extension bump alone (with no
|
|
233
|
+
// structural app-space change) still re-pins extension artefacts on
|
|
234
|
+
// disk. Drift warnings are non-fatal — the on-disk artefacts are refreshed
|
|
235
|
+
// and the user is notified that the bump is being captured.
|
|
236
|
+
const extensionInputs: readonly MigrateExtensionInput[] = (config.extensionPacks ?? []).map(
|
|
237
|
+
(pack) => {
|
|
238
|
+
const cs = (pack as { readonly contractSpace?: MigrateExtensionInput['contractSpace'] })
|
|
239
|
+
.contractSpace;
|
|
240
|
+
return cs !== undefined ? { id: pack.id, contractSpace: cs } : { id: pack.id };
|
|
241
|
+
},
|
|
242
|
+
);
|
|
243
|
+
const migratePass = await runContractSpaceMigratePass({
|
|
244
|
+
migrationsDir,
|
|
245
|
+
extensionPacks: extensionInputs,
|
|
246
|
+
});
|
|
247
|
+
if (!flags.json && !flags.quiet) {
|
|
248
|
+
for (const drift of migratePass.drifts) {
|
|
249
|
+
if (drift.kind === 'drift') {
|
|
250
|
+
ui.stderr(formatContractSpaceDriftWarning(drift));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Materialise descriptor-shipped migration packages onto disk under
|
|
256
|
+
// `migrations/<spaceId>/<dirName>/` for any package not yet present.
|
|
257
|
+
// Idempotent (existing dirs are left untouched).
|
|
258
|
+
// Uses `planAllSpaces` for deterministic ordering + duplicate-spaceId
|
|
259
|
+
// detection.
|
|
260
|
+
const extensionMigrationsInputs: readonly ExtensionMigrationsExtensionInput[] = (
|
|
261
|
+
config.extensionPacks ?? []
|
|
262
|
+
).map((pack) => {
|
|
263
|
+
const cs = (
|
|
264
|
+
pack as {
|
|
265
|
+
readonly contractSpace?: ExtensionMigrationsExtensionInput['contractSpace'];
|
|
266
|
+
}
|
|
267
|
+
).contractSpace;
|
|
268
|
+
return cs !== undefined ? { id: pack.id, contractSpace: cs } : { id: pack.id };
|
|
269
|
+
});
|
|
270
|
+
const extensionMigrationsResult = await runContractSpaceExtensionMigrationsPass({
|
|
271
|
+
migrationsDir,
|
|
272
|
+
extensionPacks: extensionMigrationsInputs,
|
|
273
|
+
});
|
|
274
|
+
if (!flags.json && !flags.quiet) {
|
|
275
|
+
for (const entry of extensionMigrationsResult.emitted) {
|
|
276
|
+
ui.step(`Emitted ${entry.spaceId}/${entry.dirName}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
223
280
|
// Check for no-op (same hash means no changes)
|
|
224
281
|
if (fromHash === toStorageHash) {
|
|
225
282
|
const result: MigrationPlanResult = {
|
|
@@ -253,7 +310,7 @@ async function executeMigrationPlanCommand(
|
|
|
253
310
|
const timestamp = new Date();
|
|
254
311
|
const slug = options.name ?? 'migration';
|
|
255
312
|
const dirName = formatMigrationDirName(timestamp, slug);
|
|
256
|
-
const packageDir = join(
|
|
313
|
+
const packageDir = join(appMigrationsDir, dirName);
|
|
257
314
|
|
|
258
315
|
const baseMetadata: Omit<MigrationMetadata, 'migrationHash' | 'providedInvariants'> = {
|
|
259
316
|
from: fromHash,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
reconstructGraph,
|
|
10
10
|
} from '@prisma-next/migration-tools/migration-graph';
|
|
11
11
|
import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
|
|
12
|
+
import { APP_SPACE_ID, spaceMigrationDirectory } from '@prisma-next/migration-tools/spaces';
|
|
12
13
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
13
14
|
import { Command } from 'commander';
|
|
14
15
|
import { relative, resolve } from 'pathe';
|
|
@@ -103,16 +104,17 @@ async function executeMigrationShowCommand(
|
|
|
103
104
|
? relative(process.cwd(), resolve(options.config))
|
|
104
105
|
: 'prisma-next.config.ts';
|
|
105
106
|
|
|
106
|
-
const
|
|
107
|
+
const migrationsDirRoot = resolve(
|
|
107
108
|
options.config ? resolve(options.config, '..') : process.cwd(),
|
|
108
109
|
config.migrations?.dir ?? 'migrations',
|
|
109
110
|
);
|
|
110
|
-
const
|
|
111
|
+
const appMigrationsDir = spaceMigrationDirectory(migrationsDirRoot, APP_SPACE_ID);
|
|
112
|
+
const appMigrationsRelative = relative(process.cwd(), appMigrationsDir);
|
|
111
113
|
|
|
112
114
|
if (!flags.json && !flags.quiet) {
|
|
113
115
|
const details: Array<{ label: string; value: string }> = [
|
|
114
116
|
{ label: 'config', value: configPath },
|
|
115
|
-
{ label: 'migrations', value:
|
|
117
|
+
{ label: 'migrations', value: appMigrationsRelative },
|
|
116
118
|
];
|
|
117
119
|
if (target) {
|
|
118
120
|
details.push({ label: 'target', value: target });
|
|
@@ -132,11 +134,11 @@ async function executeMigrationShowCommand(
|
|
|
132
134
|
if (target && looksLikePath(target)) {
|
|
133
135
|
pkg = await readMigrationPackage(resolve(target));
|
|
134
136
|
} else {
|
|
135
|
-
const allPackages = await readMigrationsDir(
|
|
137
|
+
const allPackages = await readMigrationsDir(appMigrationsDir);
|
|
136
138
|
if (allPackages.length === 0) {
|
|
137
139
|
return notOk(
|
|
138
140
|
errorRuntime('No migrations found', {
|
|
139
|
-
why: `No migration packages found in ${
|
|
141
|
+
why: `No migration packages found in ${appMigrationsRelative}`,
|
|
140
142
|
fix: 'Run `prisma-next migration plan` to create a migration first.',
|
|
141
143
|
}),
|
|
142
144
|
);
|
|
@@ -369,7 +369,7 @@ async function executeMigrationStatusCommand(
|
|
|
369
369
|
ui: TerminalUI,
|
|
370
370
|
): Promise<Result<MigrationStatusResult, CliStructuredError>> {
|
|
371
371
|
const config = await loadConfig(options.config);
|
|
372
|
-
const { configPath,
|
|
372
|
+
const { configPath, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(
|
|
373
373
|
options.config,
|
|
374
374
|
config,
|
|
375
375
|
);
|
|
@@ -414,7 +414,7 @@ async function executeMigrationStatusCommand(
|
|
|
414
414
|
if (!flags.json && !flags.quiet) {
|
|
415
415
|
const details: Array<{ label: string; value: string }> = [
|
|
416
416
|
{ label: 'config', value: configPath },
|
|
417
|
-
{ label: 'migrations', value:
|
|
417
|
+
{ label: 'migrations', value: appMigrationsRelative },
|
|
418
418
|
];
|
|
419
419
|
if (dbConnection && hasDriver) {
|
|
420
420
|
details.push({ label: 'database', value: maskConnectionUrl(String(dbConnection)) });
|
|
@@ -454,7 +454,7 @@ async function executeMigrationStatusCommand(
|
|
|
454
454
|
let bundles: readonly OnDiskMigrationPackage[];
|
|
455
455
|
let graph: MigrationGraph;
|
|
456
456
|
try {
|
|
457
|
-
({ bundles, graph } = await loadMigrationPackages(
|
|
457
|
+
({ bundles, graph } = await loadMigrationPackages(appMigrationsDir));
|
|
458
458
|
} catch (error) {
|
|
459
459
|
if (MigrationToolsError.is(error)) {
|
|
460
460
|
return notOk(mapMigrationToolsError(error));
|
|
@@ -28,7 +28,9 @@ import { enrichContract } from './contract-enrichment';
|
|
|
28
28
|
import { ContractValidationError } from './errors';
|
|
29
29
|
import { executeDbInit } from './operations/db-init';
|
|
30
30
|
import { executeDbUpdate } from './operations/db-update';
|
|
31
|
+
import { type ExecuteDbVerifyResult, executeDbVerify } from './operations/db-verify';
|
|
31
32
|
import { executeMigrationApply } from './operations/migration-apply';
|
|
33
|
+
|
|
32
34
|
import type {
|
|
33
35
|
ControlActionName,
|
|
34
36
|
ControlClient,
|
|
@@ -37,6 +39,7 @@ import type {
|
|
|
37
39
|
DbInitResult,
|
|
38
40
|
DbUpdateOptions,
|
|
39
41
|
DbUpdateResult,
|
|
42
|
+
DbVerifyOptions,
|
|
40
43
|
EmitOptions,
|
|
41
44
|
EmitResult,
|
|
42
45
|
IntrospectOptions,
|
|
@@ -368,6 +371,9 @@ class ControlClientImpl implements ControlClient {
|
|
|
368
371
|
mode: options.mode,
|
|
369
372
|
migrations: this.options.target.migrations,
|
|
370
373
|
frameworkComponents,
|
|
374
|
+
migrationsDir: options.migrationsDir,
|
|
375
|
+
targetId: this.options.target.targetId,
|
|
376
|
+
extensionPacks: this.options.extensionPacks ?? [],
|
|
371
377
|
...ifDefined('onProgress', onProgress),
|
|
372
378
|
});
|
|
373
379
|
}
|
|
@@ -396,11 +402,42 @@ class ControlClientImpl implements ControlClient {
|
|
|
396
402
|
mode: options.mode,
|
|
397
403
|
migrations: this.options.target.migrations,
|
|
398
404
|
frameworkComponents,
|
|
405
|
+
migrationsDir: options.migrationsDir,
|
|
406
|
+
targetId: this.options.target.targetId,
|
|
407
|
+
extensionPacks: this.options.extensionPacks ?? [],
|
|
399
408
|
...ifDefined('acceptDataLoss', options.acceptDataLoss),
|
|
400
409
|
...ifDefined('onProgress', onProgress),
|
|
401
410
|
});
|
|
402
411
|
}
|
|
403
412
|
|
|
413
|
+
async dbVerify(options: DbVerifyOptions): Promise<ExecuteDbVerifyResult> {
|
|
414
|
+
const { onProgress } = options;
|
|
415
|
+
await this.connectWithProgress(options.connection, 'dbVerify', onProgress);
|
|
416
|
+
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
417
|
+
|
|
418
|
+
let contract: Contract;
|
|
419
|
+
try {
|
|
420
|
+
contract = familyInstance.validateContract(options.contract);
|
|
421
|
+
} catch (error) {
|
|
422
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
423
|
+
throw new ContractValidationError(message, error);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return executeDbVerify({
|
|
427
|
+
driver,
|
|
428
|
+
familyInstance,
|
|
429
|
+
contract,
|
|
430
|
+
migrationsDir: options.migrationsDir,
|
|
431
|
+
targetId: this.options.target.targetId,
|
|
432
|
+
extensionPacks: this.options.extensionPacks ?? [],
|
|
433
|
+
frameworkComponents,
|
|
434
|
+
mode: options.strict ? 'strict' : 'lenient',
|
|
435
|
+
skipSchema: options.skipSchema,
|
|
436
|
+
skipMarker: options.skipMarker,
|
|
437
|
+
...ifDefined('onProgress', onProgress),
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
404
441
|
async readMarker(): Promise<ContractMarkerRecord | null> {
|
|
405
442
|
const { driver, familyInstance } = await this.ensureConnected();
|
|
406
443
|
// The CLI client's readMarker reads the app's marker. Per-extension
|
|
@@ -410,6 +447,11 @@ class ControlClientImpl implements ControlClient {
|
|
|
410
447
|
return familyInstance.readMarker({ driver, space: APP_SPACE_ID });
|
|
411
448
|
}
|
|
412
449
|
|
|
450
|
+
async readAllMarkers(): Promise<ReadonlyMap<string, ContractMarkerRecord>> {
|
|
451
|
+
const { driver, familyInstance } = await this.ensureConnected();
|
|
452
|
+
return familyInstance.readAllMarkers({ driver });
|
|
453
|
+
}
|
|
454
|
+
|
|
413
455
|
async migrationApply(options: MigrationApplyOptions): Promise<MigrationApplyResult> {
|
|
414
456
|
const { onProgress } = options;
|
|
415
457
|
await this.connectWithProgress(options.connection, 'migrationApply', onProgress);
|