create-prisma 0.11.2 → 0.11.3

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.
@@ -1,1987 +0,0 @@
1
- #!/usr/bin/env node
2
- import { z } from "zod";
3
- import { cancel, confirm, intro, isCancel, log, note, outro, select, spinner, taskLog, text } from "@clack/prompts";
4
- import fs from "fs-extra";
5
- import path from "node:path";
6
- import { randomUUID } from "node:crypto";
7
- import os from "node:os";
8
- import { PostHog } from "posthog-node";
9
- import Handlebars from "handlebars";
10
- import { existsSync } from "node:fs";
11
- import { fileURLToPath } from "node:url";
12
- import { execa } from "execa";
13
- import { Writable } from "node:stream";
14
- import { createInterface } from "node:readline";
15
- import { styleText } from "node:util";
16
-
17
- //#region src/create-outcome.ts
18
- var CreateCancellationError = class extends Error {
19
- stage;
20
- constructor(stage) {
21
- super("Operation cancelled.");
22
- this.name = "CreateCancellationError";
23
- this.stage = stage;
24
- }
25
- };
26
- var ClassifiedCreateError = class extends Error {
27
- reason;
28
- constructor(reason, message, options) {
29
- super(message, options);
30
- this.name = "ClassifiedCreateError";
31
- this.reason = reason;
32
- }
33
- };
34
- function getCreateFailureReason(error, fallback) {
35
- return error instanceof ClassifiedCreateError ? error.reason : fallback;
36
- }
37
-
38
- //#endregion
39
- //#region src/result.ts
40
- const CREATE_PRISMA_RESULT_SCHEMA_VERSION = 1;
41
- function createCommandFailureResult(stage, message, project) {
42
- return {
43
- schemaVersion: CREATE_PRISMA_RESULT_SCHEMA_VERSION,
44
- ok: false,
45
- error: {
46
- stage,
47
- message
48
- },
49
- ...project ? { project } : {}
50
- };
51
- }
52
-
53
- //#endregion
54
- //#region src/telemetry/client.ts
55
- const TELEMETRY_API_KEY = "phc_cmc85avbWyuJ2JyKdGPdv7dxXli8xLdWDBPbvIXWJfs";
56
- const TELEMETRY_HOST = "https://us.i.posthog.com";
57
- const TELEMETRY_CONFIG_FILE = "telemetry.json";
58
- const UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
59
- function isTruthyEnvValue(value) {
60
- return [
61
- "1",
62
- "true",
63
- "yes",
64
- "on"
65
- ].includes(String(value ?? "").trim().toLowerCase());
66
- }
67
- function shouldDisableTelemetry() {
68
- if (isTruthyEnvValue(process.env.CI) || isTruthyEnvValue(process.env.GITHUB_ACTIONS)) return true;
69
- return process.env.CREATE_PRISMA_DISABLE_TELEMETRY !== void 0 || process.env.CREATE_PRISMA_TELEMETRY_DISABLED !== void 0 || process.env.DO_NOT_TRACK !== void 0;
70
- }
71
- function getTelemetryConfigDir() {
72
- if (process.platform === "darwin") return path.join(os.homedir(), "Library", "Application Support", "create-prisma");
73
- if (process.platform === "win32") return path.join(process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming"), "create-prisma");
74
- return path.join(process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config"), "create-prisma");
75
- }
76
- async function getAnonymousId() {
77
- const telemetryConfigPath = path.join(getTelemetryConfigDir(), TELEMETRY_CONFIG_FILE);
78
- try {
79
- const config = await fs.readJSON(telemetryConfigPath);
80
- if (typeof config.anonymousId === "string" && UUID_V4_REGEX.test(config.anonymousId)) return config.anonymousId;
81
- } catch {}
82
- const anonymousId = randomUUID();
83
- try {
84
- await fs.ensureDir(path.dirname(telemetryConfigPath));
85
- await fs.writeJSON(telemetryConfigPath, { anonymousId }, { spaces: 2 });
86
- } catch {}
87
- return anonymousId;
88
- }
89
- function getCommonProperties() {
90
- return {
91
- "cli-version": "0.11.2",
92
- "node-version": process.version,
93
- platform: process.platform,
94
- arch: process.arch
95
- };
96
- }
97
- function sanitizeProperties(properties) {
98
- return Object.fromEntries(Object.entries(properties).filter(([, value]) => value !== void 0));
99
- }
100
- async function trackCliTelemetry(event, properties) {
101
- if (shouldDisableTelemetry()) return;
102
- let client;
103
- try {
104
- const distinctId = await getAnonymousId();
105
- const sanitizedProperties = sanitizeProperties({
106
- ...getCommonProperties(),
107
- ...properties,
108
- $process_person_profile: false
109
- });
110
- client = new PostHog(TELEMETRY_API_KEY, {
111
- host: TELEMETRY_HOST,
112
- disableGeoip: true,
113
- flushAt: 1,
114
- flushInterval: 0
115
- });
116
- await client.captureImmediate({
117
- distinctId,
118
- event,
119
- properties: sanitizedProperties,
120
- disableGeoip: true
121
- });
122
- } catch {} finally {
123
- if (client) await client.shutdown().catch(() => {});
124
- }
125
- }
126
-
127
- //#endregion
128
- //#region src/telemetry/create.ts
129
- const CREATE_PRISMA_NEXT_COMPLETED_EVENT = "cli:create_prisma_next_command_completed";
130
- const CREATE_PRISMA_NEXT_FAILED_EVENT = "cli:create_prisma_next_command_failed";
131
- const CREATE_PRISMA_NEXT_CANCELLED_EVENT = "cli:create_prisma_next_command_cancelled";
132
- const expectedRejectionReasons = new Set([
133
- "invalid_input",
134
- "unsupported_node_version",
135
- "invalid_project_name",
136
- "target_path_not_directory",
137
- "target_directory_not_empty",
138
- "unsupported_configuration",
139
- "not_authenticated",
140
- "workspace_missing",
141
- "workspace_mismatch",
142
- "project_name_collision"
143
- ]);
144
- function getFailureClass(reason) {
145
- return expectedRejectionReasons.has(reason) ? "expected_rejection" : "technical_failure";
146
- }
147
- function getTargetDirectoryState(context) {
148
- if (!context.targetPathState.exists) return "new";
149
- if (context.targetPathState.isEmptyDirectory) return "empty_directory";
150
- return "non_empty_directory";
151
- }
152
- function getBaseCreateProperties(input, context) {
153
- return {
154
- "telemetry-schema-version": 2,
155
- command: "create",
156
- "uses-defaults": input.yes === true || input.json === true,
157
- json: input.json === true,
158
- verbose: input.verbose === true,
159
- force: input.force === true,
160
- template: context?.template ?? input.template ?? null,
161
- "database-provider": context?.prismaSetupContext.databaseProvider ?? input.provider ?? null,
162
- "authoring-style": context?.prismaSetupContext.authoring ?? input.authoring ?? null,
163
- "package-manager": context?.prismaSetupContext.packageManager ?? input.packageManager ?? null,
164
- "should-deploy": context?.prismaSetupContext.shouldDeploy ?? input.deploy ?? null,
165
- "target-directory-state": context ? getTargetDirectoryState(context) : null
166
- };
167
- }
168
- function getErrorName(error) {
169
- if (error instanceof Error) return error.name;
170
- return error === void 0 ? null : "UnknownError";
171
- }
172
- function getErrorCode(error) {
173
- if (typeof error !== "object" || error === null) return null;
174
- const exitCode = Reflect.get(error, "exitCode");
175
- if (typeof exitCode === "number") return exitCode;
176
- const code = Reflect.get(error, "code");
177
- return typeof code === "number" || typeof code === "string" ? code : null;
178
- }
179
- function getPrismaCliFailureProperty(error, property) {
180
- if (typeof error !== "object" || error === null) return null;
181
- const value = Reflect.get(error, property);
182
- return typeof value === "string" && value.length > 0 ? value : null;
183
- }
184
- async function trackCreateCompleted(params) {
185
- await trackCliTelemetry(CREATE_PRISMA_NEXT_COMPLETED_EVENT, {
186
- ...getBaseCreateProperties(params.input, params.context),
187
- "duration-ms": params.durationMs
188
- });
189
- }
190
- async function trackCreateFailed(params) {
191
- await trackCliTelemetry(CREATE_PRISMA_NEXT_FAILED_EVENT, {
192
- ...getBaseCreateProperties(params.input, params.context),
193
- "duration-ms": params.durationMs,
194
- "failure-class": getFailureClass(params.reason),
195
- "failure-stage": params.stage,
196
- "failure-reason": params.reason,
197
- "error-name": getErrorName(params.error),
198
- "error-code": getErrorCode(params.error),
199
- "prisma-cli-command": getPrismaCliFailureProperty(params.error, "prismaCliCommand"),
200
- "prisma-cli-error-code": getPrismaCliFailureProperty(params.error, "prismaCliErrorCode")
201
- });
202
- }
203
- async function trackCreateCancelled(params) {
204
- await trackCliTelemetry(CREATE_PRISMA_NEXT_CANCELLED_EVENT, {
205
- ...getBaseCreateProperties(params.input, params.context),
206
- "duration-ms": params.durationMs,
207
- "cancellation-stage": params.stage
208
- });
209
- }
210
-
211
- //#endregion
212
- //#region src/types.ts
213
- const databaseProviderInputs = [
214
- "postgres",
215
- "postgresql",
216
- "mongo",
217
- "mongodb"
218
- ];
219
- const packageManagers = [
220
- "npm",
221
- "pnpm",
222
- "yarn",
223
- "bun",
224
- "deno"
225
- ];
226
- const authoringStyles = ["psl", "typescript"];
227
- const createTemplates = [
228
- "minimal",
229
- "hono",
230
- "elysia",
231
- "nest",
232
- "next",
233
- "svelte",
234
- "astro",
235
- "nuxt",
236
- "tanstack-start"
237
- ];
238
- function normalizeDatabaseProvider(value) {
239
- if (value === "postgresql") return "postgres";
240
- if (value === "mongodb") return "mongo";
241
- return value;
242
- }
243
- const DatabaseProviderSchema = z.enum(databaseProviderInputs).transform(normalizeDatabaseProvider);
244
- const PackageManagerSchema = z.enum(packageManagers);
245
- const AuthoringStyleSchema = z.enum(authoringStyles);
246
- const CreateTemplateSchema = z.enum(createTemplates);
247
- const CommonCommandOptionsSchema = z.object({
248
- yes: z.boolean().optional().describe("Skip prompts and accept default choices"),
249
- verbose: z.boolean().optional().describe("Show verbose command output during setup"),
250
- json: z.boolean().optional().describe("Emit one quiet JSON result for agents and automation (non-interactive; deploys unless --no-deploy)")
251
- });
252
- const PrismaSetupOptionsSchema = z.object({
253
- provider: DatabaseProviderSchema.optional().describe("Prisma 8 database target: PostgreSQL relational models or MongoDB document models"),
254
- authoring: AuthoringStyleSchema.optional().describe("Contract authoring style"),
255
- packageManager: PackageManagerSchema.optional().describe("Package manager used for dependency installation"),
256
- deploy: z.boolean().optional().describe("Deploy the generated app to Prisma immediately"),
257
- workspace: z.string().trim().min(1, "Please enter a valid workspace id or name").optional().describe("Prisma workspace id or name to deploy into")
258
- });
259
- const PrismaSetupCommandInputSchema = CommonCommandOptionsSchema.extend(PrismaSetupOptionsSchema.shape);
260
- const CreateScaffoldOptionsSchema = z.object({
261
- name: z.string().trim().min(1, "Please enter a valid project name").optional().describe("Project name / directory"),
262
- template: CreateTemplateSchema.optional().describe("Project template"),
263
- force: z.boolean().optional().describe("Allow scaffolding into a non-empty target directory")
264
- });
265
- const CreateCommandInputSchema = PrismaSetupCommandInputSchema.extend(CreateScaffoldOptionsSchema.shape);
266
-
267
- //#endregion
268
- //#region src/utils/package-manager.ts
269
- const DENO_ALLOW_FRESH_DEPENDENCIES = "--minimum-dependency-age=0";
270
- const packageManagerManifestValues = {
271
- npm: "npm@10.9.0",
272
- pnpm: "pnpm@11.21.0",
273
- yarn: "yarn@4.13.0",
274
- bun: "bun@1.3.9"
275
- };
276
- function parseUserAgent(userAgent) {
277
- if (userAgent?.startsWith("pnpm")) return "pnpm";
278
- if (userAgent?.startsWith("yarn")) return "yarn";
279
- if (userAgent?.startsWith("bun")) return "bun";
280
- if (userAgent?.startsWith("deno")) return "deno";
281
- if (userAgent?.startsWith("npm")) return "npm";
282
- return null;
283
- }
284
- function parsePackageManagerField(packageManagerField) {
285
- if (typeof packageManagerField !== "string" || packageManagerField.length === 0) return null;
286
- const managerName = packageManagerField.split("@")[0];
287
- const parsed = PackageManagerSchema.safeParse(managerName);
288
- return parsed.success ? parsed.data : null;
289
- }
290
- async function detectFromPackageJson(projectDir) {
291
- const packageJsonPath = path.join(projectDir, "package.json");
292
- if (!await fs.pathExists(packageJsonPath)) return null;
293
- return parsePackageManagerField((await fs.readJson(packageJsonPath)).packageManager);
294
- }
295
- async function detectFromDenoConfig(projectDir) {
296
- for (const configFile of ["deno.json", "deno.jsonc"]) if (await fs.pathExists(path.join(projectDir, configFile))) return "deno";
297
- return null;
298
- }
299
- async function detectFromLockfile(projectDir) {
300
- for (const check of [
301
- {
302
- manager: "pnpm",
303
- lockfile: "pnpm-lock.yaml"
304
- },
305
- {
306
- manager: "yarn",
307
- lockfile: "yarn.lock"
308
- },
309
- {
310
- manager: "bun",
311
- lockfile: "bun.lockb"
312
- },
313
- {
314
- manager: "bun",
315
- lockfile: "bun.lock"
316
- },
317
- {
318
- manager: "npm",
319
- lockfile: "package-lock.json"
320
- },
321
- {
322
- manager: "npm",
323
- lockfile: "npm-shrinkwrap.json"
324
- },
325
- {
326
- manager: "deno",
327
- lockfile: "deno.lock"
328
- }
329
- ]) if (await fs.pathExists(path.join(projectDir, check.lockfile))) return check.manager;
330
- return null;
331
- }
332
- async function detectPackageManager(projectDir = process.cwd()) {
333
- const fromPackageJson = await detectFromPackageJson(projectDir);
334
- if (fromPackageJson) return fromPackageJson;
335
- const fromLockfile = await detectFromLockfile(projectDir);
336
- if (fromLockfile) return fromLockfile;
337
- const fromDenoConfig = await detectFromDenoConfig(projectDir);
338
- if (fromDenoConfig) return fromDenoConfig;
339
- const fromUserAgent = parseUserAgent(process.env.npm_config_user_agent);
340
- if (fromUserAgent) return fromUserAgent;
341
- return "npm";
342
- }
343
- function getPackageManagerManifestValue(packageManager) {
344
- if (!packageManager) return;
345
- if (packageManager === "deno") return;
346
- return packageManagerManifestValues[packageManager];
347
- }
348
- function getInstallCommand(packageManager) {
349
- if (packageManager === "deno") return "deno install";
350
- return `${packageManager} install`;
351
- }
352
- function getRunScriptCommand(packageManager, scriptName) {
353
- switch (packageManager) {
354
- case "deno": return `deno task ${scriptName}`;
355
- case "bun": return `bun run ${scriptName}`;
356
- case "pnpm": return `pnpm run ${scriptName}`;
357
- case "yarn": return `yarn run ${scriptName}`;
358
- default: return `npm run ${scriptName}`;
359
- }
360
- }
361
- function getRuntimeScriptCommand(packageManager, kind, options) {
362
- const { sourceEntrypoint, builtEntrypoint } = options;
363
- if (packageManager === "deno") switch (kind) {
364
- case "dev": return `deno run -A --env-file=.env --watch ${sourceEntrypoint}`;
365
- case "build": return `deno check ${sourceEntrypoint}`;
366
- case "start": return `deno run -A --env-file=.env ${sourceEntrypoint}`;
367
- }
368
- if (packageManager === "bun") switch (kind) {
369
- case "dev": return `bun --watch ${sourceEntrypoint}`;
370
- case "build": return "tsc --noEmit";
371
- case "start": return `bun ${sourceEntrypoint}`;
372
- }
373
- switch (kind) {
374
- case "dev": return `tsx watch ${sourceEntrypoint}`;
375
- case "build": return "tsc";
376
- case "start": return builtEntrypoint ? `node ${builtEntrypoint}` : `tsx ${sourceEntrypoint}`;
377
- }
378
- }
379
- function getInstallArgs(packageManager) {
380
- if (packageManager === "deno") return {
381
- command: "deno",
382
- args: ["install", DENO_ALLOW_FRESH_DEPENDENCIES]
383
- };
384
- return {
385
- command: packageManager,
386
- args: ["install"]
387
- };
388
- }
389
- function getPackageExecutionArgs(packageManager, commandArgs) {
390
- switch (packageManager) {
391
- case "deno": {
392
- const [packageName, ...args] = commandArgs;
393
- if (!packageName) throw new Error("Package execution requires a package name.");
394
- return {
395
- command: "deno",
396
- args: [
397
- "run",
398
- "-A",
399
- DENO_ALLOW_FRESH_DEPENDENCIES,
400
- `npm:${packageName}`,
401
- ...args
402
- ]
403
- };
404
- }
405
- case "pnpm": return {
406
- command: "pnpm",
407
- args: ["dlx", ...commandArgs]
408
- };
409
- case "yarn": return {
410
- command: "yarn",
411
- args: ["dlx", ...commandArgs]
412
- };
413
- case "bun": return {
414
- command: "bunx",
415
- args: [...commandArgs]
416
- };
417
- default: return {
418
- command: "npx",
419
- args: ["--yes", ...commandArgs]
420
- };
421
- }
422
- }
423
- function getPackageExecutionCommand(packageManager, commandArgs) {
424
- const execution = getPackageExecutionArgs(packageManager, commandArgs);
425
- return [execution.command, ...execution.args].join(" ");
426
- }
427
- function getRunScriptArgs(packageManager, scriptName) {
428
- switch (packageManager) {
429
- case "deno": return {
430
- command: "deno",
431
- args: ["task", scriptName]
432
- };
433
- case "bun": return {
434
- command: "bun",
435
- args: ["run", scriptName]
436
- };
437
- case "pnpm": return {
438
- command: "pnpm",
439
- args: ["run", scriptName]
440
- };
441
- case "yarn": return {
442
- command: "yarn",
443
- args: ["run", scriptName]
444
- };
445
- default: return {
446
- command: "npm",
447
- args: ["run", scriptName]
448
- };
449
- }
450
- }
451
-
452
- //#endregion
453
- //#region src/templates/shared.ts
454
- Handlebars.registerHelper("eq", (left, right) => left === right);
455
- Handlebars.registerHelper("runScriptCommand", (packageManager, scriptName) => packageManager ? getRunScriptCommand(packageManager, scriptName) : "");
456
- Handlebars.registerHelper("packageManagerManifestValue", (packageManager) => getPackageManagerManifestValue(packageManager) ?? "");
457
- Handlebars.registerHelper("runtimeScript", (packageManager, kind, sourceEntrypoint, builtEntrypoint, _options) => {
458
- if (!packageManager) return "";
459
- return getRuntimeScriptCommand(packageManager, kind, {
460
- sourceEntrypoint,
461
- builtEntrypoint
462
- });
463
- });
464
- function findPackageRoot(startDir) {
465
- let currentDir = startDir;
466
- while (true) {
467
- if (existsSync(path.join(currentDir, "package.json"))) return currentDir;
468
- const parentDir = path.dirname(currentDir);
469
- if (parentDir === currentDir) break;
470
- currentDir = parentDir;
471
- }
472
- throw new Error(`Unable to locate package root from: ${startDir}`);
473
- }
474
- function resolveTemplatesDir(relativeTemplatesDir) {
475
- const currentFilePath = fileURLToPath(import.meta.url);
476
- const packageRoot = findPackageRoot(path.dirname(currentFilePath));
477
- const templatePath = path.join(packageRoot, relativeTemplatesDir);
478
- if (!existsSync(templatePath)) throw new Error(`Template directory not found at: ${templatePath}`);
479
- return templatePath;
480
- }
481
- async function getTemplateFilesRecursively(dir) {
482
- const entries = await fs.readdir(dir, { withFileTypes: true });
483
- return (await Promise.all(entries.map(async (entry) => {
484
- const entryPath = path.join(dir, entry.name);
485
- if (entry.isDirectory()) return getTemplateFilesRecursively(entryPath);
486
- if (!entry.isFile()) return [];
487
- return [entryPath];
488
- }))).flat();
489
- }
490
- function stripHbsExtension(filePath) {
491
- return filePath.endsWith(".hbs") ? filePath.slice(0, -4) : filePath;
492
- }
493
- function ensureTrailingNewline(content) {
494
- return content.endsWith("\n") ? content : `${content}\n`;
495
- }
496
- async function renderTemplateFile(opts) {
497
- const { templateFilePath, outputPath, context } = opts;
498
- const templateContent = await fs.readFile(templateFilePath, "utf8");
499
- const outputContent = templateFilePath.endsWith(".hbs") ? Handlebars.compile(templateContent, {
500
- noEscape: true,
501
- strict: true
502
- })(context) : templateContent;
503
- if (templateFilePath.endsWith(".hbs") && outputContent.trim().length === 0) return;
504
- await fs.outputFile(outputPath, ensureTrailingNewline(outputContent), "utf8");
505
- }
506
- async function renderTemplateTree(opts) {
507
- const { templateRoot, outputDir, context } = opts;
508
- const templateFiles = await getTemplateFilesRecursively(templateRoot);
509
- for (const templateFilePath of templateFiles) {
510
- const relativeOutputPath = stripHbsExtension(path.relative(templateRoot, templateFilePath));
511
- await renderTemplateFile({
512
- templateFilePath,
513
- outputPath: path.join(outputDir, relativeOutputPath),
514
- context
515
- });
516
- }
517
- }
518
-
519
- //#endregion
520
- //#region src/templates/render-create-template.ts
521
- const tsdownEntries = {
522
- minimal: "src/index.ts",
523
- hono: "src/index.ts",
524
- elysia: "src/index.ts",
525
- nest: "src/main.ts"
526
- };
527
- function getCreateTemplateDir(template) {
528
- return resolveTemplatesDir(`templates/create/${template}`);
529
- }
530
- function getCreateSharedTemplateDir() {
531
- return resolveTemplatesDir("templates/create/_shared");
532
- }
533
- function createTemplateContext(projectName, template, provider, authoring, packageManager) {
534
- return {
535
- projectName,
536
- template,
537
- provider,
538
- authoring,
539
- packageManager,
540
- tsdownEntry: tsdownEntries[template] ?? null
541
- };
542
- }
543
- async function scaffoldCreateSharedTemplates(opts) {
544
- const { projectDir, projectName, template, provider, authoring, packageManager } = opts;
545
- await renderTemplateTree({
546
- templateRoot: getCreateSharedTemplateDir(),
547
- outputDir: projectDir,
548
- context: createTemplateContext(projectName, template, provider, authoring, packageManager)
549
- });
550
- }
551
- async function scaffoldCreateFrameworkTemplate(opts) {
552
- const { projectDir, projectName, template, provider, authoring, packageManager } = opts;
553
- await renderTemplateTree({
554
- templateRoot: getCreateTemplateDir(template),
555
- outputDir: projectDir,
556
- context: createTemplateContext(projectName, template, provider, authoring, packageManager)
557
- });
558
- }
559
-
560
- //#endregion
561
- //#region src/constants/dependencies.ts
562
- const dependencyVersionMap = {
563
- "@astrojs/node": "^10.0.2",
564
- "@elysiajs/node": "^1.4.5",
565
- "@prisma/composer": "0.16.0",
566
- "@prisma/composer-prisma-cloud": "0.16.0",
567
- "@prisma/orm-mongo": "8.0.0-rc.8",
568
- "@prisma/orm-postgres": "8.0.0-rc.8",
569
- "@sveltejs/adapter-node": "^5.3.2",
570
- "@types/node": "^25.6.2",
571
- alchemy: "2.0.0-beta.74",
572
- arktype: "^2.2.3",
573
- dotenv: "^17.4.2",
574
- effect: "4.0.0-rc.112",
575
- mongodb: "^7.1.0",
576
- "mongodb-memory-server": "^11.1.0",
577
- nitro: "^3.0.260610-beta",
578
- prisma: "latest",
579
- "temporal-polyfill": "^1.0.4",
580
- tsdown: "^0.22.14",
581
- tsx: "^4.21.0",
582
- typescript: "^5.9.3"
583
- };
584
- const PRISMA_PLATFORM_CLI_PACKAGE = "prisma@latest";
585
- const PRISMA_DENO_CLI_PACKAGE = PRISMA_PLATFORM_CLI_PACKAGE;
586
- function getDependencyVersion(packageName) {
587
- return dependencyVersionMap[packageName];
588
- }
589
- function usesTsdown(template) {
590
- return template === "minimal" || template === "hono" || template === "elysia" || template === "nest";
591
- }
592
- function getCreateTemplateDependencies(template, _packageManager) {
593
- const dependencies = [
594
- "@prisma/composer",
595
- "@prisma/composer-prisma-cloud",
596
- "alchemy"
597
- ];
598
- const devDependencies = [];
599
- if (usesTsdown(template)) {
600
- devDependencies.push("tsdown");
601
- devDependencies.push("tsx");
602
- }
603
- if (template === "minimal") devDependencies.push("typescript");
604
- if (template === "elysia") {
605
- dependencies.push("@elysiajs/node");
606
- devDependencies.push("@types/node");
607
- }
608
- if (template === "svelte") devDependencies.push("@sveltejs/adapter-node");
609
- if (template === "astro") dependencies.push("@astrojs/node");
610
- if (template === "tanstack-start") devDependencies.push("nitro");
611
- return [{
612
- packageJsonPath: "package.json",
613
- dependencies,
614
- devDependencies
615
- }];
616
- }
617
-
618
- //#endregion
619
- //#region src/constants/db-packages.ts
620
- function getDbPackages(provider) {
621
- switch (provider) {
622
- case "postgres": return "@prisma/orm-postgres";
623
- case "mongo": return "@prisma/orm-mongo";
624
- }
625
- }
626
-
627
- //#endregion
628
- //#region src/utils/run-command.ts
629
- /**
630
- * Runs a setup command without allowing child output to corrupt structured CLI output.
631
- * Human verbose mode keeps native streaming; JSON mode always captures child output.
632
- */
633
- async function runSetupCommand(options) {
634
- const shouldInheritOutput = options.verbose && !options.json;
635
- await execa(options.command, options.args, {
636
- cwd: options.cwd,
637
- env: options.env,
638
- stdio: shouldInheritOutput ? "inherit" : "pipe"
639
- });
640
- }
641
-
642
- //#endregion
643
- //#region src/tasks/install.ts
644
- function getPrismaScriptMap(packageManager) {
645
- if (packageManager === "deno") {
646
- const prismaCommand = (needsDatabase, ...args) => [
647
- "deno run -A",
648
- ...needsDatabase ? ["--env-file=.env"] : [],
649
- `npm:${PRISMA_DENO_CLI_PACKAGE}`,
650
- ...args
651
- ].join(" ");
652
- return {
653
- "contract:emit": prismaCommand(false, "contract", "emit"),
654
- "db:init": prismaCommand(true, "db", "init"),
655
- "db:update": prismaCommand(true, "db", "update"),
656
- "db:verify": prismaCommand(true, "db", "verify"),
657
- "migration:plan": prismaCommand(true, "migration", "plan"),
658
- migrate: prismaCommand(true, "db", "migrate"),
659
- "migration:status": prismaCommand(true, "migration", "status"),
660
- "migration:show": prismaCommand(true, "migration", "show")
661
- };
662
- }
663
- const prismaCommand = (...args) => ["prisma", ...args].join(" ");
664
- return {
665
- "contract:emit": prismaCommand("contract", "emit"),
666
- "db:init": prismaCommand("db", "init"),
667
- "db:update": prismaCommand("db", "update"),
668
- "db:verify": prismaCommand("db", "verify"),
669
- "migration:plan": prismaCommand("migration", "plan"),
670
- migrate: prismaCommand("db", "migrate"),
671
- "migration:status": prismaCommand("migration", "status"),
672
- "migration:show": prismaCommand("migration", "show"),
673
- "skills:sync": `${prismaCommand("skills", "sync")} || exit 0`
674
- };
675
- }
676
- function getComposerScriptMap(packageManager) {
677
- if (packageManager === "deno") return {};
678
- const composerCommand = (subcommand) => [
679
- "prisma",
680
- subcommand,
681
- "module.ts"
682
- ].join(" ");
683
- return {
684
- "composer:dev": composerCommand("dev"),
685
- "composer:deploy": composerCommand("deploy"),
686
- deploy: `${getRunScriptCommand(packageManager, "build")} && ${getRunScriptCommand(packageManager, "composer:deploy")}`,
687
- "dev:composer": `${getRunScriptCommand(packageManager, "build")} && ${getRunScriptCommand(packageManager, "composer:dev")}`
688
- };
689
- }
690
- function unique(items) {
691
- return [...new Set(items)];
692
- }
693
- function sortRecord(record) {
694
- return Object.fromEntries(Object.entries(record).sort(([a], [b]) => a.localeCompare(b)));
695
- }
696
- async function addPackageDependency(opts) {
697
- const { dependencies = [], devDependencies = [], customDependencies = {}, scripts = {}, scriptMode, projectDir } = opts;
698
- const pkgJsonPath = path.join(projectDir, "package.json");
699
- if (!await fs.pathExists(pkgJsonPath)) throw new Error(`No package.json found in ${projectDir}. Run this command inside an existing JavaScript/TypeScript project.`);
700
- const pkgJson = await fs.readJson(pkgJsonPath);
701
- pkgJson.dependencies ??= {};
702
- pkgJson.devDependencies ??= {};
703
- pkgJson.scripts ??= {};
704
- for (const packageName of unique(dependencies)) {
705
- const version = getDependencyVersion(packageName);
706
- if (!version) throw new Error(`Dependency ${packageName} is missing from the version map.`);
707
- pkgJson.dependencies[packageName] = version;
708
- }
709
- for (const packageName of unique(devDependencies)) {
710
- const version = getDependencyVersion(packageName);
711
- if (!version) throw new Error(`Dependency ${packageName} is missing from the version map.`);
712
- pkgJson.devDependencies[packageName] = version;
713
- }
714
- for (const [packageName, version] of Object.entries(customDependencies)) pkgJson.dependencies[packageName] = version;
715
- for (const [scriptName, command] of Object.entries(scripts)) {
716
- if (scriptMode === "if-missing" && typeof pkgJson.scripts[scriptName] === "string" && pkgJson.scripts[scriptName].trim().length > 0) continue;
717
- pkgJson.scripts[scriptName] = command;
718
- }
719
- pkgJson.dependencies = sortRecord(pkgJson.dependencies);
720
- pkgJson.devDependencies = sortRecord(pkgJson.devDependencies);
721
- pkgJson.scripts = sortRecord(pkgJson.scripts);
722
- await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
723
- }
724
- async function writePrismaDependencies(provider, packageManager, _authoring, projectDir = process.cwd()) {
725
- const dependencies = [getDbPackages(provider)];
726
- if (provider === "postgres" && packageManager !== "deno") dependencies.push("temporal-polyfill");
727
- if (provider === "mongo") dependencies.push("arktype", "mongodb");
728
- if (packageManager === "deno") dependencies.push("dotenv");
729
- await addPackageDependency({
730
- dependencies,
731
- devDependencies: ["@types/node", "prisma"],
732
- scripts: getPrismaScriptMap(packageManager),
733
- projectDir
734
- });
735
- }
736
- async function writeCreateTemplateDependencies(opts) {
737
- const { template, packageManager, projectDir = process.cwd() } = opts;
738
- if (packageManager === "deno") return;
739
- for (const target of getCreateTemplateDependencies(template, packageManager)) await addPackageDependency({
740
- dependencies: target.dependencies,
741
- devDependencies: target.devDependencies,
742
- customDependencies: target.customDependencies,
743
- scripts: getComposerScriptMap(packageManager),
744
- projectDir: path.join(projectDir, path.dirname(target.packageJsonPath))
745
- });
746
- const packageJsonPath = path.join(projectDir, "package.json");
747
- const packageJson = await fs.readJson(packageJsonPath);
748
- const effectVersion = getDependencyVersion("effect");
749
- if (!effectVersion) throw new Error("Dependency effect is missing from the version map.");
750
- if (packageManager === "yarn") packageJson.resolutions = {
751
- ...packageJson.resolutions,
752
- effect: effectVersion
753
- };
754
- else if (packageManager !== "pnpm") packageJson.overrides = {
755
- ...packageJson.overrides,
756
- effect: effectVersion
757
- };
758
- await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
759
- }
760
- async function installProjectDependencies(packageManager, projectDir = process.cwd(), options = {}) {
761
- const installCommand = getInstallArgs(packageManager);
762
- const env = packageManager === "yarn" ? { YARN_ENABLE_IMMUTABLE_INSTALLS: "false" } : void 0;
763
- await runSetupCommand({
764
- command: installCommand.command,
765
- args: installCommand.args,
766
- cwd: projectDir,
767
- env,
768
- verbose: options.verbose === true,
769
- json: options.json === true
770
- });
771
- }
772
-
773
- //#endregion
774
- //#region src/ui/output.ts
775
- const silentOutput = new Writable({ write(_chunk, _encoding, callback) {
776
- callback();
777
- } });
778
- /** Resolves the shared interaction policy for human and machine-readable modes. */
779
- function resolveExecutionSettings(options) {
780
- const json = options.json === true;
781
- return {
782
- json,
783
- output: json ? silentOutput : process.stdout,
784
- useDefaults: options.yes === true || json
785
- };
786
- }
787
-
788
- //#endregion
789
- //#region src/utils/errors.ts
790
- function redactSecrets(message) {
791
- return message.replace(/\b((?:(?:prisma\+)?postgres(?:ql)?|mongodb(?:\+srv)?):\/\/)[^\s'"]+/gi, "$1<redacted>").replace(/\b([A-Z0-9_]*(?:MONGODB_(?:URL|URI)|DATABASE_URL|TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE_KEY)[A-Z0-9_]*\s*=\s*)(?:"[^"]*"|'[^']*'|[^\s]+)/gi, "$1<redacted>").replace(/(\bAuthorization\s*:\s*Bearer\s+)[^\s'"]+/gi, "$1<redacted>");
792
- }
793
- function getErrorMessage(error) {
794
- if (error instanceof Error && "stderr" in error) {
795
- const stderr = String(error.stderr ?? "").trim();
796
- if (stderr) return redactSecrets(stderr);
797
- }
798
- return redactSecrets(error instanceof Error ? error.message : String(error));
799
- }
800
-
801
- //#endregion
802
- //#region src/tasks/deploy-with-composer.ts
803
- var PrismaCliCommandError = class extends Error {
804
- prismaCliCommand;
805
- prismaCliErrorCode;
806
- constructor(options) {
807
- super(options.message);
808
- this.name = "PrismaCliCommandError";
809
- this.prismaCliCommand = options.command;
810
- this.prismaCliErrorCode = options.code;
811
- }
812
- };
813
- function stripResourcePrefix(id, prefix) {
814
- const marker = `${prefix}_`;
815
- return id.startsWith(marker) ? id.slice(marker.length) : id;
816
- }
817
- function getConsoleProjectUrl(workspaceId, projectId) {
818
- const consoleWorkspaceId = stripResourcePrefix(workspaceId, "wksp");
819
- const consoleProjectId = stripResourcePrefix(projectId, "proj");
820
- return `https://console.prisma.io/${encodeURIComponent(consoleWorkspaceId)}/${encodeURIComponent(consoleProjectId)}`;
821
- }
822
- function parsePrismaCliEnvelope(output) {
823
- const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).reverse();
824
- for (const line of lines) try {
825
- const parsed = JSON.parse(line);
826
- const candidate = parsed.kind === "result" ? parsed.envelope : parsed;
827
- if (typeof candidate !== "object" || candidate === null) continue;
828
- if (typeof Reflect.get(candidate, "ok") !== "boolean") continue;
829
- return candidate;
830
- } catch {}
831
- throw new Error("Prisma CLI returned output that is not a valid result envelope.");
832
- }
833
- function getPrismaCliArgs(packageManager, args) {
834
- return getPackageExecutionArgs(packageManager, [PRISMA_PLATFORM_CLI_PACKAGE, ...args]);
835
- }
836
- async function runPrismaJsonCommand(options) {
837
- const invocation = getPrismaCliArgs(options.packageManager, [
838
- ...options.args,
839
- "--json",
840
- "--no-interactive"
841
- ]);
842
- const subprocess = execa(invocation.command, invocation.args, {
843
- cwd: options.projectDir,
844
- env: process.env,
845
- reject: false
846
- });
847
- const stderrLines = options.onStderrLine && subprocess.stderr ? (async () => {
848
- const lines = createInterface({ input: subprocess.stderr });
849
- for await (const line of lines) if (line.trim()) options.onStderrLine?.(line);
850
- })() : Promise.resolve();
851
- const [result] = await Promise.all([subprocess, stderrLines]);
852
- let envelope;
853
- try {
854
- envelope = parsePrismaCliEnvelope(result.stdout);
855
- } catch (error) {
856
- if (result.exitCode !== 0 && result.stderr.trim()) throw new Error(result.stderr.trim());
857
- throw error;
858
- }
859
- if (result.exitCode !== 0 || !envelope.ok || envelope.result === void 0) throw new PrismaCliCommandError({
860
- message: [envelope.error?.summary ?? envelope.error?.message, envelope.error?.why].filter(Boolean).join(": ") || result.stderr.trim() || "Prisma CLI command failed.",
861
- ...envelope.commandId || envelope.command ? { command: envelope.commandId ?? envelope.command } : {},
862
- ...envelope.error?.code ? { code: envelope.error.code } : {}
863
- });
864
- return envelope.result;
865
- }
866
- function findProjectNameCollisions(projects, appName) {
867
- return projects.filter((project) => project.name === appName);
868
- }
869
- async function ensureProjectNameAvailable(options) {
870
- const collisions = findProjectNameCollisions((await runPrismaJsonCommand({
871
- packageManager: options.packageManager,
872
- projectDir: options.projectDir,
873
- args: ["project", "list"]
874
- })).items, options.appName);
875
- if (collisions.length === 0) return;
876
- const projectIds = collisions.map((project) => project.id).join(", ");
877
- throw new ClassifiedCreateError("project_name_collision", `A Prisma project named "${options.appName}" already exists in workspace ${workspaceLabel(options.workspace)} (${options.workspace.id}). Choose a different project name or delete the existing project (${projectIds}) in Prisma Console, then retry.`);
878
- }
879
- async function ensureAuthentication(options) {
880
- const whoami = () => runPrismaJsonCommand({
881
- packageManager: options.packageManager,
882
- projectDir: options.projectDir,
883
- args: ["auth", "whoami"]
884
- });
885
- const authState = await whoami();
886
- if (authState.authenticated) return authState;
887
- const loginCommand = getPackageExecutionCommand(options.packageManager, [
888
- PRISMA_PLATFORM_CLI_PACKAGE,
889
- "auth",
890
- "login"
891
- ]);
892
- if (!options.allowInteractiveLogin || process.stdin.isTTY !== true) throw new ClassifiedCreateError("not_authenticated", `Sign in first with ${loginCommand}, then run ${getRunScriptCommand(options.packageManager, "deploy")}.`);
893
- options.beforeInteractiveLogin?.();
894
- log.info("Sign in to Prisma to deploy.", { output: options.output });
895
- const login = getPrismaCliArgs(options.packageManager, ["auth", "login"]);
896
- await execa(login.command, login.args, {
897
- cwd: options.projectDir,
898
- env: process.env,
899
- stdio: "inherit"
900
- });
901
- const authenticatedState = await whoami();
902
- if (!authenticatedState.authenticated) throw new ClassifiedCreateError("authentication_failed", "Prisma sign-in completed without an active workspace session.");
903
- return authenticatedState;
904
- }
905
- function workspaceLabel(workspace) {
906
- return workspace.name ?? workspace.id;
907
- }
908
- async function useWorkspace(options) {
909
- return (await runPrismaJsonCommand({
910
- packageManager: options.packageManager,
911
- projectDir: options.projectDir,
912
- args: [
913
- "auth",
914
- "workspace",
915
- "use",
916
- options.workspace
917
- ]
918
- })).workspace;
919
- }
920
- async function selectDeploymentWorkspace(options) {
921
- const activeWorkspace = options.authState.workspace;
922
- if (!activeWorkspace) throw new ClassifiedCreateError("workspace_missing", "The active Prisma credential does not specify a workspace.");
923
- if (options.workspace) {
924
- if (options.authState.source === "environment") {
925
- if (options.workspace === activeWorkspace.id || options.workspace === activeWorkspace.name) return {
926
- ok: true,
927
- workspace: activeWorkspace
928
- };
929
- throw new ClassifiedCreateError("workspace_mismatch", `The environment credential is fixed to workspace ${workspaceLabel(activeWorkspace)}. Unset it before using --workspace ${options.workspace}.`);
930
- }
931
- return {
932
- ok: true,
933
- workspace: await useWorkspace({
934
- packageManager: options.packageManager,
935
- projectDir: options.projectDir,
936
- workspace: options.workspace
937
- })
938
- };
939
- }
940
- if (!options.shouldPrompt || process.stdin.isTTY !== true) return {
941
- ok: true,
942
- workspace: activeWorkspace
943
- };
944
- const available = await runPrismaJsonCommand({
945
- packageManager: options.packageManager,
946
- projectDir: options.projectDir,
947
- args: [
948
- "auth",
949
- "workspace",
950
- "list"
951
- ]
952
- });
953
- if (available.items.length <= 1) return {
954
- ok: true,
955
- workspace: activeWorkspace
956
- };
957
- options.beforePrompt?.();
958
- const selectedWorkspaceId = await select({
959
- message: "Select Prisma workspace for deployment",
960
- initialValue: activeWorkspace.id,
961
- options: available.items.map((workspace) => ({
962
- value: workspace.workspaceId,
963
- label: workspace.workspaceName ?? workspace.workspaceId,
964
- hint: workspace.current ? `${workspace.workspaceId}, current` : workspace.workspaceId
965
- })),
966
- output: options.output
967
- });
968
- if (isCancel(selectedWorkspaceId)) {
969
- cancel("Operation cancelled.", { output: options.output });
970
- return {
971
- ok: false,
972
- cancelled: true
973
- };
974
- }
975
- options.afterPrompt?.();
976
- if (selectedWorkspaceId === activeWorkspace.id) return {
977
- ok: true,
978
- workspace: activeWorkspace
979
- };
980
- return {
981
- ok: true,
982
- workspace: await useWorkspace({
983
- packageManager: options.packageManager,
984
- projectDir: options.projectDir,
985
- workspace: selectedWorkspaceId
986
- })
987
- };
988
- }
989
- function parseComposerDeployResult(result) {
990
- const summary = result.summary;
991
- if (!summary) return;
992
- const computeService = summary.nodes.flatMap((node) => node.entities).find((entity) => entity.kind === "compute-service");
993
- return {
994
- appName: summary.app,
995
- ...computeService?.id ? { serviceId: computeService.id } : {},
996
- ...computeService?.url ? { appUrl: computeService.url.replace(/\/$/, "") } : {}
997
- };
998
- }
999
- async function getProjectDetails(options) {
1000
- try {
1001
- const result = await runPrismaJsonCommand({
1002
- packageManager: options.packageManager,
1003
- projectDir: options.projectDir,
1004
- args: [
1005
- "project",
1006
- "show",
1007
- options.appName
1008
- ]
1009
- });
1010
- if (!result.project) return;
1011
- return {
1012
- workspace: result.workspace,
1013
- project: {
1014
- id: result.project.id,
1015
- name: result.project.name,
1016
- consoleUrl: getConsoleProjectUrl(result.workspace.id, result.project.id)
1017
- }
1018
- };
1019
- } catch {
1020
- return;
1021
- }
1022
- }
1023
- /**
1024
- * Performs the optional one-shot deployment at the end of a create-prisma scaffold.
1025
- * Generated projects use their own `deploy` script for every subsequent deployment.
1026
- */
1027
- async function deployNewProjectWithComposer(options) {
1028
- const output = options.output ?? process.stdout;
1029
- const progress = options.verbose ? void 0 : spinner({ output });
1030
- let deploymentLog;
1031
- let progressRunning = false;
1032
- let failureStage = "authenticate";
1033
- let failureReason = "prisma_auth_command_failed";
1034
- const showProgress = (message) => {
1035
- if (!progress) return;
1036
- if (progressRunning) progress.message(message);
1037
- else {
1038
- progress.start(message);
1039
- progressRunning = true;
1040
- }
1041
- };
1042
- const clearProgress = () => {
1043
- if (!progress || !progressRunning) return;
1044
- progress.clear();
1045
- progressRunning = false;
1046
- };
1047
- try {
1048
- showProgress("Checking Prisma account...");
1049
- if (options.verbose) log.step("Checking Prisma account.", { output });
1050
- const authState = await ensureAuthentication({
1051
- packageManager: options.packageManager,
1052
- projectDir: options.projectDir,
1053
- output,
1054
- allowInteractiveLogin: options.allowInteractiveLogin ?? true,
1055
- beforeInteractiveLogin: clearProgress
1056
- });
1057
- showProgress("Checking Prisma workspace...");
1058
- failureStage = "select_workspace";
1059
- failureReason = "workspace_selection_failed";
1060
- if (options.verbose) log.step("Checking Prisma workspace.", { output });
1061
- const workspaceResult = await selectDeploymentWorkspace({
1062
- packageManager: options.packageManager,
1063
- projectDir: options.projectDir,
1064
- shouldPrompt: options.shouldPromptForWorkspace,
1065
- authState,
1066
- output,
1067
- beforePrompt: clearProgress,
1068
- afterPrompt: () => showProgress("Selecting Prisma workspace..."),
1069
- ...options.workspace ? { workspace: options.workspace } : {}
1070
- });
1071
- if (!workspaceResult.ok) return {
1072
- ok: false,
1073
- cancelled: true,
1074
- stage: "select_workspace"
1075
- };
1076
- const selectedWorkspace = workspaceResult.workspace;
1077
- showProgress("Checking Prisma project name...");
1078
- failureStage = "check_project_name";
1079
- failureReason = "project_lookup_failed";
1080
- if (options.verbose) log.step("Checking Prisma project name.", { output });
1081
- await ensureProjectNameAvailable({
1082
- appName: options.appName,
1083
- packageManager: options.packageManager,
1084
- projectDir: options.projectDir,
1085
- workspace: selectedWorkspace
1086
- });
1087
- showProgress("Building for deployment...");
1088
- failureStage = "build";
1089
- failureReason = "build_failed";
1090
- if (options.verbose) log.step("Building for deployment.", { output });
1091
- const build = getRunScriptArgs(options.packageManager, "build");
1092
- await runSetupCommand({
1093
- command: build.command,
1094
- args: build.args,
1095
- cwd: options.projectDir,
1096
- env: process.env,
1097
- verbose: options.verbose,
1098
- json: options.json === true
1099
- });
1100
- clearProgress();
1101
- failureStage = "composer_deploy";
1102
- failureReason = "composer_deploy_failed";
1103
- const deployCommand = getPackageExecutionCommand(options.packageManager, [
1104
- PRISMA_PLATFORM_CLI_PACKAGE,
1105
- "deploy",
1106
- "module.ts"
1107
- ]);
1108
- if (options.verbose) log.step(`Deploying to Prisma with ${deployCommand}.`, { output });
1109
- else {
1110
- deploymentLog = taskLog({
1111
- title: "Deploying to Prisma...",
1112
- limit: 10,
1113
- output
1114
- });
1115
- deploymentLog.message(`$ ${deployCommand}`);
1116
- }
1117
- const deployment = parseComposerDeployResult(await runPrismaJsonCommand({
1118
- packageManager: options.packageManager,
1119
- projectDir: options.projectDir,
1120
- args: ["deploy", "module.ts"],
1121
- onStderrLine: (line) => {
1122
- const redactedLine = redactSecrets(line);
1123
- if (options.verbose) output.write(`${redactedLine}\n`);
1124
- else deploymentLog?.message(redactedLine);
1125
- }
1126
- }));
1127
- const appName = deployment?.appName ?? options.appName;
1128
- if (options.verbose) log.step("Loading deployment details.", { output });
1129
- else deploymentLog?.message("Loading deployment details...");
1130
- const details = await getProjectDetails({
1131
- packageManager: options.packageManager,
1132
- projectDir: options.projectDir,
1133
- appName
1134
- });
1135
- deploymentLog?.success("Deployed to Prisma.");
1136
- deploymentLog = void 0;
1137
- progressRunning = false;
1138
- if (options.verbose) log.success("Deployed to Prisma.", { output });
1139
- const workspace = details?.workspace ?? selectedWorkspace;
1140
- return {
1141
- ok: true,
1142
- deployment: {
1143
- appName,
1144
- ...deployment?.appUrl ? { appUrl: deployment.appUrl } : {},
1145
- ...deployment?.serviceId ? { serviceId: deployment.serviceId } : {},
1146
- ...workspace ? { workspace } : {},
1147
- project: details?.project ?? { name: appName }
1148
- }
1149
- };
1150
- } catch (error) {
1151
- if (deploymentLog) {
1152
- deploymentLog.error("Deployment failed.");
1153
- deploymentLog = void 0;
1154
- } else progress?.error("Deployment failed.");
1155
- progressRunning = false;
1156
- log.error(`Deploy failed: ${getErrorMessage(error)}`, { output });
1157
- return {
1158
- ok: false,
1159
- stage: failureStage,
1160
- reason: getCreateFailureReason(error, failureReason),
1161
- error
1162
- };
1163
- }
1164
- }
1165
-
1166
- //#endregion
1167
- //#region src/tasks/initialize-git.ts
1168
- function errorMessage(error) {
1169
- if (error instanceof Error && "stderr" in error) {
1170
- const stderr = String(error.stderr ?? "").trim();
1171
- if (stderr) return stderr;
1172
- }
1173
- return error instanceof Error ? error.message : String(error);
1174
- }
1175
- /**
1176
- * Initializes a standalone scaffold as a Git repository and records its generated files.
1177
- * Projects created inside an existing repository remain part of that repository.
1178
- */
1179
- async function initializeGitRepository(projectDir, env = process.env) {
1180
- try {
1181
- const existing = await execa("git", ["rev-parse", "--is-inside-work-tree"], {
1182
- cwd: projectDir,
1183
- env,
1184
- reject: false
1185
- });
1186
- if (existing.exitCode === 0 && existing.stdout.trim() === "true") return { status: "already-in-repository" };
1187
- } catch (error) {
1188
- return {
1189
- status: "skipped",
1190
- reason: errorMessage(error)
1191
- };
1192
- }
1193
- let initialized = false;
1194
- try {
1195
- await execa("git", ["init"], {
1196
- cwd: projectDir,
1197
- env
1198
- });
1199
- initialized = true;
1200
- await execa("git", ["add", "--all"], {
1201
- cwd: projectDir,
1202
- env
1203
- });
1204
- await execa("git", [
1205
- "commit",
1206
- "--no-verify",
1207
- "-m",
1208
- "Initial commit from create-prisma"
1209
- ], {
1210
- cwd: projectDir,
1211
- env
1212
- });
1213
- return { status: "initialized" };
1214
- } catch (error) {
1215
- if (initialized) await fs.remove(path.join(projectDir, ".git"));
1216
- return {
1217
- status: "skipped",
1218
- reason: errorMessage(error)
1219
- };
1220
- }
1221
- }
1222
-
1223
- //#endregion
1224
- //#region src/tasks/setup-prisma.ts
1225
- const DEFAULT_DATABASE_PROVIDER = "postgres";
1226
- const DEFAULT_AUTHORING = "psl";
1227
- async function promptForDatabaseProvider(output) {
1228
- const databaseProvider = await select({
1229
- message: "Select your database",
1230
- initialValue: DEFAULT_DATABASE_PROVIDER,
1231
- options: [{
1232
- value: "postgres",
1233
- label: "PostgreSQL",
1234
- hint: "Prisma Postgres with Composer"
1235
- }, {
1236
- value: "mongo",
1237
- label: "MongoDB",
1238
- hint: "Connect an existing MongoDB database"
1239
- }],
1240
- output
1241
- });
1242
- if (isCancel(databaseProvider)) {
1243
- cancel("Operation cancelled.", { output });
1244
- throw new CreateCancellationError("database_provider");
1245
- }
1246
- return DatabaseProviderSchema.parse(databaseProvider);
1247
- }
1248
- async function promptForAuthoringStyle(output) {
1249
- const authoring = await select({
1250
- message: "Choose contract authoring style",
1251
- initialValue: DEFAULT_AUTHORING,
1252
- options: [{
1253
- value: "psl",
1254
- label: "PSL",
1255
- hint: "Prisma schema syntax"
1256
- }, {
1257
- value: "typescript",
1258
- label: "TypeScript",
1259
- hint: "TypeScript contract builder"
1260
- }],
1261
- output
1262
- });
1263
- if (isCancel(authoring)) {
1264
- cancel("Operation cancelled.", { output });
1265
- throw new CreateCancellationError("authoring_style");
1266
- }
1267
- return AuthoringStyleSchema.parse(authoring);
1268
- }
1269
- function getPackageManagerHint(option, detected) {
1270
- const hints = {
1271
- npm: "Node.js default",
1272
- pnpm: "Fast, disk-efficient package manager",
1273
- yarn: "Yarn package manager",
1274
- bun: "Fast runtime and package manager",
1275
- deno: "Deno runtime (minimal PostgreSQL apps)"
1276
- };
1277
- return option === detected ? `Detected; ${hints[option]}` : hints[option];
1278
- }
1279
- async function promptForPackageManager(detected, output) {
1280
- const packageManager = await select({
1281
- message: "Choose package manager",
1282
- initialValue: detected,
1283
- options: packageManagers.map((value) => ({
1284
- value,
1285
- label: value,
1286
- hint: getPackageManagerHint(value, detected)
1287
- })),
1288
- output
1289
- });
1290
- if (isCancel(packageManager)) {
1291
- cancel("Operation cancelled.", { output });
1292
- throw new CreateCancellationError("package_manager");
1293
- }
1294
- return PackageManagerSchema.parse(packageManager);
1295
- }
1296
- async function promptForDeployment(output) {
1297
- const shouldDeploy = await confirm({
1298
- message: "Deploy to Prisma now?",
1299
- initialValue: true,
1300
- output
1301
- });
1302
- if (isCancel(shouldDeploy)) {
1303
- cancel("Operation cancelled.", { output });
1304
- throw new CreateCancellationError("deployment_intent");
1305
- }
1306
- return Boolean(shouldDeploy);
1307
- }
1308
- async function collectPrismaSetupContext(input, options = {}) {
1309
- const projectDir = path.resolve(options.projectDir ?? process.cwd());
1310
- const { json, output, useDefaults } = resolveExecutionSettings(input);
1311
- const databaseProvider = input.provider ?? (useDefaults ? DEFAULT_DATABASE_PROVIDER : await promptForDatabaseProvider(output));
1312
- const authoring = input.authoring ?? (useDefaults ? DEFAULT_AUTHORING : await promptForAuthoringStyle(output));
1313
- const detectedPackageManager = await detectPackageManager(projectDir);
1314
- const packageManager = input.packageManager ?? (useDefaults ? detectedPackageManager : await promptForPackageManager(detectedPackageManager, output));
1315
- if (packageManager === "deno" && databaseProvider !== "postgres") throw new ClassifiedCreateError("unsupported_configuration", "Deno support currently requires PostgreSQL.");
1316
- if (packageManager === "deno" && options.template && options.template !== "minimal") throw new ClassifiedCreateError("unsupported_configuration", "Deno support currently requires the minimal template.");
1317
- if (packageManager === "deno" && input.deploy === true) throw new ClassifiedCreateError("unsupported_configuration", "Prisma Compute does not support Deno deployments yet. Use --no-deploy.");
1318
- const shouldDeploy = packageManager === "deno" ? false : input.deploy ?? (json ? true : useDefaults ? false : await promptForDeployment(output));
1319
- return {
1320
- projectDir,
1321
- verbose: input.verbose === true,
1322
- json,
1323
- output,
1324
- databaseProvider,
1325
- authoring,
1326
- packageManager,
1327
- shouldDeploy,
1328
- shouldPromptForWorkspace: !useDefaults,
1329
- ...input.workspace ? { workspace: input.workspace } : {}
1330
- };
1331
- }
1332
- function getContractPath(authoring) {
1333
- return `src/prisma/contract${authoring === "typescript" ? ".ts" : ".prisma"}`;
1334
- }
1335
- function getInitTarget(provider) {
1336
- return provider === "mongo" ? "mongodb" : "postgres";
1337
- }
1338
- function getPrismaCliInvocation(packageManager, args) {
1339
- return getPackageExecutionArgs(packageManager, [packageManager === "deno" ? PRISMA_DENO_CLI_PACKAGE : PRISMA_PLATFORM_CLI_PACKAGE, ...args]);
1340
- }
1341
- async function runPrismaInit(context, projectDir) {
1342
- const args = [
1343
- "orm",
1344
- "init",
1345
- "--yes",
1346
- "--no-interactive",
1347
- "--target",
1348
- getInitTarget(context.databaseProvider),
1349
- "--authoring",
1350
- context.authoring,
1351
- "--schema-path",
1352
- getContractPath(context.authoring),
1353
- "--skip-install"
1354
- ];
1355
- const invocation = getPrismaCliInvocation(context.packageManager, args);
1356
- if (context.verbose) log.step(`Running ${[invocation.command, ...invocation.args].join(" ")}`, { output: context.output });
1357
- await runSetupCommand({
1358
- command: invocation.command,
1359
- args: invocation.args,
1360
- cwd: projectDir,
1361
- env: {
1362
- ...process.env,
1363
- CI: "1"
1364
- },
1365
- verbose: context.verbose,
1366
- json: context.json
1367
- });
1368
- if (context.packageManager === "deno") await fs.remove(path.join(projectDir, "prisma-next.md"));
1369
- }
1370
- async function initializeAgentSkills(context, projectDir) {
1371
- if (context.packageManager === "deno") return;
1372
- const invocation = getPrismaCliInvocation(context.packageManager, [
1373
- "init",
1374
- "--yes",
1375
- "--no-interactive"
1376
- ]);
1377
- if (context.verbose) log.step(`Running ${[invocation.command, ...invocation.args].join(" ")}`, { output: context.output });
1378
- await runSetupCommand({
1379
- command: invocation.command,
1380
- args: invocation.args,
1381
- cwd: projectDir,
1382
- env: {
1383
- ...process.env,
1384
- CI: "1"
1385
- },
1386
- verbose: context.verbose,
1387
- json: context.json
1388
- });
1389
- }
1390
- async function ensureGitignoreEntry(projectDir, entry) {
1391
- const gitignorePath = path.join(projectDir, ".gitignore");
1392
- const existing = await fs.pathExists(gitignorePath) ? await fs.readFile(gitignorePath, "utf8") : "";
1393
- const lines = existing.split(/\r?\n/).map((line) => line.trim());
1394
- if (lines.includes(entry) || lines.includes(`/${entry}`)) return;
1395
- const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
1396
- await fs.writeFile(gitignorePath, `${existing}${separator}${entry}\n`, "utf8");
1397
- }
1398
- async function ensureMongoEnvironment(projectDir) {
1399
- const envPath = path.join(projectDir, ".env");
1400
- if (!await fs.pathExists(envPath)) await fs.writeFile(envPath, "DATABASE_URL=\"mongodb://localhost:27017/mydb?replicaSet=rs0&directConnection=true\"\n", "utf8");
1401
- await ensureGitignoreEntry(projectDir, ".env");
1402
- }
1403
- async function ensureComposerTypeScriptOptions(projectDir) {
1404
- const tsconfigPath = path.join(projectDir, "tsconfig.json");
1405
- const tsconfig = await fs.readFile(tsconfigPath, "utf8");
1406
- const additions = [];
1407
- if (!/"allowImportingTsExtensions"\s*:/.test(tsconfig)) additions.push(" \"allowImportingTsExtensions\": true,");
1408
- if (!/"noEmit"\s*:/.test(tsconfig)) additions.push(" \"noEmit\": true,");
1409
- if (additions.length === 0) return;
1410
- const updated = tsconfig.replace(/"compilerOptions"\s*:\s*\{/, (match) => `${match}\n${additions.join("\n")}`);
1411
- if (updated === tsconfig) throw new Error("tsconfig.json is missing compilerOptions.");
1412
- await fs.writeFile(tsconfigPath, updated, "utf8");
1413
- }
1414
- async function runPrismaCli(context, projectDir, args) {
1415
- const invocation = getPrismaCliInvocation(context.packageManager, args);
1416
- if (context.verbose) log.step([invocation.command, ...invocation.args].join(" "), { output: context.output });
1417
- await runSetupCommand({
1418
- command: invocation.command,
1419
- args: invocation.args,
1420
- cwd: projectDir,
1421
- env: {
1422
- ...process.env,
1423
- CI: "1"
1424
- },
1425
- verbose: context.verbose,
1426
- json: context.json
1427
- });
1428
- }
1429
- async function emitContract(context, projectDir) {
1430
- await runPrismaCli(context, projectDir, ["contract", "emit"]);
1431
- }
1432
- async function planBaselineMigration(context, projectDir) {
1433
- await runPrismaCli(context, projectDir, [
1434
- "migration",
1435
- "plan",
1436
- "--name",
1437
- "init"
1438
- ]);
1439
- }
1440
- function formatNextSteps(steps) {
1441
- return steps.map((step) => `${step.command}\n ${step.description}`).join("\n\n");
1442
- }
1443
- function formatPlatformTarget(name, id) {
1444
- return name ? `${name} (${id})` : id;
1445
- }
1446
- function formatProjectSummary(options) {
1447
- const lines = [];
1448
- if (options.createdProjectPath) lines.push(`Path: ${path.resolve(options.createdProjectPath)}`);
1449
- if (options.deployment?.workspace) lines.push(`Workspace: ${formatPlatformTarget(options.deployment.workspace.name, options.deployment.workspace.id)}`);
1450
- if (options.deployment) {
1451
- lines.push(`Project: ${options.deployment.project.id ? formatPlatformTarget(options.deployment.project.name, options.deployment.project.id) : options.deployment.project.name}`);
1452
- lines.push(`App: ${options.deployment.appUrl ?? options.deployment.appName}`);
1453
- if (options.deployment.project.consoleUrl) lines.push(`Console: ${options.deployment.project.consoleUrl}`);
1454
- }
1455
- return lines.join("\n");
1456
- }
1457
- function buildNextSteps(context, options) {
1458
- const nextSteps = [...options.prependNextSteps ?? []];
1459
- if (context.databaseProvider === "mongo") nextSteps.push({
1460
- command: "Set MONGODB_URL in your environment",
1461
- description: "Composer uses this secret when deploying the MongoDB template."
1462
- });
1463
- if (options.includeDevNextStep) nextSteps.push({
1464
- command: getRunScriptCommand(context.packageManager, context.packageManager === "deno" ? "dev" : "dev:composer"),
1465
- description: context.packageManager === "deno" ? "Start the Deno app after setting DATABASE_URL in .env." : "Build and start the app with Prisma Composer locally."
1466
- });
1467
- if (context.packageManager === "deno") return nextSteps;
1468
- nextSteps.push({
1469
- command: getRunScriptCommand(context.packageManager, "deploy"),
1470
- description: "Build and deploy the app with Prisma Composer."
1471
- });
1472
- return nextSteps;
1473
- }
1474
- async function executePrismaSetupContext(context, options = {}) {
1475
- const projectDir = path.resolve(options.projectDir ?? context.projectDir);
1476
- const projectName = options.projectName ?? path.basename(projectDir);
1477
- const template = options.template ?? "minimal";
1478
- const progress = context.verbose ? void 0 : options.progressSpinner ?? spinner({ output: context.output });
1479
- const ownsProgress = progress !== void 0 && !options.progressSpinner;
1480
- let gitInitialization;
1481
- let setupStage = "initialize_prisma";
1482
- let setupReason = "prisma_init_failed";
1483
- if (ownsProgress) progress.start("Creating Prisma 8 project...");
1484
- try {
1485
- progress?.message("Preparing Prisma 8 project files...");
1486
- await runPrismaInit(context, projectDir);
1487
- setupStage = "configure_project";
1488
- setupReason = "project_configuration_failed";
1489
- await scaffoldCreateSharedTemplates({
1490
- projectDir,
1491
- projectName,
1492
- template,
1493
- provider: context.databaseProvider,
1494
- authoring: context.authoring,
1495
- packageManager: context.packageManager
1496
- });
1497
- await writePrismaDependencies(context.databaseProvider, context.packageManager, context.authoring, projectDir);
1498
- await ensureComposerTypeScriptOptions(projectDir);
1499
- if (context.databaseProvider === "mongo") await ensureMongoEnvironment(projectDir);
1500
- if (context.packageManager !== "deno") {
1501
- await ensureGitignoreEntry(projectDir, "/.alchemy");
1502
- await ensureGitignoreEntry(projectDir, "/.prisma-composer");
1503
- }
1504
- progress?.message(`Installing dependencies with ${getInstallCommand(context.packageManager)}...`);
1505
- setupStage = "install_dependencies";
1506
- setupReason = "dependency_install_failed";
1507
- await installProjectDependencies(context.packageManager, projectDir, {
1508
- verbose: context.verbose,
1509
- json: context.json
1510
- });
1511
- progress?.message("Installing Prisma agent skills...");
1512
- setupStage = "initialize_agent_skills";
1513
- setupReason = "agent_skills_init_failed";
1514
- await initializeAgentSkills(context, projectDir);
1515
- progress?.message("Generating Prisma 8 contract artifacts...");
1516
- setupStage = "emit_contract";
1517
- setupReason = "contract_emit_failed";
1518
- await emitContract(context, projectDir);
1519
- if (context.databaseProvider === "postgres") {
1520
- progress?.message("Authoring the baseline migration...");
1521
- setupStage = "plan_migration";
1522
- setupReason = "migration_plan_failed";
1523
- await planBaselineMigration(context, projectDir);
1524
- }
1525
- if (options.initializeGit) {
1526
- progress?.message("Initializing Git repository...");
1527
- setupStage = "initialize_git";
1528
- setupReason = "git_initialization_failed";
1529
- gitInitialization = await initializeGitRepository(projectDir);
1530
- }
1531
- progress?.stop("Prisma 8 project ready.");
1532
- if (gitInitialization?.status === "initialized" && context.verbose) log.success("Initialized Git repository with an initial commit.", { output: context.output });
1533
- else if (gitInitialization?.status === "skipped") log.warn(`Could not initialize Git repository: ${gitInitialization.reason}`, { output: context.output });
1534
- } catch (error) {
1535
- progress?.error("Could not create Prisma 8 project.");
1536
- cancel(getErrorMessage(error), { output: context.output });
1537
- return {
1538
- ok: false,
1539
- stage: setupStage,
1540
- reason: getCreateFailureReason(error, setupReason),
1541
- error,
1542
- errorReported: true
1543
- };
1544
- }
1545
- let deployment;
1546
- if (context.shouldDeploy) {
1547
- const deploymentResult = await deployNewProjectWithComposer({
1548
- appName: projectName,
1549
- packageManager: context.packageManager,
1550
- projectDir,
1551
- shouldPromptForWorkspace: context.shouldPromptForWorkspace,
1552
- verbose: context.verbose,
1553
- output: context.output,
1554
- allowInteractiveLogin: !context.json,
1555
- json: context.json,
1556
- ...context.workspace ? { workspace: context.workspace } : {}
1557
- });
1558
- if (!deploymentResult.ok) {
1559
- if (deploymentResult.cancelled) return {
1560
- ok: false,
1561
- cancelled: true,
1562
- stage: deploymentResult.stage,
1563
- errorReported: true
1564
- };
1565
- return {
1566
- ok: false,
1567
- stage: deploymentResult.stage,
1568
- reason: deploymentResult.reason,
1569
- error: deploymentResult.error,
1570
- errorReported: true
1571
- };
1572
- }
1573
- deployment = deploymentResult.deployment;
1574
- }
1575
- const nextSteps = buildNextSteps(context, options);
1576
- const warnings = gitInitialization?.status === "skipped" ? [`Could not initialize Git repository: ${gitInitialization.reason}`] : [];
1577
- const projectSummary = formatProjectSummary({
1578
- createdProjectPath: options.createdProjectPath,
1579
- deployment
1580
- });
1581
- if (projectSummary) note(projectSummary, context.shouldDeploy ? "Deployment" : "Project", { output: context.output });
1582
- note(formatNextSteps(nextSteps), "Next steps", { output: context.output });
1583
- outro(context.shouldDeploy ? "Prisma 8 app deployed." : "Prisma 8 project ready.", { output: context.output });
1584
- return {
1585
- ok: true,
1586
- deployment: deployment ?? null,
1587
- nextSteps,
1588
- ...gitInitialization ? { gitInitialization } : {},
1589
- warnings
1590
- };
1591
- }
1592
-
1593
- //#endregion
1594
- //#region src/ui/branding.ts
1595
- const prismaTitle = `${styleText(["bold", "cyanBright"], "◭")} ${styleText(["bold", "cyanBright"], "Create")} ${styleText(["bold", "magentaBright"], "Prisma")} ${styleText(["bold", "blueBright"], "8")}`;
1596
- function getCreatePrismaIntro() {
1597
- return prismaTitle;
1598
- }
1599
-
1600
- //#endregion
1601
- //#region src/utils/node-version.ts
1602
- const MINIMUM_NODE_VERSION = [
1603
- 22,
1604
- 18,
1605
- 0
1606
- ];
1607
- function parseVersion(version) {
1608
- const [major = "0", minor = "0", patch = "0"] = version.replace(/^v/, "").split(".");
1609
- return [
1610
- Number(major),
1611
- Number(minor),
1612
- Number.parseInt(patch, 10)
1613
- ];
1614
- }
1615
- function supportsPrisma(nodeVersion = process.versions.node) {
1616
- const current = parseVersion(nodeVersion);
1617
- for (let index = 0; index < MINIMUM_NODE_VERSION.length; index += 1) {
1618
- if (current[index] > MINIMUM_NODE_VERSION[index]) return true;
1619
- if (current[index] < MINIMUM_NODE_VERSION[index]) return false;
1620
- }
1621
- return true;
1622
- }
1623
- function getUnsupportedNodeMessage(nodeVersion = process.versions.node) {
1624
- return [
1625
- `Node.js ${nodeVersion} is unsupported by create-prisma@latest.`,
1626
- "Required: Node.js 22.18 or newer.",
1627
- "Update Node.js and run the command again."
1628
- ].join("\n");
1629
- }
1630
-
1631
- //#endregion
1632
- //#region src/commands/create.ts
1633
- const DEFAULT_PROJECT_NAME = "my-app";
1634
- const DEFAULT_TEMPLATE = "minimal";
1635
- function toPackageName(projectName) {
1636
- return projectName.toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/^-+/, "").replace(/-+$/, "") || "app";
1637
- }
1638
- function formatPathForDisplay(filePath) {
1639
- return path.relative(process.cwd(), filePath) || ".";
1640
- }
1641
- function validateProjectName(value) {
1642
- const trimmed = String(value ?? "").trim();
1643
- if (trimmed.length === 0) return "Please enter a project name.";
1644
- if (trimmed === "..") return "Project name cannot be '..'.";
1645
- if (path.isAbsolute(trimmed)) return "Use a relative project name instead of an absolute path.";
1646
- }
1647
- function getProjectResult(context) {
1648
- return {
1649
- name: context.projectPackageName,
1650
- path: context.targetDirectory,
1651
- template: context.template,
1652
- databaseProvider: context.prismaSetupContext.databaseProvider,
1653
- authoring: context.prismaSetupContext.authoring,
1654
- packageManager: context.prismaSetupContext.packageManager
1655
- };
1656
- }
1657
- async function promptForProjectName(output) {
1658
- const projectName = await text({
1659
- message: "Project name",
1660
- placeholder: DEFAULT_PROJECT_NAME,
1661
- initialValue: DEFAULT_PROJECT_NAME,
1662
- validate: validateProjectName,
1663
- output
1664
- });
1665
- if (isCancel(projectName)) {
1666
- cancel("Operation cancelled.", { output });
1667
- throw new CreateCancellationError("project_name");
1668
- }
1669
- return String(projectName).trim();
1670
- }
1671
- async function promptForCreateTemplate(output) {
1672
- const template = await select({
1673
- message: "Select template",
1674
- initialValue: DEFAULT_TEMPLATE,
1675
- options: [
1676
- {
1677
- value: "minimal",
1678
- label: "Minimal",
1679
- hint: "Script-first Prisma 8 starter with no web framework"
1680
- },
1681
- {
1682
- value: "hono",
1683
- label: "Hono",
1684
- hint: "Lightweight TypeScript API server"
1685
- },
1686
- {
1687
- value: "elysia",
1688
- label: "Elysia",
1689
- hint: "Bun-friendly TypeScript API server"
1690
- },
1691
- {
1692
- value: "nest",
1693
- label: "NestJS",
1694
- hint: "Structured Node API with controllers and services"
1695
- },
1696
- {
1697
- value: "next",
1698
- label: "Next.js",
1699
- hint: "Full-stack React app with App Router"
1700
- },
1701
- {
1702
- value: "svelte",
1703
- label: "SvelteKit",
1704
- hint: "Full-stack Svelte 5 app with Vite"
1705
- },
1706
- {
1707
- value: "astro",
1708
- label: "Astro",
1709
- hint: "Content-oriented web app with server routes"
1710
- },
1711
- {
1712
- value: "nuxt",
1713
- label: "Nuxt",
1714
- hint: "Full-stack Vue app with Nitro server routes"
1715
- },
1716
- {
1717
- value: "tanstack-start",
1718
- label: "TanStack Start",
1719
- hint: "React app with file routes and server functions"
1720
- }
1721
- ],
1722
- output
1723
- });
1724
- if (isCancel(template)) {
1725
- cancel("Operation cancelled.", { output });
1726
- throw new CreateCancellationError("template");
1727
- }
1728
- return CreateTemplateSchema.parse(template);
1729
- }
1730
- async function inspectTargetPath(targetPath) {
1731
- if (!await fs.pathExists(targetPath)) return {
1732
- exists: false,
1733
- isDirectory: true,
1734
- isEmptyDirectory: true
1735
- };
1736
- if (!(await fs.stat(targetPath)).isDirectory()) return {
1737
- exists: true,
1738
- isDirectory: false,
1739
- isEmptyDirectory: false
1740
- };
1741
- return {
1742
- exists: true,
1743
- isDirectory: true,
1744
- isEmptyDirectory: (await fs.readdir(targetPath)).length === 0
1745
- };
1746
- }
1747
- async function runCreateCommand(rawInput = {}) {
1748
- const startedAt = Date.now();
1749
- let input = {};
1750
- let context;
1751
- let failureStage = "validate_input";
1752
- let failureReason = "invalid_input";
1753
- const { output } = resolveExecutionSettings(rawInput);
1754
- try {
1755
- input = CreateCommandInputSchema.parse(rawInput);
1756
- if (input.json && input.verbose) throw new Error("--verbose cannot be used with --json because JSON mode is output-only.");
1757
- if (!supportsPrisma()) {
1758
- const message = getUnsupportedNodeMessage();
1759
- cancel(message, { output });
1760
- process.exitCode = 1;
1761
- await trackCreateFailed({
1762
- input,
1763
- durationMs: Date.now() - startedAt,
1764
- stage: failureStage,
1765
- reason: "unsupported_node_version"
1766
- });
1767
- return createCommandFailureResult(failureStage, message);
1768
- }
1769
- intro(getCreatePrismaIntro(), { output });
1770
- failureStage = "collect_context";
1771
- failureReason = "unexpected_error";
1772
- const collected = await collectCreateContext(input);
1773
- if (!collected.ok) {
1774
- process.exitCode = 1;
1775
- const result = createCommandFailureResult(failureStage, collected.message);
1776
- await trackCreateFailed({
1777
- input,
1778
- durationMs: Date.now() - startedAt,
1779
- stage: failureStage,
1780
- reason: collected.reason
1781
- });
1782
- return result;
1783
- }
1784
- context = collected.context;
1785
- failureStage = "unknown";
1786
- const executionResult = await executeCreateContext(context);
1787
- if (!executionResult.ok) {
1788
- process.exitCode = 1;
1789
- if (executionResult.cancelled) {
1790
- await trackCreateCancelled({
1791
- input,
1792
- context,
1793
- durationMs: Date.now() - startedAt,
1794
- stage: executionResult.stage
1795
- });
1796
- return createCommandFailureResult(executionResult.stage, "Operation cancelled.", getProjectResult(context));
1797
- }
1798
- const message = executionResult.error ? getErrorMessage(executionResult.error) : "Project setup did not complete.";
1799
- if (executionResult.error && !executionResult.errorReported) cancel(`Create command failed: ${message}`, { output });
1800
- await trackCreateFailed({
1801
- input,
1802
- context,
1803
- durationMs: Date.now() - startedAt,
1804
- error: executionResult.error,
1805
- stage: executionResult.stage,
1806
- reason: executionResult.reason
1807
- });
1808
- return createCommandFailureResult(executionResult.stage, message, getProjectResult(context));
1809
- }
1810
- await trackCreateCompleted({
1811
- input,
1812
- context,
1813
- durationMs: Date.now() - startedAt
1814
- });
1815
- return executionResult.result;
1816
- } catch (error) {
1817
- process.exitCode = 1;
1818
- if (error instanceof CreateCancellationError) {
1819
- await trackCreateCancelled({
1820
- input,
1821
- context,
1822
- durationMs: Date.now() - startedAt,
1823
- stage: error.stage
1824
- });
1825
- return createCommandFailureResult(error.stage, error.message, context ? getProjectResult(context) : void 0);
1826
- }
1827
- const message = getErrorMessage(error);
1828
- cancel(`Create command failed: ${message}`, { output });
1829
- await trackCreateFailed({
1830
- input,
1831
- context,
1832
- durationMs: Date.now() - startedAt,
1833
- error,
1834
- stage: failureStage,
1835
- reason: getCreateFailureReason(error, failureReason)
1836
- });
1837
- return createCommandFailureResult(failureStage, message, context ? getProjectResult(context) : void 0);
1838
- }
1839
- }
1840
- async function collectCreateContext(input) {
1841
- const force = input.force === true;
1842
- const { output, useDefaults } = resolveExecutionSettings(input);
1843
- const projectNameInput = input.name ?? (useDefaults ? DEFAULT_PROJECT_NAME : await promptForProjectName(output));
1844
- const projectName = String(projectNameInput).trim();
1845
- const projectNameValidationError = validateProjectName(projectName);
1846
- if (projectNameValidationError) {
1847
- cancel(projectNameValidationError, { output });
1848
- return {
1849
- ok: false,
1850
- message: projectNameValidationError,
1851
- reason: "invalid_project_name"
1852
- };
1853
- }
1854
- const template = input.template ?? (useDefaults ? DEFAULT_TEMPLATE : await promptForCreateTemplate(output));
1855
- const targetDirectory = path.resolve(process.cwd(), projectName);
1856
- const targetPathState = await inspectTargetPath(targetDirectory);
1857
- if (targetPathState.exists && !targetPathState.isDirectory) {
1858
- const message = `Target path ${formatPathForDisplay(targetDirectory)} already exists and is not a directory. Choose a different project name.`;
1859
- cancel(message, { output });
1860
- return {
1861
- ok: false,
1862
- message,
1863
- reason: "target_path_not_directory"
1864
- };
1865
- }
1866
- if (targetPathState.exists && !targetPathState.isEmptyDirectory && !force) {
1867
- const message = `Target directory ${formatPathForDisplay(targetDirectory)} is not empty. Use --force to continue.`;
1868
- cancel(message, { output });
1869
- return {
1870
- ok: false,
1871
- message,
1872
- reason: "target_directory_not_empty"
1873
- };
1874
- }
1875
- const prismaSetupContext = await collectPrismaSetupContext(input, {
1876
- projectDir: targetDirectory,
1877
- template
1878
- });
1879
- return {
1880
- ok: true,
1881
- context: {
1882
- targetDirectory,
1883
- targetPathState,
1884
- force,
1885
- template,
1886
- projectPackageName: toPackageName(path.basename(targetDirectory)),
1887
- prismaSetupContext
1888
- }
1889
- };
1890
- }
1891
- async function executeCreateContext(context) {
1892
- const output = context.prismaSetupContext.output;
1893
- const createSpinner = context.prismaSetupContext.verbose ? void 0 : spinner({ output });
1894
- createSpinner?.start("Creating Prisma 8 project...");
1895
- try {
1896
- if (context.prismaSetupContext.verbose) log.step(`Scaffolding ${context.template} starter.`, { output });
1897
- await scaffoldCreateFrameworkTemplate({
1898
- projectDir: context.targetDirectory,
1899
- projectName: context.projectPackageName,
1900
- template: context.template,
1901
- provider: context.prismaSetupContext.databaseProvider,
1902
- authoring: context.prismaSetupContext.authoring,
1903
- packageManager: context.prismaSetupContext.packageManager
1904
- });
1905
- if (context.prismaSetupContext.verbose) log.success("Starter files scaffolded.", { output });
1906
- } catch (error) {
1907
- createSpinner?.error("Could not create Prisma 8 project.");
1908
- return {
1909
- ok: false,
1910
- stage: "scaffold_template",
1911
- reason: "template_scaffold_failed",
1912
- error
1913
- };
1914
- }
1915
- try {
1916
- await writeCreateTemplateDependencies({
1917
- template: context.template,
1918
- packageManager: context.prismaSetupContext.packageManager,
1919
- projectDir: context.targetDirectory
1920
- });
1921
- } catch (error) {
1922
- createSpinner?.error("Could not create Prisma 8 project.");
1923
- return {
1924
- ok: false,
1925
- stage: "scaffold_template",
1926
- reason: "template_scaffold_failed",
1927
- error
1928
- };
1929
- }
1930
- const forceWarning = context.targetPathState.exists && !context.targetPathState.isEmptyDirectory && context.force ? `Used --force in non-empty directory ${formatPathForDisplay(context.targetDirectory)}.` : void 0;
1931
- if (forceWarning) log.warn(forceWarning, { output });
1932
- const nextSteps = formatPathForDisplay(context.targetDirectory) === "." ? [] : [{
1933
- command: `cd ${formatPathForDisplay(context.targetDirectory)}`,
1934
- description: "Enter your new project directory."
1935
- }];
1936
- try {
1937
- const setupResult = await executePrismaSetupContext(context.prismaSetupContext, {
1938
- prependNextSteps: nextSteps,
1939
- projectDir: context.targetDirectory,
1940
- projectName: context.projectPackageName,
1941
- template: context.template,
1942
- createdProjectPath: context.targetDirectory,
1943
- includeDevNextStep: true,
1944
- initializeGit: !context.targetPathState.exists || context.targetPathState.isEmptyDirectory,
1945
- progressSpinner: createSpinner
1946
- });
1947
- if (!setupResult.ok) {
1948
- if (setupResult.cancelled) return {
1949
- ok: false,
1950
- cancelled: true,
1951
- stage: setupResult.stage,
1952
- errorReported: setupResult.errorReported
1953
- };
1954
- return {
1955
- ok: false,
1956
- stage: setupResult.stage,
1957
- reason: setupResult.reason,
1958
- error: setupResult.error,
1959
- errorReported: setupResult.errorReported
1960
- };
1961
- }
1962
- const warnings = [...setupResult.warnings];
1963
- if (forceWarning) warnings.unshift(forceWarning);
1964
- return {
1965
- ok: true,
1966
- result: {
1967
- schemaVersion: CREATE_PRISMA_RESULT_SCHEMA_VERSION,
1968
- ok: true,
1969
- project: getProjectResult(context),
1970
- deployment: setupResult.deployment,
1971
- nextSteps: setupResult.nextSteps,
1972
- warnings
1973
- }
1974
- };
1975
- } catch (error) {
1976
- createSpinner?.error("Could not create Prisma 8 project.");
1977
- return {
1978
- ok: false,
1979
- stage: "unknown",
1980
- reason: getCreateFailureReason(error, "unexpected_error"),
1981
- error
1982
- };
1983
- }
1984
- }
1985
-
1986
- //#endregion
1987
- export { DatabaseProviderSchema as a, createCommandFailureResult as c, CreateTemplateSchema as i, AuthoringStyleSchema as n, PackageManagerSchema as o, CreateCommandInputSchema as r, CREATE_PRISMA_RESULT_SCHEMA_VERSION as s, runCreateCommand as t };