create-prisma 0.7.1-pr.52.181.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +25 -19
  2. package/dist/cli.mjs +2 -32
  3. package/dist/index.d.mts +25 -1
  4. package/dist/index.mjs +2 -2290
  5. package/dist/src-B3hRLZ0U.mjs +2527 -0
  6. package/package.json +2 -4
  7. package/templates/create/astro/README.md.hbs +14 -7
  8. package/templates/create/astro/astro.config.mjs.hbs +0 -11
  9. package/templates/create/astro/deno.json.hbs +5 -0
  10. package/templates/create/astro/prisma/schema.prisma.hbs +5 -0
  11. package/templates/create/astro/prisma/seed.ts.hbs +5 -1
  12. package/templates/create/astro/prisma.compute.ts.hbs +10 -0
  13. package/templates/create/astro/src/lib/prisma.ts.hbs +4 -18
  14. package/templates/create/astro/src/pages/api/users.ts.hbs +11 -1
  15. package/templates/create/astro/src/pages/index.astro.hbs +176 -36
  16. package/templates/create/elysia/README.md.hbs +13 -7
  17. package/templates/create/elysia/deno.json.hbs +5 -0
  18. package/templates/create/elysia/package.json.hbs +3 -4
  19. package/templates/create/elysia/prisma/schema.prisma.hbs +6 -0
  20. package/templates/create/elysia/prisma/seed.ts.hbs +5 -1
  21. package/templates/create/elysia/prisma.compute.ts.hbs +11 -0
  22. package/templates/create/elysia/src/index.ts.hbs +17 -13
  23. package/templates/create/elysia/src/lib/prisma.ts.hbs +4 -18
  24. package/templates/create/elysia/tsconfig.json +0 -1
  25. package/templates/create/hono/README.md.hbs +13 -7
  26. package/templates/create/hono/deno.json.hbs +5 -0
  27. package/templates/create/hono/package.json.hbs +2 -2
  28. package/templates/create/hono/prisma/schema.prisma.hbs +6 -0
  29. package/templates/create/hono/prisma/seed.ts.hbs +5 -1
  30. package/templates/create/hono/prisma.compute.ts.hbs +10 -0
  31. package/templates/create/hono/src/index.ts.hbs +7 -9
  32. package/templates/create/hono/src/lib/prisma.ts.hbs +4 -18
  33. package/templates/create/hono/tsconfig.json +0 -1
  34. package/templates/create/nest/README.md.hbs +12 -6
  35. package/templates/create/nest/deno.json.hbs +5 -0
  36. package/templates/create/nest/package.json.hbs +2 -2
  37. package/templates/create/nest/prisma/schema.prisma.hbs +6 -0
  38. package/templates/create/nest/prisma/seed.ts.hbs +5 -1
  39. package/templates/create/nest/prisma.compute.ts.hbs +10 -0
  40. package/templates/create/nest/src/app.controller.ts.hbs +1 -6
  41. package/templates/create/nest/src/app.module.ts.hbs +14 -7
  42. package/templates/create/nest/src/lib/prisma.ts.hbs +4 -17
  43. package/templates/create/nest/src/main.ts.hbs +6 -2
  44. package/templates/create/nest/src/prisma.service.ts.hbs +2 -2
  45. package/templates/create/nest/src/users.controller.ts.hbs +3 -1
  46. package/templates/create/nest/src/users.service.ts.hbs +3 -1
  47. package/templates/create/nest/tsconfig.json +0 -1
  48. package/templates/create/next/README.md.hbs +11 -7
  49. package/templates/create/next/deno.json.hbs +12 -0
  50. package/templates/create/next/prisma/schema.prisma.hbs +5 -0
  51. package/templates/create/next/prisma/seed.ts.hbs +5 -1
  52. package/templates/create/next/prisma.compute.ts.hbs +9 -0
  53. package/templates/create/next/src/app/globals.css +122 -0
  54. package/templates/create/next/src/app/layout.tsx.hbs +2 -2
  55. package/templates/create/next/src/app/page.tsx.hbs +58 -34
  56. package/templates/create/next/src/lib/prisma.ts.hbs +4 -18
  57. package/templates/create/nuxt/README.md.hbs +11 -7
  58. package/templates/create/nuxt/app/pages/index.vue.hbs +175 -43
  59. package/templates/create/nuxt/deno.json.hbs +5 -0
  60. package/templates/create/nuxt/nuxt.config.ts +0 -1
  61. package/templates/create/nuxt/prisma/schema.prisma.hbs +5 -0
  62. package/templates/create/nuxt/prisma/seed.ts.hbs +5 -1
  63. package/templates/create/nuxt/prisma.compute.ts.hbs +9 -0
  64. package/templates/create/nuxt/server/api/users.get.ts.hbs +6 -0
  65. package/templates/create/nuxt/server/utils/prisma.ts.hbs +4 -18
  66. package/templates/create/svelte/README.md.hbs +13 -4
  67. package/templates/create/svelte/deno.json.hbs +5 -0
  68. package/templates/create/svelte/package.json.hbs +1 -2
  69. package/templates/create/svelte/prisma/schema.prisma.hbs +5 -0
  70. package/templates/create/svelte/prisma/seed.ts.hbs +5 -1
  71. package/templates/create/svelte/src/lib/server/prisma.ts.hbs +2 -18
  72. package/templates/create/svelte/src/routes/+layout.svelte +0 -1
  73. package/templates/create/svelte/src/routes/+page.server.ts.hbs +7 -1
  74. package/templates/create/svelte/src/routes/+page.svelte.hbs +297 -41
  75. package/templates/create/svelte/svelte.config.js +13 -0
  76. package/templates/create/svelte/vite.config.ts +0 -3
  77. package/templates/create/tanstack-start/README.md.hbs +11 -7
  78. package/templates/create/tanstack-start/deno.json.hbs +13 -0
  79. package/templates/create/tanstack-start/prisma/schema.prisma.hbs +5 -0
  80. package/templates/create/tanstack-start/prisma/seed.ts.hbs +5 -1
  81. package/templates/create/tanstack-start/prisma.compute.ts.hbs +9 -0
  82. package/templates/create/tanstack-start/src/lib/prisma.server.ts.hbs +4 -18
  83. package/templates/create/tanstack-start/src/routes/__root.tsx.hbs +29 -4
  84. package/templates/create/tanstack-start/src/routes/index.tsx.hbs +76 -35
  85. package/templates/create/tanstack-start/src/styles.css +146 -0
  86. package/templates/create/tanstack-start/tsconfig.json +1 -1
  87. package/templates/create/turborepo/README.md.hbs +9 -7
  88. package/templates/create/turborepo/apps/api/package.json.hbs +9 -2
  89. package/templates/create/turborepo/apps/api/src/index.ts.hbs +12 -28
  90. package/templates/create/turborepo/apps/api/tsconfig.json +0 -1
  91. package/templates/create/turborepo/deno.json.hbs +5 -0
  92. package/templates/create/turborepo/package.json.hbs +6 -0
  93. package/templates/create/turborepo/packages/db/package.json.hbs +5 -4
  94. package/templates/create/turborepo/packages/db/prisma/schema.prisma.hbs +5 -0
  95. package/templates/create/turborepo/packages/db/prisma/seed.ts.hbs +5 -1
  96. package/templates/create/turborepo/packages/db/src/client.ts.hbs +5 -2
  97. package/templates/create/turborepo/packages/db/tsconfig.json +0 -1
  98. package/templates/create/turborepo/prisma.compute.ts.hbs +14 -0
  99. package/templates/create/astro/module.ts.hbs +0 -30
  100. package/templates/create/astro/prisma-composer.config.ts.hbs +0 -8
  101. package/templates/create/astro/service.ts.hbs +0 -19
  102. package/templates/create/elysia/.yarnrc.yml.hbs +0 -3
  103. package/templates/create/elysia/module.ts.hbs +0 -30
  104. package/templates/create/elysia/prisma-composer.config.ts.hbs +0 -8
  105. package/templates/create/elysia/service.ts.hbs +0 -19
  106. package/templates/create/hono/module.ts.hbs +0 -30
  107. package/templates/create/hono/prisma-composer.config.ts.hbs +0 -8
  108. package/templates/create/hono/service.ts.hbs +0 -19
  109. package/templates/create/nest/module.ts.hbs +0 -30
  110. package/templates/create/nest/prisma-composer.config.ts.hbs +0 -8
  111. package/templates/create/nest/src/service.ts.hbs +0 -19
  112. package/templates/create/next/module.ts.hbs +0 -30
  113. package/templates/create/next/prisma-composer.config.ts.hbs +0 -8
  114. package/templates/create/next/service.ts.hbs +0 -19
  115. package/templates/create/nuxt/module.ts.hbs +0 -30
  116. package/templates/create/nuxt/prisma-composer.config.ts.hbs +0 -8
  117. package/templates/create/nuxt/service.ts.hbs +0 -19
  118. package/templates/create/svelte/module.ts.hbs +0 -30
  119. package/templates/create/svelte/prisma-composer.config.ts.hbs +0 -8
  120. package/templates/create/svelte/service.ts.hbs +0 -19
  121. package/templates/create/svelte/svelte.config.js.hbs +0 -10
  122. package/templates/create/tanstack-start/module.ts.hbs +0 -30
  123. package/templates/create/tanstack-start/prisma-composer.config.ts.hbs +0 -8
  124. package/templates/create/tanstack-start/service.ts.hbs +0 -19
  125. package/templates/create/turborepo/apps/api/src/service.ts.hbs +0 -19
  126. package/templates/create/turborepo/module.ts.hbs +0 -30
  127. package/templates/create/turborepo/prisma-composer.config.ts.hbs +0 -8
  128. package/templates/shared/setup-composer-postgres.mjs.hbs +0 -179
  129. package/templates/shared/starter.css +0 -276
package/dist/index.mjs CHANGED
@@ -1,2291 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { os } from "@orpc/server";
3
- import { createCli } from "trpc-cli";
4
- import { cancel, confirm, intro, isCancel, log, multiselect, outro, select, spinner, text } from "@clack/prompts";
5
- import fs from "fs-extra";
6
- import path from "node:path";
7
- import { isMap, isScalar, parseDocument } from "yaml";
8
- import Handlebars from "handlebars";
9
- import { existsSync } from "node:fs";
10
- import { fileURLToPath } from "node:url";
11
- import { z } from "zod";
12
- import { execa } from "execa";
13
- import { randomUUID } from "node:crypto";
14
- import os$1 from "node:os";
15
- import { PostHog } from "posthog-node";
16
- import { styleText } from "node:util";
17
- //#region src/utils/regexp.ts
18
- function escapeRegExp(value) {
19
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
20
- }
21
- //#endregion
22
- //#region src/utils/runtime.ts
23
- function usesNodeStyleRuntime(packageManager) {
24
- return packageManager !== void 0 && packageManager !== "bun";
25
- }
26
- function requiresDotenvConfigImport(packageManager) {
27
- return usesNodeStyleRuntime(packageManager);
28
- }
29
- function requiresPrismaConfigDotenvImport(_packageManager) {
30
- return true;
31
- }
32
- //#endregion
33
- //#region src/constants/dependencies.ts
34
- const dependencyVersionMap = {
35
- "@elysiajs/node": "^1.4.5",
36
- "@libsql/client": "^0.17.4",
37
- "@prisma/client": "^7.8.0",
38
- "@prisma/adapter-pg": "^7.8.0",
39
- "@prisma/adapter-libsql": "^7.8.0",
40
- "@prisma/adapter-mariadb": "^7.8.0",
41
- "@prisma/adapter-mssql": "^7.8.0",
42
- "@prisma/composer": "0.6.0",
43
- "@prisma/composer-prisma-cloud": "0.6.0",
44
- "@types/node": "^26.0.0",
45
- arktype: "^2.2.3",
46
- dotenv: "^17.4.2",
47
- effect: "4.0.0-beta.93",
48
- esbuild: "^0.28.2",
49
- prisma: "^7.8.0",
50
- tsx: "^4.22.4"
51
- };
52
- const prismaPlatformCliPackage = "@prisma/cli@next";
53
- function getWorkspaceDependencyVersion(packageManager) {
54
- return packageManager === "npm" ? "*" : "workspace:*";
55
- }
56
- function getCreateTemplateDependencies(template, packageManager) {
57
- const targets = [];
58
- if (template === "hono" || template === "elysia" || template === "nest") {
59
- const runtimeDevDependencies = usesNodeStyleRuntime(packageManager) ? ["tsx"] : [];
60
- if (template === "elysia") targets.push({
61
- packageJsonPath: "package.json",
62
- dependencies: ["@elysiajs/node"],
63
- devDependencies: ["@types/node", ...runtimeDevDependencies]
64
- });
65
- else if (runtimeDevDependencies.length > 0) targets.push({
66
- packageJsonPath: "package.json",
67
- dependencies: [],
68
- devDependencies: runtimeDevDependencies
69
- });
70
- }
71
- if (template === "turborepo") targets.push({
72
- packageJsonPath: "apps/api/package.json",
73
- dependencies: ["dotenv"],
74
- devDependencies: ["tsx"],
75
- customDependencies: { "@repo/db": getWorkspaceDependencyVersion(packageManager) }
76
- });
77
- targets.push({
78
- packageJsonPath: "package.json",
79
- dependencies: [
80
- "@prisma/composer",
81
- "@prisma/composer-prisma-cloud",
82
- "arktype",
83
- "effect",
84
- ...template === "turborepo" ? ["dotenv"] : []
85
- ],
86
- devDependencies: template === "hono" || template === "elysia" || template === "nest" ? ["esbuild"] : []
87
- });
88
- if (template === "turborepo") targets.push({
89
- packageJsonPath: "apps/api/package.json",
90
- dependencies: [],
91
- devDependencies: ["esbuild"]
92
- });
93
- return targets;
94
- }
95
- //#endregion
96
- //#region src/types.ts
97
- const databaseProviders = [
98
- "postgresql",
99
- "mysql",
100
- "sqlite",
101
- "sqlserver",
102
- "cockroachdb"
103
- ];
104
- const packageManagers = [
105
- "npm",
106
- "pnpm",
107
- "yarn",
108
- "bun"
109
- ];
110
- const createTemplates = [
111
- "hono",
112
- "elysia",
113
- "nest",
114
- "next",
115
- "svelte",
116
- "astro",
117
- "nuxt",
118
- "tanstack-start",
119
- "turborepo"
120
- ];
121
- const createAddons = [
122
- "skills",
123
- "mcp",
124
- "extension"
125
- ];
126
- const addonInstallScopes = ["project", "global"];
127
- const extensionTargets = [
128
- "vscode",
129
- "cursor",
130
- "windsurf"
131
- ];
132
- const prismaSkillNames = [
133
- "prisma-cli",
134
- "prisma-client-api",
135
- "prisma-compute",
136
- "prisma-database-setup",
137
- "prisma-upgrade-v7",
138
- "prisma-postgres"
139
- ];
140
- const DatabaseProviderSchema = z.enum(databaseProviders);
141
- const PackageManagerSchema = z.enum(packageManagers);
142
- const CreateTemplateSchema = z.enum(createTemplates);
143
- z.enum(createAddons);
144
- z.enum(addonInstallScopes);
145
- z.enum(extensionTargets);
146
- z.enum(prismaSkillNames);
147
- const CommonCommandOptionsSchema = z.object({
148
- yes: z.boolean().optional().describe("Skip prompts and accept default choices"),
149
- verbose: z.boolean().optional().describe("Show verbose command output during setup")
150
- });
151
- const PrismaSetupOptionsSchema = z.object({
152
- provider: DatabaseProviderSchema.optional().describe("Database provider"),
153
- packageManager: PackageManagerSchema.optional().describe("Package manager used for dependency installation"),
154
- install: z.boolean().optional().describe("Install dependencies with selected package manager")
155
- });
156
- const PrismaSetupCommandInputSchema = CommonCommandOptionsSchema.extend(PrismaSetupOptionsSchema.shape);
157
- const CreateScaffoldOptionsSchema = z.object({
158
- name: z.string().trim().min(1, "Please enter a valid project name").optional().describe("Project name / directory"),
159
- template: CreateTemplateSchema.optional().describe("Project template"),
160
- skills: z.boolean().optional().describe("Enable skills addon"),
161
- mcp: z.boolean().optional().describe("Enable MCP addon"),
162
- extension: z.boolean().optional().describe("Enable extension addon"),
163
- deploy: z.boolean().optional().describe("Deploy the scaffolded project with Prisma Composer"),
164
- force: z.boolean().optional().describe("Allow scaffolding into a non-empty target directory")
165
- });
166
- const CreateCommandInputSchema = PrismaSetupCommandInputSchema.extend(CreateScaffoldOptionsSchema.shape);
167
- //#endregion
168
- //#region src/utils/package-manager.ts
169
- const packageManagerManifestValues = {
170
- npm: "npm@11.17.0",
171
- pnpm: "pnpm@11.8.0",
172
- yarn: "yarn@4.17.0",
173
- bun: "bun@1.3.14"
174
- };
175
- function parseUserAgent(userAgent) {
176
- if (userAgent?.startsWith("pnpm")) return "pnpm";
177
- if (userAgent?.startsWith("yarn")) return "yarn";
178
- if (userAgent?.startsWith("bun")) return "bun";
179
- if (userAgent?.startsWith("npm")) return "npm";
180
- return null;
181
- }
182
- function parsePackageManagerField(packageManagerField) {
183
- if (typeof packageManagerField !== "string" || packageManagerField.length === 0) return null;
184
- const managerName = packageManagerField.split("@")[0];
185
- const parsed = PackageManagerSchema.safeParse(managerName);
186
- return parsed.success ? parsed.data : null;
187
- }
188
- async function detectFromPackageJson(projectDir) {
189
- const packageJsonPath = path.join(projectDir, "package.json");
190
- if (!await fs.pathExists(packageJsonPath)) return null;
191
- return parsePackageManagerField((await fs.readJson(packageJsonPath)).packageManager);
192
- }
193
- async function detectFromLockfile(projectDir) {
194
- for (const check of [
195
- {
196
- manager: "pnpm",
197
- lockfile: "pnpm-lock.yaml"
198
- },
199
- {
200
- manager: "yarn",
201
- lockfile: "yarn.lock"
202
- },
203
- {
204
- manager: "bun",
205
- lockfile: "bun.lockb"
206
- },
207
- {
208
- manager: "bun",
209
- lockfile: "bun.lock"
210
- },
211
- {
212
- manager: "npm",
213
- lockfile: "package-lock.json"
214
- },
215
- {
216
- manager: "npm",
217
- lockfile: "npm-shrinkwrap.json"
218
- }
219
- ]) if (await fs.pathExists(path.join(projectDir, check.lockfile))) return check.manager;
220
- return null;
221
- }
222
- async function detectPackageManager(projectDir = process.cwd()) {
223
- const fromPackageJson = await detectFromPackageJson(projectDir);
224
- if (fromPackageJson) return fromPackageJson;
225
- const fromLockfile = await detectFromLockfile(projectDir);
226
- if (fromLockfile) return fromLockfile;
227
- const fromUserAgent = parseUserAgent(process.env.npm_config_user_agent);
228
- if (fromUserAgent) return fromUserAgent;
229
- return "npm";
230
- }
231
- function getPackageManagerManifestValue(packageManager) {
232
- if (!packageManager) return;
233
- return packageManagerManifestValues[packageManager];
234
- }
235
- function getInstallCommand(packageManager) {
236
- return `${packageManager} install`;
237
- }
238
- function getRunScriptCommand(packageManager, scriptName) {
239
- const { command, args } = getRunScriptArgs(packageManager, scriptName);
240
- return [command, ...args].join(" ");
241
- }
242
- function getRunScriptArgs(packageManager, scriptName) {
243
- switch (packageManager) {
244
- case "bun": return {
245
- command: "bun",
246
- args: ["run", scriptName]
247
- };
248
- case "pnpm": return {
249
- command: "pnpm",
250
- args: ["run", scriptName]
251
- };
252
- case "yarn": return {
253
- command: "yarn",
254
- args: ["run", scriptName]
255
- };
256
- default: return {
257
- command: "npm",
258
- args: ["run", scriptName]
259
- };
260
- }
261
- }
262
- function getRunScriptInDirectoryCommand(packageManager, directory, scriptName) {
263
- switch (packageManager) {
264
- case "bun": return `bun run --cwd ${directory} ${scriptName}`;
265
- case "pnpm": return `pnpm --dir ${directory} run ${scriptName}`;
266
- case "yarn": return `yarn --cwd ${directory} run ${scriptName}`;
267
- default: return `npm --prefix ${directory} run ${scriptName}`;
268
- }
269
- }
270
- function getRuntimeScriptCommand(packageManager, kind, options) {
271
- const { sourceEntrypoint, builtEntrypoint, emit = false } = options;
272
- if (packageManager === "bun") switch (kind) {
273
- case "dev": return `bun --watch ${sourceEntrypoint}`;
274
- case "build": return emit ? "tsc" : "tsc --noEmit";
275
- case "start": return `bun ${sourceEntrypoint}`;
276
- }
277
- switch (kind) {
278
- case "dev": return `tsx watch ${sourceEntrypoint}`;
279
- case "build": return "tsc";
280
- case "start": return builtEntrypoint ? `node ${builtEntrypoint}` : `tsx ${sourceEntrypoint}`;
281
- }
282
- }
283
- function getInstallArgs(packageManager) {
284
- return {
285
- command: packageManager,
286
- args: ["install"]
287
- };
288
- }
289
- function getPackageExecutionArgs(packageManager, commandArgs, options = {}) {
290
- switch (packageManager) {
291
- case "pnpm": return {
292
- command: "pnpm",
293
- args: [
294
- ...options.silent ? ["--silent"] : [],
295
- "dlx",
296
- ...commandArgs
297
- ]
298
- };
299
- case "yarn": return {
300
- command: "yarn",
301
- args: [
302
- "dlx",
303
- ...options.silent ? ["--quiet"] : [],
304
- ...commandArgs
305
- ]
306
- };
307
- case "bun": return {
308
- command: "bunx",
309
- args: [...options.silent ? ["--silent"] : [], ...commandArgs]
310
- };
311
- default: return {
312
- command: "npx",
313
- args: [...options.silent ? ["--yes"] : [], ...commandArgs]
314
- };
315
- }
316
- }
317
- function getPackageExecutionCommand(packageManager, commandArgs, options = {}) {
318
- const execution = getPackageExecutionArgs(packageManager, commandArgs, options);
319
- return [execution.command, ...execution.args].join(" ");
320
- }
321
- function getPrismaCliArgs(packageManager, prismaArgs) {
322
- if (packageManager === "bun") return {
323
- command: "bunx",
324
- args: [
325
- "--bun",
326
- "prisma",
327
- ...prismaArgs
328
- ]
329
- };
330
- if (packageManager === "pnpm") return {
331
- command: "pnpm",
332
- args: [
333
- "exec",
334
- "prisma",
335
- ...prismaArgs
336
- ]
337
- };
338
- if (packageManager === "yarn") return {
339
- command: "yarn",
340
- args: [
341
- "exec",
342
- "prisma",
343
- ...prismaArgs
344
- ]
345
- };
346
- return getPackageExecutionArgs(packageManager, ["prisma", ...prismaArgs]);
347
- }
348
- //#endregion
349
- //#region src/templates/shared.ts
350
- function getSeedCommand(packageManager) {
351
- if (packageManager === "bun") return "bun ./prisma/seed.ts";
352
- return "tsx ./prisma/seed.ts";
353
- }
354
- function getPrismaCommand(packageManager, subcommand) {
355
- return `prisma ${subcommand}`;
356
- }
357
- Handlebars.registerHelper("eq", (left, right) => left === right);
358
- Handlebars.registerHelper("composerPlatformCliInvocation", (packageManager) => packageManager ? JSON.stringify(getPackageExecutionArgs(packageManager, [prismaPlatformCliPackage], { silent: true })) : "{}");
359
- Handlebars.registerHelper("prismaAuthLoginCommand", (packageManager) => packageManager ? getPackageExecutionCommand(packageManager, [
360
- prismaPlatformCliPackage,
361
- "auth",
362
- "login"
363
- ], { silent: true }) : "");
364
- Handlebars.registerHelper("prismaCliInvocation", (packageManager) => packageManager ? JSON.stringify(getPrismaCliArgs(packageManager, [])) : "{}");
365
- Handlebars.registerHelper("runScriptCommand", (packageManager, scriptName) => packageManager ? getRunScriptCommand(packageManager, scriptName) : "");
366
- Handlebars.registerHelper("runScriptInDirectoryCommand", (packageManager, directory, scriptName) => packageManager ? getRunScriptInDirectoryCommand(packageManager, directory, scriptName) : "");
367
- Handlebars.registerHelper("packageManagerManifestValue", (packageManager) => getPackageManagerManifestValue(packageManager) ?? "");
368
- Handlebars.registerHelper("requiresDotenvConfigImport", (packageManager) => requiresDotenvConfigImport(packageManager));
369
- Handlebars.registerHelper("requiresPrismaConfigDotenvImport", (packageManager) => requiresPrismaConfigDotenvImport(packageManager));
370
- Handlebars.registerHelper("sqliteAdapterPackage", () => "@prisma/adapter-libsql");
371
- Handlebars.registerHelper("sqliteAdapterClass", () => "PrismaLibSql");
372
- Handlebars.registerHelper("seedCommand", (packageManager) => getSeedCommand(packageManager));
373
- Handlebars.registerHelper("prismaCommand", (packageManager, subcommand) => getPrismaCommand(packageManager, subcommand));
374
- Handlebars.registerHelper("runtimeScript", (packageManager, kind, sourceEntrypoint, builtEntrypoint, options) => {
375
- if (!packageManager) return "";
376
- const hash = options.hash;
377
- return getRuntimeScriptCommand(packageManager, kind, {
378
- sourceEntrypoint,
379
- builtEntrypoint,
380
- emit: hash.emit === true
381
- });
382
- });
383
- function findPackageRoot(startDir) {
384
- let currentDir = startDir;
385
- while (true) {
386
- if (existsSync(path.join(currentDir, "package.json"))) return currentDir;
387
- const parentDir = path.dirname(currentDir);
388
- if (parentDir === currentDir) break;
389
- currentDir = parentDir;
390
- }
391
- throw new Error(`Unable to locate package root from: ${startDir}`);
392
- }
393
- function resolveTemplatesDir(relativeTemplatesDir) {
394
- const currentFilePath = fileURLToPath(import.meta.url);
395
- const packageRoot = findPackageRoot(path.dirname(currentFilePath));
396
- const templatePath = path.join(packageRoot, relativeTemplatesDir);
397
- if (!existsSync(templatePath)) throw new Error(`Template directory not found at: ${templatePath}`);
398
- return templatePath;
399
- }
400
- async function getTemplateFilesRecursively(dir) {
401
- const entries = await fs.readdir(dir, { withFileTypes: true });
402
- return (await Promise.all(entries.map(async (entry) => {
403
- const entryPath = path.join(dir, entry.name);
404
- if (entry.isDirectory()) return getTemplateFilesRecursively(entryPath);
405
- if (!entry.isFile()) return [];
406
- return [entryPath];
407
- }))).flat();
408
- }
409
- function stripHbsExtension(filePath) {
410
- return filePath.endsWith(".hbs") ? filePath.slice(0, -4) : filePath;
411
- }
412
- function ensureTrailingNewline(content) {
413
- return content.endsWith("\n") ? content : `${content}\n`;
414
- }
415
- async function renderTemplateFile(opts) {
416
- const { templateFilePath, outputPath, context } = opts;
417
- const templateContent = await fs.readFile(templateFilePath, "utf8");
418
- const outputContent = templateFilePath.endsWith(".hbs") ? Handlebars.compile(templateContent, {
419
- noEscape: true,
420
- strict: true
421
- })(context) : templateContent;
422
- if (templateFilePath.endsWith(".hbs") && outputContent.trim().length === 0) return;
423
- await fs.outputFile(outputPath, ensureTrailingNewline(outputContent), "utf8");
424
- }
425
- async function renderTemplateTree(opts) {
426
- const { templateRoot, outputDir, context } = opts;
427
- const templateFiles = await getTemplateFilesRecursively(templateRoot);
428
- for (const templateFilePath of templateFiles) {
429
- const relativeOutputPath = stripHbsExtension(path.relative(templateRoot, templateFilePath));
430
- await renderTemplateFile({
431
- templateFilePath,
432
- outputPath: path.join(outputDir, relativeOutputPath),
433
- context
434
- });
435
- }
436
- }
437
- //#endregion
438
- //#region src/templates/render-create-template.ts
439
- const starterStyleOutputPaths = {
440
- astro: "src/styles.css",
441
- next: "src/app/globals.css",
442
- nuxt: "app/assets/css/main.css",
443
- svelte: "src/app.css",
444
- "tanstack-start": "src/styles.css"
445
- };
446
- function getCreateTemplateDir(template) {
447
- return resolveTemplatesDir(`templates/create/${template}`);
448
- }
449
- function createTemplateContext(projectName, template, provider, packageManager, composerPostgres) {
450
- return {
451
- projectName,
452
- template,
453
- provider,
454
- packageManager,
455
- composerPostgres
456
- };
457
- }
458
- const pnpmAllowedBuilds = [
459
- "@prisma/engines",
460
- "@parcel/watcher",
461
- "esbuild",
462
- "msgpackr-extract",
463
- "prisma",
464
- "sharp",
465
- "unrs-resolver",
466
- "workerd"
467
- ];
468
- const composerEffectOverrides = {
469
- "@effect/platform-bun": "4.0.0-beta.93",
470
- "@effect/platform-node": "4.0.0-beta.93",
471
- "@effect/platform-node-shared": "4.0.0-beta.93",
472
- "@effect/sql-d1": "4.0.0-beta.93",
473
- "@effect/sql-pg": "4.0.0-beta.93",
474
- "@effect/vitest": "4.0.0-beta.93"
475
- };
476
- function renderPnpmAllowBuildLine(packageName) {
477
- return ` ${packageName.startsWith("@") ? JSON.stringify(packageName) : packageName}: true`;
478
- }
479
- function renderPnpmAllowBuilds() {
480
- return ["allowBuilds:", ...pnpmAllowedBuilds.map(renderPnpmAllowBuildLine)].join("\n");
481
- }
482
- function hasPnpmAllowBuild(content, packageName) {
483
- const key = escapeRegExp(packageName);
484
- return new RegExp(`^\\s*["']?${key}["']?\\s*:\\s*true\\s*$`, "m").test(content);
485
- }
486
- function mergePnpmAllowBuilds(content) {
487
- const missingBuilds = pnpmAllowedBuilds.filter((packageName) => !hasPnpmAllowBuild(content, packageName));
488
- if (missingBuilds.length === 0) return content;
489
- const missingLines = missingBuilds.map(renderPnpmAllowBuildLine);
490
- const trimmedContent = content.trimEnd();
491
- const lines = trimmedContent.length > 0 ? trimmedContent.split("\n") : [];
492
- const allowBuildsIndex = lines.findIndex((line) => /^allowBuilds:\s*$/.test(line));
493
- if (allowBuildsIndex === -1) {
494
- const allowBuilds = ["allowBuilds:", ...missingLines].join("\n");
495
- return trimmedContent.length > 0 ? `${trimmedContent}\n\n${allowBuilds}\n` : `${allowBuilds}\n`;
496
- }
497
- lines.splice(allowBuildsIndex + 1, 0, ...missingLines);
498
- return `${lines.join("\n")}\n`;
499
- }
500
- function mergePnpmComposerOverrides(content) {
501
- const document = parseDocument(content);
502
- if (document.errors.length > 0) throw new Error(`Could not update pnpm-workspace.yaml: ${document.errors[0]?.message}`);
503
- if (!document.has("overrides")) document.set("overrides", document.createNode({}));
504
- let overrides = document.get("overrides", true);
505
- if (isScalar(overrides) && overrides.value === null) {
506
- document.set("overrides", document.createNode({}));
507
- overrides = document.get("overrides", true);
508
- }
509
- if (!isMap(overrides)) throw new Error("Could not update pnpm-workspace.yaml: \"overrides\" must be a mapping.");
510
- const missingOverrides = Object.entries(composerEffectOverrides).filter(([packageName]) => !overrides.has(packageName));
511
- if (missingOverrides.length === 0) return content;
512
- for (const [packageName, version] of missingOverrides) overrides.set(packageName, version);
513
- return document.toString();
514
- }
515
- async function ensurePnpmWorkspace(projectDir) {
516
- const workspacePath = path.join(projectDir, "pnpm-workspace.yaml");
517
- if (!await fs.pathExists(workspacePath)) {
518
- const content = mergePnpmComposerOverrides(`${renderPnpmAllowBuilds()}\n`);
519
- await fs.writeFile(workspacePath, content, "utf8");
520
- return;
521
- }
522
- const existingContent = await fs.readFile(workspacePath, "utf8");
523
- const nextContent = mergePnpmComposerOverrides(mergePnpmAllowBuilds(existingContent));
524
- if (nextContent !== existingContent) await fs.writeFile(workspacePath, nextContent, "utf8");
525
- }
526
- async function scaffoldCreateTemplate(opts) {
527
- const { projectDir, projectName, template, provider, packageManager } = opts;
528
- const templateRoot = getCreateTemplateDir(template);
529
- const context = createTemplateContext(projectName, template, provider, packageManager, opts.composerPostgres === true);
530
- await renderTemplateTree({
531
- templateRoot,
532
- outputDir: projectDir,
533
- context
534
- });
535
- const starterStyleOutputPath = starterStyleOutputPaths[template];
536
- if (starterStyleOutputPath) await renderTemplateFile({
537
- templateFilePath: resolveTemplatesDir("templates/shared/starter.css"),
538
- outputPath: path.join(projectDir, starterStyleOutputPath),
539
- context
540
- });
541
- if (context.composerPostgres) await renderTemplateFile({
542
- templateFilePath: resolveTemplatesDir("templates/shared/setup-composer-postgres.mjs.hbs"),
543
- outputPath: path.join(projectDir, "scripts/setup-composer-postgres.mjs"),
544
- context
545
- });
546
- if (packageManager === "pnpm") await ensurePnpmWorkspace(projectDir);
547
- }
548
- //#endregion
549
- //#region src/constants/db-packages.ts
550
- function getDbPackages(provider, _packageManager) {
551
- switch (provider) {
552
- case "postgresql":
553
- case "cockroachdb": return "@prisma/adapter-pg";
554
- case "mysql": return "@prisma/adapter-mariadb";
555
- case "sqlite": return "@prisma/adapter-libsql";
556
- case "sqlserver": return "@prisma/adapter-mssql";
557
- default: throw new Error(`Unsupported database provider: ${String(provider)}`);
558
- }
559
- }
560
- //#endregion
561
- //#region src/tasks/install.ts
562
- function getPrismaScriptMap() {
563
- return {
564
- "db:generate": "prisma generate",
565
- "db:push": "prisma db push",
566
- "db:migrate": "prisma migrate dev",
567
- "db:migrate:deploy": "prisma migrate deploy",
568
- "db:seed": "prisma db seed"
569
- };
570
- }
571
- function getVersion(packageName) {
572
- return dependencyVersionMap[packageName];
573
- }
574
- function unique(items) {
575
- return [...new Set(items)];
576
- }
577
- function sortRecord(record) {
578
- return Object.fromEntries(Object.entries(record).sort(([a], [b]) => a.localeCompare(b)));
579
- }
580
- async function projectContainsText(projectDir, text) {
581
- const directories = [projectDir];
582
- while (directories.length > 0) {
583
- const currentDirectory = directories.pop();
584
- if (!currentDirectory) continue;
585
- const entries = await fs.readdir(currentDirectory, { withFileTypes: true });
586
- for (const entry of entries) {
587
- if (entry.name === "node_modules" || entry.name === ".git") continue;
588
- const entryPath = path.join(currentDirectory, entry.name);
589
- if (entry.isDirectory()) {
590
- directories.push(entryPath);
591
- continue;
592
- }
593
- if (!entry.isFile() || !/\.(c|m)?[jt]sx?$/.test(entry.name)) continue;
594
- if ((await fs.readFile(entryPath, "utf8")).includes(text)) return true;
595
- }
596
- }
597
- return false;
598
- }
599
- async function addPackageDependency(opts) {
600
- const { dependencies = [], devDependencies = [], customDependencies = {}, scripts = {}, scriptMode, projectDir } = opts;
601
- const pkgJsonPath = path.join(projectDir, "package.json");
602
- if (!await fs.pathExists(pkgJsonPath)) throw new Error(`No package.json found in ${projectDir}. Run this command inside an existing JavaScript/TypeScript project.`);
603
- const pkgJson = await fs.readJson(pkgJsonPath);
604
- if (!pkgJson.dependencies) pkgJson.dependencies = {};
605
- if (!pkgJson.devDependencies) pkgJson.devDependencies = {};
606
- if (!pkgJson.scripts) pkgJson.scripts = {};
607
- for (const pkgName of unique(dependencies)) {
608
- const version = getVersion(pkgName);
609
- if (version) pkgJson.dependencies[pkgName] = version;
610
- else console.warn(`Warning: Dependency ${pkgName} not found in version map.`);
611
- }
612
- for (const pkgName of unique(devDependencies)) {
613
- const version = getVersion(pkgName);
614
- if (version) pkgJson.devDependencies[pkgName] = version;
615
- else console.warn(`Warning: Dev dependency ${pkgName} not found in version map.`);
616
- }
617
- for (const [pkgName, version] of Object.entries(customDependencies)) pkgJson.dependencies[pkgName] = version;
618
- for (const [scriptName, command] of Object.entries(scripts)) {
619
- if (scriptMode === "if-missing") {
620
- if (typeof pkgJson.scripts[scriptName] !== "string" || pkgJson.scripts[scriptName].trim().length === 0) pkgJson.scripts[scriptName] = command;
621
- continue;
622
- }
623
- pkgJson.scripts[scriptName] = command;
624
- }
625
- pkgJson.dependencies = sortRecord(pkgJson.dependencies);
626
- pkgJson.devDependencies = sortRecord(pkgJson.devDependencies);
627
- await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
628
- }
629
- async function writePrismaDependencies(provider, packageManager, projectDir = process.cwd()) {
630
- const dependencies = ["@prisma/client"];
631
- const devDependencies = ["prisma"];
632
- dependencies.push(getDbPackages(provider, packageManager));
633
- if (provider === "sqlite") dependencies.push("@libsql/client");
634
- if (requiresDotenvConfigImport(packageManager) || await projectContainsText(projectDir, "dotenv/config")) dependencies.push("dotenv");
635
- await addPackageDependency({
636
- dependencies,
637
- devDependencies,
638
- scripts: getPrismaScriptMap(),
639
- scriptMode: "if-missing",
640
- projectDir
641
- });
642
- }
643
- async function writeCreateTemplateDependencies(opts) {
644
- const { template, packageManager, projectDir = process.cwd() } = opts;
645
- const targets = getCreateTemplateDependencies(template, packageManager);
646
- for (const dependencyTarget of targets) {
647
- const targetDirectory = path.join(projectDir, path.dirname(dependencyTarget.packageJsonPath));
648
- await addPackageDependency({
649
- dependencies: dependencyTarget.dependencies,
650
- devDependencies: dependencyTarget.devDependencies,
651
- customDependencies: dependencyTarget.customDependencies,
652
- projectDir: targetDirectory
653
- });
654
- }
655
- const packageJsonPath = path.join(projectDir, "package.json");
656
- const pkgJson = await fs.readJson(packageJsonPath);
657
- const effectVersions = {
658
- "@effect/platform-bun": "4.0.0-beta.93",
659
- "@effect/platform-node": "4.0.0-beta.93",
660
- "@effect/platform-node-shared": "4.0.0-beta.93",
661
- "@effect/sql-d1": "4.0.0-beta.93",
662
- "@effect/sql-pg": "4.0.0-beta.93",
663
- "@effect/vitest": "4.0.0-beta.93"
664
- };
665
- if (packageManager === "yarn") pkgJson.resolutions = {
666
- ...pkgJson.resolutions ?? {},
667
- ...effectVersions
668
- };
669
- else if (packageManager !== "pnpm") pkgJson.overrides = {
670
- ...pkgJson.overrides ?? {},
671
- ...effectVersions
672
- };
673
- pkgJson.engines = {
674
- ...pkgJson.engines ?? {},
675
- node: ">=24"
676
- };
677
- await fs.writeJson(packageJsonPath, pkgJson, { spaces: 2 });
678
- }
679
- async function installProjectDependencies(packageManager, projectDir = process.cwd(), options = {}) {
680
- const verbose = options.verbose === true;
681
- const installCommand = getInstallArgs(packageManager);
682
- const env = packageManager === "yarn" ? {
683
- ...process.env,
684
- YARN_ENABLE_IMMUTABLE_INSTALLS: "false"
685
- } : void 0;
686
- await execa(installCommand.command, installCommand.args, {
687
- cwd: projectDir,
688
- env,
689
- stdio: verbose ? "inherit" : "pipe"
690
- });
691
- }
692
- //#endregion
693
- //#region src/tasks/setup-prisma.ts
694
- const DEFAULT_DATABASE_PROVIDER = "postgresql";
695
- const DEFAULT_INSTALL = true;
696
- const INITIAL_MIGRATION_NAME = "00000000000000_init";
697
- const requiredPrismaFileGroups = [
698
- ["prisma/schema.prisma", "packages/db/prisma/schema.prisma"],
699
- ["prisma/seed.ts", "packages/db/prisma/seed.ts"],
700
- ["prisma.config.ts", "packages/db/prisma.config.ts"],
701
- [
702
- "src/lib/prisma.ts",
703
- "src/lib/prisma.server.ts",
704
- "src/lib/server/prisma.ts",
705
- "server/utils/prisma.ts",
706
- "packages/db/src/client.ts"
707
- ]
708
- ];
709
- async function resolvePrismaProjectDir(projectDir) {
710
- const monorepoDbDir = path.join(projectDir, "packages/db");
711
- if (await fs.pathExists(path.join(monorepoDbDir, "prisma/schema.prisma"))) return monorepoDbDir;
712
- return projectDir;
713
- }
714
- async function promptForDatabaseProvider() {
715
- const databaseProvider = await select({
716
- message: "Select your database",
717
- initialValue: DEFAULT_DATABASE_PROVIDER,
718
- options: [
719
- {
720
- value: "postgresql",
721
- label: "PostgreSQL",
722
- hint: "Default"
723
- },
724
- {
725
- value: "mysql",
726
- label: "MySQL"
727
- },
728
- {
729
- value: "sqlite",
730
- label: "SQLite"
731
- },
732
- {
733
- value: "sqlserver",
734
- label: "SQL Server"
735
- },
736
- {
737
- value: "cockroachdb",
738
- label: "CockroachDB"
739
- }
740
- ]
741
- });
742
- if (isCancel(databaseProvider)) {
743
- cancel("Operation cancelled.");
744
- return;
745
- }
746
- return DatabaseProviderSchema.parse(databaseProvider);
747
- }
748
- function getPackageManagerHint(option, detected) {
749
- if (option === detected) return "Detected";
750
- if (option === "bun") return "Fast runtime + package manager";
751
- }
752
- async function promptForPackageManager(detectedPackageManager) {
753
- const packageManager = await select({
754
- message: "Choose package manager",
755
- initialValue: detectedPackageManager,
756
- options: [
757
- {
758
- value: "npm",
759
- label: "npm",
760
- hint: getPackageManagerHint("npm", detectedPackageManager)
761
- },
762
- {
763
- value: "pnpm",
764
- label: "pnpm",
765
- hint: getPackageManagerHint("pnpm", detectedPackageManager)
766
- },
767
- {
768
- value: "yarn",
769
- label: "yarn",
770
- hint: getPackageManagerHint("yarn", detectedPackageManager)
771
- },
772
- {
773
- value: "bun",
774
- label: "bun",
775
- hint: getPackageManagerHint("bun", detectedPackageManager)
776
- }
777
- ]
778
- });
779
- if (isCancel(packageManager)) {
780
- cancel("Operation cancelled.");
781
- return;
782
- }
783
- return PackageManagerSchema.parse(packageManager);
784
- }
785
- async function promptForDependencyInstall(packageManager) {
786
- const shouldInstall = await confirm({
787
- message: `Install dependencies now with ${getInstallCommand(packageManager)}?`,
788
- initialValue: true
789
- });
790
- if (isCancel(shouldInstall)) {
791
- cancel("Operation cancelled.");
792
- return;
793
- }
794
- return Boolean(shouldInstall);
795
- }
796
- function getCommandErrorMessage(error) {
797
- if (error instanceof Error && "stderr" in error) {
798
- const stderr = String(error.stderr ?? "").trim();
799
- if (stderr.length > 0) return stderr;
800
- }
801
- return error instanceof Error ? error.message : String(error);
802
- }
803
- async function collectPrismaSetupInitialContext(input, options = {}) {
804
- const projectDir = path.resolve(options.projectDir ?? process.cwd());
805
- const useDefaults = input.yes === true;
806
- const verbose = input.verbose === true;
807
- const databaseProvider = input.provider ?? (useDefaults ? DEFAULT_DATABASE_PROVIDER : await promptForDatabaseProvider());
808
- if (!databaseProvider) return;
809
- const databaseUrl = (process.env.DATABASE_URL ?? "").trim() || void 0;
810
- const detectedPackageManager = await detectPackageManager(projectDir);
811
- const packageManager = input.packageManager ?? (useDefaults ? detectedPackageManager : await promptForPackageManager(detectedPackageManager));
812
- if (!packageManager) return;
813
- const shouldInstall = input.install ?? (useDefaults ? DEFAULT_INSTALL : await promptForDependencyInstall(packageManager));
814
- if (shouldInstall === void 0) return;
815
- return {
816
- projectDir,
817
- verbose,
818
- databaseProvider,
819
- databaseUrl,
820
- packageManager,
821
- shouldInstall
822
- };
823
- }
824
- async function completePrismaSetupContext(context, options = {}) {
825
- const shouldUsePrismaPostgres = context.databaseProvider === "postgresql";
826
- return {
827
- ...context,
828
- shouldUsePrismaPostgres,
829
- shouldMigrateAndSeed: options.shouldMigrateAndSeed === true
830
- };
831
- }
832
- function getDefaultDatabaseUrl(provider) {
833
- switch (provider) {
834
- case "postgresql": return "postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public";
835
- case "cockroachdb": return "postgresql://johndoe:randompassword@localhost:26257/mydb?schema=public";
836
- case "mysql": return "mysql://johndoe:randompassword@localhost:3306/mydb";
837
- case "sqlite": return "file:./dev.db";
838
- case "sqlserver": return "sqlserver://localhost:1433;database=mydb;user=SA;password=randompassword;";
839
- default: throw new Error(`Unsupported provider: ${String(provider)}`);
840
- }
841
- }
842
- function hasGitignoreEntry(content, entry) {
843
- const escapedEntry = escapeRegExp(entry);
844
- const escapedWithLeadingSlash = escapeRegExp(`/${entry}`);
845
- const escapedWithTrailingSlash = escapeRegExp(`${entry}/`);
846
- const escapedWithLeadingAndTrailingSlash = escapeRegExp(`/${entry}/`);
847
- return new RegExp(`(^|\\n)\\s*(?:${escapedEntry}|${escapedWithLeadingSlash}|${escapedWithTrailingSlash}|${escapedWithLeadingAndTrailingSlash})\\s*(?=\\n|$)`).test(content);
848
- }
849
- async function ensureGitignoreEntry(projectDir, entry) {
850
- const gitignorePath = path.join(projectDir, ".gitignore");
851
- if (!await fs.pathExists(gitignorePath)) {
852
- await fs.writeFile(gitignorePath, `${entry}\n`, "utf8");
853
- return;
854
- }
855
- const existingContent = await fs.readFile(gitignorePath, "utf8");
856
- if (hasGitignoreEntry(existingContent, entry)) return;
857
- const separator = existingContent.endsWith("\n") ? "" : "\n";
858
- await fs.appendFile(gitignorePath, `${separator}${entry}\n`, "utf8");
859
- }
860
- async function ensureRequiredPrismaFiles(projectDir) {
861
- const missingFiles = [];
862
- for (const candidates of requiredPrismaFileGroups) {
863
- let foundCandidate = false;
864
- for (const relativePath of candidates) {
865
- const absolutePath = path.join(projectDir, relativePath);
866
- if (await fs.pathExists(absolutePath)) {
867
- foundCandidate = true;
868
- break;
869
- }
870
- }
871
- if (!foundCandidate) missingFiles.push(candidates.join(" or "));
872
- }
873
- if (missingFiles.length > 0) throw new Error(`Template is missing required Prisma files: ${missingFiles.join(", ")}`);
874
- }
875
- async function finalizePrismaFiles(options) {
876
- const projectDir = options.projectDir ?? process.cwd();
877
- const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
878
- await ensureRequiredPrismaFiles(projectDir);
879
- const generatedDir = await fs.pathExists(path.join(prismaProjectDir, "server/utils/prisma.ts")) ? "server/generated" : "src/generated";
880
- if (options.provider !== "postgresql") {
881
- const envExamplePath = path.join(prismaProjectDir, ".env.example");
882
- if (!await fs.pathExists(envExamplePath)) await fs.writeFile(envExamplePath, `# Copy this file to .env and replace the value before deploying.\nDATABASE_URL="${getDefaultDatabaseUrl(options.provider)}"\n`, "utf8");
883
- }
884
- await ensureGitignoreEntry(prismaProjectDir, generatedDir);
885
- }
886
- async function writeDependenciesForContext(context, projectDir) {
887
- const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
888
- try {
889
- await writePrismaDependencies(context.databaseProvider, context.packageManager, prismaProjectDir);
890
- return true;
891
- } catch (error) {
892
- cancel(getCommandErrorMessage(error));
893
- return false;
894
- }
895
- }
896
- async function installDependenciesForContext(context, projectDir) {
897
- if (!context.shouldInstall) return true;
898
- const installCommand = getInstallCommand(context.packageManager);
899
- if (context.verbose) {
900
- log.step(`Running ${installCommand}`);
901
- try {
902
- await installProjectDependencies(context.packageManager, projectDir, { verbose: context.verbose });
903
- log.success("Dependencies installed.");
904
- return true;
905
- } catch (error) {
906
- cancel(`Failed to run ${installCommand}: ${getCommandErrorMessage(error)}`);
907
- return false;
908
- }
909
- }
910
- const installSpinner = spinner();
911
- installSpinner.start(`Running ${installCommand}...`);
912
- try {
913
- await installProjectDependencies(context.packageManager, projectDir, { verbose: context.verbose });
914
- installSpinner.stop("Dependencies installed.");
915
- return true;
916
- } catch (error) {
917
- installSpinner.stop("Could not install dependencies.");
918
- cancel(`Failed to run ${installCommand}: ${getCommandErrorMessage(error)}`);
919
- return false;
920
- }
921
- }
922
- async function finalizePrismaFilesForContext(context, projectDir) {
923
- const initSpinner = spinner();
924
- initSpinner.start("Preparing Prisma files...");
925
- try {
926
- await finalizePrismaFiles({
927
- provider: context.databaseProvider,
928
- projectDir
929
- });
930
- initSpinner.stop("Prisma files ready.");
931
- return true;
932
- } catch (error) {
933
- initSpinner.stop("Could not prepare Prisma files.");
934
- cancel(getCommandErrorMessage(error));
935
- return false;
936
- }
937
- }
938
- async function generatePrismaClientForContext(context, projectDir) {
939
- const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
940
- const generateCommand = getRunScriptCommand(context.packageManager, "db:generate");
941
- if (context.verbose) log.step(`Running ${generateCommand}`);
942
- const generateSpinner = context.verbose ? void 0 : spinner();
943
- generateSpinner?.start("Generating Prisma Client...");
944
- try {
945
- const generateArgs = getRunScriptArgs(context.packageManager, "db:generate");
946
- await execa(generateArgs.command, generateArgs.args, {
947
- cwd: prismaProjectDir,
948
- env: {
949
- ...process.env,
950
- DATABASE_URL: context.databaseUrl ?? getDefaultDatabaseUrl(context.databaseProvider)
951
- },
952
- stdio: context.verbose ? "inherit" : "pipe"
953
- });
954
- if (context.verbose) log.success("Prisma Client generated.");
955
- else generateSpinner?.stop("Prisma Client generated.");
956
- return { didGenerateClient: true };
957
- } catch (error) {
958
- if (context.verbose) log.warn("Could not generate Prisma Client.");
959
- else generateSpinner?.stop("Could not generate Prisma Client.");
960
- return {
961
- didGenerateClient: false,
962
- warning: `Prisma generate failed: ${getCommandErrorMessage(error)}`
963
- };
964
- }
965
- }
966
- async function generateInitialMigrationForContext(context, projectDir) {
967
- const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
968
- const migrationsDir = path.join(prismaProjectDir, "prisma/migrations");
969
- if (await fs.pathExists(migrationsDir)) {
970
- if ((await fs.readdir(migrationsDir, { withFileTypes: true })).some((entry) => entry.isDirectory())) return { didGenerateMigration: true };
971
- }
972
- if (!context.shouldInstall) return { didGenerateMigration: false };
973
- const migrationDir = path.join(migrationsDir, INITIAL_MIGRATION_NAME);
974
- const migrationFile = path.join(migrationDir, "migration.sql");
975
- const migrationInvocation = getPrismaCliArgs(context.packageManager, [
976
- "migrate",
977
- "diff",
978
- "--from-empty",
979
- "--to-schema",
980
- "prisma/schema.prisma",
981
- "--script",
982
- "--output",
983
- migrationFile
984
- ]);
985
- const migrationSpinner = context.verbose ? void 0 : spinner();
986
- migrationSpinner?.start("Generating initial migration...");
987
- try {
988
- await fs.ensureDir(migrationDir);
989
- await execa(migrationInvocation.command, migrationInvocation.args, {
990
- cwd: prismaProjectDir,
991
- env: {
992
- ...process.env,
993
- DATABASE_URL: context.databaseUrl ?? getDefaultDatabaseUrl(context.databaseProvider)
994
- },
995
- stdio: context.verbose ? "inherit" : "pipe"
996
- });
997
- await fs.writeFile(path.join(migrationsDir, "migration_lock.toml"), `# Please do not edit this file manually\nprovider = "${context.databaseProvider}"\n`, "utf8");
998
- if (context.verbose) log.success("Initial migration generated.");
999
- else migrationSpinner?.stop("Initial migration generated.");
1000
- return { didGenerateMigration: true };
1001
- } catch (error) {
1002
- await fs.remove(migrationDir);
1003
- if (context.verbose) log.warn("Could not generate the initial migration.");
1004
- else migrationSpinner?.stop("Could not generate the initial migration.");
1005
- return {
1006
- didGenerateMigration: false,
1007
- warning: `Initial migration generation failed: ${getCommandErrorMessage(error)}`
1008
- };
1009
- }
1010
- }
1011
- function buildWarningLines(generateWarning, migrationGenerationWarning, migrateAndSeedWarning) {
1012
- const warningLines = [];
1013
- if (generateWarning) warningLines.push(`- ${generateWarning}`);
1014
- if (migrationGenerationWarning) warningLines.push(`- ${migrationGenerationWarning}`);
1015
- if (migrateAndSeedWarning) warningLines.push(`- ${migrateAndSeedWarning}`);
1016
- return warningLines;
1017
- }
1018
- function buildNextStepsForContext(opts) {
1019
- const { context, options, didGenerateClient, didMigrate, didSeed } = opts;
1020
- const nextSteps = [...options.prependNextSteps ?? []];
1021
- if (!context.shouldInstall) nextSteps.push(`- ${getInstallCommand(context.packageManager)}`);
1022
- if (!didGenerateClient) nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "db:generate")}`);
1023
- if (options.includeMigrationAndSeedNextSteps !== false && !didMigrate) nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "db:migrate")}`);
1024
- if (options.includeMigrationAndSeedNextSteps !== false && !didSeed) nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "db:seed")}`);
1025
- if (options.includeDevNextStep) nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "dev")}`);
1026
- return nextSteps;
1027
- }
1028
- async function executePrismaSetupContext(context, options = {}) {
1029
- const projectDir = path.resolve(options.projectDir ?? context.projectDir);
1030
- if (!await writeDependenciesForContext(context, projectDir)) return { ok: false };
1031
- if (!await installDependenciesForContext(context, projectDir)) return { ok: false };
1032
- if (!await finalizePrismaFilesForContext(context, projectDir)) return { ok: false };
1033
- const generateResult = await generatePrismaClientForContext(context, projectDir);
1034
- const migrationGenerationResult = await generateInitialMigrationForContext(context, projectDir);
1035
- const migrateAndSeedResult = await migrateAndSeedIfRequested(context, projectDir, {
1036
- databaseUrl: context.databaseUrl,
1037
- didGenerateClient: generateResult.didGenerateClient
1038
- });
1039
- const warningLines = buildWarningLines(generateResult.warning, migrationGenerationResult.warning, migrateAndSeedResult.warning);
1040
- return {
1041
- ok: true,
1042
- nextSteps: buildNextStepsForContext({
1043
- context,
1044
- options,
1045
- didGenerateClient: generateResult.didGenerateClient,
1046
- didMigrate: migrateAndSeedResult.didMigrate,
1047
- didSeed: migrateAndSeedResult.didSeed
1048
- }),
1049
- warningSection: warningLines.length > 0 ? `\n\n${warningLines.join("\n")}` : "",
1050
- didGenerateClient: generateResult.didGenerateClient,
1051
- didGenerateMigration: migrationGenerationResult.didGenerateMigration
1052
- };
1053
- }
1054
- async function migrateAndSeedIfRequested(context, projectDir, options) {
1055
- const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
1056
- if (!context.shouldMigrateAndSeed) return {
1057
- didMigrate: false,
1058
- didSeed: false
1059
- };
1060
- if (!options.didGenerateClient) return {
1061
- didMigrate: false,
1062
- didSeed: false,
1063
- warning: "Skipped migrate + seed because the Prisma Client was not generated."
1064
- };
1065
- if (!options.databaseUrl) return {
1066
- didMigrate: false,
1067
- didSeed: false,
1068
- warning: "Skipped migrate + seed because no DATABASE_URL is available."
1069
- };
1070
- const migrateInvocation = getPrismaCliArgs(context.packageManager, ["migrate", "deploy"]);
1071
- const seedInvocation = getPrismaCliArgs(context.packageManager, ["db", "seed"]);
1072
- const migrateSpinner = spinner();
1073
- migrateSpinner.start("Applying migrations...");
1074
- let didMigrate = false;
1075
- try {
1076
- await execa(migrateInvocation.command, migrateInvocation.args, {
1077
- cwd: prismaProjectDir,
1078
- env: {
1079
- ...process.env,
1080
- DATABASE_URL: options.databaseUrl
1081
- },
1082
- stdio: context.verbose ? "inherit" : "pipe"
1083
- });
1084
- migrateSpinner.stop("Migrations applied.");
1085
- didMigrate = true;
1086
- } catch (error) {
1087
- migrateSpinner.stop(`Migration failed${error instanceof Error ? `: ${error.message}` : "."}`);
1088
- return {
1089
- didMigrate: false,
1090
- didSeed: false,
1091
- warning: `Migration failed; run \`${getRunScriptCommand(context.packageManager, "db:migrate:deploy")}\` manually.`
1092
- };
1093
- }
1094
- const seedSpinner = spinner();
1095
- seedSpinner.start("Seeding database...");
1096
- let didSeed = false;
1097
- try {
1098
- await execa(seedInvocation.command, seedInvocation.args, {
1099
- cwd: prismaProjectDir,
1100
- env: {
1101
- ...process.env,
1102
- DATABASE_URL: options.databaseUrl
1103
- },
1104
- stdio: context.verbose ? "inherit" : "pipe"
1105
- });
1106
- seedSpinner.stop("Database seeded.");
1107
- didSeed = true;
1108
- } catch (error) {
1109
- seedSpinner.stop(`Seed failed${error instanceof Error ? `: ${error.message}` : "."}`);
1110
- return {
1111
- didMigrate,
1112
- didSeed: false,
1113
- warning: `Seed failed; run \`${getRunScriptCommand(context.packageManager, "db:seed")}\` manually.`
1114
- };
1115
- }
1116
- return {
1117
- didMigrate,
1118
- didSeed
1119
- };
1120
- }
1121
- //#endregion
1122
- //#region src/tasks/setup-addons.ts
1123
- const DEFAULT_ADDON_SCOPE = "project";
1124
- const DEFAULT_SKILLS_AGENTS = [
1125
- "claude-code",
1126
- "codex",
1127
- "cursor"
1128
- ];
1129
- const DEFAULT_MCP_AGENTS = [
1130
- "claude-code",
1131
- "codex",
1132
- "cursor"
1133
- ];
1134
- const DEFAULT_EXTENSION_TARGETS = ["vscode", "cursor"];
1135
- const PRISMA_MCP_SERVER = "https://mcp.prisma.io/mcp";
1136
- const ADDON_OPTIONS = [
1137
- {
1138
- value: "skills",
1139
- label: "Skills",
1140
- hint: "Install curated Prisma skills to your selected coding agents"
1141
- },
1142
- {
1143
- value: "mcp",
1144
- label: "MCP",
1145
- hint: "Configure Prisma MCP server in agent MCP config files"
1146
- },
1147
- {
1148
- value: "extension",
1149
- label: "IDE Extension",
1150
- hint: "Install Prisma extension in selected IDEs (VS Code, Cursor, Windsurf)"
1151
- }
1152
- ];
1153
- const SKILLS_AGENT_OPTIONS = [
1154
- {
1155
- value: "cursor",
1156
- label: "Cursor"
1157
- },
1158
- {
1159
- value: "claude-code",
1160
- label: "Claude Code"
1161
- },
1162
- {
1163
- value: "cline",
1164
- label: "Cline"
1165
- },
1166
- {
1167
- value: "github-copilot",
1168
- label: "GitHub Copilot"
1169
- },
1170
- {
1171
- value: "codex",
1172
- label: "Codex"
1173
- },
1174
- {
1175
- value: "opencode",
1176
- label: "OpenCode"
1177
- },
1178
- {
1179
- value: "windsurf",
1180
- label: "Windsurf"
1181
- },
1182
- {
1183
- value: "goose",
1184
- label: "Goose"
1185
- },
1186
- {
1187
- value: "roo",
1188
- label: "Roo Code"
1189
- },
1190
- {
1191
- value: "kilo",
1192
- label: "Kilo Code"
1193
- },
1194
- {
1195
- value: "gemini-cli",
1196
- label: "Gemini CLI"
1197
- },
1198
- {
1199
- value: "antigravity",
1200
- label: "Antigravity"
1201
- },
1202
- {
1203
- value: "openhands",
1204
- label: "OpenHands"
1205
- },
1206
- {
1207
- value: "trae",
1208
- label: "Trae"
1209
- },
1210
- {
1211
- value: "amp",
1212
- label: "Amp"
1213
- },
1214
- {
1215
- value: "pi",
1216
- label: "Pi"
1217
- },
1218
- {
1219
- value: "qoder",
1220
- label: "Qoder"
1221
- },
1222
- {
1223
- value: "qwen-code",
1224
- label: "Qwen Code"
1225
- },
1226
- {
1227
- value: "kiro-cli",
1228
- label: "Kiro CLI"
1229
- },
1230
- {
1231
- value: "droid",
1232
- label: "Droid"
1233
- },
1234
- {
1235
- value: "command-code",
1236
- label: "Command Code"
1237
- },
1238
- {
1239
- value: "clawdbot",
1240
- label: "Clawdbot"
1241
- },
1242
- {
1243
- value: "zencoder",
1244
- label: "Zencoder"
1245
- },
1246
- {
1247
- value: "neovate",
1248
- label: "Neovate"
1249
- },
1250
- {
1251
- value: "mcpjam",
1252
- label: "MCPJam"
1253
- }
1254
- ];
1255
- const MCP_AGENT_OPTIONS = [
1256
- {
1257
- value: "claude-code",
1258
- label: "Claude Code"
1259
- },
1260
- {
1261
- value: "codex",
1262
- label: "Codex"
1263
- },
1264
- {
1265
- value: "cursor",
1266
- label: "Cursor"
1267
- },
1268
- {
1269
- value: "vscode",
1270
- label: "VS Code"
1271
- },
1272
- {
1273
- value: "github-copilot-cli",
1274
- label: "GitHub Copilot CLI"
1275
- },
1276
- {
1277
- value: "opencode",
1278
- label: "OpenCode"
1279
- },
1280
- {
1281
- value: "gemini-cli",
1282
- label: "Gemini CLI"
1283
- },
1284
- {
1285
- value: "goose",
1286
- label: "Goose"
1287
- },
1288
- {
1289
- value: "zed",
1290
- label: "Zed"
1291
- },
1292
- {
1293
- value: "antigravity",
1294
- label: "Antigravity"
1295
- },
1296
- {
1297
- value: "cline",
1298
- label: "Cline VS Code Extension"
1299
- },
1300
- {
1301
- value: "cline-cli",
1302
- label: "Cline CLI"
1303
- },
1304
- {
1305
- value: "claude-desktop",
1306
- label: "Claude Desktop"
1307
- },
1308
- {
1309
- value: "mcporter",
1310
- label: "MCPorter"
1311
- }
1312
- ];
1313
- const SHARED_PRISMA_SKILLS = [
1314
- "prisma-cli",
1315
- "prisma-client-api",
1316
- "prisma-database-setup",
1317
- "prisma-upgrade-v7"
1318
- ];
1319
- function getAvailablePrismaSkills(provider) {
1320
- const skills = [...SHARED_PRISMA_SKILLS, "prisma-compute"];
1321
- if (provider === "postgresql") return [...skills, "prisma-postgres"];
1322
- return skills;
1323
- }
1324
- function getSkillOptions(provider) {
1325
- const available = getAvailablePrismaSkills(provider);
1326
- const options = {
1327
- "prisma-cli": {
1328
- value: "prisma-cli",
1329
- label: "prisma-cli",
1330
- hint: "Prisma CLI reference"
1331
- },
1332
- "prisma-client-api": {
1333
- value: "prisma-client-api",
1334
- label: "prisma-client-api",
1335
- hint: "Prisma Client query patterns"
1336
- },
1337
- "prisma-compute": {
1338
- value: "prisma-compute",
1339
- label: "prisma-compute",
1340
- hint: "Prisma Compute deploy and hosting workflows"
1341
- },
1342
- "prisma-database-setup": {
1343
- value: "prisma-database-setup",
1344
- label: "prisma-database-setup",
1345
- hint: "Database provider setup guides"
1346
- },
1347
- "prisma-upgrade-v7": {
1348
- value: "prisma-upgrade-v7",
1349
- label: "prisma-upgrade-v7",
1350
- hint: "v6 to v7 migration guide"
1351
- },
1352
- "prisma-postgres": {
1353
- value: "prisma-postgres",
1354
- label: "prisma-postgres",
1355
- hint: "Prisma Postgres workflows"
1356
- }
1357
- };
1358
- return available.map((skill) => options[skill]);
1359
- }
1360
- function collectAddonsFromInput(input) {
1361
- const addons = [];
1362
- if (input.skills === true) addons.push("skills");
1363
- if (input.mcp === true) addons.push("mcp");
1364
- if (input.extension === true) addons.push("extension");
1365
- return uniqueValues(addons);
1366
- }
1367
- const EXTENSION_TARGET_OPTIONS = [
1368
- {
1369
- value: "vscode",
1370
- label: "VS Code",
1371
- hint: "Uses the `code` CLI"
1372
- },
1373
- {
1374
- value: "cursor",
1375
- label: "Cursor",
1376
- hint: "Uses the `cursor` CLI"
1377
- },
1378
- {
1379
- value: "windsurf",
1380
- label: "Windsurf",
1381
- hint: "Uses the `windsurf` CLI"
1382
- }
1383
- ];
1384
- function uniqueValues(values) {
1385
- return Array.from(new Set(values));
1386
- }
1387
- function getRecommendedPrismaSkills(provider, shouldUsePrismaPostgres) {
1388
- const skills = [...SHARED_PRISMA_SKILLS];
1389
- if (provider === "postgresql" && shouldUsePrismaPostgres) skills.push("prisma-postgres");
1390
- return uniqueValues(skills);
1391
- }
1392
- async function promptForAddons() {
1393
- const selectedAddons = await multiselect({
1394
- message: "Select add-ons (optional)",
1395
- options: ADDON_OPTIONS,
1396
- required: false
1397
- });
1398
- if (isCancel(selectedAddons)) {
1399
- cancel("Operation cancelled.");
1400
- return;
1401
- }
1402
- return uniqueValues(selectedAddons);
1403
- }
1404
- async function promptForAddonScope() {
1405
- const selectedScope = await select({
1406
- message: "Where should add-ons write config?",
1407
- initialValue: DEFAULT_ADDON_SCOPE,
1408
- options: [{
1409
- value: "project",
1410
- label: "Project",
1411
- hint: "Recommended for teams (checked into the project when applicable)"
1412
- }, {
1413
- value: "global",
1414
- label: "Global",
1415
- hint: "Personal machine-level setup"
1416
- }]
1417
- });
1418
- if (isCancel(selectedScope)) {
1419
- cancel("Operation cancelled.");
1420
- return;
1421
- }
1422
- return selectedScope;
1423
- }
1424
- async function promptForPrismaSkills(provider, recommendedSkills) {
1425
- const options = getSkillOptions(provider);
1426
- const optionValues = new Set(options.map((option) => option.value));
1427
- const selectedSkills = await multiselect({
1428
- message: "Select Prisma skills",
1429
- options,
1430
- required: false,
1431
- initialValues: recommendedSkills.filter((skill) => optionValues.has(skill))
1432
- });
1433
- if (isCancel(selectedSkills)) {
1434
- cancel("Operation cancelled.");
1435
- return;
1436
- }
1437
- return uniqueValues(selectedSkills);
1438
- }
1439
- async function promptForSkillsAgents() {
1440
- const selectedAgents = await multiselect({
1441
- message: "Select agents for skills",
1442
- options: SKILLS_AGENT_OPTIONS,
1443
- required: false,
1444
- initialValues: [...DEFAULT_SKILLS_AGENTS]
1445
- });
1446
- if (isCancel(selectedAgents)) {
1447
- cancel("Operation cancelled.");
1448
- return;
1449
- }
1450
- return uniqueValues(selectedAgents);
1451
- }
1452
- async function promptForMcpAgents() {
1453
- const selectedAgents = await multiselect({
1454
- message: "Select agents for MCP",
1455
- options: MCP_AGENT_OPTIONS,
1456
- required: false,
1457
- initialValues: [...DEFAULT_MCP_AGENTS]
1458
- });
1459
- if (isCancel(selectedAgents)) {
1460
- cancel("Operation cancelled.");
1461
- return;
1462
- }
1463
- return uniqueValues(selectedAgents);
1464
- }
1465
- async function promptForExtensionTargets() {
1466
- const selectedTargets = await multiselect({
1467
- message: "Select IDEs for extension install",
1468
- options: EXTENSION_TARGET_OPTIONS,
1469
- required: false,
1470
- initialValues: DEFAULT_EXTENSION_TARGETS
1471
- });
1472
- if (isCancel(selectedTargets)) {
1473
- cancel("Operation cancelled.");
1474
- return;
1475
- }
1476
- return uniqueValues(selectedTargets);
1477
- }
1478
- async function collectCreateAddonSetupContext(input, options) {
1479
- const hasExplicitAddonSelection = input.skills !== void 0 || input.mcp !== void 0 || input.extension !== void 0;
1480
- const selectedFromInput = collectAddonsFromInput(input);
1481
- const selectedAddons = selectedFromInput.length > 0 ? selectedFromInput : hasExplicitAddonSelection ? [] : options.useDefaults ? [] : await promptForAddons();
1482
- if (!selectedAddons) return;
1483
- const addons = uniqueValues(selectedAddons);
1484
- if (addons.length === 0) return null;
1485
- const scope = addons.includes("skills") || addons.includes("mcp") ? options.useDefaults ? DEFAULT_ADDON_SCOPE : await promptForAddonScope() : DEFAULT_ADDON_SCOPE;
1486
- if (!scope) return;
1487
- const recommendedSkills = getRecommendedPrismaSkills(options.provider, options.shouldUsePrismaPostgres);
1488
- const skills = !addons.includes("skills") ? [] : options.useDefaults ? recommendedSkills : await promptForPrismaSkills(options.provider, recommendedSkills);
1489
- if (!skills) return;
1490
- const skillsAgents = !addons.includes("skills") ? [] : options.useDefaults ? [...DEFAULT_SKILLS_AGENTS] : await promptForSkillsAgents();
1491
- if (!skillsAgents) return;
1492
- const mcpAgents = !addons.includes("mcp") ? [] : options.useDefaults ? [...DEFAULT_MCP_AGENTS] : await promptForMcpAgents();
1493
- if (!mcpAgents) return;
1494
- const extensionTargets = !addons.includes("extension") ? [] : options.useDefaults ? [...DEFAULT_EXTENSION_TARGETS] : await promptForExtensionTargets();
1495
- if (!extensionTargets) return;
1496
- return {
1497
- addons,
1498
- scope,
1499
- skills,
1500
- skillsAgents: uniqueValues(skillsAgents),
1501
- mcpAgents: uniqueValues(mcpAgents),
1502
- extensionTargets: uniqueValues(extensionTargets)
1503
- };
1504
- }
1505
- async function executeExternalCommand(params) {
1506
- await execa(params.command, params.args, {
1507
- cwd: params.cwd,
1508
- stdio: params.verbose ? "inherit" : "pipe",
1509
- env: {
1510
- ...process.env,
1511
- CI: "true"
1512
- }
1513
- });
1514
- }
1515
- async function installSkillsAddon(params) {
1516
- if (params.agents.length === 0 || params.skills.length === 0) return "Skipped skills addon because no skills or agents were selected.";
1517
- const scopeArgs = params.scope === "global" ? ["-g"] : [];
1518
- const skillArgs = params.skills.flatMap((skill) => ["-s", skill]);
1519
- const agentArgs = params.agents.flatMap((agent) => ["-a", agent]);
1520
- const commandArgs = [
1521
- "skills@latest",
1522
- "add",
1523
- "prisma/skills",
1524
- ...scopeArgs,
1525
- ...skillArgs,
1526
- ...agentArgs,
1527
- "-y"
1528
- ];
1529
- const execution = getPackageExecutionArgs(params.packageManager, commandArgs);
1530
- try {
1531
- await executeExternalCommand({
1532
- command: execution.command,
1533
- args: execution.args,
1534
- cwd: params.projectDir,
1535
- verbose: params.verbose
1536
- });
1537
- return;
1538
- } catch (error) {
1539
- return `Skills addon failed: ${error instanceof Error ? error.message : String(error)}`;
1540
- }
1541
- }
1542
- async function installMcpAddon(params) {
1543
- if (params.agents.length === 0) return "Skipped MCP addon because no agents were selected.";
1544
- const scopeArgs = params.scope === "global" ? ["-g"] : [];
1545
- const agentArgs = params.agents.flatMap((agent) => ["-a", agent]);
1546
- const commandArgs = [
1547
- "add-mcp@latest",
1548
- PRISMA_MCP_SERVER,
1549
- ...scopeArgs,
1550
- ...agentArgs,
1551
- "--name",
1552
- "prisma",
1553
- "--gitignore",
1554
- "-y"
1555
- ];
1556
- const execution = getPackageExecutionArgs(params.packageManager, commandArgs);
1557
- try {
1558
- await executeExternalCommand({
1559
- command: execution.command,
1560
- args: execution.args,
1561
- cwd: params.projectDir,
1562
- verbose: params.verbose
1563
- });
1564
- return;
1565
- } catch (error) {
1566
- return `MCP addon failed: ${error instanceof Error ? error.message : String(error)}`;
1567
- }
1568
- }
1569
- function getExtensionInstallBinary(target) {
1570
- switch (target) {
1571
- case "vscode": return "code";
1572
- case "cursor": return "cursor";
1573
- case "windsurf": return "windsurf";
1574
- default: throw new Error(`Unsupported extension target: ${String(target)}`);
1575
- }
1576
- }
1577
- async function installExtensionAddon(params) {
1578
- if (params.targets.length === 0) return ["Skipped extension addon because no IDE targets were selected."];
1579
- const warnings = [];
1580
- for (const target of params.targets) {
1581
- const binary = getExtensionInstallBinary(target);
1582
- try {
1583
- await executeExternalCommand({
1584
- command: binary,
1585
- args: ["--version"],
1586
- cwd: params.projectDir,
1587
- verbose: false
1588
- });
1589
- } catch {
1590
- warnings.push(`Skipped ${target} extension install because the \`${binary}\` CLI is not available.`);
1591
- continue;
1592
- }
1593
- try {
1594
- await executeExternalCommand({
1595
- command: binary,
1596
- args: [
1597
- "--install-extension",
1598
- "Prisma.prisma",
1599
- "--force"
1600
- ],
1601
- cwd: params.projectDir,
1602
- verbose: params.verbose
1603
- });
1604
- } catch (error) {
1605
- warnings.push(`${target} extension install failed: ${error instanceof Error ? error.message : String(error)}`);
1606
- }
1607
- }
1608
- return warnings;
1609
- }
1610
- async function executeCreateAddonSetupContext(params) {
1611
- const { context, packageManager, projectDir, verbose } = params;
1612
- const addonSpinner = spinner();
1613
- addonSpinner.start("Applying selected add-ons...");
1614
- const warnings = [];
1615
- if (context.addons.includes("skills")) {
1616
- const warning = await installSkillsAddon({
1617
- packageManager,
1618
- projectDir,
1619
- scope: context.scope,
1620
- skills: context.skills,
1621
- agents: context.skillsAgents,
1622
- verbose
1623
- });
1624
- if (warning) warnings.push(warning);
1625
- }
1626
- if (context.addons.includes("mcp")) {
1627
- const warning = await installMcpAddon({
1628
- packageManager,
1629
- projectDir,
1630
- scope: context.scope,
1631
- agents: context.mcpAgents,
1632
- verbose
1633
- });
1634
- if (warning) warnings.push(warning);
1635
- }
1636
- if (context.addons.includes("extension")) {
1637
- const extensionWarnings = await installExtensionAddon({
1638
- projectDir,
1639
- verbose,
1640
- targets: context.extensionTargets
1641
- });
1642
- warnings.push(...extensionWarnings);
1643
- }
1644
- if (warnings.length > 0) {
1645
- addonSpinner.stop("Add-ons applied with warnings.");
1646
- for (const warning of warnings) log.warn(warning);
1647
- return;
1648
- }
1649
- addonSpinner.stop("Add-ons applied.");
1650
- }
1651
- //#endregion
1652
- //#region src/tasks/deploy-with-composer.ts
1653
- function redactSecrets(message) {
1654
- return message.replace(/\b((?:prisma\+)?postgres(?:ql)?:\/\/)[^\s'"]+/gi, "$1<redacted>").replace(/(['"])([A-Z0-9_]*(?:DATABASE_URL|DIRECT_URL|TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE_KEY|ACCESS_KEY)[A-Z0-9_]*=)(.*?)\1/g, "$1$2<redacted>$1").replace(/\b([A-Z0-9_]*(?:DATABASE_URL|DIRECT_URL|TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE_KEY|ACCESS_KEY)[A-Z0-9_]*=)[^\s]+/g, "$1<redacted>");
1655
- }
1656
- function getErrorMessage(error) {
1657
- if (error instanceof Error) return redactSecrets(error.message);
1658
- if (typeof error === "object" && error !== null) {
1659
- const message = Reflect.get(error, "message");
1660
- const summary = Reflect.get(error, "summary");
1661
- if (typeof summary === "string") return redactSecrets(summary);
1662
- if (typeof message === "string") return redactSecrets(message);
1663
- }
1664
- return redactSecrets(String(error));
1665
- }
1666
- function createExplicitDeployError(reason, error) {
1667
- const detail = error === void 0 ? "" : `: ${getErrorMessage(error)}`;
1668
- return /* @__PURE__ */ new Error(`Deploy requested but ${reason}${detail}`);
1669
- }
1670
- function parsePrismaCliEnvelope(output) {
1671
- const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
1672
- for (const line of lines.reverse()) {
1673
- let parsed;
1674
- try {
1675
- parsed = JSON.parse(line);
1676
- } catch {
1677
- continue;
1678
- }
1679
- if (typeof parsed !== "object" || parsed === null) continue;
1680
- const record = parsed;
1681
- const candidate = record.kind === "result" ? record.envelope : parsed;
1682
- if (typeof candidate !== "object" || candidate === null) continue;
1683
- const envelope = candidate;
1684
- if (typeof envelope.ok !== "boolean") continue;
1685
- return envelope;
1686
- }
1687
- throw new Error("Prisma CLI returned output that is not a valid result envelope.");
1688
- }
1689
- function getPrismaPlatformCliArgs(packageManager, args) {
1690
- return getPackageExecutionArgs(packageManager, [prismaPlatformCliPackage, ...args], { silent: true });
1691
- }
1692
- function getPrismaAuthLoginCommand(packageManager) {
1693
- return getPackageExecutionCommand(packageManager, [
1694
- prismaPlatformCliPackage,
1695
- "auth",
1696
- "login"
1697
- ], { silent: true });
1698
- }
1699
- async function isAuthenticatedWithPrisma(packageManager, projectDir) {
1700
- const invocation = getPrismaPlatformCliArgs(packageManager, [
1701
- "auth",
1702
- "whoami",
1703
- "--json",
1704
- "--no-interactive"
1705
- ]);
1706
- const result = await execa(invocation.command, invocation.args, {
1707
- cwd: projectDir,
1708
- env: process.env,
1709
- reject: false
1710
- });
1711
- let envelope;
1712
- try {
1713
- envelope = parsePrismaCliEnvelope(result.stdout);
1714
- } catch (error) {
1715
- const detail = result.stderr.trim() || result.stdout.trim() || getErrorMessage(error);
1716
- throw new Error(redactSecrets(detail));
1717
- }
1718
- if (result.exitCode !== 0 || !envelope.ok) throw new Error(envelope.error?.summary ?? envelope.error?.message ?? (result.stderr.trim() || "Prisma authentication check failed."));
1719
- if (typeof envelope.result !== "object" || envelope.result === null) throw new Error("Prisma CLI authentication output did not include a result.");
1720
- const authenticated = Reflect.get(envelope.result, "authenticated");
1721
- if (typeof authenticated !== "boolean") throw new Error("Prisma CLI authentication output did not include an authentication status.");
1722
- return authenticated;
1723
- }
1724
- async function ensurePrismaAuthentication(packageManager, projectDir) {
1725
- if (await isAuthenticatedWithPrisma(packageManager, projectDir)) return;
1726
- if (process.stdin.isTTY !== true) throw new Error(`Prisma authentication is required. Run ${getPrismaAuthLoginCommand(packageManager)} in an interactive terminal, then ${getRunScriptCommand(packageManager, "deploy")}. For CI, set PRISMA_SERVICE_TOKEN.`);
1727
- log.info("Sign in to Prisma to deploy.");
1728
- const login = getPrismaPlatformCliArgs(packageManager, ["auth", "login"]);
1729
- await execa(login.command, login.args, {
1730
- cwd: projectDir,
1731
- env: process.env,
1732
- stdio: "inherit"
1733
- });
1734
- if (!await isAuthenticatedWithPrisma(packageManager, projectDir)) throw new Error("Prisma sign-in completed without an active workspace session.");
1735
- }
1736
- function getComposerDeployScriptMap(context) {
1737
- const steps = [
1738
- getRunScriptCommand(context.packageManager, "build"),
1739
- getRunScriptCommand(context.packageManager, "composer:deploy"),
1740
- ...context.useComposerPostgres ? [getRunScriptCommand(context.packageManager, "composer:database:setup")] : []
1741
- ];
1742
- return {
1743
- "composer:deploy": getPackageExecutionCommand(context.packageManager, [
1744
- prismaPlatformCliPackage,
1745
- "composer",
1746
- "deploy",
1747
- "module.ts"
1748
- ], { silent: true }),
1749
- ...context.useComposerPostgres ? { "composer:database:setup": `${context.packageManager === "bun" ? "bun" : "node"} scripts/setup-composer-postgres.mjs` } : {},
1750
- deploy: steps.join(" && ")
1751
- };
1752
- }
1753
- async function collectComposerDeployContext(input, options) {
1754
- if (input.deploy === false) return null;
1755
- let wantsDeploy;
1756
- if (input.deploy === true) wantsDeploy = true;
1757
- else if (options.useDefaults) return null;
1758
- else {
1759
- const confirmed = await confirm({
1760
- message: "Deploy to Prisma now?",
1761
- initialValue: false
1762
- });
1763
- if (isCancel(confirmed)) {
1764
- cancel("Operation cancelled.");
1765
- return;
1766
- }
1767
- wantsDeploy = confirmed;
1768
- }
1769
- if (!wantsDeploy) return null;
1770
- if (options.databaseProvider !== "postgresql" && (process.env.DATABASE_URL ?? "").trim().length === 0) {
1771
- const reason = `immediate deployment for ${options.databaseProvider} needs DATABASE_URL`;
1772
- if (input.deploy === true) throw createExplicitDeployError(reason);
1773
- log.warn(`${reason}. Scaffolding without deployment; configure the generated .env file and run the deploy script later.`);
1774
- return null;
1775
- }
1776
- return {
1777
- template: options.template,
1778
- packageManager: options.packageManager,
1779
- projectName: options.projectName,
1780
- useComposerPostgres: false,
1781
- verbose: options.verbose
1782
- };
1783
- }
1784
- async function executeComposerDeployContext(params) {
1785
- const deploy = getRunScriptArgs(params.context.packageManager, "deploy");
1786
- const deploySpinner = params.context.verbose ? void 0 : spinner();
1787
- let deployStarted = false;
1788
- try {
1789
- await ensurePrismaAuthentication(params.context.packageManager, params.projectDir);
1790
- if (params.context.verbose) log.step("Prisma deployment output follows.");
1791
- else {
1792
- deploySpinner?.start("Deploying to Prisma...");
1793
- deployStarted = true;
1794
- }
1795
- await execa(deploy.command, deploy.args, {
1796
- cwd: params.projectDir,
1797
- env: process.env,
1798
- stdio: params.context.verbose ? "inherit" : "pipe"
1799
- });
1800
- if (params.context.verbose) log.success("Deployed to Prisma.");
1801
- else deploySpinner?.stop("Deployed to Prisma.");
1802
- return {
1803
- ok: true,
1804
- result: { appName: params.context.projectName }
1805
- };
1806
- } catch (error) {
1807
- if (deployStarted) deploySpinner?.stop("Deployment failed.");
1808
- const deployError = new Error(getErrorMessage(error));
1809
- log.error(`Deploy failed: ${deployError.message}`);
1810
- return {
1811
- ok: false,
1812
- cancelled: false,
1813
- error: deployError
1814
- };
1815
- }
1816
- }
1817
- //#endregion
1818
- //#region src/telemetry/client.ts
1819
- const TELEMETRY_API_KEY = "";
1820
- const TELEMETRY_HOST = "https://us.i.posthog.com";
1821
- const TELEMETRY_CONFIG_FILE = "telemetry.json";
1822
- 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;
1823
- function shouldDisableTelemetry() {
1824
- return true;
1825
- }
1826
- function getTelemetryConfigDir() {
1827
- if (process.platform === "darwin") return path.join(os$1.homedir(), "Library", "Application Support", "create-prisma");
1828
- if (process.platform === "win32") return path.join(process.env.APPDATA ?? path.join(os$1.homedir(), "AppData", "Roaming"), "create-prisma");
1829
- return path.join(process.env.XDG_CONFIG_HOME ?? path.join(os$1.homedir(), ".config"), "create-prisma");
1830
- }
1831
- async function getAnonymousId() {
1832
- const telemetryConfigPath = path.join(getTelemetryConfigDir(), TELEMETRY_CONFIG_FILE);
1833
- try {
1834
- const config = await fs.readJSON(telemetryConfigPath);
1835
- if (typeof config.anonymousId === "string" && UUID_V4_REGEX.test(config.anonymousId)) return config.anonymousId;
1836
- } catch {}
1837
- const anonymousId = randomUUID();
1838
- try {
1839
- await fs.ensureDir(path.dirname(telemetryConfigPath));
1840
- await fs.writeJSON(telemetryConfigPath, { anonymousId }, { spaces: 2 });
1841
- } catch {}
1842
- return anonymousId;
1843
- }
1844
- function getCommonProperties() {
1845
- return {
1846
- "cli-version": "0.7.1-pr.52.181.1",
1847
- "node-version": process.version,
1848
- platform: process.platform,
1849
- arch: process.arch
1850
- };
1851
- }
1852
- function sanitizeProperties(properties) {
1853
- return Object.fromEntries(Object.entries(properties).filter(([, value]) => value !== void 0));
1854
- }
1855
- async function trackCliTelemetry(event, properties) {
1856
- if (shouldDisableTelemetry()) return;
1857
- let client;
1858
- try {
1859
- const distinctId = await getAnonymousId();
1860
- const sanitizedProperties = sanitizeProperties({
1861
- ...getCommonProperties(),
1862
- ...properties,
1863
- $process_person_profile: false
1864
- });
1865
- client = new PostHog(TELEMETRY_API_KEY, {
1866
- host: TELEMETRY_HOST,
1867
- disableGeoip: true,
1868
- flushAt: 1,
1869
- flushInterval: 0
1870
- });
1871
- await client.captureImmediate({
1872
- distinctId,
1873
- event,
1874
- properties: sanitizedProperties,
1875
- disableGeoip: true
1876
- });
1877
- } catch {} finally {
1878
- if (client) await client.shutdown().catch(() => {});
1879
- }
1880
- }
1881
- //#endregion
1882
- //#region src/telemetry/create.ts
1883
- function getRequestedAddons(input) {
1884
- const addons = [];
1885
- if (input.skills === true) addons.push("skills");
1886
- if (input.mcp === true) addons.push("mcp");
1887
- if (input.extension === true) addons.push("extension");
1888
- return addons;
1889
- }
1890
- function getTargetDirectoryState(context) {
1891
- if (!context.targetPathState.exists) return "new";
1892
- if (context.targetPathState.isEmptyDirectory) return "empty_directory";
1893
- return "non_empty_directory";
1894
- }
1895
- function getBaseCreateProperties(input, context) {
1896
- const resolvedAddons = context?.addonSetupContext?.addons ?? getRequestedAddons(input);
1897
- return {
1898
- command: "create",
1899
- "uses-defaults": input.yes === true,
1900
- verbose: input.verbose === true,
1901
- force: input.force === true,
1902
- template: context?.template ?? input.template ?? null,
1903
- "database-provider": context?.prismaSetupContext.databaseProvider ?? input.provider ?? null,
1904
- "package-manager": context?.prismaSetupContext.packageManager ?? input.packageManager ?? null,
1905
- "should-install": context?.prismaSetupContext.shouldInstall ?? input.install ?? null,
1906
- "should-generate": true,
1907
- "uses-prisma-postgres": context?.prismaSetupContext.shouldUsePrismaPostgres ?? (input.provider === void 0 ? null : input.provider === "postgresql"),
1908
- addons: resolvedAddons,
1909
- "addon-count": resolvedAddons.length,
1910
- "addon-scope": context?.addonSetupContext?.scope ?? null,
1911
- "skills-count": context?.addonSetupContext?.skills.length ?? null,
1912
- "skills-agents-count": context?.addonSetupContext?.skillsAgents.length ?? null,
1913
- "mcp-agents-count": context?.addonSetupContext?.mcpAgents.length ?? null,
1914
- "extension-target-count": context?.addonSetupContext?.extensionTargets.length ?? null,
1915
- "target-directory-state": context ? getTargetDirectoryState(context) : null
1916
- };
1917
- }
1918
- function getErrorName(error) {
1919
- if (error instanceof Error) return error.name;
1920
- return error === void 0 ? null : "UnknownError";
1921
- }
1922
- function getErrorCode(error) {
1923
- if (typeof error !== "object" || error === null) return null;
1924
- const exitCode = Reflect.get(error, "exitCode");
1925
- if (typeof exitCode === "number") return exitCode;
1926
- const code = Reflect.get(error, "code");
1927
- return typeof code === "number" || typeof code === "string" ? code : null;
1928
- }
1929
- async function trackCreateCompleted(params) {
1930
- await trackCliTelemetry("cli:create_command_completed", {
1931
- ...getBaseCreateProperties(params.input, params.context),
1932
- "duration-ms": params.durationMs
1933
- });
1934
- }
1935
- async function trackCreateFailed(params) {
1936
- await trackCliTelemetry("cli:create_command_failed", {
1937
- ...getBaseCreateProperties(params.input, params.context),
1938
- "duration-ms": params.durationMs,
1939
- "failure-stage": params.stage,
1940
- "error-name": getErrorName(params.error),
1941
- "error-code": getErrorCode(params.error)
1942
- });
1943
- }
1944
- //#endregion
1945
- //#region src/ui/branding.ts
1946
- const prismaTitle = `${styleText(["bold", "cyan"], "Create")} ${styleText(["bold", "magenta"], "Prisma")}`;
1947
- function getCreatePrismaIntro() {
1948
- return prismaTitle;
1949
- }
1950
- //#endregion
1951
- //#region src/commands/create.ts
1952
- const DEFAULT_PROJECT_NAME = "my-app";
1953
- const DEFAULT_TEMPLATE = "hono";
1954
- function toPackageName(projectName) {
1955
- return projectName.toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/^-+/, "").replace(/-+$/, "") || "app";
1956
- }
1957
- function formatPathForDisplay(filePath) {
1958
- return path.relative(process.cwd(), filePath) || ".";
1959
- }
1960
- function validateProjectName(value) {
1961
- const trimmed = String(value ?? "").trim();
1962
- if (trimmed.length === 0) return "Please enter a project name.";
1963
- if (trimmed === "..") return "Project name cannot be '..'.";
1964
- if (path.isAbsolute(trimmed)) return "Use a relative project name instead of an absolute path.";
1965
- }
1966
- async function promptForProjectName() {
1967
- const projectName = await text({
1968
- message: "Project name",
1969
- placeholder: DEFAULT_PROJECT_NAME,
1970
- initialValue: DEFAULT_PROJECT_NAME,
1971
- validate: validateProjectName
1972
- });
1973
- if (isCancel(projectName)) {
1974
- cancel("Operation cancelled.");
1975
- return;
1976
- }
1977
- return String(projectName).trim();
1978
- }
1979
- async function promptForCreateTemplate() {
1980
- const template = await select({
1981
- message: "Select template",
1982
- initialValue: DEFAULT_TEMPLATE,
1983
- options: [
1984
- {
1985
- value: "hono",
1986
- label: "Hono",
1987
- hint: "TypeScript API starter"
1988
- },
1989
- {
1990
- value: "elysia",
1991
- label: "Elysia",
1992
- hint: "TypeScript API starter with Elysia's Node adapter"
1993
- },
1994
- {
1995
- value: "nest",
1996
- label: "NestJS",
1997
- hint: "Official Nest-style API starter with a Prisma service"
1998
- },
1999
- {
2000
- value: "next",
2001
- label: "Next.js",
2002
- hint: "App Router + TypeScript starter"
2003
- },
2004
- {
2005
- value: "svelte",
2006
- label: "SvelteKit",
2007
- hint: "Official minimal SvelteKit + TypeScript starter"
2008
- },
2009
- {
2010
- value: "astro",
2011
- label: "Astro",
2012
- hint: "Official minimal Astro starter with API route example"
2013
- },
2014
- {
2015
- value: "nuxt",
2016
- label: "Nuxt",
2017
- hint: "Official minimal Nuxt starter with Nitro API route example"
2018
- },
2019
- {
2020
- value: "tanstack-start",
2021
- label: "TanStack Start",
2022
- hint: "TanStack Start React app with file routes and server functions"
2023
- },
2024
- {
2025
- value: "turborepo",
2026
- label: "Turborepo",
2027
- hint: "Monorepo starter with apps + packages/db Prisma package"
2028
- }
2029
- ]
2030
- });
2031
- if (isCancel(template)) {
2032
- cancel("Operation cancelled.");
2033
- return;
2034
- }
2035
- return CreateTemplateSchema.parse(template);
2036
- }
2037
- async function inspectTargetPath(targetPath) {
2038
- if (!await fs.pathExists(targetPath)) return {
2039
- exists: false,
2040
- isDirectory: true,
2041
- isEmptyDirectory: true
2042
- };
2043
- if (!(await fs.stat(targetPath)).isDirectory()) return {
2044
- exists: true,
2045
- isDirectory: false,
2046
- isEmptyDirectory: false
2047
- };
2048
- return {
2049
- exists: true,
2050
- isDirectory: true,
2051
- isEmptyDirectory: (await fs.readdir(targetPath)).length === 0
2052
- };
2053
- }
2054
- async function runCreateCommand(rawInput = {}) {
2055
- const startedAt = Date.now();
2056
- let input = {};
2057
- let context;
2058
- let failureStage = "validate_input";
2059
- try {
2060
- input = CreateCommandInputSchema.parse(rawInput);
2061
- intro(getCreatePrismaIntro());
2062
- failureStage = "collect_context";
2063
- context = await collectCreateContext(input);
2064
- if (!context) return;
2065
- failureStage = "unknown";
2066
- const executionResult = await executeCreateContext(context);
2067
- if (!executionResult.ok) {
2068
- failureStage = executionResult.stage;
2069
- throw executionResult.error instanceof Error ? executionResult.error : new Error(executionResult.error === void 0 ? `Create command failed during ${executionResult.stage}` : String(executionResult.error));
2070
- }
2071
- await trackCreateCompleted({
2072
- input,
2073
- context,
2074
- durationMs: Date.now() - startedAt
2075
- });
2076
- } catch (error) {
2077
- const commandError = error instanceof Error ? error : new Error(String(error));
2078
- cancel(`Create command failed: ${commandError.message}`);
2079
- try {
2080
- await trackCreateFailed({
2081
- input,
2082
- context,
2083
- durationMs: Date.now() - startedAt,
2084
- error: commandError,
2085
- stage: failureStage
2086
- });
2087
- } catch {}
2088
- throw commandError;
2089
- }
2090
- }
2091
- async function collectCreateContext(input) {
2092
- const useDefaults = input.yes === true;
2093
- const force = input.force === true;
2094
- const projectNameInput = input.name ?? (useDefaults ? DEFAULT_PROJECT_NAME : await promptForProjectName());
2095
- if (projectNameInput === void 0) return;
2096
- const projectName = String(projectNameInput).trim();
2097
- const projectNameValidationError = validateProjectName(projectName);
2098
- if (projectNameValidationError) {
2099
- cancel(projectNameValidationError);
2100
- return;
2101
- }
2102
- const template = input.template ?? (useDefaults ? DEFAULT_TEMPLATE : await promptForCreateTemplate());
2103
- if (!template) return;
2104
- const targetDirectory = path.resolve(process.cwd(), projectName);
2105
- const targetPathState = await inspectTargetPath(targetDirectory);
2106
- if (targetPathState.exists && !targetPathState.isDirectory) {
2107
- cancel(`Target path ${formatPathForDisplay(targetDirectory)} already exists and is not a directory. Choose a different project name.`);
2108
- return;
2109
- }
2110
- if (targetPathState.exists && !targetPathState.isEmptyDirectory && !force) {
2111
- cancel(`Target directory ${formatPathForDisplay(targetDirectory)} is not empty. Use --force to continue.`);
2112
- return;
2113
- }
2114
- const prismaSetupInitialContext = await collectPrismaSetupInitialContext(input, { projectDir: targetDirectory });
2115
- if (!prismaSetupInitialContext) return;
2116
- const projectPackageName = toPackageName(path.basename(targetDirectory));
2117
- const composerDeployContext = await collectComposerDeployContext(input, {
2118
- template,
2119
- databaseProvider: prismaSetupInitialContext.databaseProvider,
2120
- packageManager: prismaSetupInitialContext.packageManager,
2121
- projectName: projectPackageName,
2122
- useDefaults,
2123
- verbose: prismaSetupInitialContext.verbose
2124
- });
2125
- if (composerDeployContext === void 0) return;
2126
- const prismaSetupContext = await completePrismaSetupContext(prismaSetupInitialContext, { shouldMigrateAndSeed: Boolean(composerDeployContext) });
2127
- if (!prismaSetupContext) return;
2128
- const useComposerPostgres = prismaSetupContext.shouldUsePrismaPostgres;
2129
- if (composerDeployContext) composerDeployContext.useComposerPostgres = useComposerPostgres;
2130
- if (composerDeployContext && useComposerPostgres) log.info("Composer will provision Prisma Postgres and wire it into the application.");
2131
- const composerScaffoldContext = composerDeployContext ?? {
2132
- template,
2133
- packageManager: prismaSetupContext.packageManager,
2134
- projectName: projectPackageName,
2135
- useComposerPostgres,
2136
- verbose: prismaSetupContext.verbose
2137
- };
2138
- const addonSetupContext = await collectCreateAddonSetupContext(input, {
2139
- useDefaults,
2140
- provider: prismaSetupContext.databaseProvider,
2141
- shouldUsePrismaPostgres: prismaSetupContext.shouldUsePrismaPostgres
2142
- });
2143
- if (addonSetupContext === void 0) return;
2144
- return {
2145
- targetDirectory,
2146
- targetPathState,
2147
- force,
2148
- template,
2149
- projectPackageName,
2150
- prismaSetupContext,
2151
- addonSetupContext: addonSetupContext ?? void 0,
2152
- composerScaffoldContext,
2153
- composerDeployContext: composerDeployContext ?? void 0,
2154
- useComposerPostgres
2155
- };
2156
- }
2157
- async function executeCreateContext(context) {
2158
- const scaffoldSpinner = spinner();
2159
- scaffoldSpinner.start(`Scaffolding ${context.template} project...`);
2160
- try {
2161
- await scaffoldCreateTemplate({
2162
- projectDir: context.targetDirectory,
2163
- projectName: context.projectPackageName,
2164
- template: context.template,
2165
- provider: context.prismaSetupContext.databaseProvider,
2166
- packageManager: context.prismaSetupContext.packageManager,
2167
- composerPostgres: context.useComposerPostgres
2168
- });
2169
- scaffoldSpinner.stop("Project files scaffolded.");
2170
- } catch (error) {
2171
- scaffoldSpinner.stop("Could not scaffold project files.");
2172
- return {
2173
- ok: false,
2174
- stage: "scaffold_template",
2175
- error
2176
- };
2177
- }
2178
- try {
2179
- await writeCreateTemplateDependencies({
2180
- template: context.template,
2181
- packageManager: context.prismaSetupContext.packageManager,
2182
- projectDir: context.targetDirectory
2183
- });
2184
- await addPackageDependency({
2185
- scripts: getComposerDeployScriptMap(context.composerScaffoldContext),
2186
- scriptMode: "if-missing",
2187
- projectDir: context.targetDirectory
2188
- });
2189
- } catch (error) {
2190
- return {
2191
- ok: false,
2192
- stage: "scaffold_template",
2193
- error
2194
- };
2195
- }
2196
- if (context.targetPathState.exists && !context.targetPathState.isEmptyDirectory && context.force) log.warn(`Used --force in non-empty directory ${formatPathForDisplay(context.targetDirectory)}.`);
2197
- const nextSteps = formatPathForDisplay(context.targetDirectory) === "." ? [] : [`- cd ${formatPathForDisplay(context.targetDirectory)}`];
2198
- if (context.addonSetupContext) try {
2199
- await executeCreateAddonSetupContext({
2200
- context: context.addonSetupContext,
2201
- packageManager: context.prismaSetupContext.packageManager,
2202
- projectDir: context.targetDirectory,
2203
- verbose: context.prismaSetupContext.verbose
2204
- });
2205
- } catch (error) {
2206
- return {
2207
- ok: false,
2208
- stage: "addons",
2209
- error
2210
- };
2211
- }
2212
- let prismaResult;
2213
- try {
2214
- prismaResult = await executePrismaSetupContext(Boolean(context.composerDeployContext && context.useComposerPostgres) ? {
2215
- ...context.prismaSetupContext,
2216
- shouldMigrateAndSeed: false
2217
- } : context.prismaSetupContext, {
2218
- prependNextSteps: nextSteps,
2219
- projectDir: context.targetDirectory,
2220
- includeDevNextStep: true,
2221
- includeMigrationAndSeedNextSteps: !context.useComposerPostgres
2222
- });
2223
- if (!prismaResult.ok) return {
2224
- ok: false,
2225
- stage: "prisma_setup"
2226
- };
2227
- if (context.composerDeployContext && (!prismaResult.didGenerateClient || !prismaResult.didGenerateMigration)) return {
2228
- ok: false,
2229
- stage: "prisma_setup",
2230
- error: /* @__PURE__ */ new Error("Could not generate Prisma Client and the initial migration required for deployment.")
2231
- };
2232
- } catch (error) {
2233
- return {
2234
- ok: false,
2235
- stage: "prisma_setup",
2236
- error
2237
- };
2238
- }
2239
- let deployResult;
2240
- if (context.composerDeployContext) try {
2241
- const result = await executeComposerDeployContext({
2242
- context: context.composerDeployContext,
2243
- projectDir: context.targetDirectory
2244
- });
2245
- if (!result.ok && !result.cancelled) return {
2246
- ok: false,
2247
- stage: "composer_deploy",
2248
- error: result.error
2249
- };
2250
- if (!result.ok) prismaResult.warningSection += "\n\n- Prisma deployment was cancelled.";
2251
- if (result.ok) deployResult = result.result;
2252
- } catch (error) {
2253
- return {
2254
- ok: false,
2255
- stage: "composer_deploy",
2256
- error
2257
- };
2258
- }
2259
- if (!deployResult) {
2260
- const deployNextStep = `- ${getRunScriptCommand(context.prismaSetupContext.packageManager, "deploy")}`;
2261
- if (!prismaResult.nextSteps.includes(deployNextStep)) prismaResult.nextSteps.push(deployNextStep);
2262
- }
2263
- const summaryLines = [];
2264
- summaryLines.push(`Setup complete.${prismaResult.warningSection}`);
2265
- if (deployResult) summaryLines.push("", "Deployed to Prisma:", `- App: ${deployResult.appName}`);
2266
- summaryLines.push("", "Next steps:", prismaResult.nextSteps.join("\n"));
2267
- outro(summaryLines.join("\n"));
2268
- return { ok: true };
2269
- }
2270
- //#endregion
2271
- //#region src/index.ts
2272
- const CLI_VERSION = "0.7.1-pr.52.181.1";
2273
- const router = os.router({ create: os.meta({
2274
- description: "Create a new project with Prisma setup",
2275
- default: true,
2276
- negateBooleans: true
2277
- }).input(CreateCommandInputSchema.optional()).handler(async ({ input }) => {
2278
- await runCreateCommand(input ?? {});
2279
- }) });
2280
- function createCreatePrismaCli() {
2281
- return createCli({
2282
- router,
2283
- name: "create-prisma",
2284
- version: CLI_VERSION
2285
- });
2286
- }
2287
- async function create(input = {}) {
2288
- await runCreateCommand(input);
2289
- }
2290
- //#endregion
2291
- export { CreateCommandInputSchema, CreateTemplateSchema, DatabaseProviderSchema, PackageManagerSchema, create, createCreatePrismaCli, router };
2
+ import { a as CreateTemplateSchema, c as PackageManagerSchema, i as CreateCommandInputSchema, l as SchemaPresetSchema, n as createCreatePrismaCli, o as DatabaseProviderSchema, r as router, s as DatabaseUrlSchema, t as create } from "./src-B3hRLZ0U.mjs";
3
+ export { CreateCommandInputSchema, CreateTemplateSchema, DatabaseProviderSchema, DatabaseUrlSchema, PackageManagerSchema, SchemaPresetSchema, create, createCreatePrismaCli, router };