@prisma-next/cli 0.1.0-dev.2 → 0.1.0-dev.20
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 +172 -20
- package/dist/{chunk-4Q3MO4TK.js → chunk-VWAVGWUP.js} +2 -2
- package/dist/chunk-VWAVGWUP.js.map +1 -0
- package/dist/chunk-YDE4ILKH.js +55 -0
- package/dist/chunk-YDE4ILKH.js.map +1 -0
- package/dist/{chunk-3EODSNGS.js → chunk-ZKEJZ3NU.js} +94 -32
- package/dist/chunk-ZKEJZ3NU.js.map +1 -0
- package/dist/cli.js +417 -99
- package/dist/cli.js.map +1 -1
- package/dist/commands/contract-emit.js +2 -2
- package/dist/commands/db-init.d.ts +5 -0
- package/dist/commands/db-init.js +240 -0
- package/dist/commands/db-init.js.map +1 -0
- package/dist/commands/db-introspect.js +6 -8
- package/dist/commands/db-introspect.js.map +1 -1
- package/dist/commands/db-schema-verify.js +14 -5
- package/dist/commands/db-schema-verify.js.map +1 -1
- package/dist/commands/db-sign.js +25 -20
- package/dist/commands/db-sign.js.map +1 -1
- package/dist/commands/db-verify.js +3 -4
- package/dist/commands/db-verify.js.map +1 -1
- package/dist/index.js +4 -4
- package/package.json +17 -10
- package/dist/chunk-3EODSNGS.js.map +0 -1
- package/dist/chunk-4Q3MO4TK.js.map +0 -1
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ The `contract emit` command requires a `driver` in the config (even though it do
|
|
|
53
53
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
54
54
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
55
55
|
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
56
|
-
import postgres from '@prisma-next/
|
|
56
|
+
import postgres from '@prisma-next/target-postgres/control';
|
|
57
57
|
import sql from '@prisma-next/family-sql/control';
|
|
58
58
|
import { contract } from './prisma/contract';
|
|
59
59
|
|
|
@@ -134,7 +134,7 @@ The `db verify` command requires a `driver` in the config to connect to the data
|
|
|
134
134
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
135
135
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
136
136
|
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
137
|
-
import postgres from '@prisma-next/
|
|
137
|
+
import postgres from '@prisma-next/target-postgres/control';
|
|
138
138
|
import sql from '@prisma-next/family-sql/control';
|
|
139
139
|
import { contract } from './prisma/contract';
|
|
140
140
|
|
|
@@ -221,20 +221,21 @@ Failure:
|
|
|
221
221
|
|
|
222
222
|
**Family Requirements:**
|
|
223
223
|
|
|
224
|
-
The family must provide a `create()` method in the family descriptor that returns a `
|
|
224
|
+
The family must provide a `create()` method in the family descriptor that returns a `ControlFamilyInstance` with a `verify()` method:
|
|
225
225
|
|
|
226
226
|
```typescript
|
|
227
|
-
interface
|
|
227
|
+
interface ControlFamilyDescriptor {
|
|
228
228
|
create(options: {
|
|
229
|
-
target:
|
|
230
|
-
adapter:
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
target: ControlTargetDescriptor;
|
|
230
|
+
adapter: ControlAdapterDescriptor;
|
|
231
|
+
driver: ControlDriverDescriptor;
|
|
232
|
+
extensions: ControlExtensionDescriptor[];
|
|
233
|
+
}): ControlFamilyInstance;
|
|
233
234
|
}
|
|
234
235
|
|
|
235
|
-
interface
|
|
236
|
+
interface ControlFamilyInstance {
|
|
236
237
|
verify(options: {
|
|
237
|
-
driver:
|
|
238
|
+
driver: ControlDriverInstance;
|
|
238
239
|
contractIR: ContractIR;
|
|
239
240
|
expectedTargetId: string;
|
|
240
241
|
contractPath: string;
|
|
@@ -287,7 +288,7 @@ The `db introspect` command requires a `driver` in the config to connect to the
|
|
|
287
288
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
288
289
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
289
290
|
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
290
|
-
import postgres from '@prisma-next/
|
|
291
|
+
import postgres from '@prisma-next/target-postgres/control';
|
|
291
292
|
import sql from '@prisma-next/family-sql/control';
|
|
292
293
|
|
|
293
294
|
export default defineConfig({
|
|
@@ -377,11 +378,11 @@ sql schema (tables: 2)
|
|
|
377
378
|
**Family Requirements:**
|
|
378
379
|
|
|
379
380
|
The family must provide:
|
|
380
|
-
1. A `create()` method in the family descriptor that returns a `
|
|
381
|
-
2. An optional `toSchemaView()` method on the `
|
|
381
|
+
1. A `create()` method in the family descriptor that returns a `ControlFamilyInstance` with an `introspect()` method
|
|
382
|
+
2. An optional `toSchemaView()` method on the `ControlFamilyInstance` to project family-specific schema IR into `CoreSchemaView`
|
|
382
383
|
|
|
383
384
|
```typescript
|
|
384
|
-
interface
|
|
385
|
+
interface ControlFamilyInstance {
|
|
385
386
|
introspect(options: {
|
|
386
387
|
driver: ControlDriverInstance;
|
|
387
388
|
contractIR?: ContractIR;
|
|
@@ -438,7 +439,7 @@ The `db sign` command requires a `driver` in the config to connect to the databa
|
|
|
438
439
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
439
440
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
440
441
|
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
441
|
-
import postgres from '@prisma-next/
|
|
442
|
+
import postgres from '@prisma-next/target-postgres/control';
|
|
442
443
|
import sql from '@prisma-next/family-sql/control';
|
|
443
444
|
import { contract } from './prisma/contract';
|
|
444
445
|
|
|
@@ -583,10 +584,10 @@ The `db sign` command is idempotent and safe to run multiple times:
|
|
|
583
584
|
- Safe to run in CI/deployment pipelines
|
|
584
585
|
|
|
585
586
|
**Family Requirements:**
|
|
586
|
-
The family must provide a `create()` method in the family descriptor that returns a `
|
|
587
|
+
The family must provide a `create()` method in the family descriptor that returns a `ControlFamilyInstance` with `schemaVerify()` and `sign()` methods:
|
|
587
588
|
|
|
588
589
|
```typescript
|
|
589
|
-
interface
|
|
590
|
+
interface ControlFamilyInstance {
|
|
590
591
|
schemaVerify(options: {
|
|
591
592
|
driver: ControlDriverInstance;
|
|
592
593
|
contractIR: ContractIR;
|
|
@@ -606,6 +607,156 @@ interface FamilyInstance {
|
|
|
606
607
|
|
|
607
608
|
The SQL family provides this via `@prisma-next/family-sql/control`. The `sign()` method handles ensuring the marker schema/table exist, reading existing markers, comparing hashes, and writing/updating markers internally.
|
|
608
609
|
|
|
610
|
+
### `prisma-next db init`
|
|
611
|
+
|
|
612
|
+
Initialize a database schema from the contract. This command generates a migration plan to bring an empty database in sync with the contract and executes it.
|
|
613
|
+
|
|
614
|
+
**Command:**
|
|
615
|
+
```bash
|
|
616
|
+
prisma-next db init [--db <url>] [--config <path>] [--plan] [--json] [-v] [-q] [--timestamps] [--color/--no-color]
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
Options:
|
|
620
|
+
- `--db <url>`: Database connection string (optional, falls back to `config.db.url` or `DATABASE_URL` environment variable)
|
|
621
|
+
- `--config <path>`: Optional. Path to `prisma-next.config.ts` (defaults to `./prisma-next.config.ts` if present)
|
|
622
|
+
- `--plan`: Only show the migration plan, do not apply it
|
|
623
|
+
- `--json`: Output as JSON object
|
|
624
|
+
- `-q, --quiet`: Quiet mode (errors only)
|
|
625
|
+
- `-v, --verbose`: Verbose output (debug info, timings)
|
|
626
|
+
- `-vv, --trace`: Trace output (deep internals, stack traces)
|
|
627
|
+
- `--timestamps`: Add timestamps to output
|
|
628
|
+
- `--color/--no-color`: Force/disable color output
|
|
629
|
+
|
|
630
|
+
Examples:
|
|
631
|
+
```bash
|
|
632
|
+
# Initialize database with config defaults
|
|
633
|
+
prisma-next db init
|
|
634
|
+
|
|
635
|
+
# Preview migration plan without applying
|
|
636
|
+
prisma-next db init --plan
|
|
637
|
+
|
|
638
|
+
# Specify database URL
|
|
639
|
+
prisma-next db init --db postgresql://user:pass@localhost/db
|
|
640
|
+
|
|
641
|
+
# JSON output
|
|
642
|
+
prisma-next db init --json
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
**Config File Requirements:**
|
|
646
|
+
|
|
647
|
+
The `db init` command requires a `driver` in the config to connect to the database:
|
|
648
|
+
|
|
649
|
+
```typescript
|
|
650
|
+
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
651
|
+
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
652
|
+
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
653
|
+
import postgres from '@prisma-next/target-postgres/control';
|
|
654
|
+
import sql from '@prisma-next/family-sql/control';
|
|
655
|
+
import { contract } from './prisma/contract';
|
|
656
|
+
|
|
657
|
+
export default defineConfig({
|
|
658
|
+
family: sql,
|
|
659
|
+
target: postgres,
|
|
660
|
+
adapter: postgresAdapter,
|
|
661
|
+
driver: postgresDriver,
|
|
662
|
+
extensions: [],
|
|
663
|
+
contract: {
|
|
664
|
+
source: contract,
|
|
665
|
+
output: 'src/prisma/contract.json',
|
|
666
|
+
types: 'src/prisma/contract.d.ts',
|
|
667
|
+
},
|
|
668
|
+
db: {
|
|
669
|
+
url: process.env.DATABASE_URL, // Optional: can also use --db flag
|
|
670
|
+
},
|
|
671
|
+
});
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
**Initialization Process:**
|
|
675
|
+
|
|
676
|
+
1. **Load Contract**: Reads the emitted `contract.json` from `config.contract.output`
|
|
677
|
+
2. **Connect to Database**: Uses `config.driver.create(url)` to create a driver
|
|
678
|
+
3. **Create Family Instance**: Calls `config.family.create()` with target, adapter, driver, and extensions
|
|
679
|
+
4. **Introspect Schema**: Calls `familyInstance.introspect()` to get the current database schema IR
|
|
680
|
+
5. **Create Planner/Runner**: Asks the target to construct a `MigrationPlanner` and `MigrationRunner`
|
|
681
|
+
6. **Plan Migration**: Calls `planner.plan()` with the contract IR, schema IR, and additive-only policy
|
|
682
|
+
- On conflict: Returns a structured failure with conflict list
|
|
683
|
+
- On success: Returns a migration plan with operations
|
|
684
|
+
7. **Apply Migration** (if not `--plan`):
|
|
685
|
+
- Calls `runner.execute()` to apply the plan
|
|
686
|
+
- Runner executes pre/post checks for each operation
|
|
687
|
+
- After execution, verifies schema matches contract
|
|
688
|
+
- Writes contract marker and ledger entry
|
|
689
|
+
|
|
690
|
+
**Output Format (TTY - Plan Mode):**
|
|
691
|
+
|
|
692
|
+
```
|
|
693
|
+
prisma-next db init ➜ Initialize database schema from contract
|
|
694
|
+
config: prisma-next.config.ts
|
|
695
|
+
contract: src/prisma/contract.json
|
|
696
|
+
database: localhost:5432/mydb
|
|
697
|
+
|
|
698
|
+
Migration Plan (4 operations)
|
|
699
|
+
├─ Create extension "plpgsql"
|
|
700
|
+
├─ Create table "user"
|
|
701
|
+
│ ├─ id: int4 (not null, primary key)
|
|
702
|
+
│ └─ email: text (not null)
|
|
703
|
+
└─ Create unique index "user_email_key"
|
|
704
|
+
|
|
705
|
+
Run without --plan to apply this migration.
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
**Output Format (TTY - Apply Mode):**
|
|
709
|
+
|
|
710
|
+
```
|
|
711
|
+
prisma-next db init ➜ Initialize database schema from contract
|
|
712
|
+
config: prisma-next.config.ts
|
|
713
|
+
contract: src/prisma/contract.json
|
|
714
|
+
database: localhost:5432/mydb
|
|
715
|
+
|
|
716
|
+
✔ Applied 4 migration operations
|
|
717
|
+
├─ Created extension "plpgsql"
|
|
718
|
+
├─ Created table "user"
|
|
719
|
+
└─ Created unique index "user_email_key"
|
|
720
|
+
✔ Contract marker written
|
|
721
|
+
coreHash: sha256:abc123...
|
|
722
|
+
✔ Ledger entry recorded
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
**Output Format (JSON):**
|
|
726
|
+
|
|
727
|
+
```json
|
|
728
|
+
{
|
|
729
|
+
"ok": true,
|
|
730
|
+
"mode": "apply",
|
|
731
|
+
"plan": {
|
|
732
|
+
"operations": [...],
|
|
733
|
+
"conflicts": []
|
|
734
|
+
},
|
|
735
|
+
"execution": {
|
|
736
|
+
"operations": [...],
|
|
737
|
+
"marker": {
|
|
738
|
+
"coreHash": "sha256:abc123...",
|
|
739
|
+
"profileHash": "sha256:def456..."
|
|
740
|
+
},
|
|
741
|
+
"ledger": {
|
|
742
|
+
"id": "ledger-entry-uuid",
|
|
743
|
+
"createdAt": "2025-01-01T00:00:00Z"
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
**Error Codes:**
|
|
750
|
+
- `PN-CLI-4010`: Missing driver in config — provide a driver descriptor
|
|
751
|
+
- `PN-CLI-4011`: Missing database URL — provide `--db` flag or `config.db.url` or `DATABASE_URL` environment variable
|
|
752
|
+
- `PN-CLI-4011`: Migration planning failed due to conflicts (exit code 1)
|
|
753
|
+
- `PN-CLI-4012`: Target does not support migrations
|
|
754
|
+
|
|
755
|
+
**Current Limitations (v1):**
|
|
756
|
+
- Only supports empty databases (no existing tables)
|
|
757
|
+
- Non-empty databases result in a planning failure with conflict details
|
|
758
|
+
- Future `db update` command will support additive changes to existing schemas
|
|
759
|
+
|
|
609
760
|
**Config File (`prisma-next.config.ts`):**
|
|
610
761
|
|
|
611
762
|
The CLI uses a config file to specify the target family, target, adapter, extensions, and contract.
|
|
@@ -620,7 +771,7 @@ The CLI uses a config file to specify the target family, target, adapter, extens
|
|
|
620
771
|
```typescript
|
|
621
772
|
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
622
773
|
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
623
|
-
import postgres from '@prisma-next/
|
|
774
|
+
import postgres from '@prisma-next/target-postgres/control';
|
|
624
775
|
import sql from '@prisma-next/family-sql/control';
|
|
625
776
|
import { contract } from './prisma/contract';
|
|
626
777
|
|
|
@@ -724,7 +875,7 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
|
|
|
724
875
|
|
|
725
876
|
### Pack Assembly
|
|
726
877
|
- **Family instances** now handle pack assembly internally. The CLI creates a family instance via `config.family.create()` and reads assembly data (operation registry, type imports, extension IDs) from the instance.
|
|
727
|
-
- **Removed**: `pack-assembly.ts` has been removed. Pack assembly is now handled by family instances. For SQL family, tests can import pack-based helpers directly from `packages/sql/family/src/core/assembly.ts` using relative paths.
|
|
878
|
+
- **Removed**: `pack-assembly.ts` has been removed. Pack assembly is now handled by family instances. For SQL family, tests can import pack-based helpers directly from `packages/2-sql/3-tooling/family/src/core/assembly.ts` using relative paths.
|
|
728
879
|
- Assembly logic is family-specific and owned by each family's instance implementation (e.g., `createSqlFamilyInstance` in `@prisma-next/family-sql`).
|
|
729
880
|
|
|
730
881
|
### Output Formatting (`utils/output.ts`)
|
|
@@ -832,6 +983,7 @@ The CLI package exports several subpaths for different use cases:
|
|
|
832
983
|
- **`@prisma-next/cli`** (main export): Exports `loadContractFromTs` and `createContractEmitCommand`
|
|
833
984
|
- **`@prisma-next/cli/config-types`**: Exports `defineConfig` and config types
|
|
834
985
|
- **`@prisma-next/cli/pack-loading`**: Exports `loadExtensionPacks` and `loadExtensionPackManifest`
|
|
986
|
+
- **`@prisma-next/cli/commands/db-init`**: Exports `createDbInitCommand`
|
|
835
987
|
- **`@prisma-next/cli/commands/db-introspect`**: Exports `createDbIntrospectCommand`
|
|
836
988
|
- **`@prisma-next/cli/commands/db-schema-verify`**: Exports `createDbSchemaVerifyCommand`
|
|
837
989
|
- **`@prisma-next/cli/commands/db-sign`**: Exports `createDbSignCommand`
|
|
@@ -847,7 +999,7 @@ This package is part of the **framework domain**, **tooling layer**, **migration
|
|
|
847
999
|
- **Domain**: framework (target-agnostic)
|
|
848
1000
|
- **Layer**: tooling
|
|
849
1001
|
- **Plane**: migration
|
|
850
|
-
- **Path**: `packages/framework/tooling/cli`
|
|
1002
|
+
- **Path**: `packages/1-framework/3-tooling/cli`
|
|
851
1003
|
|
|
852
1004
|
## See Also
|
|
853
1005
|
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
performAction,
|
|
10
10
|
setCommandDescriptions,
|
|
11
11
|
withSpinner
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZKEJZ3NU.js";
|
|
13
13
|
import {
|
|
14
14
|
loadConfig
|
|
15
15
|
} from "./chunk-HWYQOCAJ.js";
|
|
@@ -131,4 +131,4 @@ function createContractEmitCommand() {
|
|
|
131
131
|
export {
|
|
132
132
|
createContractEmitCommand
|
|
133
133
|
};
|
|
134
|
-
//# sourceMappingURL=chunk-
|
|
134
|
+
//# sourceMappingURL=chunk-VWAVGWUP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/contract-emit.ts"],"sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, relative, resolve } from 'node:path';\nimport { errorContractConfigMissing } from '@prisma-next/core-control-plane/errors';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { setCommandDescriptions } from '../utils/command-helpers';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport {\n formatCommandHelp,\n formatEmitJson,\n formatEmitOutput,\n formatStyledHeader,\n formatSuccessMessage,\n} from '../utils/output';\nimport { performAction } from '../utils/result';\nimport { handleResult } from '../utils/result-handler';\nimport { withSpinner } from '../utils/spinner';\n\ninterface ContractEmitOptions {\n readonly config?: string;\n readonly json?: string | boolean;\n readonly quiet?: boolean;\n readonly q?: boolean;\n readonly verbose?: boolean;\n readonly v?: boolean;\n readonly vv?: boolean;\n readonly trace?: boolean;\n readonly timestamps?: boolean;\n readonly color?: boolean;\n readonly 'no-color'?: boolean;\n}\n\nexport function createContractEmitCommand(): Command {\n const command = new Command('emit');\n setCommandDescriptions(\n command,\n 'Write your contract to JSON and sign it',\n 'Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\\n' +\n 'contract.d.ts. The contract.json contains the canonical contract structure, and\\n' +\n 'contract.d.ts provides TypeScript types for type-safe query building.',\n );\n command\n .configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n })\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--json [format]', 'Output as JSON (object or ndjson)', false)\n .option('-q, --quiet', 'Quiet mode: errors only')\n .option('-v, --verbose', 'Verbose output: debug info, timings')\n .option('-vv, --trace', 'Trace output: deep internals, stack traces')\n .option('--timestamps', 'Add timestamps to output')\n .option('--color', 'Force color output')\n .option('--no-color', 'Disable color output')\n .action(async (options: ContractEmitOptions) => {\n const flags = parseGlobalFlags(options);\n\n const result = await performAction(async () => {\n // Load config\n const config = await loadConfig(options.config);\n\n // Resolve contract from config\n if (!config.contract) {\n throw errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ..., types: ... }',\n });\n }\n\n // Contract config is already normalized by defineConfig() with defaults applied\n const contractConfig = config.contract;\n\n // Resolve artifact paths from config (already normalized by defineConfig() with defaults)\n if (!contractConfig.output || !contractConfig.types) {\n throw errorContractConfigMissing({\n why: 'Contract config must have output and types paths. This should not happen if defineConfig() was used.',\n });\n }\n const outputJsonPath = resolve(contractConfig.output);\n const outputDtsPath = resolve(contractConfig.types);\n\n // Output header (only for human-readable output)\n if (flags.json !== 'object' && !flags.quiet) {\n // Normalize config path for display (match contract path format - no ./ prefix)\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n // Convert absolute paths to relative paths for display\n const contractPath = relative(process.cwd(), outputJsonPath);\n const typesPath = relative(process.cwd(), outputDtsPath);\n const header = formatStyledHeader({\n command: 'contract emit',\n description: 'Write your contract to JSON and sign it',\n url: 'https://pris.ly/contract-emit',\n details: [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n { label: 'types', value: typesPath },\n ],\n flags,\n });\n console.log(header);\n }\n\n // Create family instance (assembles operation registry, type imports, extension IDs)\n // Note: emit command doesn't need driver, but ControlFamilyDescriptor.create() requires it\n // We'll need to provide a minimal driver descriptor or make driver optional for emit\n // For now, we'll require driver to be present in config even for emit\n if (!config.driver) {\n throw errorContractConfigMissing({\n why: 'Config.driver is required. Even though emit does not use the driver, it is required by ControlFamilyDescriptor.create()',\n });\n }\n const familyInstance = config.family.create({\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensions: config.extensions ?? [],\n });\n\n // Resolve contract source from config (user's config handles loading)\n let contractRaw: unknown;\n if (typeof contractConfig.source === 'function') {\n contractRaw = await contractConfig.source();\n } else {\n contractRaw = contractConfig.source;\n }\n\n // Call emitContract on family instance (handles stripping mappings and validation internally)\n const emitResult = await withSpinner(\n () => familyInstance.emitContract({ contractIR: contractRaw }),\n {\n message: 'Emitting contract...',\n flags,\n },\n );\n\n // Create directories if needed\n mkdirSync(dirname(outputJsonPath), { recursive: true });\n mkdirSync(dirname(outputDtsPath), { recursive: true });\n\n // Write the results to files\n writeFileSync(outputJsonPath, emitResult.contractJson, 'utf-8');\n writeFileSync(outputDtsPath, emitResult.contractDts, 'utf-8');\n\n // Add blank line after all async operations if spinners were shown\n if (!flags.quiet && flags.json !== 'object' && process.stdout.isTTY) {\n console.log('');\n }\n\n // Return result with file paths for output formatting\n return {\n coreHash: emitResult.coreHash,\n profileHash: emitResult.profileHash,\n outDir: dirname(outputJsonPath),\n files: {\n json: outputJsonPath,\n dts: outputDtsPath,\n },\n timings: {\n total: 0, // Timing is handled by emitContract internally if needed\n },\n };\n });\n\n // Handle result - formats output and returns exit code\n const exitCode = handleResult(result, flags, (emitResult) => {\n // Output based on flags\n if (flags.json === 'object') {\n // JSON output to stdout\n console.log(formatEmitJson(emitResult));\n } else {\n // Human-readable output to stdout\n const output = formatEmitOutput(emitResult, flags);\n if (output) {\n console.log(output);\n }\n // Output success message\n if (!flags.quiet) {\n console.log(formatSuccessMessage(flags));\n }\n }\n });\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
errorConfigValidation
|
|
3
|
+
} from "./chunk-ZKEJZ3NU.js";
|
|
4
|
+
|
|
5
|
+
// src/utils/framework-components.ts
|
|
6
|
+
function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId, frameworkComponents) {
|
|
7
|
+
for (let i = 0; i < frameworkComponents.length; i++) {
|
|
8
|
+
const component = frameworkComponents[i];
|
|
9
|
+
if (typeof component !== "object" || component === null) {
|
|
10
|
+
throw errorConfigValidation("frameworkComponents[]", {
|
|
11
|
+
why: `Framework component at index ${i} must be an object`
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const record = component;
|
|
15
|
+
if (!Object.hasOwn(record, "kind")) {
|
|
16
|
+
throw errorConfigValidation("frameworkComponents[].kind", {
|
|
17
|
+
why: `Framework component at index ${i} must have 'kind' property`
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
const kind = record["kind"];
|
|
21
|
+
if (kind !== "target" && kind !== "adapter" && kind !== "extension" && kind !== "driver") {
|
|
22
|
+
throw errorConfigValidation("frameworkComponents[].kind", {
|
|
23
|
+
why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')`
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (!Object.hasOwn(record, "familyId")) {
|
|
27
|
+
throw errorConfigValidation("frameworkComponents[].familyId", {
|
|
28
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property`
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const familyId = record["familyId"];
|
|
32
|
+
if (familyId !== expectedFamilyId) {
|
|
33
|
+
throw errorConfigValidation("frameworkComponents[].familyId", {
|
|
34
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'`
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
if (!Object.hasOwn(record, "targetId")) {
|
|
38
|
+
throw errorConfigValidation("frameworkComponents[].targetId", {
|
|
39
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property`
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const targetId = record["targetId"];
|
|
43
|
+
if (targetId !== expectedTargetId) {
|
|
44
|
+
throw errorConfigValidation("frameworkComponents[].targetId", {
|
|
45
|
+
why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'`
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return frameworkComponents;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
assertFrameworkComponentsCompatible
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=chunk-YDE4ILKH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/framework-components.ts"],"sourcesContent":["import type { TargetBoundComponentDescriptor } from '@prisma-next/contract/framework-components';\nimport { errorConfigValidation } from './cli-errors';\n\n/**\n * Asserts that all framework components are compatible with the expected family and target.\n *\n * This function validates that each component in the framework components array:\n * - Has kind 'target', 'adapter', 'extension', or 'driver'\n * - Has familyId matching expectedFamilyId\n * - Has targetId matching expectedTargetId\n *\n * This validation happens at the CLI composition boundary, before passing components\n * to typed planner/runner instances. It fills the gap between runtime validation\n * (via `validateConfig()`) and compile-time type enforcement.\n *\n * @param expectedFamilyId - The expected family ID (e.g., 'sql')\n * @param expectedTargetId - The expected target ID (e.g., 'postgres')\n * @param frameworkComponents - Array of framework components to validate\n * @returns The same array typed as TargetBoundComponentDescriptor\n * @throws CliStructuredError if any component is incompatible\n *\n * @example\n * ```ts\n * const config = await loadConfig();\n * const frameworkComponents = [config.target, config.adapter, ...(config.extensions ?? [])];\n *\n * // Validate and type-narrow components before passing to planner\n * const typedComponents = assertFrameworkComponentsCompatible(\n * config.family.familyId,\n * config.target.targetId,\n * frameworkComponents\n * );\n *\n * const planner = target.migrations.createPlanner(familyInstance);\n * planner.plan({ contract, schema, policy, frameworkComponents: typedComponents });\n * ```\n */\nexport function assertFrameworkComponentsCompatible<\n TFamilyId extends string,\n TTargetId extends string,\n>(\n expectedFamilyId: TFamilyId,\n expectedTargetId: TTargetId,\n frameworkComponents: ReadonlyArray<unknown>,\n): ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>> {\n for (let i = 0; i < frameworkComponents.length; i++) {\n const component = frameworkComponents[i];\n\n // Check that component is an object\n if (typeof component !== 'object' || component === null) {\n throw errorConfigValidation('frameworkComponents[]', {\n why: `Framework component at index ${i} must be an object`,\n });\n }\n\n const record = component as Record<string, unknown>;\n\n // Check kind\n if (!Object.hasOwn(record, 'kind')) {\n throw errorConfigValidation('frameworkComponents[].kind', {\n why: `Framework component at index ${i} must have 'kind' property`,\n });\n }\n\n const kind = record['kind'];\n if (kind !== 'target' && kind !== 'adapter' && kind !== 'extension' && kind !== 'driver') {\n throw errorConfigValidation('frameworkComponents[].kind', {\n why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')`,\n });\n }\n\n // Check familyId\n if (!Object.hasOwn(record, 'familyId')) {\n throw errorConfigValidation('frameworkComponents[].familyId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property`,\n });\n }\n\n const familyId = record['familyId'];\n if (familyId !== expectedFamilyId) {\n throw errorConfigValidation('frameworkComponents[].familyId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'`,\n });\n }\n\n // Check targetId\n if (!Object.hasOwn(record, 'targetId')) {\n throw errorConfigValidation('frameworkComponents[].targetId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property`,\n });\n }\n\n const targetId = record['targetId'];\n if (targetId !== expectedTargetId) {\n throw errorConfigValidation('frameworkComponents[].targetId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'`,\n });\n }\n }\n\n // Type assertion is safe because we've validated all components above\n return frameworkComponents as ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n}\n"],"mappings":";;;;;AAqCO,SAAS,oCAId,kBACA,kBACA,qBACqE;AACrE,WAAS,IAAI,GAAG,IAAI,oBAAoB,QAAQ,KAAK;AACnD,UAAM,YAAY,oBAAoB,CAAC;AAGvC,QAAI,OAAO,cAAc,YAAY,cAAc,MAAM;AACvD,YAAM,sBAAsB,yBAAyB;AAAA,QACnD,KAAK,gCAAgC,CAAC;AAAA,MACxC,CAAC;AAAA,IACH;AAEA,UAAM,SAAS;AAGf,QAAI,CAAC,OAAO,OAAO,QAAQ,MAAM,GAAG;AAClC,YAAM,sBAAsB,8BAA8B;AAAA,QACxD,KAAK,gCAAgC,CAAC;AAAA,MACxC,CAAC;AAAA,IACH;AAEA,UAAM,OAAO,OAAO,MAAM;AAC1B,QAAI,SAAS,YAAY,SAAS,aAAa,SAAS,eAAe,SAAS,UAAU;AACxF,YAAM,sBAAsB,8BAA8B;AAAA,QACxD,KAAK,gCAAgC,CAAC,sBAAsB,OAAO,IAAI,CAAC;AAAA,MAC1E,CAAC;AAAA,IACH;AAGA,QAAI,CAAC,OAAO,OAAO,QAAQ,UAAU,GAAG;AACtC,YAAM,sBAAsB,kCAAkC;AAAA,QAC5D,KAAK,gCAAgC,CAAC,WAAW,OAAO,IAAI,CAAC;AAAA,MAC/D,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,OAAO,UAAU;AAClC,QAAI,aAAa,kBAAkB;AACjC,YAAM,sBAAsB,kCAAkC;AAAA,QAC5D,KAAK,gCAAgC,CAAC,WAAW,OAAO,IAAI,CAAC,mBAAmB,OAAO,QAAQ,CAAC,mBAAmB,gBAAgB;AAAA,MACrI,CAAC;AAAA,IACH;AAGA,QAAI,CAAC,OAAO,OAAO,QAAQ,UAAU,GAAG;AACtC,YAAM,sBAAsB,kCAAkC;AAAA,QAC5D,KAAK,gCAAgC,CAAC,WAAW,OAAO,IAAI,CAAC;AAAA,MAC/D,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,OAAO,UAAU;AAClC,QAAI,aAAa,kBAAkB;AACjC,YAAM,sBAAsB,kCAAkC;AAAA,QAC5D,KAAK,gCAAgC,CAAC,WAAW,OAAO,IAAI,CAAC,mBAAmB,OAAO,QAAQ,CAAC,mBAAmB,gBAAgB;AAAA,MACrI,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO;AACT;","names":[]}
|
|
@@ -111,6 +111,15 @@ function formatErrorOutput(error, flags) {
|
|
|
111
111
|
const whereLine = error.where.line ? `${error.where.path}:${error.where.line}` : error.where.path;
|
|
112
112
|
lines.push(`${prefix}${formatDimText(` Where: ${whereLine}`)}`);
|
|
113
113
|
}
|
|
114
|
+
if (isVerbose(flags, 1) && error.meta?.["conflicts"]) {
|
|
115
|
+
const conflicts = error.meta["conflicts"];
|
|
116
|
+
if (conflicts.length > 0) {
|
|
117
|
+
lines.push(`${prefix}${formatDimText(" Conflicts:")}`);
|
|
118
|
+
for (const conflict of conflicts) {
|
|
119
|
+
lines.push(`${prefix}${formatDimText(` - [${conflict.kind}] ${conflict.summary}`)}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
114
123
|
if (error.docsUrl && isVerbose(flags, 1)) {
|
|
115
124
|
lines.push(formatDimText(error.docsUrl));
|
|
116
125
|
}
|
|
@@ -544,6 +553,69 @@ function formatSignOutput(result, flags) {
|
|
|
544
553
|
function formatSignJson(result) {
|
|
545
554
|
return JSON.stringify(result, null, 2);
|
|
546
555
|
}
|
|
556
|
+
function formatDbInitPlanOutput(result, flags) {
|
|
557
|
+
if (flags.quiet) {
|
|
558
|
+
return "";
|
|
559
|
+
}
|
|
560
|
+
const lines = [];
|
|
561
|
+
const prefix = createPrefix(flags);
|
|
562
|
+
const useColor = flags.color !== false;
|
|
563
|
+
const formatGreen = createColorFormatter(useColor, green);
|
|
564
|
+
const formatDimText = (text) => formatDim(useColor, text);
|
|
565
|
+
const operationCount = result.plan?.operations.length ?? 0;
|
|
566
|
+
lines.push(`${prefix}${formatGreen("\u2714")} Planned ${operationCount} operation(s)`);
|
|
567
|
+
if (result.plan?.operations && result.plan.operations.length > 0) {
|
|
568
|
+
lines.push(`${prefix}${formatDimText("\u2502")}`);
|
|
569
|
+
for (let i = 0; i < result.plan.operations.length; i++) {
|
|
570
|
+
const op = result.plan.operations[i];
|
|
571
|
+
if (!op) continue;
|
|
572
|
+
const isLast = i === result.plan.operations.length - 1;
|
|
573
|
+
const treeChar = isLast ? "\u2514" : "\u251C";
|
|
574
|
+
const opClass = formatDimText(`[${op.operationClass}]`);
|
|
575
|
+
lines.push(`${prefix}${formatDimText(treeChar)}\u2500 ${op.label} ${opClass}`);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
if (result.plan?.destination) {
|
|
579
|
+
lines.push(`${prefix}`);
|
|
580
|
+
lines.push(
|
|
581
|
+
`${prefix}${formatDimText(`Destination hash: ${result.plan.destination.coreHash}`)}`
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
if (isVerbose(flags, 1)) {
|
|
585
|
+
lines.push(`${prefix}${formatDimText(`Total time: ${result.timings.total}ms`)}`);
|
|
586
|
+
}
|
|
587
|
+
lines.push(`${prefix}`);
|
|
588
|
+
lines.push(`${prefix}${formatDimText("This is a dry run. No changes were applied.")}`);
|
|
589
|
+
lines.push(`${prefix}${formatDimText("Run without --plan to apply changes.")}`);
|
|
590
|
+
return lines.join("\n");
|
|
591
|
+
}
|
|
592
|
+
function formatDbInitApplyOutput(result, flags) {
|
|
593
|
+
if (flags.quiet) {
|
|
594
|
+
return "";
|
|
595
|
+
}
|
|
596
|
+
const lines = [];
|
|
597
|
+
const prefix = createPrefix(flags);
|
|
598
|
+
const useColor = flags.color !== false;
|
|
599
|
+
const formatGreen = createColorFormatter(useColor, green);
|
|
600
|
+
const formatDimText = (text) => formatDim(useColor, text);
|
|
601
|
+
if (result.ok) {
|
|
602
|
+
const executed = result.execution?.operationsExecuted ?? 0;
|
|
603
|
+
lines.push(`${prefix}${formatGreen("\u2714")} Applied ${executed} operation(s)`);
|
|
604
|
+
if (result.marker) {
|
|
605
|
+
lines.push(`${prefix}${formatDimText(` Marker written: ${result.marker.coreHash}`)}`);
|
|
606
|
+
if (result.marker.profileHash) {
|
|
607
|
+
lines.push(`${prefix}${formatDimText(` Profile hash: ${result.marker.profileHash}`)}`);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
if (isVerbose(flags, 1)) {
|
|
611
|
+
lines.push(`${prefix}${formatDimText(` Total time: ${result.timings.total}ms`)}`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return lines.join("\n");
|
|
615
|
+
}
|
|
616
|
+
function formatDbInitJson(result) {
|
|
617
|
+
return JSON.stringify(result, null, 2);
|
|
618
|
+
}
|
|
547
619
|
var LEFT_COLUMN_WIDTH = 20;
|
|
548
620
|
var RIGHT_COLUMN_MIN_WIDTH = 40;
|
|
549
621
|
var RIGHT_COLUMN_MAX_WIDTH = 90;
|
|
@@ -801,8 +873,10 @@ import {
|
|
|
801
873
|
errorFileNotFound,
|
|
802
874
|
errorHashMismatch,
|
|
803
875
|
errorMarkerMissing,
|
|
876
|
+
errorMigrationPlanningFailed,
|
|
804
877
|
errorQueryRunnerFactoryRequired,
|
|
805
878
|
errorRuntime,
|
|
879
|
+
errorTargetMigrationNotSupported,
|
|
806
880
|
errorTargetMismatch,
|
|
807
881
|
errorUnexpected
|
|
808
882
|
} from "@prisma-next/core-control-plane/errors";
|
|
@@ -847,46 +921,23 @@ function handleResult(result, flags, onSuccess) {
|
|
|
847
921
|
// src/utils/spinner.ts
|
|
848
922
|
import ora from "ora";
|
|
849
923
|
async function withSpinner(operation, options) {
|
|
850
|
-
const { message, flags
|
|
924
|
+
const { message, flags } = options;
|
|
851
925
|
const shouldShowSpinner = !flags.quiet && flags.json !== "object" && process.stdout.isTTY;
|
|
852
926
|
if (!shouldShowSpinner) {
|
|
853
927
|
return operation();
|
|
854
928
|
}
|
|
855
929
|
const startTime = Date.now();
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
if (!operationCompleted) {
|
|
861
|
-
spinner = ora({
|
|
862
|
-
text: message,
|
|
863
|
-
color: flags.color !== false ? "cyan" : false
|
|
864
|
-
}).start();
|
|
865
|
-
}
|
|
866
|
-
}, delayThreshold);
|
|
930
|
+
const spinner = ora({
|
|
931
|
+
text: message,
|
|
932
|
+
color: flags.color !== false ? "cyan" : false
|
|
933
|
+
}).start();
|
|
867
934
|
try {
|
|
868
935
|
const result = await operation();
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
clearTimeout(timeoutId);
|
|
872
|
-
timeoutId = null;
|
|
873
|
-
}
|
|
874
|
-
if (spinner !== null) {
|
|
875
|
-
const elapsed = Date.now() - startTime;
|
|
876
|
-
spinner.succeed(`${message} (${elapsed}ms)`);
|
|
877
|
-
}
|
|
936
|
+
const elapsed = Date.now() - startTime;
|
|
937
|
+
spinner.succeed(`${message} (${elapsed}ms)`);
|
|
878
938
|
return result;
|
|
879
939
|
} catch (error) {
|
|
880
|
-
|
|
881
|
-
if (timeoutId) {
|
|
882
|
-
clearTimeout(timeoutId);
|
|
883
|
-
timeoutId = null;
|
|
884
|
-
}
|
|
885
|
-
if (spinner !== null) {
|
|
886
|
-
spinner.fail(
|
|
887
|
-
`${message} failed: ${error instanceof Error ? error.message : String(error)}`
|
|
888
|
-
);
|
|
889
|
-
}
|
|
940
|
+
spinner.fail(`${message} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
890
941
|
throw error;
|
|
891
942
|
}
|
|
892
943
|
}
|
|
@@ -904,11 +955,22 @@ export {
|
|
|
904
955
|
formatSchemaVerifyJson,
|
|
905
956
|
formatSignOutput,
|
|
906
957
|
formatSignJson,
|
|
958
|
+
formatDbInitPlanOutput,
|
|
959
|
+
formatDbInitApplyOutput,
|
|
960
|
+
formatDbInitJson,
|
|
907
961
|
formatStyledHeader,
|
|
908
962
|
formatSuccessMessage,
|
|
909
963
|
formatCommandHelp,
|
|
964
|
+
errorConfigValidation,
|
|
965
|
+
errorDatabaseUrlRequired,
|
|
966
|
+
errorDriverRequired,
|
|
967
|
+
errorFileNotFound,
|
|
968
|
+
errorMigrationPlanningFailed,
|
|
969
|
+
errorRuntime,
|
|
970
|
+
errorTargetMigrationNotSupported,
|
|
971
|
+
errorUnexpected,
|
|
910
972
|
performAction,
|
|
911
973
|
handleResult,
|
|
912
974
|
withSpinner
|
|
913
975
|
};
|
|
914
|
-
//# sourceMappingURL=chunk-
|
|
976
|
+
//# sourceMappingURL=chunk-ZKEJZ3NU.js.map
|