@prisma-next/cli 0.3.0-dev.16 → 0.3.0-dev.18

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.
Files changed (45) hide show
  1. package/dist/chunk-BO73VO4I.js +45 -0
  2. package/dist/chunk-BO73VO4I.js.map +1 -0
  3. package/dist/{chunk-VI2YETW7.js → chunk-MPSJAVF6.js} +4 -2
  4. package/dist/{chunk-U6QI3AZ3.js → chunk-RIONCN4I.js} +45 -6
  5. package/dist/chunk-RIONCN4I.js.map +1 -0
  6. package/dist/{chunk-74IELXRA.js → chunk-RPYY5SM7.js} +273 -19
  7. package/dist/chunk-RPYY5SM7.js.map +1 -0
  8. package/dist/cli.js +708 -551
  9. package/dist/cli.js.map +1 -1
  10. package/dist/commands/contract-emit.js +2 -3
  11. package/dist/commands/db-init.js +5 -46
  12. package/dist/commands/db-init.js.map +1 -1
  13. package/dist/commands/db-introspect.d.ts.map +1 -1
  14. package/dist/commands/db-introspect.js +107 -133
  15. package/dist/commands/db-introspect.js.map +1 -1
  16. package/dist/commands/db-schema-verify.d.ts.map +1 -1
  17. package/dist/commands/db-schema-verify.js +119 -107
  18. package/dist/commands/db-schema-verify.js.map +1 -1
  19. package/dist/commands/db-sign.d.ts.map +1 -1
  20. package/dist/commands/db-sign.js +151 -150
  21. package/dist/commands/db-sign.js.map +1 -1
  22. package/dist/commands/db-verify.d.ts.map +1 -1
  23. package/dist/commands/db-verify.js +141 -116
  24. package/dist/commands/db-verify.js.map +1 -1
  25. package/dist/control-api/client.d.ts.map +1 -1
  26. package/dist/control-api/types.d.ts +41 -0
  27. package/dist/control-api/types.d.ts.map +1 -1
  28. package/dist/exports/control-api.js +2 -3
  29. package/dist/exports/index.js +2 -3
  30. package/dist/exports/index.js.map +1 -1
  31. package/package.json +10 -10
  32. package/src/commands/contract-emit.ts +1 -1
  33. package/src/commands/db-introspect.ts +151 -178
  34. package/src/commands/db-schema-verify.ts +150 -143
  35. package/src/commands/db-sign.ts +202 -196
  36. package/src/commands/db-verify.ts +179 -149
  37. package/src/control-api/client.ts +256 -22
  38. package/src/control-api/types.ts +42 -0
  39. package/dist/chunk-5MPKZYVI.js +0 -47
  40. package/dist/chunk-5MPKZYVI.js.map +0 -1
  41. package/dist/chunk-6EPKRATC.js +0 -91
  42. package/dist/chunk-6EPKRATC.js.map +0 -1
  43. package/dist/chunk-74IELXRA.js.map +0 -1
  44. package/dist/chunk-U6QI3AZ3.js.map +0 -1
  45. /package/dist/{chunk-VI2YETW7.js.map → chunk-MPSJAVF6.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import { Command as Command7 } from "commander";
7
7
  import { mkdirSync, writeFileSync } from "fs";
8
8
  import { dirname as dirname2, relative as relative2, resolve as resolve2 } from "path";
9
9
  import { errorContractConfigMissing as errorContractConfigMissing2 } from "@prisma-next/core-control-plane/errors";
10
- import { createControlPlaneStack } from "@prisma-next/core-control-plane/types";
10
+ import { createControlPlaneStack } from "@prisma-next/core-control-plane/stack";
11
11
  import { Command } from "commander";
12
12
 
13
13
  // src/config-loader.ts
@@ -1247,37 +1247,6 @@ function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId,
1247
1247
  }
1248
1248
  return frameworkComponents;
1249
1249
  }
1250
- function assertContractRequirementsSatisfied({
1251
- contract,
1252
- stack
1253
- }) {
1254
- const providedComponentIds = /* @__PURE__ */ new Set([stack.target.id, stack.adapter.id]);
1255
- for (const extension of stack.extensionPacks) {
1256
- providedComponentIds.add(extension.id);
1257
- }
1258
- const result = checkContractComponentRequirements({
1259
- contract,
1260
- expectedTargetFamily: stack.target.familyId,
1261
- expectedTargetId: stack.target.targetId,
1262
- providedComponentIds
1263
- });
1264
- if (result.familyMismatch) {
1265
- throw errorConfigValidation("contract.targetFamily", {
1266
- why: `Contract was emitted for family '${result.familyMismatch.actual}' but CLI config is wired to '${result.familyMismatch.expected}'.`
1267
- });
1268
- }
1269
- if (result.targetMismatch) {
1270
- throw errorConfigValidation("contract.target", {
1271
- why: `Contract target '${result.targetMismatch.actual}' does not match CLI target '${result.targetMismatch.expected}'.`
1272
- });
1273
- }
1274
- if (result.missingExtensionPackIds.length > 0) {
1275
- throw errorContractMissingExtensionPacks({
1276
- missingExtensionPacks: result.missingExtensionPackIds,
1277
- providedComponentIds: [...providedComponentIds]
1278
- });
1279
- }
1280
- }
1281
1250
 
1282
1251
  // src/control-api/operations/db-init.ts
1283
1252
  import { notOk as notOk2, ok as ok2 } from "@prisma-next/utils/result";
@@ -1560,34 +1529,182 @@ var ControlClientImpl = class {
1560
1529
  };
1561
1530
  }
1562
1531
  async verify(options) {
1532
+ const { onProgress } = options;
1533
+ if (options.connection !== void 0) {
1534
+ onProgress?.({
1535
+ action: "verify",
1536
+ kind: "spanStart",
1537
+ spanId: "connect",
1538
+ label: "Connecting to database..."
1539
+ });
1540
+ try {
1541
+ await this.connect(options.connection);
1542
+ onProgress?.({
1543
+ action: "verify",
1544
+ kind: "spanEnd",
1545
+ spanId: "connect",
1546
+ outcome: "ok"
1547
+ });
1548
+ } catch (error) {
1549
+ onProgress?.({
1550
+ action: "verify",
1551
+ kind: "spanEnd",
1552
+ spanId: "connect",
1553
+ outcome: "error"
1554
+ });
1555
+ throw error;
1556
+ }
1557
+ }
1563
1558
  const { driver, familyInstance } = await this.ensureConnected();
1564
1559
  const contractIR = familyInstance.validateContractIR(options.contractIR);
1565
- return familyInstance.verify({
1566
- driver,
1567
- contractIR,
1568
- expectedTargetId: this.options.target.targetId,
1569
- contractPath: ""
1560
+ onProgress?.({
1561
+ action: "verify",
1562
+ kind: "spanStart",
1563
+ spanId: "verify",
1564
+ label: "Verifying contract marker..."
1570
1565
  });
1566
+ try {
1567
+ const result = await familyInstance.verify({
1568
+ driver,
1569
+ contractIR,
1570
+ expectedTargetId: this.options.target.targetId,
1571
+ contractPath: ""
1572
+ });
1573
+ onProgress?.({
1574
+ action: "verify",
1575
+ kind: "spanEnd",
1576
+ spanId: "verify",
1577
+ outcome: result.ok ? "ok" : "error"
1578
+ });
1579
+ return result;
1580
+ } catch (error) {
1581
+ onProgress?.({
1582
+ action: "verify",
1583
+ kind: "spanEnd",
1584
+ spanId: "verify",
1585
+ outcome: "error"
1586
+ });
1587
+ throw error;
1588
+ }
1571
1589
  }
1572
1590
  async schemaVerify(options) {
1591
+ const { onProgress } = options;
1592
+ if (options.connection !== void 0) {
1593
+ onProgress?.({
1594
+ action: "schemaVerify",
1595
+ kind: "spanStart",
1596
+ spanId: "connect",
1597
+ label: "Connecting to database..."
1598
+ });
1599
+ try {
1600
+ await this.connect(options.connection);
1601
+ onProgress?.({
1602
+ action: "schemaVerify",
1603
+ kind: "spanEnd",
1604
+ spanId: "connect",
1605
+ outcome: "ok"
1606
+ });
1607
+ } catch (error) {
1608
+ onProgress?.({
1609
+ action: "schemaVerify",
1610
+ kind: "spanEnd",
1611
+ spanId: "connect",
1612
+ outcome: "error"
1613
+ });
1614
+ throw error;
1615
+ }
1616
+ }
1573
1617
  const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
1574
1618
  const contractIR = familyInstance.validateContractIR(options.contractIR);
1575
- return familyInstance.schemaVerify({
1576
- driver,
1577
- contractIR,
1578
- strict: options.strict ?? false,
1579
- contractPath: "",
1580
- frameworkComponents
1619
+ onProgress?.({
1620
+ action: "schemaVerify",
1621
+ kind: "spanStart",
1622
+ spanId: "schemaVerify",
1623
+ label: "Verifying database schema..."
1581
1624
  });
1625
+ try {
1626
+ const result = await familyInstance.schemaVerify({
1627
+ driver,
1628
+ contractIR,
1629
+ strict: options.strict ?? false,
1630
+ contractPath: "",
1631
+ frameworkComponents
1632
+ });
1633
+ onProgress?.({
1634
+ action: "schemaVerify",
1635
+ kind: "spanEnd",
1636
+ spanId: "schemaVerify",
1637
+ outcome: result.ok ? "ok" : "error"
1638
+ });
1639
+ return result;
1640
+ } catch (error) {
1641
+ onProgress?.({
1642
+ action: "schemaVerify",
1643
+ kind: "spanEnd",
1644
+ spanId: "schemaVerify",
1645
+ outcome: "error"
1646
+ });
1647
+ throw error;
1648
+ }
1582
1649
  }
1583
1650
  async sign(options) {
1651
+ const { onProgress } = options;
1652
+ if (options.connection !== void 0) {
1653
+ onProgress?.({
1654
+ action: "sign",
1655
+ kind: "spanStart",
1656
+ spanId: "connect",
1657
+ label: "Connecting to database..."
1658
+ });
1659
+ try {
1660
+ await this.connect(options.connection);
1661
+ onProgress?.({
1662
+ action: "sign",
1663
+ kind: "spanEnd",
1664
+ spanId: "connect",
1665
+ outcome: "ok"
1666
+ });
1667
+ } catch (error) {
1668
+ onProgress?.({
1669
+ action: "sign",
1670
+ kind: "spanEnd",
1671
+ spanId: "connect",
1672
+ outcome: "error"
1673
+ });
1674
+ throw error;
1675
+ }
1676
+ }
1584
1677
  const { driver, familyInstance } = await this.ensureConnected();
1585
1678
  const contractIR = familyInstance.validateContractIR(options.contractIR);
1586
- return familyInstance.sign({
1587
- driver,
1588
- contractIR,
1589
- contractPath: ""
1679
+ onProgress?.({
1680
+ action: "sign",
1681
+ kind: "spanStart",
1682
+ spanId: "sign",
1683
+ label: "Signing database..."
1590
1684
  });
1685
+ try {
1686
+ const result = await familyInstance.sign({
1687
+ driver,
1688
+ contractIR,
1689
+ contractPath: options.contractPath ?? "",
1690
+ ...options.configPath ? { configPath: options.configPath } : {}
1691
+ });
1692
+ onProgress?.({
1693
+ action: "sign",
1694
+ kind: "spanEnd",
1695
+ spanId: "sign",
1696
+ outcome: "ok"
1697
+ });
1698
+ return result;
1699
+ } catch (error) {
1700
+ onProgress?.({
1701
+ action: "sign",
1702
+ kind: "spanEnd",
1703
+ spanId: "sign",
1704
+ outcome: "error"
1705
+ });
1706
+ throw error;
1707
+ }
1591
1708
  }
1592
1709
  async dbInit(options) {
1593
1710
  const { onProgress } = options;
@@ -1632,10 +1749,66 @@ var ControlClientImpl = class {
1632
1749
  });
1633
1750
  }
1634
1751
  async introspect(options) {
1752
+ const onProgress = options?.onProgress;
1753
+ if (options?.connection !== void 0) {
1754
+ onProgress?.({
1755
+ action: "introspect",
1756
+ kind: "spanStart",
1757
+ spanId: "connect",
1758
+ label: "Connecting to database..."
1759
+ });
1760
+ try {
1761
+ await this.connect(options.connection);
1762
+ onProgress?.({
1763
+ action: "introspect",
1764
+ kind: "spanEnd",
1765
+ spanId: "connect",
1766
+ outcome: "ok"
1767
+ });
1768
+ } catch (error) {
1769
+ onProgress?.({
1770
+ action: "introspect",
1771
+ kind: "spanEnd",
1772
+ spanId: "connect",
1773
+ outcome: "error"
1774
+ });
1775
+ throw error;
1776
+ }
1777
+ }
1635
1778
  const { driver, familyInstance } = await this.ensureConnected();
1636
1779
  const _schema = options?.schema;
1637
1780
  void _schema;
1638
- return familyInstance.introspect({ driver });
1781
+ onProgress?.({
1782
+ action: "introspect",
1783
+ kind: "spanStart",
1784
+ spanId: "introspect",
1785
+ label: "Introspecting database schema..."
1786
+ });
1787
+ try {
1788
+ const result = await familyInstance.introspect({ driver });
1789
+ onProgress?.({
1790
+ action: "introspect",
1791
+ kind: "spanEnd",
1792
+ spanId: "introspect",
1793
+ outcome: "ok"
1794
+ });
1795
+ return result;
1796
+ } catch (error) {
1797
+ onProgress?.({
1798
+ action: "introspect",
1799
+ kind: "spanEnd",
1800
+ spanId: "introspect",
1801
+ outcome: "error"
1802
+ });
1803
+ throw error;
1804
+ }
1805
+ }
1806
+ toSchemaView(schemaIR) {
1807
+ this.init();
1808
+ if (this.familyInstance?.toSchemaView) {
1809
+ return this.familyInstance.toSchemaView(schemaIR);
1810
+ }
1811
+ return void 0;
1639
1812
  }
1640
1813
  };
1641
1814
 
@@ -1903,16 +2076,92 @@ function createDbInitCommand() {
1903
2076
  }
1904
2077
 
1905
2078
  // src/commands/db-introspect.ts
1906
- import { readFile as readFile2 } from "fs/promises";
1907
2079
  import { relative as relative4, resolve as resolve4 } from "path";
1908
- import {
1909
- errorDatabaseConnectionRequired as errorDatabaseConnectionRequired2,
1910
- errorDriverRequired as errorDriverRequired2,
1911
- errorRuntime as errorRuntime2,
1912
- errorUnexpected as errorUnexpected3
1913
- } from "@prisma-next/core-control-plane/errors";
1914
- import { createControlPlaneStack as createControlPlaneStack3 } from "@prisma-next/core-control-plane/types";
2080
+ import { notOk as notOk4, ok as ok4 } from "@prisma-next/utils/result";
1915
2081
  import { Command as Command3 } from "commander";
2082
+ async function executeDbIntrospectCommand(options, flags, startTime) {
2083
+ const config = await loadConfig(options.config);
2084
+ const configPath = options.config ? relative4(process.cwd(), resolve4(options.config)) : "prisma-next.config.ts";
2085
+ if (flags.json !== "object" && !flags.quiet) {
2086
+ const details = [
2087
+ { label: "config", value: configPath }
2088
+ ];
2089
+ if (options.db) {
2090
+ const maskedUrl = options.db.replace(/:([^:@]+)@/, ":****@");
2091
+ details.push({ label: "database", value: maskedUrl });
2092
+ } else if (config.db?.connection && typeof config.db.connection === "string") {
2093
+ const maskedUrl = config.db.connection.replace(/:([^:@]+)@/, ":****@");
2094
+ details.push({ label: "database", value: maskedUrl });
2095
+ }
2096
+ const header = formatStyledHeader({
2097
+ command: "db introspect",
2098
+ description: "Inspect the database schema",
2099
+ url: "https://pris.ly/db-introspect",
2100
+ details,
2101
+ flags
2102
+ });
2103
+ console.log(header);
2104
+ }
2105
+ const dbConnection = options.db ?? config.db?.connection;
2106
+ if (!dbConnection) {
2107
+ return notOk4(
2108
+ errorDatabaseConnectionRequired({
2109
+ why: `Database connection is required for db introspect (set db.connection in ${configPath}, or pass --db <url>)`
2110
+ })
2111
+ );
2112
+ }
2113
+ if (!config.driver) {
2114
+ return notOk4(errorDriverRequired({ why: "Config.driver is required for db introspect" }));
2115
+ }
2116
+ const client = createControlClient({
2117
+ family: config.family,
2118
+ target: config.target,
2119
+ adapter: config.adapter,
2120
+ driver: config.driver,
2121
+ extensionPacks: config.extensionPacks ?? []
2122
+ });
2123
+ const onProgress = createProgressAdapter({ flags });
2124
+ try {
2125
+ const schemaIR = await client.introspect({
2126
+ connection: dbConnection,
2127
+ onProgress
2128
+ });
2129
+ if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
2130
+ console.log("");
2131
+ }
2132
+ const schemaView = client.toSchemaView(schemaIR);
2133
+ const totalTime = Date.now() - startTime;
2134
+ const connectionForMeta = typeof dbConnection === "string" ? dbConnection.replace(/:([^:@]+)@/, ":****@") : void 0;
2135
+ const introspectResult = {
2136
+ ok: true,
2137
+ summary: "Schema introspected successfully",
2138
+ target: {
2139
+ familyId: config.family.familyId,
2140
+ id: config.target.targetId
2141
+ },
2142
+ schema: schemaIR,
2143
+ meta: {
2144
+ ...configPath ? { configPath } : {},
2145
+ ...connectionForMeta ? { dbUrl: connectionForMeta } : {}
2146
+ },
2147
+ timings: {
2148
+ total: totalTime
2149
+ }
2150
+ };
2151
+ return ok4({ introspectResult, schemaView });
2152
+ } catch (error) {
2153
+ if (error instanceof CliStructuredError) {
2154
+ return notOk4(error);
2155
+ }
2156
+ return notOk4(
2157
+ errorUnexpected2(error instanceof Error ? error.message : String(error), {
2158
+ why: `Unexpected error during db introspect: ${error instanceof Error ? error.message : String(error)}`
2159
+ })
2160
+ );
2161
+ } finally {
2162
+ await client.close();
2163
+ }
2164
+ }
1916
2165
  function createDbIntrospectCommand() {
1917
2166
  const command = new Command3("introspect");
1918
2167
  setCommandDescriptions(
@@ -1925,128 +2174,21 @@ function createDbIntrospectCommand() {
1925
2174
  const flags = parseGlobalFlags({});
1926
2175
  return formatCommandHelp({ command: cmd, flags });
1927
2176
  }
1928
- }).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object or ndjson)", false).option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("-vv, --trace", "Trace output: deep internals, stack traces").option("--timestamps", "Add timestamps to output").option("--color", "Force color output").option("--no-color", "Disable color output").action(async (options) => {
2177
+ }).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object)", false).option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("-vv, --trace", "Trace output: deep internals, stack traces").option("--timestamps", "Add timestamps to output").option("--color", "Force color output").option("--no-color", "Disable color output").action(async (options) => {
1929
2178
  const flags = parseGlobalFlags(options);
1930
- const result = await performAction(async () => {
1931
- const startTime = Date.now();
1932
- const config = await loadConfig(options.config);
1933
- const configPath = options.config ? relative4(process.cwd(), resolve4(options.config)) : "prisma-next.config.ts";
1934
- let contractIR;
1935
- if (config.contract?.output) {
1936
- const contractPath = resolve4(config.contract.output);
1937
- try {
1938
- const contractJsonContent = await readFile2(contractPath, "utf-8");
1939
- contractIR = JSON.parse(contractJsonContent);
1940
- } catch (error) {
1941
- if (error instanceof Error && error.code !== "ENOENT") {
1942
- throw errorUnexpected3(error.message, {
1943
- why: `Failed to read contract file: ${error.message}`
1944
- });
1945
- }
1946
- }
1947
- }
1948
- if (flags.json !== "object" && !flags.quiet) {
1949
- const details = [
1950
- { label: "config", value: configPath }
1951
- ];
1952
- if (options.db) {
1953
- const maskedUrl = options.db.replace(/:([^:@]+)@/, ":****@");
1954
- details.push({ label: "database", value: maskedUrl });
1955
- } else if (config.db?.connection && typeof config.db.connection === "string") {
1956
- const maskedUrl = config.db.connection.replace(/:([^:@]+)@/, ":****@");
1957
- details.push({ label: "database", value: maskedUrl });
1958
- }
1959
- const header = formatStyledHeader({
2179
+ const startTime = Date.now();
2180
+ if (flags.json === "ndjson") {
2181
+ const result2 = notOk4(
2182
+ errorJsonFormatNotSupported({
1960
2183
  command: "db introspect",
1961
- description: "Inspect the database schema",
1962
- url: "https://pris.ly/db-introspect",
1963
- details,
1964
- flags
1965
- });
1966
- console.log(header);
1967
- }
1968
- const dbConnection = options.db ?? config.db?.connection;
1969
- if (!dbConnection) {
1970
- throw errorDatabaseConnectionRequired2();
1971
- }
1972
- if (!config.driver) {
1973
- throw errorDriverRequired2();
1974
- }
1975
- const driverDescriptor = config.driver;
1976
- const driver = await withSpinner(() => driverDescriptor.create(dbConnection), {
1977
- message: "Connecting to database...",
1978
- flags
1979
- });
1980
- try {
1981
- const stack = createControlPlaneStack3({
1982
- target: config.target,
1983
- adapter: config.adapter,
1984
- driver: driverDescriptor,
1985
- extensionPacks: config.extensionPacks
1986
- });
1987
- const familyInstance = config.family.create(stack);
1988
- if (contractIR) {
1989
- const validatedContract = familyInstance.validateContractIR(contractIR);
1990
- assertContractRequirementsSatisfied({ contract: validatedContract, stack });
1991
- contractIR = validatedContract;
1992
- }
1993
- let schemaIR;
1994
- try {
1995
- schemaIR = await withSpinner(
1996
- () => familyInstance.introspect({
1997
- driver,
1998
- contractIR
1999
- }),
2000
- {
2001
- message: "Introspecting database schema...",
2002
- flags
2003
- }
2004
- );
2005
- } catch (error) {
2006
- throw errorRuntime2(error instanceof Error ? error.message : String(error), {
2007
- why: `Failed to introspect database: ${error instanceof Error ? error.message : String(error)}`
2008
- });
2009
- }
2010
- let schemaView;
2011
- if (familyInstance.toSchemaView) {
2012
- try {
2013
- schemaView = familyInstance.toSchemaView(schemaIR);
2014
- } catch (error) {
2015
- if (flags.verbose) {
2016
- console.error(
2017
- `Warning: Failed to project schema to view: ${error instanceof Error ? error.message : String(error)}`
2018
- );
2019
- }
2020
- }
2021
- }
2022
- const totalTime = Date.now() - startTime;
2023
- if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
2024
- console.log("");
2025
- }
2026
- const connectionForMeta = typeof dbConnection === "string" ? dbConnection.replace(/:([^:@]+)@/, ":****@") : void 0;
2027
- const introspectResult = {
2028
- ok: true,
2029
- summary: "Schema introspected successfully",
2030
- target: {
2031
- familyId: config.family.familyId,
2032
- id: config.target.targetId
2033
- },
2034
- schema: schemaIR,
2035
- ...configPath || connectionForMeta ? {
2036
- meta: {
2037
- ...configPath ? { configPath } : {},
2038
- ...connectionForMeta ? { dbUrl: connectionForMeta } : {}
2039
- }
2040
- } : {},
2041
- timings: {
2042
- total: totalTime
2043
- }
2044
- };
2045
- return { introspectResult, schemaView };
2046
- } finally {
2047
- await driver.close();
2048
- }
2049
- });
2184
+ format: "ndjson",
2185
+ supportedFormats: ["object"]
2186
+ })
2187
+ );
2188
+ const exitCode2 = handleResult(result2, flags);
2189
+ process.exit(exitCode2);
2190
+ }
2191
+ const result = await executeDbIntrospectCommand(options, flags, startTime);
2050
2192
  const exitCode = handleResult(result, flags, (value) => {
2051
2193
  const { introspectResult, schemaView } = value;
2052
2194
  if (flags.json === "object") {
@@ -2064,124 +2206,130 @@ function createDbIntrospectCommand() {
2064
2206
  }
2065
2207
 
2066
2208
  // src/commands/db-schema-verify.ts
2067
- import { readFile as readFile3 } from "fs/promises";
2209
+ import { readFile as readFile2 } from "fs/promises";
2068
2210
  import { relative as relative5, resolve as resolve5 } from "path";
2069
- import {
2070
- errorDatabaseConnectionRequired as errorDatabaseConnectionRequired3,
2071
- errorDriverRequired as errorDriverRequired3,
2072
- errorFileNotFound as errorFileNotFound2,
2073
- errorRuntime as errorRuntime3,
2074
- errorUnexpected as errorUnexpected4
2075
- } from "@prisma-next/core-control-plane/errors";
2076
- import { createControlPlaneStack as createControlPlaneStack4 } from "@prisma-next/core-control-plane/types";
2211
+ import { notOk as notOk5, ok as ok5 } from "@prisma-next/utils/result";
2077
2212
  import { Command as Command4 } from "commander";
2078
- function createDbSchemaVerifyCommand() {
2079
- const command = new Command4("schema-verify");
2080
- setCommandDescriptions(
2081
- command,
2082
- "Check whether the database schema satisfies your contract",
2083
- "Verifies that your database schema satisfies the emitted contract. Compares table structures,\ncolumn types, constraints, and extensions. Reports any mismatches via a contract-shaped\nverification tree. This is a read-only operation that does not modify the database."
2084
- );
2085
- command.configureHelp({
2086
- formatHelp: (cmd) => {
2087
- const flags = parseGlobalFlags({});
2088
- return formatCommandHelp({ command: cmd, flags });
2089
- }
2090
- }).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object or ndjson)", false).option("--strict", "Strict mode: extra schema elements cause failures", false).option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("-vv, --trace", "Trace output: deep internals, stack traces").option("--timestamps", "Add timestamps to output").option("--color", "Force color output").option("--no-color", "Disable color output").action(async (options) => {
2213
+ async function executeDbSchemaVerifyCommand(options, flags) {
2214
+ const config = await loadConfig(options.config);
2215
+ const configPath = options.config ? relative5(process.cwd(), resolve5(options.config)) : "prisma-next.config.ts";
2216
+ const contractPathAbsolute = config.contract?.output ? resolve5(config.contract.output) : resolve5("src/prisma/contract.json");
2217
+ const contractPath = relative5(process.cwd(), contractPathAbsolute);
2218
+ if (flags.json !== "object" && !flags.quiet) {
2219
+ const details = [
2220
+ { label: "config", value: configPath },
2221
+ { label: "contract", value: contractPath }
2222
+ ];
2223
+ if (options.db) {
2224
+ details.push({ label: "database", value: options.db });
2225
+ }
2226
+ const header = formatStyledHeader({
2227
+ command: "db schema-verify",
2228
+ description: "Check whether the database schema satisfies your contract",
2229
+ url: "https://pris.ly/db-schema-verify",
2230
+ details,
2231
+ flags
2232
+ });
2233
+ console.log(header);
2234
+ }
2235
+ let contractJsonContent;
2236
+ try {
2237
+ contractJsonContent = await readFile2(contractPathAbsolute, "utf-8");
2238
+ } catch (error) {
2239
+ if (error instanceof Error && error.code === "ENOENT") {
2240
+ return notOk5(
2241
+ errorFileNotFound(contractPathAbsolute, {
2242
+ why: `Contract file not found at ${contractPathAbsolute}`,
2243
+ fix: `Run \`prisma-next contract emit\` to generate ${contractPath}, or update \`config.contract.output\` in ${configPath}`
2244
+ })
2245
+ );
2246
+ }
2247
+ return notOk5(
2248
+ errorUnexpected2(error instanceof Error ? error.message : String(error), {
2249
+ why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`
2250
+ })
2251
+ );
2252
+ }
2253
+ let contractJson;
2254
+ try {
2255
+ contractJson = JSON.parse(contractJsonContent);
2256
+ } catch (error) {
2257
+ return notOk5(
2258
+ errorContractValidationFailed(
2259
+ `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,
2260
+ { where: { path: contractPathAbsolute } }
2261
+ )
2262
+ );
2263
+ }
2264
+ const dbConnection = options.db ?? config.db?.connection;
2265
+ if (!dbConnection) {
2266
+ return notOk5(
2267
+ errorDatabaseConnectionRequired({
2268
+ why: `Database connection is required for db schema-verify (set db.connection in ${configPath}, or pass --db <url>)`
2269
+ })
2270
+ );
2271
+ }
2272
+ if (!config.driver) {
2273
+ return notOk5(errorDriverRequired({ why: "Config.driver is required for db schema-verify" }));
2274
+ }
2275
+ const client = createControlClient({
2276
+ family: config.family,
2277
+ target: config.target,
2278
+ adapter: config.adapter,
2279
+ driver: config.driver,
2280
+ extensionPacks: config.extensionPacks ?? []
2281
+ });
2282
+ const onProgress = createProgressAdapter({ flags });
2283
+ try {
2284
+ const schemaVerifyResult = await client.schemaVerify({
2285
+ contractIR: contractJson,
2286
+ strict: options.strict ?? false,
2287
+ connection: dbConnection,
2288
+ onProgress
2289
+ });
2290
+ if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
2291
+ console.log("");
2292
+ }
2293
+ return ok5(schemaVerifyResult);
2294
+ } catch (error) {
2295
+ if (error instanceof CliStructuredError) {
2296
+ return notOk5(error);
2297
+ }
2298
+ return notOk5(
2299
+ errorUnexpected2(error instanceof Error ? error.message : String(error), {
2300
+ why: `Unexpected error during db schema-verify: ${error instanceof Error ? error.message : String(error)}`
2301
+ })
2302
+ );
2303
+ } finally {
2304
+ await client.close();
2305
+ }
2306
+ }
2307
+ function createDbSchemaVerifyCommand() {
2308
+ const command = new Command4("schema-verify");
2309
+ setCommandDescriptions(
2310
+ command,
2311
+ "Check whether the database schema satisfies your contract",
2312
+ "Verifies that your database schema satisfies the emitted contract. Compares table structures,\ncolumn types, constraints, and extensions. Reports any mismatches via a contract-shaped\nverification tree. This is a read-only operation that does not modify the database."
2313
+ );
2314
+ command.configureHelp({
2315
+ formatHelp: (cmd) => {
2316
+ const flags = parseGlobalFlags({});
2317
+ return formatCommandHelp({ command: cmd, flags });
2318
+ }
2319
+ }).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object)", false).option("--strict", "Strict mode: extra schema elements cause failures", false).option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("-vv, --trace", "Trace output: deep internals, stack traces").option("--timestamps", "Add timestamps to output").option("--color", "Force color output").option("--no-color", "Disable color output").action(async (options) => {
2091
2320
  const flags = parseGlobalFlags(options);
2092
- const result = await performAction(async () => {
2093
- const config = await loadConfig(options.config);
2094
- const configPath = options.config ? relative5(process.cwd(), resolve5(options.config)) : "prisma-next.config.ts";
2095
- const contractPathAbsolute = config.contract?.output ? resolve5(config.contract.output) : resolve5("src/prisma/contract.json");
2096
- const contractPath = relative5(process.cwd(), contractPathAbsolute);
2097
- if (flags.json !== "object" && !flags.quiet) {
2098
- const details = [
2099
- { label: "config", value: configPath },
2100
- { label: "contract", value: contractPath }
2101
- ];
2102
- if (options.db) {
2103
- details.push({ label: "database", value: options.db });
2104
- }
2105
- const header = formatStyledHeader({
2321
+ if (flags.json === "ndjson") {
2322
+ const result2 = notOk5(
2323
+ errorJsonFormatNotSupported({
2106
2324
  command: "db schema-verify",
2107
- description: "Check whether the database schema satisfies your contract",
2108
- url: "https://pris.ly/db-schema-verify",
2109
- details,
2110
- flags
2111
- });
2112
- console.log(header);
2113
- }
2114
- let contractJsonContent;
2115
- try {
2116
- contractJsonContent = await readFile3(contractPathAbsolute, "utf-8");
2117
- } catch (error) {
2118
- if (error instanceof Error && error.code === "ENOENT") {
2119
- throw errorFileNotFound2(contractPathAbsolute, {
2120
- why: `Contract file not found at ${contractPathAbsolute}`
2121
- });
2122
- }
2123
- throw errorUnexpected4(error instanceof Error ? error.message : String(error), {
2124
- why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`
2125
- });
2126
- }
2127
- const contractJson = JSON.parse(contractJsonContent);
2128
- if (!config.driver) {
2129
- throw errorDriverRequired3();
2130
- }
2131
- const driverDescriptor = config.driver;
2132
- const stack = createControlPlaneStack4({
2133
- target: config.target,
2134
- adapter: config.adapter,
2135
- driver: driverDescriptor,
2136
- extensionPacks: config.extensionPacks
2137
- });
2138
- const familyInstance = config.family.create(stack);
2139
- const contractIR = familyInstance.validateContractIR(contractJson);
2140
- assertContractRequirementsSatisfied({ contract: contractIR, stack });
2141
- const dbConnection = options.db ?? config.db?.connection;
2142
- if (!dbConnection) {
2143
- throw errorDatabaseConnectionRequired3();
2144
- }
2145
- const driver = await withSpinner(() => driverDescriptor.create(dbConnection), {
2146
- message: "Connecting to database...",
2147
- flags
2148
- });
2149
- try {
2150
- const rawComponents = [config.target, config.adapter, ...config.extensionPacks ?? []];
2151
- const frameworkComponents = assertFrameworkComponentsCompatible(
2152
- config.family.familyId,
2153
- config.target.targetId,
2154
- rawComponents
2155
- );
2156
- let schemaVerifyResult;
2157
- try {
2158
- schemaVerifyResult = await withSpinner(
2159
- () => familyInstance.schemaVerify({
2160
- driver,
2161
- contractIR,
2162
- strict: options.strict ?? false,
2163
- contractPath: contractPathAbsolute,
2164
- configPath,
2165
- frameworkComponents
2166
- }),
2167
- {
2168
- message: "Verifying database schema...",
2169
- flags
2170
- }
2171
- );
2172
- } catch (error) {
2173
- throw errorRuntime3(error instanceof Error ? error.message : String(error), {
2174
- why: `Failed to verify database schema: ${error instanceof Error ? error.message : String(error)}`
2175
- });
2176
- }
2177
- if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
2178
- console.log("");
2179
- }
2180
- return schemaVerifyResult;
2181
- } finally {
2182
- await driver.close();
2183
- }
2184
- });
2325
+ format: "ndjson",
2326
+ supportedFormats: ["object"]
2327
+ })
2328
+ );
2329
+ const exitCode2 = handleResult(result2, flags);
2330
+ process.exit(exitCode2);
2331
+ }
2332
+ const result = await executeDbSchemaVerifyCommand(options, flags);
2185
2333
  const exitCode = handleResult(result, flags, (schemaVerifyResult) => {
2186
2334
  if (flags.json === "object") {
2187
2335
  console.log(formatSchemaVerifyJson(schemaVerifyResult));
@@ -2202,17 +2350,116 @@ function createDbSchemaVerifyCommand() {
2202
2350
  }
2203
2351
 
2204
2352
  // src/commands/db-sign.ts
2205
- import { readFile as readFile4 } from "fs/promises";
2353
+ import { readFile as readFile3 } from "fs/promises";
2206
2354
  import { relative as relative6, resolve as resolve6 } from "path";
2207
- import {
2208
- errorDatabaseConnectionRequired as errorDatabaseConnectionRequired4,
2209
- errorDriverRequired as errorDriverRequired4,
2210
- errorFileNotFound as errorFileNotFound3,
2211
- errorRuntime as errorRuntime4,
2212
- errorUnexpected as errorUnexpected5
2213
- } from "@prisma-next/core-control-plane/errors";
2214
- import { createControlPlaneStack as createControlPlaneStack5 } from "@prisma-next/core-control-plane/types";
2355
+ import { notOk as notOk6, ok as ok6 } from "@prisma-next/utils/result";
2215
2356
  import { Command as Command5 } from "commander";
2357
+ async function executeDbSignCommand(options, flags) {
2358
+ const config = await loadConfig(options.config);
2359
+ const configPath = options.config ? relative6(process.cwd(), resolve6(options.config)) : "prisma-next.config.ts";
2360
+ const contractPathAbsolute = config.contract?.output ? resolve6(config.contract.output) : resolve6("src/prisma/contract.json");
2361
+ const contractPath = relative6(process.cwd(), contractPathAbsolute);
2362
+ if (flags.json !== "object" && !flags.quiet) {
2363
+ const details = [
2364
+ { label: "config", value: configPath },
2365
+ { label: "contract", value: contractPath }
2366
+ ];
2367
+ if (options.db) {
2368
+ details.push({ label: "database", value: options.db });
2369
+ }
2370
+ const header = formatStyledHeader({
2371
+ command: "db sign",
2372
+ description: "Sign the database with your contract so you can safely run queries",
2373
+ url: "https://pris.ly/db-sign",
2374
+ details,
2375
+ flags
2376
+ });
2377
+ console.log(header);
2378
+ }
2379
+ let contractJsonContent;
2380
+ try {
2381
+ contractJsonContent = await readFile3(contractPathAbsolute, "utf-8");
2382
+ } catch (error) {
2383
+ if (error instanceof Error && error.code === "ENOENT") {
2384
+ return notOk6(
2385
+ errorFileNotFound(contractPathAbsolute, {
2386
+ why: `Contract file not found at ${contractPathAbsolute}`,
2387
+ fix: `Run \`prisma-next contract emit\` to generate ${contractPath}, or update \`config.contract.output\` in ${configPath}`
2388
+ })
2389
+ );
2390
+ }
2391
+ return notOk6(
2392
+ errorUnexpected2(error instanceof Error ? error.message : String(error), {
2393
+ why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`
2394
+ })
2395
+ );
2396
+ }
2397
+ let contractJson;
2398
+ try {
2399
+ contractJson = JSON.parse(contractJsonContent);
2400
+ } catch (error) {
2401
+ return notOk6(
2402
+ errorContractValidationFailed(
2403
+ `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,
2404
+ { where: { path: contractPathAbsolute } }
2405
+ )
2406
+ );
2407
+ }
2408
+ const dbConnection = options.db ?? config.db?.connection;
2409
+ if (!dbConnection) {
2410
+ return notOk6(
2411
+ errorDatabaseConnectionRequired({
2412
+ why: `Database connection is required for db sign (set db.connection in ${configPath}, or pass --db <url>)`
2413
+ })
2414
+ );
2415
+ }
2416
+ if (!config.driver) {
2417
+ return notOk6(errorDriverRequired({ why: "Config.driver is required for db sign" }));
2418
+ }
2419
+ const client = createControlClient({
2420
+ family: config.family,
2421
+ target: config.target,
2422
+ adapter: config.adapter,
2423
+ driver: config.driver,
2424
+ extensionPacks: config.extensionPacks ?? []
2425
+ });
2426
+ const onProgress = createProgressAdapter({ flags });
2427
+ try {
2428
+ const schemaVerifyResult = await client.schemaVerify({
2429
+ contractIR: contractJson,
2430
+ strict: false,
2431
+ connection: dbConnection,
2432
+ onProgress
2433
+ });
2434
+ if (!schemaVerifyResult.ok) {
2435
+ if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
2436
+ console.log("");
2437
+ }
2438
+ return notOk6(schemaVerifyResult);
2439
+ }
2440
+ const signResult = await client.sign({
2441
+ contractIR: contractJson,
2442
+ contractPath,
2443
+ configPath,
2444
+ onProgress
2445
+ });
2446
+ if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
2447
+ console.log("");
2448
+ }
2449
+ return ok6(signResult);
2450
+ } catch (error) {
2451
+ if (error instanceof CliStructuredError) {
2452
+ return notOk6(error);
2453
+ }
2454
+ return notOk6(
2455
+ errorUnexpected2(error instanceof Error ? error.message : String(error), {
2456
+ why: `Unexpected error during db sign: ${error instanceof Error ? error.message : String(error)}`
2457
+ })
2458
+ );
2459
+ } finally {
2460
+ await client.close();
2461
+ }
2462
+ }
2216
2463
  function createDbSignCommand() {
2217
2464
  const command = new Command5("sign");
2218
2465
  setCommandDescriptions(
@@ -2225,168 +2472,170 @@ function createDbSignCommand() {
2225
2472
  const flags = parseGlobalFlags({});
2226
2473
  return formatCommandHelp({ command: cmd, flags });
2227
2474
  }
2228
- }).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object or ndjson)", false).option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("-vv, --trace", "Trace output: deep internals, stack traces").option("--timestamps", "Add timestamps to output").option("--color", "Force color output").option("--no-color", "Disable color output").action(async (options) => {
2475
+ }).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object)", false).option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("-vv, --trace", "Trace output: deep internals, stack traces").option("--timestamps", "Add timestamps to output").option("--color", "Force color output").option("--no-color", "Disable color output").action(async (options) => {
2229
2476
  const flags = parseGlobalFlags(options);
2230
- const result = await performAction(async () => {
2231
- const config = await loadConfig(options.config);
2232
- const configPath = options.config ? relative6(process.cwd(), resolve6(options.config)) : "prisma-next.config.ts";
2233
- const contractPathAbsolute = config.contract?.output ? resolve6(config.contract.output) : resolve6("src/prisma/contract.json");
2234
- const contractPath = relative6(process.cwd(), contractPathAbsolute);
2235
- if (flags.json !== "object" && !flags.quiet) {
2236
- const details = [
2237
- { label: "config", value: configPath },
2238
- { label: "contract", value: contractPath }
2239
- ];
2240
- if (options.db) {
2241
- details.push({ label: "database", value: options.db });
2242
- }
2243
- const header = formatStyledHeader({
2477
+ if (flags.json === "ndjson") {
2478
+ const result2 = notOk6(
2479
+ errorJsonFormatNotSupported({
2244
2480
  command: "db sign",
2245
- description: "Sign the database with your contract so you can safely run queries",
2246
- url: "https://pris.ly/db-sign",
2247
- details,
2248
- flags
2249
- });
2250
- console.log(header);
2251
- }
2252
- let contractJsonContent;
2253
- try {
2254
- contractJsonContent = await readFile4(contractPathAbsolute, "utf-8");
2255
- } catch (error) {
2256
- if (error instanceof Error && error.code === "ENOENT") {
2257
- throw errorFileNotFound3(contractPathAbsolute, {
2258
- why: `Contract file not found at ${contractPathAbsolute}`
2259
- });
2260
- }
2261
- throw errorUnexpected5(error instanceof Error ? error.message : String(error), {
2262
- why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`
2263
- });
2264
- }
2265
- const contractJson = JSON.parse(contractJsonContent);
2266
- const dbConnection = options.db ?? config.db?.connection;
2267
- if (!dbConnection) {
2268
- throw errorDatabaseConnectionRequired4();
2269
- }
2270
- if (!config.driver) {
2271
- throw errorDriverRequired4();
2272
- }
2273
- const driverDescriptor = config.driver;
2274
- const stack = createControlPlaneStack5({
2275
- target: config.target,
2276
- adapter: config.adapter,
2277
- driver: driverDescriptor,
2278
- extensionPacks: config.extensionPacks
2279
- });
2280
- const familyInstance = config.family.create(stack);
2281
- const contractIR = familyInstance.validateContractIR(contractJson);
2282
- assertContractRequirementsSatisfied({ contract: contractIR, stack });
2283
- const rawComponents = [config.target, config.adapter, ...config.extensionPacks ?? []];
2284
- const frameworkComponents = assertFrameworkComponentsCompatible(
2285
- config.family.familyId,
2286
- config.target.targetId,
2287
- rawComponents
2481
+ format: "ndjson",
2482
+ supportedFormats: ["object"]
2483
+ })
2288
2484
  );
2289
- const driver = await driverDescriptor.create(dbConnection);
2290
- try {
2291
- let schemaVerifyResult;
2292
- try {
2293
- schemaVerifyResult = await withSpinner(
2294
- () => familyInstance.schemaVerify({
2295
- driver,
2296
- contractIR,
2297
- strict: false,
2298
- contractPath: contractPathAbsolute,
2299
- configPath,
2300
- frameworkComponents
2301
- }),
2302
- {
2303
- message: "Verifying database satisfies contract",
2304
- flags
2305
- }
2306
- );
2307
- } catch (error) {
2308
- throw errorRuntime4(error instanceof Error ? error.message : String(error), {
2309
- why: `Failed to verify database schema: ${error instanceof Error ? error.message : String(error)}`
2310
- });
2311
- }
2312
- if (!schemaVerifyResult.ok) {
2313
- return { schemaVerifyResult, signResult: void 0 };
2314
- }
2315
- let signResult;
2316
- try {
2317
- signResult = await withSpinner(
2318
- () => familyInstance.sign({
2319
- driver,
2320
- contractIR,
2321
- contractPath: contractPathAbsolute,
2322
- configPath
2323
- }),
2324
- {
2325
- message: "Signing database...",
2326
- flags
2327
- }
2328
- );
2329
- } catch (error) {
2330
- throw errorRuntime4(error instanceof Error ? error.message : String(error), {
2331
- why: `Failed to sign database: ${error instanceof Error ? error.message : String(error)}`
2332
- });
2333
- }
2334
- if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
2335
- console.log("");
2336
- }
2337
- return { schemaVerifyResult: void 0, signResult };
2338
- } finally {
2339
- await driver.close();
2340
- }
2341
- });
2342
- const exitCode = handleResult(result, flags, (value) => {
2343
- const { schemaVerifyResult, signResult } = value;
2344
- if (schemaVerifyResult && !schemaVerifyResult.ok) {
2345
- if (flags.json === "object") {
2346
- console.log(formatSchemaVerifyJson(schemaVerifyResult));
2347
- } else {
2348
- const output = formatSchemaVerifyOutput(schemaVerifyResult, flags);
2349
- if (output) {
2350
- console.log(output);
2351
- }
2352
- }
2353
- return;
2354
- }
2355
- if (signResult) {
2356
- if (flags.json === "object") {
2357
- console.log(formatSignJson(signResult));
2358
- } else {
2359
- const output = formatSignOutput(signResult, flags);
2360
- if (output) {
2361
- console.log(output);
2362
- }
2485
+ const exitCode = handleResult(result2, flags);
2486
+ process.exit(exitCode);
2487
+ }
2488
+ const result = await executeDbSignCommand(options, flags);
2489
+ if (result.ok) {
2490
+ if (flags.json === "object") {
2491
+ console.log(formatSignJson(result.value));
2492
+ } else {
2493
+ const output = formatSignOutput(result.value, flags);
2494
+ if (output) {
2495
+ console.log(output);
2363
2496
  }
2364
2497
  }
2365
- });
2366
- if (result.ok && result.value.schemaVerifyResult && !result.value.schemaVerifyResult.ok) {
2367
- process.exit(1);
2368
- } else {
2498
+ process.exit(0);
2499
+ }
2500
+ const failure = result.failure;
2501
+ if (failure instanceof CliStructuredError) {
2502
+ const exitCode = handleResult(result, flags);
2369
2503
  process.exit(exitCode);
2370
2504
  }
2505
+ if (flags.json === "object") {
2506
+ console.log(formatSchemaVerifyJson(failure));
2507
+ } else {
2508
+ const output = formatSchemaVerifyOutput(failure, flags);
2509
+ if (output) {
2510
+ console.log(output);
2511
+ }
2512
+ }
2513
+ process.exit(1);
2371
2514
  });
2372
2515
  return command;
2373
2516
  }
2374
2517
 
2375
2518
  // src/commands/db-verify.ts
2376
- import { readFile as readFile5 } from "fs/promises";
2519
+ import { readFile as readFile4 } from "fs/promises";
2377
2520
  import { relative as relative7, resolve as resolve7 } from "path";
2378
- import {
2379
- errorDatabaseConnectionRequired as errorDatabaseConnectionRequired5,
2380
- errorDriverRequired as errorDriverRequired5,
2381
- errorFileNotFound as errorFileNotFound4,
2382
- errorHashMismatch as errorHashMismatch2,
2383
- errorMarkerMissing as errorMarkerMissing2,
2384
- errorRuntime as errorRuntime5,
2385
- errorTargetMismatch as errorTargetMismatch2,
2386
- errorUnexpected as errorUnexpected6
2387
- } from "@prisma-next/core-control-plane/errors";
2388
- import { createControlPlaneStack as createControlPlaneStack6 } from "@prisma-next/core-control-plane/types";
2521
+ import { notOk as notOk7, ok as ok7 } from "@prisma-next/utils/result";
2389
2522
  import { Command as Command6 } from "commander";
2523
+ function mapVerifyFailure(verifyResult) {
2524
+ if (!verifyResult.ok && verifyResult.code) {
2525
+ if (verifyResult.code === "PN-RTM-3001") {
2526
+ return errorMarkerMissing();
2527
+ }
2528
+ if (verifyResult.code === "PN-RTM-3002") {
2529
+ return errorHashMismatch({
2530
+ expected: verifyResult.contract.coreHash,
2531
+ ...verifyResult.marker?.coreHash ? { actual: verifyResult.marker.coreHash } : {}
2532
+ });
2533
+ }
2534
+ if (verifyResult.code === "PN-RTM-3003") {
2535
+ return errorTargetMismatch(
2536
+ verifyResult.target.expected,
2537
+ verifyResult.target.actual ?? "unknown"
2538
+ );
2539
+ }
2540
+ }
2541
+ return errorRuntime(verifyResult.summary);
2542
+ }
2543
+ async function executeDbVerifyCommand(options, flags) {
2544
+ const config = await loadConfig(options.config);
2545
+ const configPath = options.config ? relative7(process.cwd(), resolve7(options.config)) : "prisma-next.config.ts";
2546
+ const contractPathAbsolute = config.contract?.output ? resolve7(config.contract.output) : resolve7("src/prisma/contract.json");
2547
+ const contractPath = relative7(process.cwd(), contractPathAbsolute);
2548
+ if (flags.json !== "object" && !flags.quiet) {
2549
+ const details = [
2550
+ { label: "config", value: configPath },
2551
+ { label: "contract", value: contractPath }
2552
+ ];
2553
+ if (options.db) {
2554
+ details.push({ label: "database", value: options.db });
2555
+ }
2556
+ const header = formatStyledHeader({
2557
+ command: "db verify",
2558
+ description: "Check whether the database has been signed with your contract",
2559
+ url: "https://pris.ly/db-verify",
2560
+ details,
2561
+ flags
2562
+ });
2563
+ console.log(header);
2564
+ }
2565
+ let contractJsonContent;
2566
+ try {
2567
+ contractJsonContent = await readFile4(contractPathAbsolute, "utf-8");
2568
+ } catch (error) {
2569
+ if (error instanceof Error && error.code === "ENOENT") {
2570
+ return notOk7(
2571
+ errorFileNotFound(contractPathAbsolute, {
2572
+ why: `Contract file not found at ${contractPathAbsolute}`,
2573
+ fix: `Run \`prisma-next contract emit\` to generate ${contractPath}, or update \`config.contract.output\` in ${configPath}`
2574
+ })
2575
+ );
2576
+ }
2577
+ return notOk7(
2578
+ errorUnexpected2(error instanceof Error ? error.message : String(error), {
2579
+ why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`
2580
+ })
2581
+ );
2582
+ }
2583
+ let contractJson;
2584
+ try {
2585
+ contractJson = JSON.parse(contractJsonContent);
2586
+ } catch (error) {
2587
+ return notOk7(
2588
+ errorContractValidationFailed(
2589
+ `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,
2590
+ { where: { path: contractPathAbsolute } }
2591
+ )
2592
+ );
2593
+ }
2594
+ const dbConnection = options.db ?? config.db?.connection;
2595
+ if (!dbConnection) {
2596
+ return notOk7(
2597
+ errorDatabaseConnectionRequired({
2598
+ why: `Database connection is required for db verify (set db.connection in ${configPath}, or pass --db <url>)`
2599
+ })
2600
+ );
2601
+ }
2602
+ if (!config.driver) {
2603
+ return notOk7(errorDriverRequired({ why: "Config.driver is required for db verify" }));
2604
+ }
2605
+ const client = createControlClient({
2606
+ family: config.family,
2607
+ target: config.target,
2608
+ adapter: config.adapter,
2609
+ driver: config.driver,
2610
+ extensionPacks: config.extensionPacks ?? []
2611
+ });
2612
+ const onProgress = createProgressAdapter({ flags });
2613
+ try {
2614
+ const verifyResult = await client.verify({
2615
+ contractIR: contractJson,
2616
+ connection: dbConnection,
2617
+ onProgress
2618
+ });
2619
+ if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
2620
+ console.log("");
2621
+ }
2622
+ if (!verifyResult.ok) {
2623
+ return notOk7(mapVerifyFailure(verifyResult));
2624
+ }
2625
+ return ok7(verifyResult);
2626
+ } catch (error) {
2627
+ if (error instanceof CliStructuredError) {
2628
+ return notOk7(error);
2629
+ }
2630
+ return notOk7(
2631
+ errorUnexpected2(error instanceof Error ? error.message : String(error), {
2632
+ why: `Unexpected error during db verify: ${error instanceof Error ? error.message : String(error)}`
2633
+ })
2634
+ );
2635
+ } finally {
2636
+ await client.close();
2637
+ }
2638
+ }
2390
2639
  function createDbVerifyCommand() {
2391
2640
  const command = new Command6("verify");
2392
2641
  setCommandDescriptions(
@@ -2399,112 +2648,20 @@ function createDbVerifyCommand() {
2399
2648
  const flags = parseGlobalFlags({});
2400
2649
  return formatCommandHelp({ command: cmd, flags });
2401
2650
  }
2402
- }).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object or ndjson)", false).option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("-vv, --trace", "Trace output: deep internals, stack traces").option("--timestamps", "Add timestamps to output").option("--color", "Force color output").option("--no-color", "Disable color output").action(async (options) => {
2651
+ }).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object)", false).option("-q, --quiet", "Quiet mode: errors only").option("-v, --verbose", "Verbose output: debug info, timings").option("-vv, --trace", "Trace output: deep internals, stack traces").option("--timestamps", "Add timestamps to output").option("--color", "Force color output").option("--no-color", "Disable color output").action(async (options) => {
2403
2652
  const flags = parseGlobalFlags(options);
2404
- const result = await performAction(async () => {
2405
- const config = await loadConfig(options.config);
2406
- const configPath = options.config ? relative7(process.cwd(), resolve7(options.config)) : "prisma-next.config.ts";
2407
- const contractPathAbsolute = config.contract?.output ? resolve7(config.contract.output) : resolve7("src/prisma/contract.json");
2408
- const contractPath = relative7(process.cwd(), contractPathAbsolute);
2409
- if (flags.json !== "object" && !flags.quiet) {
2410
- const details = [
2411
- { label: "config", value: configPath },
2412
- { label: "contract", value: contractPath }
2413
- ];
2414
- if (options.db) {
2415
- details.push({ label: "database", value: options.db });
2416
- }
2417
- const header = formatStyledHeader({
2653
+ if (flags.json === "ndjson") {
2654
+ const result2 = notOk7(
2655
+ errorJsonFormatNotSupported({
2418
2656
  command: "db verify",
2419
- description: "Check whether the database has been signed with your contract",
2420
- url: "https://pris.ly/db-verify",
2421
- details,
2422
- flags
2423
- });
2424
- console.log(header);
2425
- }
2426
- let contractJsonContent;
2427
- try {
2428
- contractJsonContent = await readFile5(contractPathAbsolute, "utf-8");
2429
- } catch (error) {
2430
- if (error instanceof Error && error.code === "ENOENT") {
2431
- throw errorFileNotFound4(contractPathAbsolute, {
2432
- why: `Contract file not found at ${contractPathAbsolute}`
2433
- });
2434
- }
2435
- throw errorUnexpected6(error instanceof Error ? error.message : String(error), {
2436
- why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`
2437
- });
2438
- }
2439
- const contractJson = JSON.parse(contractJsonContent);
2440
- const dbConnection = options.db ?? config.db?.connection;
2441
- if (!dbConnection) {
2442
- throw errorDatabaseConnectionRequired5();
2443
- }
2444
- if (!config.driver) {
2445
- throw errorDriverRequired5();
2446
- }
2447
- const driverDescriptor = config.driver;
2448
- const driver = await withSpinner(() => driverDescriptor.create(dbConnection), {
2449
- message: "Connecting to database...",
2450
- flags
2451
- });
2452
- try {
2453
- const stack = createControlPlaneStack6({
2454
- target: config.target,
2455
- adapter: config.adapter,
2456
- driver: driverDescriptor,
2457
- extensionPacks: config.extensionPacks
2458
- });
2459
- const familyInstance = config.family.create(stack);
2460
- const contractIR = familyInstance.validateContractIR(contractJson);
2461
- assertContractRequirementsSatisfied({ contract: contractIR, stack });
2462
- let verifyResult;
2463
- try {
2464
- verifyResult = await withSpinner(
2465
- () => familyInstance.verify({
2466
- driver,
2467
- contractIR,
2468
- expectedTargetId: config.target.targetId,
2469
- contractPath: contractPathAbsolute,
2470
- configPath
2471
- }),
2472
- {
2473
- message: "Verifying database schema...",
2474
- flags
2475
- }
2476
- );
2477
- } catch (error) {
2478
- throw errorUnexpected6(error instanceof Error ? error.message : String(error), {
2479
- why: `Failed to verify database: ${error instanceof Error ? error.message : String(error)}`
2480
- });
2481
- }
2482
- if (!verifyResult.ok && verifyResult.code) {
2483
- if (verifyResult.code === "PN-RTM-3001") {
2484
- throw errorMarkerMissing2();
2485
- }
2486
- if (verifyResult.code === "PN-RTM-3002") {
2487
- throw errorHashMismatch2({
2488
- expected: verifyResult.contract.coreHash,
2489
- ...verifyResult.marker?.coreHash ? { actual: verifyResult.marker.coreHash } : {}
2490
- });
2491
- }
2492
- if (verifyResult.code === "PN-RTM-3003") {
2493
- throw errorTargetMismatch2(
2494
- verifyResult.target.expected,
2495
- verifyResult.target.actual ?? "unknown"
2496
- );
2497
- }
2498
- throw errorRuntime5(verifyResult.summary);
2499
- }
2500
- if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
2501
- console.log("");
2502
- }
2503
- return verifyResult;
2504
- } finally {
2505
- await driver.close();
2506
- }
2507
- });
2657
+ format: "ndjson",
2658
+ supportedFormats: ["object"]
2659
+ })
2660
+ );
2661
+ const exitCode2 = handleResult(result2, flags);
2662
+ process.exit(exitCode2);
2663
+ }
2664
+ const result = await executeDbVerifyCommand(options, flags);
2508
2665
  const exitCode = handleResult(result, flags, (verifyResult) => {
2509
2666
  if (flags.json === "object") {
2510
2667
  console.log(formatVerifyJson(verifyResult));