@prisma-next/cli 0.1.0-pr.32.8 → 0.1.0-pr.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/chunk-3EODSNGS.js +914 -0
- package/dist/chunk-3EODSNGS.js.map +1 -0
- package/dist/chunk-4Q3MO4TK.js +134 -0
- package/dist/chunk-4Q3MO4TK.js.map +1 -0
- package/dist/chunk-HWYQOCAJ.js +47 -0
- package/dist/chunk-HWYQOCAJ.js.map +1 -0
- package/dist/commands/contract-emit.d.ts +5 -0
- package/dist/commands/contract-emit.js +9 -0
- package/dist/commands/contract-emit.js.map +1 -0
- package/dist/commands/db-introspect.d.ts +5 -0
- package/dist/commands/db-introspect.js +181 -0
- package/dist/commands/db-introspect.js.map +1 -0
- package/dist/commands/db-schema-verify.d.ts +5 -0
- package/dist/commands/db-schema-verify.js +147 -0
- package/dist/commands/db-schema-verify.js.map +1 -0
- package/dist/commands/db-sign.d.ts +5 -0
- package/dist/commands/db-sign.js +186 -0
- package/dist/commands/db-sign.js.map +1 -0
- package/dist/commands/db-verify.d.ts +5 -0
- package/dist/commands/db-verify.js +164 -0
- package/dist/commands/db-verify.js.map +1 -0
- package/dist/config-loader.d.ts +14 -0
- package/dist/config-loader.js +7 -0
- package/dist/config-loader.js.map +1 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.js +6 -631
- package/dist/index.js.map +1 -1
- package/package.json +33 -9
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PrismaNextConfig } from '@prisma-next/core-control-plane/config-types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Loads the Prisma Next config from a TypeScript file.
|
|
5
|
+
* Supports both default export and named export.
|
|
6
|
+
* Uses c12 to automatically handle TypeScript compilation and config file discovery.
|
|
7
|
+
*
|
|
8
|
+
* @param configPath - Optional path to config file. Defaults to `./prisma-next.config.ts` in current directory.
|
|
9
|
+
* @returns The loaded config object.
|
|
10
|
+
* @throws Error if config file doesn't exist or is invalid.
|
|
11
|
+
*/
|
|
12
|
+
declare function loadConfig(configPath?: string): Promise<PrismaNextConfig>;
|
|
13
|
+
|
|
14
|
+
export { loadConfig };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
export { createContractEmitCommand } from './commands/contract-emit.js';
|
|
2
2
|
import { ContractIR } from '@prisma-next/contract/ir';
|
|
3
3
|
export { loadExtensionPackManifest, loadExtensionPacks } from './pack-loading.js';
|
|
4
|
+
import 'commander';
|
|
4
5
|
import '@prisma-next/contract/pack-manifest-types';
|
|
5
6
|
|
|
6
|
-
declare function createContractEmitCommand(): Command;
|
|
7
|
-
|
|
8
7
|
interface LoadTsContractOptions {
|
|
9
8
|
readonly allowlist?: ReadonlyArray<string>;
|
|
10
9
|
}
|
|
@@ -25,4 +24,4 @@ interface LoadTsContractOptions {
|
|
|
25
24
|
*/
|
|
26
25
|
declare function loadContractFromTs(entryPath: string, options?: LoadTsContractOptions): Promise<ContractIR>;
|
|
27
26
|
|
|
28
|
-
export { type LoadTsContractOptions,
|
|
27
|
+
export { type LoadTsContractOptions, loadContractFromTs };
|
package/dist/index.js
CHANGED
|
@@ -2,639 +2,14 @@ import {
|
|
|
2
2
|
loadExtensionPackManifest,
|
|
3
3
|
loadExtensionPacks
|
|
4
4
|
} from "./chunk-W5YXBFPY.js";
|
|
5
|
-
|
|
6
|
-
// src/commands/contract-emit.ts
|
|
7
|
-
import { mkdirSync, writeFileSync } from "fs";
|
|
8
|
-
import { dirname as dirname2, relative as relative2, resolve as resolve2 } from "path";
|
|
9
|
-
import { errorContractConfigMissing as errorContractConfigMissing2 } from "@prisma-next/core-control-plane/errors";
|
|
10
|
-
import { Command } from "commander";
|
|
11
|
-
|
|
12
|
-
// src/config-loader.ts
|
|
13
|
-
import { dirname, resolve } from "path";
|
|
14
|
-
import { validateConfig } from "@prisma-next/core-control-plane/config-validation";
|
|
15
|
-
import { errorConfigFileNotFound, errorUnexpected } from "@prisma-next/core-control-plane/errors";
|
|
16
|
-
import { loadConfig as loadConfigC12 } from "c12";
|
|
17
|
-
async function loadConfig(configPath) {
|
|
18
|
-
try {
|
|
19
|
-
const cwd = process.cwd();
|
|
20
|
-
const resolvedConfigPath = configPath ? resolve(cwd, configPath) : void 0;
|
|
21
|
-
const configCwd = resolvedConfigPath ? dirname(resolvedConfigPath) : cwd;
|
|
22
|
-
const result = await loadConfigC12({
|
|
23
|
-
name: "prisma-next",
|
|
24
|
-
...resolvedConfigPath ? { configFile: resolvedConfigPath } : {},
|
|
25
|
-
cwd: configCwd
|
|
26
|
-
});
|
|
27
|
-
if (resolvedConfigPath && result.configFile !== resolvedConfigPath) {
|
|
28
|
-
throw errorConfigFileNotFound(resolvedConfigPath);
|
|
29
|
-
}
|
|
30
|
-
if (!result.config || Object.keys(result.config).length === 0) {
|
|
31
|
-
const displayPath = result.configFile || resolvedConfigPath || configPath;
|
|
32
|
-
throw errorConfigFileNotFound(displayPath);
|
|
33
|
-
}
|
|
34
|
-
validateConfig(result.config);
|
|
35
|
-
return result.config;
|
|
36
|
-
} catch (error) {
|
|
37
|
-
if (error instanceof Error && "code" in error && typeof error.code === "string") {
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
if (error instanceof Error) {
|
|
41
|
-
if (error.message.includes("not found") || error.message.includes("Cannot find") || error.message.includes("ENOENT")) {
|
|
42
|
-
const displayPath = configPath ? resolve(process.cwd(), configPath) : void 0;
|
|
43
|
-
throw errorConfigFileNotFound(displayPath, {
|
|
44
|
-
why: error.message
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
throw errorUnexpected(error.message, {
|
|
48
|
-
why: `Failed to load config: ${error.message}`
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
throw errorUnexpected(String(error));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/utils/command-helpers.ts
|
|
56
|
-
function setCommandDescriptions(command, shortDescription, longDescription) {
|
|
57
|
-
command.description(shortDescription);
|
|
58
|
-
if (longDescription) {
|
|
59
|
-
command._longDescription = longDescription;
|
|
60
|
-
}
|
|
61
|
-
return command;
|
|
62
|
-
}
|
|
63
|
-
function getLongDescription(command) {
|
|
64
|
-
return command._longDescription;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// src/utils/global-flags.ts
|
|
68
|
-
function parseGlobalFlags(options) {
|
|
69
|
-
const flags = {};
|
|
70
|
-
if (options.json === true || options.json === "object") {
|
|
71
|
-
flags.json = "object";
|
|
72
|
-
} else if (options.json === "ndjson") {
|
|
73
|
-
flags.json = "ndjson";
|
|
74
|
-
}
|
|
75
|
-
if (options.quiet || options.q) {
|
|
76
|
-
flags.quiet = true;
|
|
77
|
-
}
|
|
78
|
-
if (options.vv || options.trace) {
|
|
79
|
-
flags.verbose = 2;
|
|
80
|
-
} else if (options.verbose || options.v) {
|
|
81
|
-
flags.verbose = 1;
|
|
82
|
-
} else {
|
|
83
|
-
flags.verbose = 0;
|
|
84
|
-
}
|
|
85
|
-
if (options.timestamps) {
|
|
86
|
-
flags.timestamps = true;
|
|
87
|
-
}
|
|
88
|
-
if (process.env["NO_COLOR"] || flags.json) {
|
|
89
|
-
flags.color = false;
|
|
90
|
-
} else if (options["no-color"]) {
|
|
91
|
-
flags.color = false;
|
|
92
|
-
} else if (options.color !== void 0) {
|
|
93
|
-
flags.color = options.color;
|
|
94
|
-
} else {
|
|
95
|
-
flags.color = process.stdout.isTTY && !process.env["CI"];
|
|
96
|
-
}
|
|
97
|
-
return flags;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// src/utils/output.ts
|
|
101
|
-
import { relative } from "path";
|
|
102
|
-
import { bgGreen, blue, bold, cyan, dim, green, magenta, red, yellow } from "colorette";
|
|
103
|
-
import stringWidth from "string-width";
|
|
104
|
-
import stripAnsi from "strip-ansi";
|
|
105
|
-
import wrapAnsi from "wrap-ansi";
|
|
106
|
-
function formatTimestamp() {
|
|
107
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
108
|
-
}
|
|
109
|
-
function createPrefix(flags) {
|
|
110
|
-
return flags.timestamps ? `[${formatTimestamp()}] ` : "";
|
|
111
|
-
}
|
|
112
|
-
function isVerbose(flags, level) {
|
|
113
|
-
return (flags.verbose ?? 0) >= level;
|
|
114
|
-
}
|
|
115
|
-
function createColorFormatter(useColor, colorFn) {
|
|
116
|
-
return useColor ? colorFn : (text) => text;
|
|
117
|
-
}
|
|
118
|
-
function formatDim(useColor, text) {
|
|
119
|
-
return useColor ? dim(text) : text;
|
|
120
|
-
}
|
|
121
|
-
function formatEmitOutput(result, flags) {
|
|
122
|
-
if (flags.quiet) {
|
|
123
|
-
return "";
|
|
124
|
-
}
|
|
125
|
-
const lines = [];
|
|
126
|
-
const prefix = createPrefix(flags);
|
|
127
|
-
const jsonPath = relative(process.cwd(), result.files.json);
|
|
128
|
-
const dtsPath = relative(process.cwd(), result.files.dts);
|
|
129
|
-
lines.push(`${prefix}\u2714 Emitted contract.json \u2192 ${jsonPath}`);
|
|
130
|
-
lines.push(`${prefix}\u2714 Emitted contract.d.ts \u2192 ${dtsPath}`);
|
|
131
|
-
lines.push(`${prefix} coreHash: ${result.coreHash}`);
|
|
132
|
-
if (result.profileHash) {
|
|
133
|
-
lines.push(`${prefix} profileHash: ${result.profileHash}`);
|
|
134
|
-
}
|
|
135
|
-
if (isVerbose(flags, 1)) {
|
|
136
|
-
lines.push(`${prefix} Total time: ${result.timings.total}ms`);
|
|
137
|
-
}
|
|
138
|
-
return lines.join("\n");
|
|
139
|
-
}
|
|
140
|
-
function formatEmitJson(result) {
|
|
141
|
-
const output = {
|
|
142
|
-
ok: true,
|
|
143
|
-
coreHash: result.coreHash,
|
|
144
|
-
...result.profileHash ? { profileHash: result.profileHash } : {},
|
|
145
|
-
outDir: result.outDir,
|
|
146
|
-
files: result.files,
|
|
147
|
-
timings: result.timings
|
|
148
|
-
};
|
|
149
|
-
return JSON.stringify(output, null, 2);
|
|
150
|
-
}
|
|
151
|
-
function formatErrorOutput(error, flags) {
|
|
152
|
-
const lines = [];
|
|
153
|
-
const prefix = createPrefix(flags);
|
|
154
|
-
const useColor = flags.color !== false;
|
|
155
|
-
const formatRed = createColorFormatter(useColor, red);
|
|
156
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
157
|
-
lines.push(`${prefix}${formatRed("\u2716")} ${error.summary} (${error.code})`);
|
|
158
|
-
if (error.why) {
|
|
159
|
-
lines.push(`${prefix}${formatDimText(` Why: ${error.why}`)}`);
|
|
160
|
-
}
|
|
161
|
-
if (error.fix) {
|
|
162
|
-
lines.push(`${prefix}${formatDimText(` Fix: ${error.fix}`)}`);
|
|
163
|
-
}
|
|
164
|
-
if (error.where?.path) {
|
|
165
|
-
const whereLine = error.where.line ? `${error.where.path}:${error.where.line}` : error.where.path;
|
|
166
|
-
lines.push(`${prefix}${formatDimText(` Where: ${whereLine}`)}`);
|
|
167
|
-
}
|
|
168
|
-
if (error.docsUrl && isVerbose(flags, 1)) {
|
|
169
|
-
lines.push(formatDimText(error.docsUrl));
|
|
170
|
-
}
|
|
171
|
-
if (isVerbose(flags, 2) && error.meta) {
|
|
172
|
-
lines.push(`${prefix}${formatDimText(` Meta: ${JSON.stringify(error.meta, null, 2)}`)}`);
|
|
173
|
-
}
|
|
174
|
-
return lines.join("\n");
|
|
175
|
-
}
|
|
176
|
-
function formatErrorJson(error) {
|
|
177
|
-
return JSON.stringify(error, null, 2);
|
|
178
|
-
}
|
|
179
|
-
var LEFT_COLUMN_WIDTH = 20;
|
|
180
|
-
var RIGHT_COLUMN_MIN_WIDTH = 40;
|
|
181
|
-
var RIGHT_COLUMN_MAX_WIDTH = 90;
|
|
182
|
-
function getTerminalWidth() {
|
|
183
|
-
const terminalWidth = process.stdout.columns;
|
|
184
|
-
const defaultWidth = Number.parseInt(process.env["CLI_WIDTH"] || "80", 10);
|
|
185
|
-
return terminalWidth || defaultWidth;
|
|
186
|
-
}
|
|
187
|
-
function calculateRightColumnWidth() {
|
|
188
|
-
const terminalWidth = getTerminalWidth();
|
|
189
|
-
const availableWidth = terminalWidth - 2 - LEFT_COLUMN_WIDTH - 2;
|
|
190
|
-
return Math.max(RIGHT_COLUMN_MIN_WIDTH, Math.min(availableWidth, RIGHT_COLUMN_MAX_WIDTH));
|
|
191
|
-
}
|
|
192
|
-
function createPrismaNextBadge(useColor) {
|
|
193
|
-
if (!useColor) {
|
|
194
|
-
return "prisma-next";
|
|
195
|
-
}
|
|
196
|
-
const text = " prisma-next ";
|
|
197
|
-
const body = bgGreen(bold(text));
|
|
198
|
-
const separator = "\uE0B0";
|
|
199
|
-
const tip = green(separator);
|
|
200
|
-
return `${body}${tip}`;
|
|
201
|
-
}
|
|
202
|
-
function createPadFunction() {
|
|
203
|
-
return (s, w) => s + " ".repeat(Math.max(0, w - s.length));
|
|
204
|
-
}
|
|
205
|
-
function formatHeaderLine(options) {
|
|
206
|
-
if (options.operation) {
|
|
207
|
-
return `${options.brand} ${options.operation} \u2192 ${options.intent}`;
|
|
208
|
-
}
|
|
209
|
-
return `${options.brand} ${options.intent}`;
|
|
210
|
-
}
|
|
211
|
-
function formatReadMoreLine(options) {
|
|
212
|
-
const pad = createPadFunction();
|
|
213
|
-
const labelPadded = pad("Read more", options.maxLabelWidth);
|
|
214
|
-
const valueColored = options.useColor ? blue(options.url) : options.url;
|
|
215
|
-
return `${options.formatDimText("\u2502")} ${labelPadded} ${valueColored}`;
|
|
216
|
-
}
|
|
217
|
-
function padToFixedWidth(text, width) {
|
|
218
|
-
const actualWidth = stringWidth(text);
|
|
219
|
-
const padding = Math.max(0, width - actualWidth);
|
|
220
|
-
return text + " ".repeat(padding);
|
|
221
|
-
}
|
|
222
|
-
function wrapTextAnsi(text, width) {
|
|
223
|
-
const wrapped = wrapAnsi(text, width, { hard: false, trim: true });
|
|
224
|
-
return wrapped.split("\n");
|
|
225
|
-
}
|
|
226
|
-
function formatDefaultValue(value, useColor) {
|
|
227
|
-
const valueStr = String(value);
|
|
228
|
-
const defaultText = `default: ${valueStr}`;
|
|
229
|
-
return useColor ? dim(defaultText) : defaultText;
|
|
230
|
-
}
|
|
231
|
-
function renderCommandTree(options) {
|
|
232
|
-
const { commands, useColor, formatDimText, hasItemsAfter, continuationPrefix } = options;
|
|
233
|
-
const lines = [];
|
|
234
|
-
if (commands.length === 0) {
|
|
235
|
-
return lines;
|
|
236
|
-
}
|
|
237
|
-
for (let i = 0; i < commands.length; i++) {
|
|
238
|
-
const cmd = commands[i];
|
|
239
|
-
if (!cmd) continue;
|
|
240
|
-
const subcommands = cmd.commands.filter((subcmd) => !subcmd.name().startsWith("_"));
|
|
241
|
-
const isLastCommand = i === commands.length - 1;
|
|
242
|
-
if (subcommands.length > 0) {
|
|
243
|
-
const prefix = isLastCommand && !hasItemsAfter ? formatDimText("\u2514") : formatDimText("\u251C");
|
|
244
|
-
const treePrefix = `${prefix}\u2500 `;
|
|
245
|
-
const treePrefixWidth = stringWidth(stripAnsi(treePrefix));
|
|
246
|
-
const remainingWidth = LEFT_COLUMN_WIDTH - treePrefixWidth;
|
|
247
|
-
const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);
|
|
248
|
-
const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;
|
|
249
|
-
lines.push(`${formatDimText("\u2502")} ${treePrefix}${commandNameColored}`);
|
|
250
|
-
for (let j = 0; j < subcommands.length; j++) {
|
|
251
|
-
const subcmd = subcommands[j];
|
|
252
|
-
if (!subcmd) continue;
|
|
253
|
-
const isLastSubcommand = j === subcommands.length - 1;
|
|
254
|
-
const shortDescription = subcmd.description() || "";
|
|
255
|
-
const treeChar = isLastSubcommand ? "\u2514" : "\u251C";
|
|
256
|
-
const continuation = continuationPrefix ?? (isLastCommand && isLastSubcommand && !hasItemsAfter ? " " : formatDimText("\u2502"));
|
|
257
|
-
const continuationStr = continuation === " " ? " " : continuation;
|
|
258
|
-
const subTreePrefix = `${continuationStr} ${formatDimText(treeChar)}\u2500 `;
|
|
259
|
-
const subTreePrefixWidth = stringWidth(stripAnsi(subTreePrefix));
|
|
260
|
-
const subRemainingWidth = LEFT_COLUMN_WIDTH - subTreePrefixWidth;
|
|
261
|
-
const subcommandNamePadded = padToFixedWidth(subcmd.name(), subRemainingWidth);
|
|
262
|
-
const subcommandNameColored = useColor ? cyan(subcommandNamePadded) : subcommandNamePadded;
|
|
263
|
-
lines.push(
|
|
264
|
-
`${formatDimText("\u2502")} ${subTreePrefix}${subcommandNameColored} ${shortDescription}`
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
} else {
|
|
268
|
-
const prefix = isLastCommand && !hasItemsAfter ? formatDimText("\u2514") : formatDimText("\u251C");
|
|
269
|
-
const treePrefix = `${prefix}\u2500 `;
|
|
270
|
-
const treePrefixWidth = stringWidth(stripAnsi(treePrefix));
|
|
271
|
-
const remainingWidth = LEFT_COLUMN_WIDTH - treePrefixWidth;
|
|
272
|
-
const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);
|
|
273
|
-
const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;
|
|
274
|
-
const shortDescription = cmd.description() || "";
|
|
275
|
-
lines.push(`${formatDimText("\u2502")} ${treePrefix}${commandNameColored} ${shortDescription}`);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
return lines;
|
|
279
|
-
}
|
|
280
|
-
function formatMultilineDescription(options) {
|
|
281
|
-
const lines = [];
|
|
282
|
-
const formatGreen = (text) => options.useColor ? green(text) : text;
|
|
283
|
-
const rightColumnWidth = calculateRightColumnWidth();
|
|
284
|
-
const totalWidth = 2 + LEFT_COLUMN_WIDTH + 2 + rightColumnWidth;
|
|
285
|
-
const wrapWidth = totalWidth - 2;
|
|
286
|
-
for (const descLine of options.descriptionLines) {
|
|
287
|
-
const formattedLine = descLine.replace(/Prisma Next/g, (match) => formatGreen(match));
|
|
288
|
-
const wrappedLines = wrapTextAnsi(formattedLine, wrapWidth);
|
|
289
|
-
for (const wrappedLine of wrappedLines) {
|
|
290
|
-
lines.push(`${options.formatDimText("\u2502")} ${wrappedLine}`);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return lines;
|
|
294
|
-
}
|
|
295
|
-
function formatStyledHeader(options) {
|
|
296
|
-
const lines = [];
|
|
297
|
-
const useColor = options.flags.color !== false;
|
|
298
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
299
|
-
const brand = createPrismaNextBadge(useColor);
|
|
300
|
-
const operation = useColor ? bold(options.command) : options.command;
|
|
301
|
-
const intent = formatDimText(options.description);
|
|
302
|
-
lines.push(formatHeaderLine({ brand, operation, intent }));
|
|
303
|
-
lines.push(formatDimText("\u2502"));
|
|
304
|
-
for (const detail of options.details) {
|
|
305
|
-
const labelWithColon = `${detail.label}:`;
|
|
306
|
-
const labelPadded = padToFixedWidth(labelWithColon, LEFT_COLUMN_WIDTH);
|
|
307
|
-
const labelColored = useColor ? cyan(labelPadded) : labelPadded;
|
|
308
|
-
lines.push(`${formatDimText("\u2502")} ${labelColored} ${detail.value}`);
|
|
309
|
-
}
|
|
310
|
-
if (options.url) {
|
|
311
|
-
lines.push(formatDimText("\u2502"));
|
|
312
|
-
lines.push(
|
|
313
|
-
formatReadMoreLine({
|
|
314
|
-
url: options.url,
|
|
315
|
-
maxLabelWidth: LEFT_COLUMN_WIDTH,
|
|
316
|
-
useColor,
|
|
317
|
-
formatDimText
|
|
318
|
-
})
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
lines.push(formatDimText("\u2514"));
|
|
322
|
-
return `${lines.join("\n")}
|
|
323
|
-
`;
|
|
324
|
-
}
|
|
325
|
-
function formatSuccessMessage(flags) {
|
|
326
|
-
const useColor = flags.color !== false;
|
|
327
|
-
const formatGreen = createColorFormatter(useColor, green);
|
|
328
|
-
return `${formatGreen("\u2714")} Success`;
|
|
329
|
-
}
|
|
330
|
-
function getCommandDocsUrl(commandPath) {
|
|
331
|
-
const docsMap = {
|
|
332
|
-
"contract emit": "https://pris.ly/contract-emit",
|
|
333
|
-
"db verify": "https://pris.ly/db-verify"
|
|
334
|
-
};
|
|
335
|
-
return docsMap[commandPath];
|
|
336
|
-
}
|
|
337
|
-
function buildCommandPath(command) {
|
|
338
|
-
const parts = [];
|
|
339
|
-
let current = command;
|
|
340
|
-
while (current && current.name() !== "prisma-next") {
|
|
341
|
-
parts.unshift(current.name());
|
|
342
|
-
current = current.parent ?? void 0;
|
|
343
|
-
}
|
|
344
|
-
return parts.join(" ");
|
|
345
|
-
}
|
|
346
|
-
function formatCommandHelp(options) {
|
|
347
|
-
const { command, flags } = options;
|
|
348
|
-
const lines = [];
|
|
349
|
-
const useColor = flags.color !== false;
|
|
350
|
-
const formatDimText = (text) => formatDim(useColor, text);
|
|
351
|
-
const commandPath = buildCommandPath(command);
|
|
352
|
-
const shortDescription = command.description() || "";
|
|
353
|
-
const longDescription = getLongDescription(command);
|
|
354
|
-
const brand = createPrismaNextBadge(useColor);
|
|
355
|
-
const operation = useColor ? bold(commandPath) : commandPath;
|
|
356
|
-
const intent = formatDimText(shortDescription);
|
|
357
|
-
lines.push(formatHeaderLine({ brand, operation, intent }));
|
|
358
|
-
lines.push(formatDimText("\u2502"));
|
|
359
|
-
const optionsList = command.options.map((opt) => {
|
|
360
|
-
const flags2 = opt.flags;
|
|
361
|
-
const description = opt.description || "";
|
|
362
|
-
const defaultValue = opt.defaultValue;
|
|
363
|
-
return { flags: flags2, description, defaultValue };
|
|
364
|
-
});
|
|
365
|
-
const subcommands = command.commands.filter((cmd) => !cmd.name().startsWith("_"));
|
|
366
|
-
if (subcommands.length > 0) {
|
|
367
|
-
const hasItemsAfter = optionsList.length > 0;
|
|
368
|
-
const treeLines = renderCommandTree({
|
|
369
|
-
commands: subcommands,
|
|
370
|
-
useColor,
|
|
371
|
-
formatDimText,
|
|
372
|
-
hasItemsAfter
|
|
373
|
-
});
|
|
374
|
-
lines.push(...treeLines);
|
|
375
|
-
}
|
|
376
|
-
if (subcommands.length > 0 && optionsList.length > 0) {
|
|
377
|
-
lines.push(formatDimText("\u2502"));
|
|
378
|
-
}
|
|
379
|
-
if (optionsList.length > 0) {
|
|
380
|
-
for (const opt of optionsList) {
|
|
381
|
-
const flagsPadded = padToFixedWidth(opt.flags, LEFT_COLUMN_WIDTH);
|
|
382
|
-
let flagsColored = flagsPadded;
|
|
383
|
-
if (useColor) {
|
|
384
|
-
flagsColored = flagsPadded.replace(/(<[^>]+>)/g, (match) => magenta(match));
|
|
385
|
-
flagsColored = cyan(flagsColored);
|
|
386
|
-
}
|
|
387
|
-
const rightColumnWidth = calculateRightColumnWidth();
|
|
388
|
-
const wrappedDescription = wrapTextAnsi(opt.description, rightColumnWidth);
|
|
389
|
-
lines.push(`${formatDimText("\u2502")} ${flagsColored} ${wrappedDescription[0] || ""}`);
|
|
390
|
-
for (let i = 1; i < wrappedDescription.length; i++) {
|
|
391
|
-
const emptyLabel = " ".repeat(LEFT_COLUMN_WIDTH);
|
|
392
|
-
lines.push(`${formatDimText("\u2502")} ${emptyLabel} ${wrappedDescription[i] || ""}`);
|
|
393
|
-
}
|
|
394
|
-
if (opt.defaultValue !== void 0) {
|
|
395
|
-
const emptyLabel = " ".repeat(LEFT_COLUMN_WIDTH);
|
|
396
|
-
const defaultText = formatDefaultValue(opt.defaultValue, useColor);
|
|
397
|
-
lines.push(`${formatDimText("\u2502")} ${emptyLabel} ${defaultText}`);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
const docsUrl = getCommandDocsUrl(commandPath);
|
|
402
|
-
if (docsUrl) {
|
|
403
|
-
lines.push(formatDimText("\u2502"));
|
|
404
|
-
lines.push(
|
|
405
|
-
formatReadMoreLine({
|
|
406
|
-
url: docsUrl,
|
|
407
|
-
maxLabelWidth: LEFT_COLUMN_WIDTH,
|
|
408
|
-
useColor,
|
|
409
|
-
formatDimText
|
|
410
|
-
})
|
|
411
|
-
);
|
|
412
|
-
}
|
|
413
|
-
if (longDescription) {
|
|
414
|
-
lines.push(formatDimText("\u2502"));
|
|
415
|
-
const descriptionLines = longDescription.split("\n").filter((line) => line.trim().length > 0);
|
|
416
|
-
lines.push(...formatMultilineDescription({ descriptionLines, useColor, formatDimText }));
|
|
417
|
-
}
|
|
418
|
-
lines.push(formatDimText("\u2514"));
|
|
419
|
-
return `${lines.join("\n")}
|
|
420
|
-
`;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// src/utils/cli-errors.ts
|
|
424
5
|
import {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
errorContractValidationFailed,
|
|
430
|
-
errorDatabaseUrlRequired,
|
|
431
|
-
errorDriverRequired,
|
|
432
|
-
errorFamilyReadMarkerSqlRequired,
|
|
433
|
-
errorFileNotFound,
|
|
434
|
-
errorHashMismatch,
|
|
435
|
-
errorMarkerMissing,
|
|
436
|
-
errorQueryRunnerFactoryRequired,
|
|
437
|
-
errorRuntime,
|
|
438
|
-
errorTargetMismatch,
|
|
439
|
-
errorUnexpected as errorUnexpected2
|
|
440
|
-
} from "@prisma-next/core-control-plane/errors";
|
|
441
|
-
|
|
442
|
-
// src/utils/result.ts
|
|
443
|
-
function ok(value) {
|
|
444
|
-
return { ok: true, value };
|
|
445
|
-
}
|
|
446
|
-
function err(error) {
|
|
447
|
-
return { ok: false, error };
|
|
448
|
-
}
|
|
449
|
-
async function performAction(fn) {
|
|
450
|
-
try {
|
|
451
|
-
const value = await fn();
|
|
452
|
-
return ok(value);
|
|
453
|
-
} catch (error) {
|
|
454
|
-
if (error instanceof CliStructuredError) {
|
|
455
|
-
return err(error);
|
|
456
|
-
}
|
|
457
|
-
throw error;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// src/utils/result-handler.ts
|
|
462
|
-
function handleResult(result, flags, onSuccess) {
|
|
463
|
-
if (result.ok) {
|
|
464
|
-
if (onSuccess) {
|
|
465
|
-
onSuccess(result.value);
|
|
466
|
-
}
|
|
467
|
-
return 0;
|
|
468
|
-
}
|
|
469
|
-
const envelope = result.error.toEnvelope();
|
|
470
|
-
if (flags.json === "object") {
|
|
471
|
-
console.error(formatErrorJson(envelope));
|
|
472
|
-
} else {
|
|
473
|
-
console.error(formatErrorOutput(envelope, flags));
|
|
474
|
-
}
|
|
475
|
-
const exitCode = result.error.domain === "CLI" ? 2 : 1;
|
|
476
|
-
return exitCode;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// src/utils/spinner.ts
|
|
480
|
-
import ora from "ora";
|
|
481
|
-
async function withSpinner(operation, options) {
|
|
482
|
-
const { message, flags, delayThreshold = 100 } = options;
|
|
483
|
-
const shouldShowSpinner = !flags.quiet && flags.json !== "object" && process.stdout.isTTY;
|
|
484
|
-
if (!shouldShowSpinner) {
|
|
485
|
-
return operation();
|
|
486
|
-
}
|
|
487
|
-
const startTime = Date.now();
|
|
488
|
-
let spinner = null;
|
|
489
|
-
let timeoutId = null;
|
|
490
|
-
let operationCompleted = false;
|
|
491
|
-
timeoutId = setTimeout(() => {
|
|
492
|
-
if (!operationCompleted) {
|
|
493
|
-
spinner = ora({
|
|
494
|
-
text: message,
|
|
495
|
-
color: flags.color !== false ? "cyan" : false
|
|
496
|
-
}).start();
|
|
497
|
-
}
|
|
498
|
-
}, delayThreshold);
|
|
499
|
-
try {
|
|
500
|
-
const result = await operation();
|
|
501
|
-
operationCompleted = true;
|
|
502
|
-
if (timeoutId) {
|
|
503
|
-
clearTimeout(timeoutId);
|
|
504
|
-
timeoutId = null;
|
|
505
|
-
}
|
|
506
|
-
if (spinner !== null) {
|
|
507
|
-
const elapsed = Date.now() - startTime;
|
|
508
|
-
spinner.succeed(`${message} (${elapsed}ms)`);
|
|
509
|
-
}
|
|
510
|
-
return result;
|
|
511
|
-
} catch (error) {
|
|
512
|
-
operationCompleted = true;
|
|
513
|
-
if (timeoutId) {
|
|
514
|
-
clearTimeout(timeoutId);
|
|
515
|
-
timeoutId = null;
|
|
516
|
-
}
|
|
517
|
-
if (spinner !== null) {
|
|
518
|
-
spinner.fail(
|
|
519
|
-
`${message} failed: ${error instanceof Error ? error.message : String(error)}`
|
|
520
|
-
);
|
|
521
|
-
}
|
|
522
|
-
throw error;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// src/commands/contract-emit.ts
|
|
527
|
-
function createContractEmitCommand() {
|
|
528
|
-
const command = new Command("emit");
|
|
529
|
-
setCommandDescriptions(
|
|
530
|
-
command,
|
|
531
|
-
"Write your contract to JSON and sign it",
|
|
532
|
-
"Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\ncontract.d.ts. The contract.json contains the canonical contract structure, and\ncontract.d.ts provides TypeScript types for type-safe query building."
|
|
533
|
-
);
|
|
534
|
-
command.configureHelp({
|
|
535
|
-
formatHelp: (cmd) => {
|
|
536
|
-
const flags = parseGlobalFlags({});
|
|
537
|
-
return formatCommandHelp({ command: cmd, flags });
|
|
538
|
-
}
|
|
539
|
-
}).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) => {
|
|
540
|
-
const flags = parseGlobalFlags(options);
|
|
541
|
-
const result = await performAction(async () => {
|
|
542
|
-
const config = await loadConfig(options.config);
|
|
543
|
-
if (!config.contract) {
|
|
544
|
-
throw errorContractConfigMissing2({
|
|
545
|
-
why: "Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ..., types: ... }"
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
const contractConfig = config.contract;
|
|
549
|
-
if (!contractConfig.output || !contractConfig.types) {
|
|
550
|
-
throw errorContractConfigMissing2({
|
|
551
|
-
why: "Contract config must have output and types paths. This should not happen if defineConfig() was used."
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
const outputJsonPath = resolve2(contractConfig.output);
|
|
555
|
-
const outputDtsPath = resolve2(contractConfig.types);
|
|
556
|
-
if (flags.json !== "object" && !flags.quiet) {
|
|
557
|
-
const configPath = options.config ? relative2(process.cwd(), resolve2(options.config)) : "prisma-next.config.ts";
|
|
558
|
-
const contractPath = relative2(process.cwd(), outputJsonPath);
|
|
559
|
-
const typesPath = relative2(process.cwd(), outputDtsPath);
|
|
560
|
-
const header = formatStyledHeader({
|
|
561
|
-
command: "contract emit",
|
|
562
|
-
description: "Write your contract to JSON and sign it",
|
|
563
|
-
url: "https://pris.ly/contract-emit",
|
|
564
|
-
details: [
|
|
565
|
-
{ label: "config", value: configPath },
|
|
566
|
-
{ label: "contract", value: contractPath },
|
|
567
|
-
{ label: "types", value: typesPath }
|
|
568
|
-
],
|
|
569
|
-
flags
|
|
570
|
-
});
|
|
571
|
-
console.log(header);
|
|
572
|
-
}
|
|
573
|
-
if (!config.driver) {
|
|
574
|
-
throw errorContractConfigMissing2({
|
|
575
|
-
why: "Config.driver is required. Even though emit does not use the driver, it is required by ControlFamilyDescriptor.create()"
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
const familyInstance = config.family.create({
|
|
579
|
-
target: config.target,
|
|
580
|
-
adapter: config.adapter,
|
|
581
|
-
driver: config.driver,
|
|
582
|
-
extensions: config.extensions ?? []
|
|
583
|
-
});
|
|
584
|
-
let contractRaw;
|
|
585
|
-
if (typeof contractConfig.source === "function") {
|
|
586
|
-
contractRaw = await contractConfig.source();
|
|
587
|
-
} else {
|
|
588
|
-
contractRaw = contractConfig.source;
|
|
589
|
-
}
|
|
590
|
-
const emitResult = await withSpinner(
|
|
591
|
-
() => familyInstance.emitContract({ contractIR: contractRaw }),
|
|
592
|
-
{
|
|
593
|
-
message: "Emitting contract...",
|
|
594
|
-
flags
|
|
595
|
-
}
|
|
596
|
-
);
|
|
597
|
-
mkdirSync(dirname2(outputJsonPath), { recursive: true });
|
|
598
|
-
mkdirSync(dirname2(outputDtsPath), { recursive: true });
|
|
599
|
-
writeFileSync(outputJsonPath, emitResult.contractJson, "utf-8");
|
|
600
|
-
writeFileSync(outputDtsPath, emitResult.contractDts, "utf-8");
|
|
601
|
-
if (!flags.quiet && flags.json !== "object" && process.stdout.isTTY) {
|
|
602
|
-
console.log("");
|
|
603
|
-
}
|
|
604
|
-
return {
|
|
605
|
-
coreHash: emitResult.coreHash,
|
|
606
|
-
profileHash: emitResult.profileHash,
|
|
607
|
-
outDir: dirname2(outputJsonPath),
|
|
608
|
-
files: {
|
|
609
|
-
json: outputJsonPath,
|
|
610
|
-
dts: outputDtsPath
|
|
611
|
-
},
|
|
612
|
-
timings: {
|
|
613
|
-
total: 0
|
|
614
|
-
// Timing is handled by emitContract internally if needed
|
|
615
|
-
}
|
|
616
|
-
};
|
|
617
|
-
});
|
|
618
|
-
const exitCode = handleResult(result, flags, (emitResult) => {
|
|
619
|
-
if (flags.json === "object") {
|
|
620
|
-
console.log(formatEmitJson(emitResult));
|
|
621
|
-
} else {
|
|
622
|
-
const output = formatEmitOutput(emitResult, flags);
|
|
623
|
-
if (output) {
|
|
624
|
-
console.log(output);
|
|
625
|
-
}
|
|
626
|
-
if (!flags.quiet) {
|
|
627
|
-
console.log(formatSuccessMessage(flags));
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
});
|
|
631
|
-
process.exit(exitCode);
|
|
632
|
-
});
|
|
633
|
-
return command;
|
|
634
|
-
}
|
|
6
|
+
createContractEmitCommand
|
|
7
|
+
} from "./chunk-4Q3MO4TK.js";
|
|
8
|
+
import "./chunk-3EODSNGS.js";
|
|
9
|
+
import "./chunk-HWYQOCAJ.js";
|
|
635
10
|
|
|
636
11
|
// src/load-ts-contract.ts
|
|
637
|
-
import { existsSync, unlinkSync, writeFileSync
|
|
12
|
+
import { existsSync, unlinkSync, writeFileSync } from "fs";
|
|
638
13
|
import { tmpdir } from "os";
|
|
639
14
|
import { join } from "path";
|
|
640
15
|
import { build } from "esbuild";
|
|
@@ -766,7 +141,7 @@ Only @prisma-next/* packages are allowed in contract files.`
|
|
|
766
141
|
if (bundleContent === void 0) {
|
|
767
142
|
throw new Error("Bundle content is undefined");
|
|
768
143
|
}
|
|
769
|
-
|
|
144
|
+
writeFileSync(tempFile, bundleContent, "utf-8");
|
|
770
145
|
const module = await import(`file://${tempFile}`);
|
|
771
146
|
unlinkSync(tempFile);
|
|
772
147
|
let contract;
|