@prisma-next/cli 0.1.0-dev.3 → 0.1.0-dev.30

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 CHANGED
@@ -19,7 +19,7 @@ Provide a command-line interface that:
19
19
  - **TS Contract Loading**: Bundle and load TypeScript contract files with import allowlist enforcement
20
20
  - **CLI Command Interface**: Parse arguments and route to command handlers using commander
21
21
  - **File I/O**: Read TS contracts, write emitted artifacts (`contract.json`, `contract.d.ts`)
22
- - **Extension Pack Loading**: Load adapter and extension pack manifests for emission
22
+ - **Extension Pack Descriptor Assembly**: Collect adapter and extension descriptors for emission
23
23
  - **Help Output Formatting**: Custom styled help output with command trees and formatted descriptions
24
24
  - **Config Management**: Load and validate `prisma-next.config.ts` files using Arktype validation
25
25
 
@@ -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/targets-postgres/control';
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
 
@@ -62,7 +62,7 @@ export default defineConfig({
62
62
  target: postgres,
63
63
  adapter: postgresAdapter,
64
64
  driver: postgresDriver, // Required even though emit doesn't use it
65
- extensions: [],
65
+ extensionPacks: [],
66
66
  contract: {
67
67
  source: contract,
68
68
  output: 'src/prisma/contract.json',
@@ -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/targets-postgres/control';
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
 
@@ -143,7 +143,7 @@ export default defineConfig({
143
143
  target: postgres,
144
144
  adapter: postgresAdapter,
145
145
  driver: postgresDriver,
146
- extensions: [],
146
+ extensionPacks: [],
147
147
  contract: {
148
148
  source: contract,
149
149
  output: 'src/prisma/contract.json',
@@ -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 `FamilyInstance` with a `verify()` method:
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 FamilyDescriptor {
227
+ interface ControlFamilyDescriptor {
228
228
  create(options: {
229
- target: TargetDescriptor;
230
- adapter: AdapterDescriptor;
231
- extensions: ExtensionDescriptor[];
232
- }): FamilyInstance;
229
+ target: ControlTargetDescriptor;
230
+ adapter: ControlAdapterDescriptor;
231
+ driver: ControlDriverDescriptor;
232
+ extensions: ControlExtensionDescriptor[];
233
+ }): ControlFamilyInstance;
233
234
  }
234
235
 
235
- interface FamilyInstance {
236
+ interface ControlFamilyInstance {
236
237
  verify(options: {
237
- driver: ControlPlaneDriver;
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/targets-postgres/control';
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({
@@ -295,7 +296,7 @@ export default defineConfig({
295
296
  target: postgres,
296
297
  adapter: postgresAdapter,
297
298
  driver: postgresDriver,
298
- extensions: [],
299
+ extensionPacks: [],
299
300
  db: {
300
301
  url: process.env.DATABASE_URL, // Optional: can also use --db flag
301
302
  },
@@ -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 `FamilyInstance` with an `introspect()` method
381
- 2. An optional `toSchemaView()` method on the `FamilyInstance` to project family-specific schema IR into `CoreSchemaView`
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 FamilyInstance {
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/targets-postgres/control';
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
 
@@ -447,7 +448,7 @@ export default defineConfig({
447
448
  target: postgres,
448
449
  adapter: postgresAdapter,
449
450
  driver: postgresDriver,
450
- extensions: [],
451
+ extensionPacks: [],
451
452
  contract: {
452
453
  source: contract,
453
454
  output: 'src/prisma/contract.json',
@@ -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 `FamilyInstance` with `schemaVerify()` and `sign()` methods:
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 FamilyInstance {
590
+ interface ControlFamilyInstance {
590
591
  schemaVerify(options: {
591
592
  driver: ControlDriverInstance;
592
593
  contractIR: ContractIR;
@@ -606,9 +607,159 @@ 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
+ extensionPacks: [],
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
- The CLI uses a config file to specify the target family, target, adapter, extensions, and contract.
762
+ The CLI uses a config file to specify the target family, target, adapter, extensionPacks, and contract.
612
763
 
613
764
  **Config Discovery:**
614
765
  - `--config <path>`: Explicit path (relative or absolute)
@@ -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/targets-postgres/control';
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
 
@@ -628,7 +779,7 @@ export default defineConfig({
628
779
  family: sql,
629
780
  target: postgres,
630
781
  adapter: postgresAdapter,
631
- extensions: [],
782
+ extensionPacks: [],
632
783
  contract: {
633
784
  source: contract, // Can be a value or a function: () => import('./contract').then(m => m.contract)
634
785
  output: 'src/prisma/contract.json', // Optional: defaults to 'src/prisma/contract.json'
@@ -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`)
@@ -758,8 +909,63 @@ See `.cursor/rules/config-validation-and-normalization.mdc` for detailed pattern
758
909
  - `schemaVerify(options)` - Verifies database schema against contract
759
910
  - `introspect(options)` - Introspects database schema
760
911
 
761
- ### Pack Manifest Types (IR)
762
- - Families define their manifest IR and related types under their own tooling packages. CLI treats manifests as opaque data.
912
+ ### Descriptor Declarative Fields
913
+ - Families expose component descriptors (target, adapter, driver, extensions) as plain TypeScript objects. Each descriptor includes **declarative fields**: metadata that describes what the component *provides* (independent of its runtime implementation), and that the CLI can safely copy into emitted artifacts.
914
+ - Common declarative keys:
915
+ - **`version`**: Component version included in emitted metadata (useful for debugging and reproducibility).
916
+ - **`capabilities`**: Feature flags the component contributes (e.g., adapter/runtime lowering requirements). Typically namespaced by target (e.g., `{ postgres: { returning: true } }`) so contracts can be validated against the active target.
917
+ - **`types`**: Type import specs and type IDs contributed by the component. Common examples:
918
+ - `types.codecTypes.import`: Where to import codec type mappings for `contract.d.ts`.
919
+ - `types.operationTypes.import`: Where to import operation type mappings for `contract.d.ts` (extensions).
920
+ - `types.storage`: Storage type bindings (`typeId`, `nativeType`, etc.) used in authoring/emission.
921
+ - **`operations`**: Operation signatures the component contributes (extensions), used for type generation and (optionally) validation/lowering.
922
+ - **Component-specific metadata**:
923
+ - Extensions may also include control-plane-only metadata like `databaseDependencies` (used by verify/schema-verify and not required at runtime).
924
+
925
+ Unlike the older **manifest-based IR** approach (separate JSON manifests + a parsing/validation step to build an IR), descriptors are imported directly from packages (e.g., `@prisma-next/*/control`). This removes a file-format boundary and keeps the data and its types co-located.
926
+ - Benefits: fewer moving parts (no JSON parsing), easier refactors (TypeScript catches drift), and clearer ownership (the package exports the canonical descriptor object).
927
+ - Trade-offs: descriptors must be available as build-time imports (less dynamic discovery vs scanning arbitrary manifest files).
928
+
929
+ **Illustrative example (descriptor object):**
930
+
931
+ ```typescript
932
+ import type { SqlControlExtensionDescriptor } from '@prisma-next/family-sql/control';
933
+
934
+ const exampleExtension: SqlControlExtensionDescriptor<'postgres'> = {
935
+ kind: 'extension',
936
+ id: 'example',
937
+ version: '1.0.0',
938
+ familyId: 'sql',
939
+ targetId: 'postgres',
940
+ capabilities: { postgres: { 'example/feature': true } },
941
+ types: {
942
+ operationTypes: {
943
+ import: {
944
+ package: '@prisma-next/extension-example/operation-types',
945
+ named: 'OperationTypes',
946
+ alias: 'ExampleOperationTypes',
947
+ },
948
+ },
949
+ },
950
+ operations: [],
951
+ create: () => ({ familyId: 'sql', targetId: 'postgres' }),
952
+ };
953
+
954
+ export default exampleExtension;
955
+ ```
956
+
957
+ **How CLI consumers import/use it:**
958
+ - Config imports descriptors directly and passes them to `defineConfig()` (see “Config File Requirements” under `prisma-next contract emit` above; also see “Entrypoints” below for the `@prisma-next/*/control` subpaths):
959
+
960
+ ```typescript
961
+ import { defineConfig } from '@prisma-next/cli/config-types';
962
+ import exampleExtension from '@prisma-next/extension-example/control';
963
+
964
+ export default defineConfig({
965
+ // family/target/adapter/driver omitted for brevity
966
+ extensionPacks: [exampleExtension],
967
+ });
968
+ ```
763
969
 
764
970
  ## Dependencies
765
971
 
@@ -831,7 +1037,7 @@ The CLI package exports several subpaths for different use cases:
831
1037
 
832
1038
  - **`@prisma-next/cli`** (main export): Exports `loadContractFromTs` and `createContractEmitCommand`
833
1039
  - **`@prisma-next/cli/config-types`**: Exports `defineConfig` and config types
834
- - **`@prisma-next/cli/pack-loading`**: Exports `loadExtensionPacks` and `loadExtensionPackManifest`
1040
+ - **`@prisma-next/cli/commands/db-init`**: Exports `createDbInitCommand`
835
1041
  - **`@prisma-next/cli/commands/db-introspect`**: Exports `createDbIntrospectCommand`
836
1042
  - **`@prisma-next/cli/commands/db-schema-verify`**: Exports `createDbSchemaVerifyCommand`
837
1043
  - **`@prisma-next/cli/commands/db-sign`**: Exports `createDbSignCommand`
@@ -839,7 +1045,7 @@ The CLI package exports several subpaths for different use cases:
839
1045
  - **`@prisma-next/cli/commands/contract-emit`**: Exports `createContractEmitCommand`
840
1046
  - **`@prisma-next/cli/config-loader`**: Exports `loadConfig` function
841
1047
 
842
- **Important**: `loadContractFromTs` is exported from the main package (`@prisma-next/cli`), not from `@prisma-next/cli/pack-loading`. See `.cursor/rules/cli-package-exports.mdc` for import patterns.
1048
+ **Important**: `loadContractFromTs` is exported from the main package (`@prisma-next/cli`). See `.cursor/rules/cli-package-exports.mdc` for import patterns.
843
1049
 
844
1050
  ## Package Location
845
1051
 
@@ -847,7 +1053,7 @@ This package is part of the **framework domain**, **tooling layer**, **migration
847
1053
  - **Domain**: framework (target-agnostic)
848
1054
  - **Layer**: tooling
849
1055
  - **Plane**: migration
850
- - **Path**: `packages/framework/tooling/cli`
1056
+ - **Path**: `packages/1-framework/3-tooling/cli`
851
1057
 
852
1058
  ## See Also
853
1059
 
@@ -9,7 +9,7 @@ import {
9
9
  performAction,
10
10
  setCommandDescriptions,
11
11
  withSpinner
12
- } from "./chunk-3EODSNGS.js";
12
+ } from "./chunk-BZMBKEEQ.js";
13
13
  import {
14
14
  loadConfig
15
15
  } from "./chunk-HWYQOCAJ.js";
@@ -74,7 +74,7 @@ function createContractEmitCommand() {
74
74
  target: config.target,
75
75
  adapter: config.adapter,
76
76
  driver: config.driver,
77
- extensions: config.extensions ?? []
77
+ extensionPacks: config.extensionPacks ?? []
78
78
  });
79
79
  let contractRaw;
80
80
  if (typeof contractConfig.source === "function") {
@@ -131,4 +131,4 @@ function createContractEmitCommand() {
131
131
  export {
132
132
  createContractEmitCommand
133
133
  };
134
- //# sourceMappingURL=chunk-4Q3MO4TK.js.map
134
+ //# sourceMappingURL=chunk-464LNZCE.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 { performAction } from '../utils/action';\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 { 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 extensionPacks: config.extensionPacks ?? [],\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":[]}