@prisma-next/cli 0.5.0-dev.74 → 0.5.0-dev.76
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/{client-0ZX24FXF.mjs → client-qVH-rEgd.mjs} +433 -236
- package/dist/client-qVH-rEgd.mjs.map +1 -0
- package/dist/{result-handler-DWb1rFS-.mjs → command-helpers-BeZHkxV8.mjs} +22 -24
- package/dist/command-helpers-BeZHkxV8.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 +5 -4
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +6 -5
- package/dist/commands/db-sign.mjs.map +1 -1
- 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.mjs +1 -1
- package/dist/commands/migration-apply.d.mts +29 -17
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +35 -129
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.mjs +4 -3
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +19 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +2 -2
- package/dist/commands/migration-ref.d.mts +1 -1
- package/dist/commands/migration-ref.mjs +3 -2
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +5 -4
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +104 -1
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -2
- package/dist/{contract-emit-DkMqO7f2.mjs → contract-emit-9DBda5Ou.mjs} +7 -5
- package/dist/{contract-emit-DkMqO7f2.mjs.map → contract-emit-9DBda5Ou.mjs.map} +1 -1
- package/dist/{contract-emit-B3ChISB_.mjs → contract-emit-B77TsJqf.mjs} +4 -15
- package/dist/{contract-emit-B3ChISB_.mjs.map → contract-emit-B77TsJqf.mjs.map} +1 -1
- package/dist/{contract-enrichment-CF6ogEJ_.mjs → contract-enrichment-Dani0mMW.mjs} +1 -1
- package/dist/{contract-enrichment-CF6ogEJ_.mjs.map → contract-enrichment-Dani0mMW.mjs.map} +1 -1
- package/dist/{contract-infer-BDKAE0B0.mjs → contract-infer-BK9YFGEG.mjs} +5 -4
- package/dist/{contract-infer-BDKAE0B0.mjs.map → contract-infer-BK9YFGEG.mjs.map} +1 -1
- package/dist/{db-verify-B4TdDKOI.mjs → db-verify-C0y1PCO2.mjs} +7 -6
- package/dist/{db-verify-B4TdDKOI.mjs.map → db-verify-C0y1PCO2.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +3 -746
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/extension-pack-inputs-C7xgE-vv.mjs +74 -0
- package/dist/extension-pack-inputs-C7xgE-vv.mjs.map +1 -0
- package/dist/{framework-components-gwAHl7ml.mjs → framework-components-ChqVUxR-.mjs} +1 -1
- package/dist/{framework-components-gwAHl7ml.mjs.map → framework-components-ChqVUxR-.mjs.map} +1 -1
- package/dist/global-flags-Icqpxk23.d.mts +12 -0
- package/dist/global-flags-Icqpxk23.d.mts.map +1 -0
- package/dist/helpers-eqdN8tH6.mjs +25 -0
- package/dist/helpers-eqdN8tH6.mjs.map +1 -0
- package/dist/{init-Deo7U8_U.mjs → init-CoDVPvQ4.mjs} +4 -4
- package/dist/{init-Deo7U8_U.mjs.map → init-CoDVPvQ4.mjs.map} +1 -1
- package/dist/{inspect-live-schema-BAgQMYpD.mjs → inspect-live-schema-CWYxGKlb.mjs} +4 -4
- package/dist/{inspect-live-schema-BAgQMYpD.mjs.map → inspect-live-schema-CWYxGKlb.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-B8J702Uh.mjs → migration-command-scaffold-B5dORFEv.mjs} +4 -4
- package/dist/{migration-command-scaffold-B8J702Uh.mjs.map → migration-command-scaffold-B5dORFEv.mjs.map} +1 -1
- package/dist/{migration-plan-BcKNnTM7.mjs → migration-plan-C6lVaHsO.mjs} +47 -23
- package/dist/migration-plan-C6lVaHsO.mjs.map +1 -0
- package/dist/{migration-status-CjwB2of-.mjs → migration-status-CZ-D5k7k.mjs} +161 -7
- package/dist/migration-status-CZ-D5k7k.mjs.map +1 -0
- package/dist/{migrations-CIK94AJf.mjs → migrations-D_UJnpuW.mjs} +67 -24
- package/dist/migrations-D_UJnpuW.mjs.map +1 -0
- package/dist/{output-DnjfCC_u.mjs → output-B16Kefzx.mjs} +1 -1
- package/dist/{output-DnjfCC_u.mjs.map → output-B16Kefzx.mjs.map} +1 -1
- package/dist/{progress-adapter-xASh41wr.mjs → progress-adapter-DFfvZcYL.mjs} +1 -1
- package/dist/{progress-adapter-xASh41wr.mjs.map → progress-adapter-DFfvZcYL.mjs.map} +1 -1
- package/dist/result-handler-rmPVKIP2.mjs +25 -0
- package/dist/result-handler-rmPVKIP2.mjs.map +1 -0
- package/dist/rolldown-runtime-twds-ZHy.mjs +14 -0
- package/dist/{terminal-ui-zaRDhJnP.mjs → terminal-ui-C_hFNbAn.mjs} +3 -23
- package/dist/terminal-ui-C_hFNbAn.mjs.map +1 -0
- package/dist/types-D7x-IFLO.d.mts +858 -0
- package/dist/types-D7x-IFLO.d.mts.map +1 -0
- package/dist/{verify-BEIa9638.mjs → verify-CiwNWM9N.mjs} +2 -2
- package/dist/{verify-BEIa9638.mjs.map → verify-CiwNWM9N.mjs.map} +1 -1
- package/package.json +14 -14
- package/src/commands/db-init.ts +1 -0
- package/src/commands/db-update.ts +1 -0
- package/src/commands/migration-apply.ts +94 -213
- package/src/commands/migration-plan.ts +89 -32
- package/src/commands/migration-status.ts +288 -5
- package/src/control-api/client.ts +16 -4
- package/src/control-api/operations/apply-aggregate.ts +290 -0
- package/src/control-api/operations/db-apply-aggregate.ts +42 -91
- package/src/control-api/operations/migration-apply.ts +420 -155
- package/src/control-api/types.ts +165 -32
- package/src/utils/contract-space-aggregate-loader.ts +24 -56
- package/src/utils/extension-pack-inputs.ts +170 -0
- package/src/utils/formatters/migrations.ts +135 -35
- package/dist/client-0ZX24FXF.mjs.map +0 -1
- package/dist/migration-plan-BcKNnTM7.mjs.map +0 -1
- package/dist/migration-status-CjwB2of-.mjs.map +0 -1
- package/dist/migrations-CIK94AJf.mjs.map +0 -1
- package/dist/result-handler-DWb1rFS-.mjs.map +0 -1
- package/dist/terminal-ui-zaRDhJnP.mjs.map +0 -1
- /package/dist/{cli-errors-QH8kf-C2.d.mts → cli-errors-B9OBbled.d.mts} +0 -0
package/src/control-api/types.ts
CHANGED
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
VerifyDatabaseSchemaResult,
|
|
19
19
|
} from '@prisma-next/framework-components/control';
|
|
20
20
|
import type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';
|
|
21
|
+
import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
|
|
21
22
|
import type { Result } from '@prisma-next/utils/result';
|
|
22
23
|
import type { ExecuteDbVerifyResult } from './operations/db-verify';
|
|
23
24
|
|
|
@@ -308,6 +309,42 @@ export interface EmitOptions {
|
|
|
308
309
|
// Result Types
|
|
309
310
|
// ============================================================================
|
|
310
311
|
|
|
312
|
+
/**
|
|
313
|
+
* Per-space breakdown of an aggregate plan / apply.
|
|
314
|
+
*
|
|
315
|
+
* Surfaces the canonical schedule shape — extensions alphabetically,
|
|
316
|
+
* then app — together with the operations attributed to each space and,
|
|
317
|
+
* when the run was applied, the resulting per-space marker hash.
|
|
318
|
+
*
|
|
319
|
+
* M6 sub-spec § Output shape contract — every space involved in a run
|
|
320
|
+
* is observable in the success summary, including its post-apply
|
|
321
|
+
* marker, so the per-space invariant is visible to the user (closing
|
|
322
|
+
* F4 / F7 from `e2e-verification.md`).
|
|
323
|
+
*/
|
|
324
|
+
export interface AggregatePerSpaceExecutionEntry {
|
|
325
|
+
readonly spaceId: string;
|
|
326
|
+
/** `'app'` for the application's contract space; `'extension'` for any extension space. */
|
|
327
|
+
readonly kind: 'app' | 'extension';
|
|
328
|
+
/**
|
|
329
|
+
* Operations attributed to this space (display ops). In `mode: 'plan'`
|
|
330
|
+
* this is the planned set; in `mode: 'apply'` it is the same set
|
|
331
|
+
* (every op was executed in order, the runner does not skip).
|
|
332
|
+
*/
|
|
333
|
+
readonly operations: ReadonlyArray<{
|
|
334
|
+
readonly id: string;
|
|
335
|
+
readonly label: string;
|
|
336
|
+
readonly operationClass: string;
|
|
337
|
+
}>;
|
|
338
|
+
/**
|
|
339
|
+
* Post-apply marker hash for this space. Present only when the run
|
|
340
|
+
* was applied (i.e. `mode: 'apply'` and the runner returned ok).
|
|
341
|
+
* Equals the per-space plan's `destination.storageHash`.
|
|
342
|
+
*/
|
|
343
|
+
readonly marker?: {
|
|
344
|
+
readonly storageHash: string;
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
311
348
|
/**
|
|
312
349
|
* Successful dbInit result.
|
|
313
350
|
*/
|
|
@@ -340,6 +377,14 @@ export interface DbInitSuccess {
|
|
|
340
377
|
readonly storageHash: string;
|
|
341
378
|
readonly profileHash?: string;
|
|
342
379
|
};
|
|
380
|
+
/**
|
|
381
|
+
* Per-space breakdown in canonical schedule order (extensions
|
|
382
|
+
* alphabetically, then app). Present whenever the aggregate flow
|
|
383
|
+
* produced one — both `mode: 'plan'` and `mode: 'apply'`.
|
|
384
|
+
*
|
|
385
|
+
* See {@link AggregatePerSpaceExecutionEntry}.
|
|
386
|
+
*/
|
|
387
|
+
readonly perSpace?: ReadonlyArray<AggregatePerSpaceExecutionEntry>;
|
|
343
388
|
readonly summary: string;
|
|
344
389
|
}
|
|
345
390
|
|
|
@@ -405,6 +450,11 @@ export interface DbUpdateSuccess {
|
|
|
405
450
|
readonly storageHash: string;
|
|
406
451
|
readonly profileHash?: string;
|
|
407
452
|
};
|
|
453
|
+
/**
|
|
454
|
+
* Per-space breakdown in canonical schedule order (extensions
|
|
455
|
+
* alphabetically, then app). See {@link AggregatePerSpaceExecutionEntry}.
|
|
456
|
+
*/
|
|
457
|
+
readonly perSpace?: ReadonlyArray<AggregatePerSpaceExecutionEntry>;
|
|
408
458
|
readonly summary: string;
|
|
409
459
|
}
|
|
410
460
|
|
|
@@ -477,44 +527,48 @@ export type EmitResult = Result<EmitSuccess, EmitFailure>;
|
|
|
477
527
|
// ============================================================================
|
|
478
528
|
|
|
479
529
|
/**
|
|
480
|
-
*
|
|
481
|
-
*
|
|
530
|
+
* Options for the aggregate-walking `migrationApply` operation.
|
|
531
|
+
*
|
|
532
|
+
* The control-api operation is responsible for: loading the
|
|
533
|
+
* contract-space aggregate, reading per-space marker rows from the
|
|
534
|
+
* live database, plotting per-space paths via `graphWalkStrategy`
|
|
535
|
+
* (replay-only — no synth, no introspection), and dispatching
|
|
536
|
+
* through the shared `applyAggregate` primitive. The CLI command
|
|
537
|
+
* just resolves the descriptor surface (config, refs, contract
|
|
538
|
+
* envelope, app-space migration packages) and hands the inputs in.
|
|
539
|
+
*
|
|
540
|
+
* Sub-spec § `migration apply` semantics + § Required changes 1.
|
|
482
541
|
*/
|
|
483
|
-
export interface
|
|
484
|
-
|
|
485
|
-
readonly
|
|
486
|
-
|
|
487
|
-
readonly
|
|
488
|
-
readonly operations: readonly MigrationPlanOperation[];
|
|
542
|
+
export interface MigrationApplyOptions {
|
|
543
|
+
/** Already-validated app contract (the canonical "where we are heading" hash). */
|
|
544
|
+
readonly contract: unknown;
|
|
545
|
+
/** Migrations root directory (`migrations/` under the project). */
|
|
546
|
+
readonly migrationsDir: string;
|
|
489
547
|
/**
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
* to the runner via `MigrationPlan.providedInvariants` so target runners
|
|
494
|
-
* read the canonical set instead of re-deriving from `operations`.
|
|
548
|
+
* Already-loaded app-space migration packages. The CLI loads these
|
|
549
|
+
* via `loadMigrationPackages(appMigrationsDir)` before invoking
|
|
550
|
+
* `migrationApply`.
|
|
495
551
|
*/
|
|
496
|
-
readonly
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* Options for the migrationApply operation.
|
|
501
|
-
*/
|
|
502
|
-
export interface MigrationApplyOptions {
|
|
552
|
+
readonly appMigrationPackages: ReadonlyArray<OnDiskMigrationPackage>;
|
|
503
553
|
/**
|
|
504
|
-
*
|
|
505
|
-
*
|
|
554
|
+
* Optional app-space ref override. When provided, the app member's
|
|
555
|
+
* graph-walk targets this hash instead of `contract.storage.storageHash`.
|
|
556
|
+
* Extension members always walk to their own `headRef.hash`.
|
|
506
557
|
*/
|
|
507
|
-
readonly
|
|
558
|
+
readonly refHash?: string;
|
|
508
559
|
/**
|
|
509
|
-
*
|
|
510
|
-
*
|
|
560
|
+
* Required invariants on the user-supplied app-space ref. Threaded
|
|
561
|
+
* into the graph-walk's `required` calculation so the planner picks
|
|
562
|
+
* an invariant-bearing path. Ignored when `refHash` is absent.
|
|
511
563
|
*/
|
|
512
|
-
readonly
|
|
564
|
+
readonly refInvariants?: readonly string[];
|
|
513
565
|
/**
|
|
514
|
-
*
|
|
515
|
-
*
|
|
566
|
+
* Resolved name of the user-supplied app-space ref (the literal the
|
|
567
|
+
* user passed to `--ref`). Decorates `pathDecision.refName` and any
|
|
568
|
+
* `MIGRATION.NO_INVARIANT_PATH` envelope raised during graph-walk.
|
|
569
|
+
* Ignored when `refHash` is absent.
|
|
516
570
|
*/
|
|
517
|
-
readonly
|
|
571
|
+
readonly refName?: string;
|
|
518
572
|
/**
|
|
519
573
|
* Database connection. If provided, migrationApply will connect before executing.
|
|
520
574
|
* If omitted, the client must already be connected.
|
|
@@ -525,23 +579,102 @@ export interface MigrationApplyOptions {
|
|
|
525
579
|
}
|
|
526
580
|
|
|
527
581
|
/**
|
|
528
|
-
*
|
|
582
|
+
* A single on-disk migration package surfaced to the operation. The
|
|
583
|
+
* SQL family already produces this shape via `loadMigrationPackages`;
|
|
584
|
+
* the operation hands it through to the framework-neutral aggregate
|
|
585
|
+
* loader's `appMigrationPackages` slot.
|
|
586
|
+
*
|
|
587
|
+
* (Originally named `MigrationApplyStep` for the legacy single-space
|
|
588
|
+
* apply path; the name is kept for compatibility with existing CLI
|
|
589
|
+
* callers and tests.)
|
|
529
590
|
*/
|
|
530
|
-
export interface
|
|
591
|
+
export interface MigrationApplyStep {
|
|
531
592
|
readonly dirName: string;
|
|
532
593
|
readonly from: string | null;
|
|
533
594
|
readonly to: string;
|
|
595
|
+
readonly toContract: Contract;
|
|
596
|
+
readonly operations: readonly MigrationPlanOperation[];
|
|
597
|
+
/**
|
|
598
|
+
* Sorted, deduplicated invariant ids from `migration.json.providedInvariants`.
|
|
599
|
+
* Verified at load time by `readMigrationPackage` (manifest copy must equal
|
|
600
|
+
* the value derived from `ops.json`).
|
|
601
|
+
*/
|
|
602
|
+
readonly providedInvariants: readonly string[];
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Record of a successfully applied per-space migration. One entry per
|
|
607
|
+
* contract space that had pending migrations — empty `applied` means
|
|
608
|
+
* every space was already at its head.
|
|
609
|
+
*/
|
|
610
|
+
/**
|
|
611
|
+
* One entry per authored migration package applied. Preserves the
|
|
612
|
+
* single-space `migrationsApplied` count semantics (each entry is
|
|
613
|
+
* one migration directory) so `applied.length === migrationsApplied`.
|
|
614
|
+
*
|
|
615
|
+
* Per-space aggregate detail (markers, ops grouped by space) lives
|
|
616
|
+
* on `perSpace[]`; this list is the per-edge view.
|
|
617
|
+
*/
|
|
618
|
+
export interface MigrationApplyAppliedEntry {
|
|
619
|
+
readonly spaceId: string;
|
|
620
|
+
readonly dirName: string;
|
|
621
|
+
readonly migrationHash: string;
|
|
622
|
+
readonly from: string;
|
|
623
|
+
readonly to: string;
|
|
534
624
|
readonly operationsExecuted: number;
|
|
535
625
|
}
|
|
536
626
|
|
|
537
627
|
/**
|
|
538
|
-
* Successful migrationApply result.
|
|
628
|
+
* Successful migrationApply result. Carries both the legacy
|
|
629
|
+
* single-space fields (`markerHash` is the **app member's** post-apply
|
|
630
|
+
* marker, surfaced for back-compat with single-space callers) and the
|
|
631
|
+
* per-space breakdown (`perSpace` — markers / operations / canonical
|
|
632
|
+
* order, per M6 sub-spec § Output shape).
|
|
539
633
|
*/
|
|
634
|
+
/**
|
|
635
|
+
* Path-decision summary for the **app member** post-apply. Surfaced
|
|
636
|
+
* for back-compat with single-space callers (and the cli-journeys
|
|
637
|
+
* suite, which inspects `requiredInvariants`/`satisfiedInvariants`/
|
|
638
|
+
* `selectedPath` to validate invariant routing).
|
|
639
|
+
*
|
|
640
|
+
* Per-space path decisions for extension members are not surfaced —
|
|
641
|
+
* extensions own their own ref/invariant control.
|
|
642
|
+
*/
|
|
643
|
+
export interface MigrationApplyPathDecision {
|
|
644
|
+
readonly fromHash: string;
|
|
645
|
+
readonly toHash: string;
|
|
646
|
+
readonly alternativeCount: number;
|
|
647
|
+
readonly tieBreakReasons: readonly string[];
|
|
648
|
+
readonly refName?: string;
|
|
649
|
+
readonly requiredInvariants: readonly string[];
|
|
650
|
+
readonly satisfiedInvariants: readonly string[];
|
|
651
|
+
readonly selectedPath: readonly {
|
|
652
|
+
readonly dirName: string;
|
|
653
|
+
readonly migrationHash: string;
|
|
654
|
+
readonly from: string;
|
|
655
|
+
readonly to: string;
|
|
656
|
+
readonly invariants: readonly string[];
|
|
657
|
+
}[];
|
|
658
|
+
}
|
|
659
|
+
|
|
540
660
|
export interface MigrationApplySuccess {
|
|
541
661
|
readonly migrationsApplied: number;
|
|
542
662
|
readonly markerHash: string;
|
|
543
663
|
readonly applied: readonly MigrationApplyAppliedEntry[];
|
|
544
664
|
readonly summary: string;
|
|
665
|
+
/**
|
|
666
|
+
* Per-space breakdown in canonical schedule order (extensions
|
|
667
|
+
* alphabetically, then app). See {@link AggregatePerSpaceExecutionEntry}.
|
|
668
|
+
* Always present for the aggregate-walking operation.
|
|
669
|
+
*/
|
|
670
|
+
readonly perSpace: ReadonlyArray<AggregatePerSpaceExecutionEntry>;
|
|
671
|
+
/**
|
|
672
|
+
* Path-decision data for the app member. Present whenever the
|
|
673
|
+
* graph-walk strategy ran for the app (i.e. always for the
|
|
674
|
+
* aggregate-walking apply path). Absent only for the no-op
|
|
675
|
+
* "Already up to date" early return when the app has no plan.
|
|
676
|
+
*/
|
|
677
|
+
readonly pathDecision?: MigrationApplyPathDecision;
|
|
545
678
|
}
|
|
546
679
|
|
|
547
680
|
/**
|
|
@@ -2,63 +2,15 @@ import type { Contract } from '@prisma-next/contract/types';
|
|
|
2
2
|
import type { ControlExtensionDescriptor } from '@prisma-next/framework-components/control';
|
|
3
3
|
import type {
|
|
4
4
|
ContractSpaceAggregate,
|
|
5
|
-
DeclaredExtensionEntry,
|
|
6
5
|
LoadAggregateError,
|
|
7
6
|
LoadAggregateInput,
|
|
8
7
|
LoadAggregateOutput,
|
|
9
8
|
} from '@prisma-next/migration-tools/aggregate';
|
|
10
9
|
import { loadContractSpaceAggregate } from '@prisma-next/migration-tools/aggregate';
|
|
10
|
+
import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
|
|
11
11
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
12
12
|
import { CliStructuredError } from './cli-errors';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Structural shape the aggregate loader needs from each declared
|
|
16
|
-
* `Config.extensionPacks` entry. Mirrors the SQL family's
|
|
17
|
-
* `SqlControlExtensionDescriptor.contractSpace` shape but kept
|
|
18
|
-
* structural so the loader doesn't depend on the SQL family.
|
|
19
|
-
*/
|
|
20
|
-
type ExtensionPackForAggregate = {
|
|
21
|
-
readonly id: string;
|
|
22
|
-
readonly targetId: string;
|
|
23
|
-
readonly contractSpace?: {
|
|
24
|
-
readonly contractJson: unknown;
|
|
25
|
-
readonly headRef: { readonly hash: string; readonly invariants: readonly string[] };
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Convert the CLI's `Config.extensionPacks` array into the loader's
|
|
31
|
-
* `DeclaredExtensionEntry[]` shape.
|
|
32
|
-
*
|
|
33
|
-
* The loader hashes `contractSpace.contractJson` to compare against the
|
|
34
|
-
* on-disk `refs/head.json.hash` (drift detection). Rather than re-running
|
|
35
|
-
* the canonical-JSON + SHA-256 pipeline at the CLI surface, we look up
|
|
36
|
-
* the descriptor's pre-computed `headRef.hash` via reference identity
|
|
37
|
-
* on the contract JSON value — the loader passes the same
|
|
38
|
-
* `entry.contractSpace.contractJson` reference through to the hasher,
|
|
39
|
-
* so identity-keyed lookup is safe.
|
|
40
|
-
*/
|
|
41
|
-
function toDeclaredExtensions(extensionPacks: ReadonlyArray<ExtensionPackForAggregate>): {
|
|
42
|
-
readonly entries: ReadonlyArray<DeclaredExtensionEntry>;
|
|
43
|
-
readonly hashByContractJson: Map<unknown, string>;
|
|
44
|
-
} {
|
|
45
|
-
const entries: DeclaredExtensionEntry[] = [];
|
|
46
|
-
const hashByContractJson = new Map<unknown, string>();
|
|
47
|
-
for (const pack of extensionPacks) {
|
|
48
|
-
const entry: DeclaredExtensionEntry = pack.contractSpace
|
|
49
|
-
? {
|
|
50
|
-
id: pack.id,
|
|
51
|
-
targetId: pack.targetId,
|
|
52
|
-
contractSpace: { contractJson: pack.contractSpace.contractJson },
|
|
53
|
-
}
|
|
54
|
-
: { id: pack.id, targetId: pack.targetId };
|
|
55
|
-
entries.push(entry);
|
|
56
|
-
if (pack.contractSpace) {
|
|
57
|
-
hashByContractJson.set(pack.contractSpace.contractJson, pack.contractSpace.headRef.hash);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return { entries, hashByContractJson };
|
|
61
|
-
}
|
|
13
|
+
import { toDeclaredExtensions, toExtensionInputs } from './extension-pack-inputs';
|
|
62
14
|
|
|
63
15
|
/**
|
|
64
16
|
* Render a {@link LoadAggregateError} into a CLI structured-error
|
|
@@ -187,16 +139,32 @@ export interface BuildAggregateInputs<TFamilyId extends string, TTargetId extend
|
|
|
187
139
|
readonly appContract: Contract;
|
|
188
140
|
readonly extensionPacks: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
189
141
|
readonly validateContract: (contractJson: unknown) => Contract;
|
|
142
|
+
/**
|
|
143
|
+
* App-space migration packages to hydrate the app member's
|
|
144
|
+
* migration graph with. Defaults to `[]` (matches the `db init` /
|
|
145
|
+
* `db update` daily-driver behaviour, where the app's authored
|
|
146
|
+
* `migrations/` graph is not walked — the planner uses the synth
|
|
147
|
+
* strategy for the app member instead).
|
|
148
|
+
*
|
|
149
|
+
* `migration apply` callers thread the user's authored app-space
|
|
150
|
+
* packages (loaded via `loadMigrationPackages(appMigrationsDir)`)
|
|
151
|
+
* through here so the graph-walk strategy can plot a path through
|
|
152
|
+
* them — the prod-time replay path explicitly forbids synth.
|
|
153
|
+
*/
|
|
154
|
+
readonly appMigrationPackages?: ReadonlyArray<OnDiskMigrationPackage>;
|
|
190
155
|
}
|
|
191
156
|
|
|
192
157
|
/**
|
|
193
158
|
* Run the aggregate loader at the CLI surface, mapping any
|
|
194
159
|
* {@link LoadAggregateError} into a {@link CliStructuredError} envelope.
|
|
195
160
|
*
|
|
196
|
-
* App-side migration packages
|
|
197
|
-
* `db init` / `db update`
|
|
198
|
-
* the app member (driven by
|
|
199
|
-
* app's authored `migrations/`
|
|
161
|
+
* App-side migration packages flow through `inputs.appMigrationPackages`
|
|
162
|
+
* (defaulting to `[]`). `db init` / `db update` leave it empty: the
|
|
163
|
+
* planner's `synth` strategy is used for the app member (driven by
|
|
164
|
+
* `callerPolicy.ignoreGraphFor`), so the app's authored `migrations/`
|
|
165
|
+
* graph does not need to be walked. `migration apply` threads the
|
|
166
|
+
* already-loaded app-space packages through so the graph-walk strategy
|
|
167
|
+
* can plot a path through them — replay forbids synth.
|
|
200
168
|
*
|
|
201
169
|
* @see specs/contract-space-aggregate-spec.md § Loader.
|
|
202
170
|
*/
|
|
@@ -207,7 +175,7 @@ export async function buildContractSpaceAggregate<
|
|
|
207
175
|
inputs: BuildAggregateInputs<TFamilyId, TTargetId>,
|
|
208
176
|
): Promise<Result<ContractSpaceAggregate, CliStructuredError>> {
|
|
209
177
|
const { entries, hashByContractJson } = toDeclaredExtensions(
|
|
210
|
-
inputs.extensionPacks
|
|
178
|
+
toExtensionInputs(inputs.extensionPacks),
|
|
211
179
|
);
|
|
212
180
|
|
|
213
181
|
const loadInput: LoadAggregateInput = {
|
|
@@ -225,7 +193,7 @@ export async function buildContractSpaceAggregate<
|
|
|
225
193
|
}
|
|
226
194
|
return precomputed;
|
|
227
195
|
},
|
|
228
|
-
appMigrationPackages: [],
|
|
196
|
+
appMigrationPackages: inputs.appMigrationPackages ?? [],
|
|
229
197
|
};
|
|
230
198
|
|
|
231
199
|
const result: LoadAggregateOutput = await loadContractSpaceAggregate(loadInput);
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single descriptor-import boundary for CLI consumers of `Config.extensionPacks`.
|
|
3
|
+
*
|
|
4
|
+
* Every CLI command / utility that reads an extension descriptor's
|
|
5
|
+
* `contractSpace` projection (loader, migrate-pass, extension-migrations
|
|
6
|
+
* pass, migration commands) goes through {@link toExtensionInputs}. The
|
|
7
|
+
* structural cast `pack as { contractSpace?: ... }` lives **only** here —
|
|
8
|
+
* downstream code consumes the canonical shape and maps it to its own
|
|
9
|
+
* narrower shape via the per-consumer adapters below.
|
|
10
|
+
*
|
|
11
|
+
* The CLI receives extension descriptors typed against the SQL family
|
|
12
|
+
* (or any other family in the future); this helper only depends on the
|
|
13
|
+
* structural shape of `contractSpace`. SQL-family callers pass the same
|
|
14
|
+
* `contractJson` / `headRef.hash` value through unchanged.
|
|
15
|
+
*/
|
|
16
|
+
import type { DeclaredExtensionEntry } from '@prisma-next/migration-tools/aggregate';
|
|
17
|
+
import type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';
|
|
18
|
+
import type { MigrationOps } from '@prisma-next/migration-tools/package';
|
|
19
|
+
import type { ExtensionMigrationsExtensionInput } from './contract-space-extension-migrations-pass';
|
|
20
|
+
import type { MigrateExtensionInput } from './contract-space-migrate-pass';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* In-memory authored migration package shipped by an extension descriptor.
|
|
24
|
+
* Mirrors the `MigrationPackage` shape from
|
|
25
|
+
* `@prisma-next/framework-components/control` minus `dirPath`; redeclared
|
|
26
|
+
* structurally here so the helper does not couple to the SQL family's
|
|
27
|
+
* `ExtensionMigrationPackage` type.
|
|
28
|
+
*/
|
|
29
|
+
export interface DescriptorMigrationPackage {
|
|
30
|
+
readonly dirName: string;
|
|
31
|
+
readonly metadata: MigrationMetadata;
|
|
32
|
+
readonly ops: MigrationOps;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The most-general projection of a single declared extension pack
|
|
37
|
+
* needed by the CLI's descriptor-import boundary.
|
|
38
|
+
*
|
|
39
|
+
* - `id` / `targetId` are always present.
|
|
40
|
+
* - `contractSpace` is present only when the extension declares one.
|
|
41
|
+
* When present, it carries the canonical inputs every downstream
|
|
42
|
+
* consumer needs — `contractJson`, `headRef`, and the descriptor's
|
|
43
|
+
* pre-built migration packages.
|
|
44
|
+
*/
|
|
45
|
+
export interface ExtensionPackInput {
|
|
46
|
+
readonly id: string;
|
|
47
|
+
readonly targetId: string;
|
|
48
|
+
readonly contractSpace?: {
|
|
49
|
+
readonly contractJson: unknown;
|
|
50
|
+
readonly headRef: {
|
|
51
|
+
readonly hash: string;
|
|
52
|
+
readonly invariants: readonly string[];
|
|
53
|
+
};
|
|
54
|
+
readonly migrations: readonly DescriptorMigrationPackage[];
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Structural shape we read off each `Config.extensionPacks` entry.
|
|
60
|
+
*
|
|
61
|
+
* The CLI is the descriptor-import boundary; `extensionPacks` is the only
|
|
62
|
+
* surface where the SQL-family-typed `ControlExtensionDescriptor` flows
|
|
63
|
+
* into framework-neutral helpers. The structural cast lives here, and
|
|
64
|
+
* here alone — every other CLI consumer reads the canonical
|
|
65
|
+
* {@link ExtensionPackInput} shape produced by {@link toExtensionInputs}.
|
|
66
|
+
*/
|
|
67
|
+
type ExtensionPackLike = {
|
|
68
|
+
readonly id: string;
|
|
69
|
+
readonly targetId: string;
|
|
70
|
+
readonly contractSpace?: {
|
|
71
|
+
readonly contractJson: unknown;
|
|
72
|
+
readonly headRef: {
|
|
73
|
+
readonly hash: string;
|
|
74
|
+
readonly invariants: readonly string[];
|
|
75
|
+
};
|
|
76
|
+
readonly migrations?: readonly DescriptorMigrationPackage[];
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Project the CLI's `Config.extensionPacks` array into the canonical
|
|
82
|
+
* {@link ExtensionPackInput} shape. The single `as ExtensionPackLike`
|
|
83
|
+
* structural cast in the CLI lives inside this function.
|
|
84
|
+
*/
|
|
85
|
+
export function toExtensionInputs(
|
|
86
|
+
extensionPacks: ReadonlyArray<unknown>,
|
|
87
|
+
): readonly ExtensionPackInput[] {
|
|
88
|
+
return extensionPacks.map((raw) => {
|
|
89
|
+
const pack = raw as ExtensionPackLike;
|
|
90
|
+
if (pack.contractSpace === undefined) {
|
|
91
|
+
return { id: pack.id, targetId: pack.targetId };
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
id: pack.id,
|
|
95
|
+
targetId: pack.targetId,
|
|
96
|
+
contractSpace: {
|
|
97
|
+
contractJson: pack.contractSpace.contractJson,
|
|
98
|
+
headRef: pack.contractSpace.headRef,
|
|
99
|
+
migrations: pack.contractSpace.migrations ?? [],
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Per-consumer adapters: take the canonical `ExtensionPackInput[]` and
|
|
107
|
+
// project to whatever narrower shape the downstream primitive needs.
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Aggregate-loader projection: surfaces `targetId` + `contractSpace.contractJson`
|
|
112
|
+
* to {@link import('./contract-space-aggregate-loader').buildContractSpaceAggregate}
|
|
113
|
+
* and a `hashByContractJson` map keyed by the same `contractJson` reference
|
|
114
|
+
* the loader hands to its hash callback.
|
|
115
|
+
*/
|
|
116
|
+
export function toDeclaredExtensions(inputs: ReadonlyArray<ExtensionPackInput>): {
|
|
117
|
+
readonly entries: ReadonlyArray<DeclaredExtensionEntry>;
|
|
118
|
+
readonly hashByContractJson: Map<unknown, string>;
|
|
119
|
+
} {
|
|
120
|
+
const entries: DeclaredExtensionEntry[] = [];
|
|
121
|
+
const hashByContractJson = new Map<unknown, string>();
|
|
122
|
+
for (const pack of inputs) {
|
|
123
|
+
if (pack.contractSpace) {
|
|
124
|
+
entries.push({
|
|
125
|
+
id: pack.id,
|
|
126
|
+
targetId: pack.targetId,
|
|
127
|
+
contractSpace: { contractJson: pack.contractSpace.contractJson },
|
|
128
|
+
});
|
|
129
|
+
hashByContractJson.set(pack.contractSpace.contractJson, pack.contractSpace.headRef.hash);
|
|
130
|
+
} else {
|
|
131
|
+
entries.push({ id: pack.id, targetId: pack.targetId });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { entries, hashByContractJson };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Migrate-time per-space pass projection. */
|
|
138
|
+
export function toMigratePassInputs(
|
|
139
|
+
inputs: ReadonlyArray<ExtensionPackInput>,
|
|
140
|
+
): readonly MigrateExtensionInput[] {
|
|
141
|
+
return inputs.map((pack) =>
|
|
142
|
+
pack.contractSpace
|
|
143
|
+
? {
|
|
144
|
+
id: pack.id,
|
|
145
|
+
contractSpace: {
|
|
146
|
+
contractJson: pack.contractSpace.contractJson,
|
|
147
|
+
headRef: pack.contractSpace.headRef,
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
: { id: pack.id },
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Extension-migrations materialisation pass projection. */
|
|
155
|
+
export function toExtensionMigrationsInputs(
|
|
156
|
+
inputs: ReadonlyArray<ExtensionPackInput>,
|
|
157
|
+
): readonly ExtensionMigrationsExtensionInput[] {
|
|
158
|
+
return inputs.map((pack) =>
|
|
159
|
+
pack.contractSpace
|
|
160
|
+
? {
|
|
161
|
+
id: pack.id,
|
|
162
|
+
contractSpace: {
|
|
163
|
+
contractJson: pack.contractSpace.contractJson,
|
|
164
|
+
headRef: pack.contractSpace.headRef,
|
|
165
|
+
migrations: pack.contractSpace.migrations,
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
: { id: pack.id },
|
|
169
|
+
);
|
|
170
|
+
}
|