@prisma-next/cli 0.3.0-pr.87.2 → 0.3.0-pr.88.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-74IELXRA.js → chunk-4GX6MW6J.js} +265 -19
- package/dist/chunk-4GX6MW6J.js.map +1 -0
- package/dist/chunk-BO73VO4I.js +45 -0
- package/dist/chunk-BO73VO4I.js.map +1 -0
- package/dist/{chunk-U6QI3AZ3.js → chunk-HLEJGWAP.js} +44 -5
- package/dist/chunk-HLEJGWAP.js.map +1 -0
- package/dist/{chunk-VI2YETW7.js → chunk-MPSJAVF6.js} +4 -2
- package/dist/cli.js +694 -522
- package/dist/cli.js.map +1 -1
- package/dist/commands/contract-emit.js +2 -3
- package/dist/commands/db-init.js +5 -46
- package/dist/commands/db-init.js.map +1 -1
- package/dist/commands/db-introspect.d.ts.map +1 -1
- package/dist/commands/db-introspect.js +128 -133
- package/dist/commands/db-introspect.js.map +1 -1
- package/dist/commands/db-schema-verify.d.ts.map +1 -1
- package/dist/commands/db-schema-verify.js +119 -107
- package/dist/commands/db-schema-verify.js.map +1 -1
- package/dist/commands/db-sign.d.ts.map +1 -1
- package/dist/commands/db-sign.js +128 -125
- package/dist/commands/db-sign.js.map +1 -1
- package/dist/commands/db-verify.d.ts.map +1 -1
- package/dist/commands/db-verify.js +141 -116
- package/dist/commands/db-verify.js.map +1 -1
- package/dist/control-api/types.d.ts +24 -0
- package/dist/control-api/types.d.ts.map +1 -1
- package/dist/exports/control-api.js +2 -3
- package/dist/exports/index.js +2 -3
- package/dist/exports/index.js.map +1 -1
- package/package.json +10 -10
- package/src/commands/db-introspect.ts +181 -177
- package/src/commands/db-schema-verify.ts +150 -143
- package/src/commands/db-sign.ts +172 -164
- package/src/commands/db-verify.ts +179 -149
- package/src/control-api/client.ts +246 -22
- package/src/control-api/types.ts +24 -0
- package/dist/chunk-5MPKZYVI.js +0 -47
- package/dist/chunk-5MPKZYVI.js.map +0 -1
- package/dist/chunk-6EPKRATC.js +0 -91
- package/dist/chunk-6EPKRATC.js.map +0 -1
- package/dist/chunk-74IELXRA.js.map +0 -1
- package/dist/chunk-U6QI3AZ3.js.map +0 -1
- /package/dist/{chunk-VI2YETW7.js.map → chunk-MPSJAVF6.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -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,181 @@ 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
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
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
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
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
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
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: ""
|
|
1690
|
+
});
|
|
1691
|
+
onProgress?.({
|
|
1692
|
+
action: "sign",
|
|
1693
|
+
kind: "spanEnd",
|
|
1694
|
+
spanId: "sign",
|
|
1695
|
+
outcome: "ok"
|
|
1696
|
+
});
|
|
1697
|
+
return result;
|
|
1698
|
+
} catch (error) {
|
|
1699
|
+
onProgress?.({
|
|
1700
|
+
action: "sign",
|
|
1701
|
+
kind: "spanEnd",
|
|
1702
|
+
spanId: "sign",
|
|
1703
|
+
outcome: "error"
|
|
1704
|
+
});
|
|
1705
|
+
throw error;
|
|
1706
|
+
}
|
|
1591
1707
|
}
|
|
1592
1708
|
async dbInit(options) {
|
|
1593
1709
|
const { onProgress } = options;
|
|
@@ -1632,10 +1748,59 @@ var ControlClientImpl = class {
|
|
|
1632
1748
|
});
|
|
1633
1749
|
}
|
|
1634
1750
|
async introspect(options) {
|
|
1751
|
+
const onProgress = options?.onProgress;
|
|
1752
|
+
if (options?.connection !== void 0) {
|
|
1753
|
+
onProgress?.({
|
|
1754
|
+
action: "introspect",
|
|
1755
|
+
kind: "spanStart",
|
|
1756
|
+
spanId: "connect",
|
|
1757
|
+
label: "Connecting to database..."
|
|
1758
|
+
});
|
|
1759
|
+
try {
|
|
1760
|
+
await this.connect(options.connection);
|
|
1761
|
+
onProgress?.({
|
|
1762
|
+
action: "introspect",
|
|
1763
|
+
kind: "spanEnd",
|
|
1764
|
+
spanId: "connect",
|
|
1765
|
+
outcome: "ok"
|
|
1766
|
+
});
|
|
1767
|
+
} catch (error) {
|
|
1768
|
+
onProgress?.({
|
|
1769
|
+
action: "introspect",
|
|
1770
|
+
kind: "spanEnd",
|
|
1771
|
+
spanId: "connect",
|
|
1772
|
+
outcome: "error"
|
|
1773
|
+
});
|
|
1774
|
+
throw error;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1635
1777
|
const { driver, familyInstance } = await this.ensureConnected();
|
|
1636
1778
|
const _schema = options?.schema;
|
|
1637
1779
|
void _schema;
|
|
1638
|
-
|
|
1780
|
+
onProgress?.({
|
|
1781
|
+
action: "introspect",
|
|
1782
|
+
kind: "spanStart",
|
|
1783
|
+
spanId: "introspect",
|
|
1784
|
+
label: "Introspecting database schema..."
|
|
1785
|
+
});
|
|
1786
|
+
try {
|
|
1787
|
+
const result = await familyInstance.introspect({ driver });
|
|
1788
|
+
onProgress?.({
|
|
1789
|
+
action: "introspect",
|
|
1790
|
+
kind: "spanEnd",
|
|
1791
|
+
spanId: "introspect",
|
|
1792
|
+
outcome: "ok"
|
|
1793
|
+
});
|
|
1794
|
+
return result;
|
|
1795
|
+
} catch (error) {
|
|
1796
|
+
onProgress?.({
|
|
1797
|
+
action: "introspect",
|
|
1798
|
+
kind: "spanEnd",
|
|
1799
|
+
spanId: "introspect",
|
|
1800
|
+
outcome: "error"
|
|
1801
|
+
});
|
|
1802
|
+
throw error;
|
|
1803
|
+
}
|
|
1639
1804
|
}
|
|
1640
1805
|
};
|
|
1641
1806
|
|
|
@@ -1905,14 +2070,111 @@ function createDbInitCommand() {
|
|
|
1905
2070
|
// src/commands/db-introspect.ts
|
|
1906
2071
|
import { readFile as readFile2 } from "fs/promises";
|
|
1907
2072
|
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";
|
|
2073
|
+
import { notOk as notOk4, ok as ok4 } from "@prisma-next/utils/result";
|
|
1915
2074
|
import { Command as Command3 } from "commander";
|
|
2075
|
+
async function executeDbIntrospectCommand(options, flags, startTime) {
|
|
2076
|
+
const config = await loadConfig(options.config);
|
|
2077
|
+
const configPath = options.config ? relative4(process.cwd(), resolve4(options.config)) : "prisma-next.config.ts";
|
|
2078
|
+
let contractIR;
|
|
2079
|
+
if (config.contract?.output) {
|
|
2080
|
+
const contractPath = resolve4(config.contract.output);
|
|
2081
|
+
try {
|
|
2082
|
+
const contractJsonContent = await readFile2(contractPath, "utf-8");
|
|
2083
|
+
contractIR = JSON.parse(contractJsonContent);
|
|
2084
|
+
} catch (error) {
|
|
2085
|
+
if (error instanceof Error && error.code !== "ENOENT") {
|
|
2086
|
+
return notOk4(
|
|
2087
|
+
errorUnexpected2(error.message, {
|
|
2088
|
+
why: `Failed to read contract file: ${error.message}`
|
|
2089
|
+
})
|
|
2090
|
+
);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
if (flags.json !== "object" && !flags.quiet) {
|
|
2095
|
+
const details = [
|
|
2096
|
+
{ label: "config", value: configPath }
|
|
2097
|
+
];
|
|
2098
|
+
if (options.db) {
|
|
2099
|
+
const maskedUrl = options.db.replace(/:([^:@]+)@/, ":****@");
|
|
2100
|
+
details.push({ label: "database", value: maskedUrl });
|
|
2101
|
+
} else if (config.db?.connection && typeof config.db.connection === "string") {
|
|
2102
|
+
const maskedUrl = config.db.connection.replace(/:([^:@]+)@/, ":****@");
|
|
2103
|
+
details.push({ label: "database", value: maskedUrl });
|
|
2104
|
+
}
|
|
2105
|
+
const header = formatStyledHeader({
|
|
2106
|
+
command: "db introspect",
|
|
2107
|
+
description: "Inspect the database schema",
|
|
2108
|
+
url: "https://pris.ly/db-introspect",
|
|
2109
|
+
details,
|
|
2110
|
+
flags
|
|
2111
|
+
});
|
|
2112
|
+
console.log(header);
|
|
2113
|
+
}
|
|
2114
|
+
const dbConnection = options.db ?? config.db?.connection;
|
|
2115
|
+
if (!dbConnection) {
|
|
2116
|
+
return notOk4(
|
|
2117
|
+
errorDatabaseConnectionRequired({
|
|
2118
|
+
why: `Database connection is required for db introspect (set db.connection in ${configPath}, or pass --db <url>)`
|
|
2119
|
+
})
|
|
2120
|
+
);
|
|
2121
|
+
}
|
|
2122
|
+
if (!config.driver) {
|
|
2123
|
+
return notOk4(errorDriverRequired({ why: "Config.driver is required for db introspect" }));
|
|
2124
|
+
}
|
|
2125
|
+
const client = createControlClient({
|
|
2126
|
+
family: config.family,
|
|
2127
|
+
target: config.target,
|
|
2128
|
+
adapter: config.adapter,
|
|
2129
|
+
driver: config.driver,
|
|
2130
|
+
extensionPacks: config.extensionPacks ?? []
|
|
2131
|
+
});
|
|
2132
|
+
const onProgress = createProgressAdapter({ flags });
|
|
2133
|
+
try {
|
|
2134
|
+
const schemaIR = await client.introspect({
|
|
2135
|
+
connection: dbConnection,
|
|
2136
|
+
onProgress
|
|
2137
|
+
});
|
|
2138
|
+
if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
|
|
2139
|
+
console.log("");
|
|
2140
|
+
}
|
|
2141
|
+
client.init();
|
|
2142
|
+
let schemaView;
|
|
2143
|
+
void contractIR;
|
|
2144
|
+
const totalTime = Date.now() - startTime;
|
|
2145
|
+
const connectionForMeta = typeof dbConnection === "string" ? dbConnection.replace(/:([^:@]+)@/, ":****@") : void 0;
|
|
2146
|
+
const introspectResult = {
|
|
2147
|
+
ok: true,
|
|
2148
|
+
summary: "Schema introspected successfully",
|
|
2149
|
+
target: {
|
|
2150
|
+
familyId: config.family.familyId,
|
|
2151
|
+
id: config.target.targetId
|
|
2152
|
+
},
|
|
2153
|
+
schema: schemaIR,
|
|
2154
|
+
...configPath || connectionForMeta ? {
|
|
2155
|
+
meta: {
|
|
2156
|
+
...configPath ? { configPath } : {},
|
|
2157
|
+
...connectionForMeta ? { dbUrl: connectionForMeta } : {}
|
|
2158
|
+
}
|
|
2159
|
+
} : {},
|
|
2160
|
+
timings: {
|
|
2161
|
+
total: totalTime
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
2164
|
+
return ok4({ introspectResult, schemaView });
|
|
2165
|
+
} catch (error) {
|
|
2166
|
+
if (error instanceof CliStructuredError) {
|
|
2167
|
+
return notOk4(error);
|
|
2168
|
+
}
|
|
2169
|
+
return notOk4(
|
|
2170
|
+
errorUnexpected2(error instanceof Error ? error.message : String(error), {
|
|
2171
|
+
why: `Unexpected error during db introspect: ${error instanceof Error ? error.message : String(error)}`
|
|
2172
|
+
})
|
|
2173
|
+
);
|
|
2174
|
+
} finally {
|
|
2175
|
+
await client.close();
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
1916
2178
|
function createDbIntrospectCommand() {
|
|
1917
2179
|
const command = new Command3("introspect");
|
|
1918
2180
|
setCommandDescriptions(
|
|
@@ -1925,128 +2187,21 @@ function createDbIntrospectCommand() {
|
|
|
1925
2187
|
const flags = parseGlobalFlags({});
|
|
1926
2188
|
return formatCommandHelp({ command: cmd, flags });
|
|
1927
2189
|
}
|
|
1928
|
-
}).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object
|
|
2190
|
+
}).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
2191
|
const flags = parseGlobalFlags(options);
|
|
1930
|
-
const
|
|
1931
|
-
|
|
1932
|
-
const
|
|
1933
|
-
|
|
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({
|
|
2192
|
+
const startTime = Date.now();
|
|
2193
|
+
if (flags.json === "ndjson") {
|
|
2194
|
+
const result2 = notOk4(
|
|
2195
|
+
errorJsonFormatNotSupported({
|
|
1960
2196
|
command: "db introspect",
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
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
|
-
});
|
|
2197
|
+
format: "ndjson",
|
|
2198
|
+
supportedFormats: ["object"]
|
|
2199
|
+
})
|
|
2200
|
+
);
|
|
2201
|
+
const exitCode2 = handleResult(result2, flags);
|
|
2202
|
+
process.exit(exitCode2);
|
|
2203
|
+
}
|
|
2204
|
+
const result = await executeDbIntrospectCommand(options, flags, startTime);
|
|
2050
2205
|
const exitCode = handleResult(result, flags, (value) => {
|
|
2051
2206
|
const { introspectResult, schemaView } = value;
|
|
2052
2207
|
if (flags.json === "object") {
|
|
@@ -2066,122 +2221,128 @@ function createDbIntrospectCommand() {
|
|
|
2066
2221
|
// src/commands/db-schema-verify.ts
|
|
2067
2222
|
import { readFile as readFile3 } from "fs/promises";
|
|
2068
2223
|
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";
|
|
2224
|
+
import { notOk as notOk5, ok as ok5 } from "@prisma-next/utils/result";
|
|
2077
2225
|
import { Command as Command4 } from "commander";
|
|
2078
|
-
function
|
|
2079
|
-
const
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
const
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
}
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
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
|
-
}
|
|
2226
|
+
async function executeDbSchemaVerifyCommand(options, flags) {
|
|
2227
|
+
const config = await loadConfig(options.config);
|
|
2228
|
+
const configPath = options.config ? relative5(process.cwd(), resolve5(options.config)) : "prisma-next.config.ts";
|
|
2229
|
+
const contractPathAbsolute = config.contract?.output ? resolve5(config.contract.output) : resolve5("src/prisma/contract.json");
|
|
2230
|
+
const contractPath = relative5(process.cwd(), contractPathAbsolute);
|
|
2231
|
+
if (flags.json !== "object" && !flags.quiet) {
|
|
2232
|
+
const details = [
|
|
2233
|
+
{ label: "config", value: configPath },
|
|
2234
|
+
{ label: "contract", value: contractPath }
|
|
2235
|
+
];
|
|
2236
|
+
if (options.db) {
|
|
2237
|
+
details.push({ label: "database", value: options.db });
|
|
2238
|
+
}
|
|
2239
|
+
const header = formatStyledHeader({
|
|
2240
|
+
command: "db schema-verify",
|
|
2241
|
+
description: "Check whether the database schema satisfies your contract",
|
|
2242
|
+
url: "https://pris.ly/db-schema-verify",
|
|
2243
|
+
details,
|
|
2244
|
+
flags
|
|
2245
|
+
});
|
|
2246
|
+
console.log(header);
|
|
2247
|
+
}
|
|
2248
|
+
let contractJsonContent;
|
|
2249
|
+
try {
|
|
2250
|
+
contractJsonContent = await readFile3(contractPathAbsolute, "utf-8");
|
|
2251
|
+
} catch (error) {
|
|
2252
|
+
if (error instanceof Error && error.code === "ENOENT") {
|
|
2253
|
+
return notOk5(
|
|
2254
|
+
errorFileNotFound(contractPathAbsolute, {
|
|
2255
|
+
why: `Contract file not found at ${contractPathAbsolute}`,
|
|
2256
|
+
fix: `Run \`prisma-next contract emit\` to generate ${contractPath}, or update \`config.contract.output\` in ${configPath}`
|
|
2257
|
+
})
|
|
2258
|
+
);
|
|
2259
|
+
}
|
|
2260
|
+
return notOk5(
|
|
2261
|
+
errorUnexpected2(error instanceof Error ? error.message : String(error), {
|
|
2262
|
+
why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`
|
|
2263
|
+
})
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2266
|
+
let contractJson;
|
|
2267
|
+
try {
|
|
2268
|
+
contractJson = JSON.parse(contractJsonContent);
|
|
2269
|
+
} catch (error) {
|
|
2270
|
+
return notOk5(
|
|
2271
|
+
errorContractValidationFailed(
|
|
2272
|
+
`Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,
|
|
2273
|
+
{ where: { path: contractPathAbsolute } }
|
|
2274
|
+
)
|
|
2275
|
+
);
|
|
2276
|
+
}
|
|
2277
|
+
const dbConnection = options.db ?? config.db?.connection;
|
|
2278
|
+
if (!dbConnection) {
|
|
2279
|
+
return notOk5(
|
|
2280
|
+
errorDatabaseConnectionRequired({
|
|
2281
|
+
why: `Database connection is required for db schema-verify (set db.connection in ${configPath}, or pass --db <url>)`
|
|
2282
|
+
})
|
|
2283
|
+
);
|
|
2284
|
+
}
|
|
2285
|
+
if (!config.driver) {
|
|
2286
|
+
return notOk5(errorDriverRequired({ why: "Config.driver is required for db schema-verify" }));
|
|
2287
|
+
}
|
|
2288
|
+
const client = createControlClient({
|
|
2289
|
+
family: config.family,
|
|
2290
|
+
target: config.target,
|
|
2291
|
+
adapter: config.adapter,
|
|
2292
|
+
driver: config.driver,
|
|
2293
|
+
extensionPacks: config.extensionPacks ?? []
|
|
2294
|
+
});
|
|
2295
|
+
const onProgress = createProgressAdapter({ flags });
|
|
2296
|
+
try {
|
|
2297
|
+
const schemaVerifyResult = await client.schemaVerify({
|
|
2298
|
+
contractIR: contractJson,
|
|
2299
|
+
strict: options.strict ?? false,
|
|
2300
|
+
connection: dbConnection,
|
|
2301
|
+
onProgress
|
|
2184
2302
|
});
|
|
2303
|
+
if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
|
|
2304
|
+
console.log("");
|
|
2305
|
+
}
|
|
2306
|
+
return ok5(schemaVerifyResult);
|
|
2307
|
+
} catch (error) {
|
|
2308
|
+
if (error instanceof CliStructuredError) {
|
|
2309
|
+
return notOk5(error);
|
|
2310
|
+
}
|
|
2311
|
+
return notOk5(
|
|
2312
|
+
errorUnexpected2(error instanceof Error ? error.message : String(error), {
|
|
2313
|
+
why: `Unexpected error during db schema-verify: ${error instanceof Error ? error.message : String(error)}`
|
|
2314
|
+
})
|
|
2315
|
+
);
|
|
2316
|
+
} finally {
|
|
2317
|
+
await client.close();
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
function createDbSchemaVerifyCommand() {
|
|
2321
|
+
const command = new Command4("schema-verify");
|
|
2322
|
+
setCommandDescriptions(
|
|
2323
|
+
command,
|
|
2324
|
+
"Check whether the database schema satisfies your contract",
|
|
2325
|
+
"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."
|
|
2326
|
+
);
|
|
2327
|
+
command.configureHelp({
|
|
2328
|
+
formatHelp: (cmd) => {
|
|
2329
|
+
const flags = parseGlobalFlags({});
|
|
2330
|
+
return formatCommandHelp({ command: cmd, flags });
|
|
2331
|
+
}
|
|
2332
|
+
}).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) => {
|
|
2333
|
+
const flags = parseGlobalFlags(options);
|
|
2334
|
+
if (flags.json === "ndjson") {
|
|
2335
|
+
const result2 = notOk5(
|
|
2336
|
+
errorJsonFormatNotSupported({
|
|
2337
|
+
command: "db schema-verify",
|
|
2338
|
+
format: "ndjson",
|
|
2339
|
+
supportedFormats: ["object"]
|
|
2340
|
+
})
|
|
2341
|
+
);
|
|
2342
|
+
const exitCode2 = handleResult(result2, flags);
|
|
2343
|
+
process.exit(exitCode2);
|
|
2344
|
+
}
|
|
2345
|
+
const result = await executeDbSchemaVerifyCommand(options, flags);
|
|
2185
2346
|
const exitCode = handleResult(result, flags, (schemaVerifyResult) => {
|
|
2186
2347
|
if (flags.json === "object") {
|
|
2187
2348
|
console.log(formatSchemaVerifyJson(schemaVerifyResult));
|
|
@@ -2204,15 +2365,112 @@ function createDbSchemaVerifyCommand() {
|
|
|
2204
2365
|
// src/commands/db-sign.ts
|
|
2205
2366
|
import { readFile as readFile4 } from "fs/promises";
|
|
2206
2367
|
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";
|
|
2368
|
+
import { notOk as notOk6, ok as ok6 } from "@prisma-next/utils/result";
|
|
2215
2369
|
import { Command as Command5 } from "commander";
|
|
2370
|
+
async function executeDbSignCommand(options, flags) {
|
|
2371
|
+
const config = await loadConfig(options.config);
|
|
2372
|
+
const configPath = options.config ? relative6(process.cwd(), resolve6(options.config)) : "prisma-next.config.ts";
|
|
2373
|
+
const contractPathAbsolute = config.contract?.output ? resolve6(config.contract.output) : resolve6("src/prisma/contract.json");
|
|
2374
|
+
const contractPath = relative6(process.cwd(), contractPathAbsolute);
|
|
2375
|
+
if (flags.json !== "object" && !flags.quiet) {
|
|
2376
|
+
const details = [
|
|
2377
|
+
{ label: "config", value: configPath },
|
|
2378
|
+
{ label: "contract", value: contractPath }
|
|
2379
|
+
];
|
|
2380
|
+
if (options.db) {
|
|
2381
|
+
details.push({ label: "database", value: options.db });
|
|
2382
|
+
}
|
|
2383
|
+
const header = formatStyledHeader({
|
|
2384
|
+
command: "db sign",
|
|
2385
|
+
description: "Sign the database with your contract so you can safely run queries",
|
|
2386
|
+
url: "https://pris.ly/db-sign",
|
|
2387
|
+
details,
|
|
2388
|
+
flags
|
|
2389
|
+
});
|
|
2390
|
+
console.log(header);
|
|
2391
|
+
}
|
|
2392
|
+
let contractJsonContent;
|
|
2393
|
+
try {
|
|
2394
|
+
contractJsonContent = await readFile4(contractPathAbsolute, "utf-8");
|
|
2395
|
+
} catch (error) {
|
|
2396
|
+
if (error instanceof Error && error.code === "ENOENT") {
|
|
2397
|
+
return notOk6(
|
|
2398
|
+
errorFileNotFound(contractPathAbsolute, {
|
|
2399
|
+
why: `Contract file not found at ${contractPathAbsolute}`,
|
|
2400
|
+
fix: `Run \`prisma-next contract emit\` to generate ${contractPath}, or update \`config.contract.output\` in ${configPath}`
|
|
2401
|
+
})
|
|
2402
|
+
);
|
|
2403
|
+
}
|
|
2404
|
+
return notOk6(
|
|
2405
|
+
errorUnexpected2(error instanceof Error ? error.message : String(error), {
|
|
2406
|
+
why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`
|
|
2407
|
+
})
|
|
2408
|
+
);
|
|
2409
|
+
}
|
|
2410
|
+
let contractJson;
|
|
2411
|
+
try {
|
|
2412
|
+
contractJson = JSON.parse(contractJsonContent);
|
|
2413
|
+
} catch (error) {
|
|
2414
|
+
return notOk6(
|
|
2415
|
+
errorContractValidationFailed(
|
|
2416
|
+
`Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,
|
|
2417
|
+
{ where: { path: contractPathAbsolute } }
|
|
2418
|
+
)
|
|
2419
|
+
);
|
|
2420
|
+
}
|
|
2421
|
+
const dbConnection = options.db ?? config.db?.connection;
|
|
2422
|
+
if (!dbConnection) {
|
|
2423
|
+
return notOk6(
|
|
2424
|
+
errorDatabaseConnectionRequired({
|
|
2425
|
+
why: `Database connection is required for db sign (set db.connection in ${configPath}, or pass --db <url>)`
|
|
2426
|
+
})
|
|
2427
|
+
);
|
|
2428
|
+
}
|
|
2429
|
+
if (!config.driver) {
|
|
2430
|
+
return notOk6(errorDriverRequired({ why: "Config.driver is required for db sign" }));
|
|
2431
|
+
}
|
|
2432
|
+
const client = createControlClient({
|
|
2433
|
+
family: config.family,
|
|
2434
|
+
target: config.target,
|
|
2435
|
+
adapter: config.adapter,
|
|
2436
|
+
driver: config.driver,
|
|
2437
|
+
extensionPacks: config.extensionPacks ?? []
|
|
2438
|
+
});
|
|
2439
|
+
const onProgress = createProgressAdapter({ flags });
|
|
2440
|
+
try {
|
|
2441
|
+
const schemaVerifyResult = await client.schemaVerify({
|
|
2442
|
+
contractIR: contractJson,
|
|
2443
|
+
strict: false,
|
|
2444
|
+
connection: dbConnection,
|
|
2445
|
+
onProgress
|
|
2446
|
+
});
|
|
2447
|
+
if (!schemaVerifyResult.ok) {
|
|
2448
|
+
if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
|
|
2449
|
+
console.log("");
|
|
2450
|
+
}
|
|
2451
|
+
return ok6({ schemaVerifyResult, signResult: void 0 });
|
|
2452
|
+
}
|
|
2453
|
+
const signResult = await client.sign({
|
|
2454
|
+
contractIR: contractJson,
|
|
2455
|
+
onProgress
|
|
2456
|
+
});
|
|
2457
|
+
if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
|
|
2458
|
+
console.log("");
|
|
2459
|
+
}
|
|
2460
|
+
return ok6({ schemaVerifyResult: void 0, signResult });
|
|
2461
|
+
} catch (error) {
|
|
2462
|
+
if (error instanceof CliStructuredError) {
|
|
2463
|
+
return notOk6(error);
|
|
2464
|
+
}
|
|
2465
|
+
return notOk6(
|
|
2466
|
+
errorUnexpected2(error instanceof Error ? error.message : String(error), {
|
|
2467
|
+
why: `Unexpected error during db sign: ${error instanceof Error ? error.message : String(error)}`
|
|
2468
|
+
})
|
|
2469
|
+
);
|
|
2470
|
+
} finally {
|
|
2471
|
+
await client.close();
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2216
2474
|
function createDbSignCommand() {
|
|
2217
2475
|
const command = new Command5("sign");
|
|
2218
2476
|
setCommandDescriptions(
|
|
@@ -2225,120 +2483,20 @@ function createDbSignCommand() {
|
|
|
2225
2483
|
const flags = parseGlobalFlags({});
|
|
2226
2484
|
return formatCommandHelp({ command: cmd, flags });
|
|
2227
2485
|
}
|
|
2228
|
-
}).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object
|
|
2486
|
+
}).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
2487
|
const flags = parseGlobalFlags(options);
|
|
2230
|
-
|
|
2231
|
-
const
|
|
2232
|
-
|
|
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({
|
|
2488
|
+
if (flags.json === "ndjson") {
|
|
2489
|
+
const result2 = notOk6(
|
|
2490
|
+
errorJsonFormatNotSupported({
|
|
2244
2491
|
command: "db sign",
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
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
|
|
2492
|
+
format: "ndjson",
|
|
2493
|
+
supportedFormats: ["object"]
|
|
2494
|
+
})
|
|
2288
2495
|
);
|
|
2289
|
-
const
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
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
|
-
});
|
|
2496
|
+
const exitCode2 = handleResult(result2, flags);
|
|
2497
|
+
process.exit(exitCode2);
|
|
2498
|
+
}
|
|
2499
|
+
const result = await executeDbSignCommand(options, flags);
|
|
2342
2500
|
const exitCode = handleResult(result, flags, (value) => {
|
|
2343
2501
|
const { schemaVerifyResult, signResult } = value;
|
|
2344
2502
|
if (schemaVerifyResult && !schemaVerifyResult.ok) {
|
|
@@ -2375,18 +2533,124 @@ function createDbSignCommand() {
|
|
|
2375
2533
|
// src/commands/db-verify.ts
|
|
2376
2534
|
import { readFile as readFile5 } from "fs/promises";
|
|
2377
2535
|
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";
|
|
2536
|
+
import { notOk as notOk7, ok as ok7 } from "@prisma-next/utils/result";
|
|
2389
2537
|
import { Command as Command6 } from "commander";
|
|
2538
|
+
function mapVerifyFailure(verifyResult) {
|
|
2539
|
+
if (!verifyResult.ok && verifyResult.code) {
|
|
2540
|
+
if (verifyResult.code === "PN-RTM-3001") {
|
|
2541
|
+
return errorMarkerMissing();
|
|
2542
|
+
}
|
|
2543
|
+
if (verifyResult.code === "PN-RTM-3002") {
|
|
2544
|
+
return errorHashMismatch({
|
|
2545
|
+
expected: verifyResult.contract.coreHash,
|
|
2546
|
+
...verifyResult.marker?.coreHash ? { actual: verifyResult.marker.coreHash } : {}
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2549
|
+
if (verifyResult.code === "PN-RTM-3003") {
|
|
2550
|
+
return errorTargetMismatch(
|
|
2551
|
+
verifyResult.target.expected,
|
|
2552
|
+
verifyResult.target.actual ?? "unknown"
|
|
2553
|
+
);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
return errorRuntime(verifyResult.summary);
|
|
2557
|
+
}
|
|
2558
|
+
async function executeDbVerifyCommand(options, flags) {
|
|
2559
|
+
const config = await loadConfig(options.config);
|
|
2560
|
+
const configPath = options.config ? relative7(process.cwd(), resolve7(options.config)) : "prisma-next.config.ts";
|
|
2561
|
+
const contractPathAbsolute = config.contract?.output ? resolve7(config.contract.output) : resolve7("src/prisma/contract.json");
|
|
2562
|
+
const contractPath = relative7(process.cwd(), contractPathAbsolute);
|
|
2563
|
+
if (flags.json !== "object" && !flags.quiet) {
|
|
2564
|
+
const details = [
|
|
2565
|
+
{ label: "config", value: configPath },
|
|
2566
|
+
{ label: "contract", value: contractPath }
|
|
2567
|
+
];
|
|
2568
|
+
if (options.db) {
|
|
2569
|
+
details.push({ label: "database", value: options.db });
|
|
2570
|
+
}
|
|
2571
|
+
const header = formatStyledHeader({
|
|
2572
|
+
command: "db verify",
|
|
2573
|
+
description: "Check whether the database has been signed with your contract",
|
|
2574
|
+
url: "https://pris.ly/db-verify",
|
|
2575
|
+
details,
|
|
2576
|
+
flags
|
|
2577
|
+
});
|
|
2578
|
+
console.log(header);
|
|
2579
|
+
}
|
|
2580
|
+
let contractJsonContent;
|
|
2581
|
+
try {
|
|
2582
|
+
contractJsonContent = await readFile5(contractPathAbsolute, "utf-8");
|
|
2583
|
+
} catch (error) {
|
|
2584
|
+
if (error instanceof Error && error.code === "ENOENT") {
|
|
2585
|
+
return notOk7(
|
|
2586
|
+
errorFileNotFound(contractPathAbsolute, {
|
|
2587
|
+
why: `Contract file not found at ${contractPathAbsolute}`,
|
|
2588
|
+
fix: `Run \`prisma-next contract emit\` to generate ${contractPath}, or update \`config.contract.output\` in ${configPath}`
|
|
2589
|
+
})
|
|
2590
|
+
);
|
|
2591
|
+
}
|
|
2592
|
+
return notOk7(
|
|
2593
|
+
errorUnexpected2(error instanceof Error ? error.message : String(error), {
|
|
2594
|
+
why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`
|
|
2595
|
+
})
|
|
2596
|
+
);
|
|
2597
|
+
}
|
|
2598
|
+
let contractJson;
|
|
2599
|
+
try {
|
|
2600
|
+
contractJson = JSON.parse(contractJsonContent);
|
|
2601
|
+
} catch (error) {
|
|
2602
|
+
return notOk7(
|
|
2603
|
+
errorContractValidationFailed(
|
|
2604
|
+
`Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,
|
|
2605
|
+
{ where: { path: contractPathAbsolute } }
|
|
2606
|
+
)
|
|
2607
|
+
);
|
|
2608
|
+
}
|
|
2609
|
+
const dbConnection = options.db ?? config.db?.connection;
|
|
2610
|
+
if (!dbConnection) {
|
|
2611
|
+
return notOk7(
|
|
2612
|
+
errorDatabaseConnectionRequired({
|
|
2613
|
+
why: `Database connection is required for db verify (set db.connection in ${configPath}, or pass --db <url>)`
|
|
2614
|
+
})
|
|
2615
|
+
);
|
|
2616
|
+
}
|
|
2617
|
+
if (!config.driver) {
|
|
2618
|
+
return notOk7(errorDriverRequired({ why: "Config.driver is required for db verify" }));
|
|
2619
|
+
}
|
|
2620
|
+
const client = createControlClient({
|
|
2621
|
+
family: config.family,
|
|
2622
|
+
target: config.target,
|
|
2623
|
+
adapter: config.adapter,
|
|
2624
|
+
driver: config.driver,
|
|
2625
|
+
extensionPacks: config.extensionPacks ?? []
|
|
2626
|
+
});
|
|
2627
|
+
const onProgress = createProgressAdapter({ flags });
|
|
2628
|
+
try {
|
|
2629
|
+
const verifyResult = await client.verify({
|
|
2630
|
+
contractIR: contractJson,
|
|
2631
|
+
connection: dbConnection,
|
|
2632
|
+
onProgress
|
|
2633
|
+
});
|
|
2634
|
+
if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
|
|
2635
|
+
console.log("");
|
|
2636
|
+
}
|
|
2637
|
+
if (!verifyResult.ok) {
|
|
2638
|
+
return notOk7(mapVerifyFailure(verifyResult));
|
|
2639
|
+
}
|
|
2640
|
+
return ok7(verifyResult);
|
|
2641
|
+
} catch (error) {
|
|
2642
|
+
if (error instanceof CliStructuredError) {
|
|
2643
|
+
return notOk7(error);
|
|
2644
|
+
}
|
|
2645
|
+
return notOk7(
|
|
2646
|
+
errorUnexpected2(error instanceof Error ? error.message : String(error), {
|
|
2647
|
+
why: `Unexpected error during db verify: ${error instanceof Error ? error.message : String(error)}`
|
|
2648
|
+
})
|
|
2649
|
+
);
|
|
2650
|
+
} finally {
|
|
2651
|
+
await client.close();
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2390
2654
|
function createDbVerifyCommand() {
|
|
2391
2655
|
const command = new Command6("verify");
|
|
2392
2656
|
setCommandDescriptions(
|
|
@@ -2399,112 +2663,20 @@ function createDbVerifyCommand() {
|
|
|
2399
2663
|
const flags = parseGlobalFlags({});
|
|
2400
2664
|
return formatCommandHelp({ command: cmd, flags });
|
|
2401
2665
|
}
|
|
2402
|
-
}).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--json [format]", "Output as JSON (object
|
|
2666
|
+
}).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
2667
|
const flags = parseGlobalFlags(options);
|
|
2404
|
-
|
|
2405
|
-
const
|
|
2406
|
-
|
|
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({
|
|
2668
|
+
if (flags.json === "ndjson") {
|
|
2669
|
+
const result2 = notOk7(
|
|
2670
|
+
errorJsonFormatNotSupported({
|
|
2418
2671
|
command: "db verify",
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
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
|
-
});
|
|
2672
|
+
format: "ndjson",
|
|
2673
|
+
supportedFormats: ["object"]
|
|
2674
|
+
})
|
|
2675
|
+
);
|
|
2676
|
+
const exitCode2 = handleResult(result2, flags);
|
|
2677
|
+
process.exit(exitCode2);
|
|
2678
|
+
}
|
|
2679
|
+
const result = await executeDbVerifyCommand(options, flags);
|
|
2508
2680
|
const exitCode = handleResult(result, flags, (verifyResult) => {
|
|
2509
2681
|
if (flags.json === "object") {
|
|
2510
2682
|
console.log(formatVerifyJson(verifyResult));
|