create-prisma 0.4.1 → 0.4.2-next.37.79.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +43 -35
  2. package/dist/cli.mjs +1 -1
  3. package/dist/{create-H6Tk0JlE.mjs → create-Btn7yJR3.mjs} +513 -913
  4. package/dist/index.d.mts +28 -25
  5. package/dist/index.mjs +3 -3
  6. package/package.json +2 -2
  7. package/templates/create/_shared/packages/db/prisma/seed.ts.hbs +43 -0
  8. package/templates/create/_shared/prisma/seed.ts.hbs +55 -0
  9. package/templates/create/astro/README.md.hbs +23 -12
  10. package/templates/create/astro/deno.json.hbs +1 -1
  11. package/templates/create/astro/prisma/contract.prisma.hbs +44 -0
  12. package/templates/create/astro/prisma/contract.ts.hbs +85 -0
  13. package/templates/create/astro/prisma-next.config.ts.hbs +13 -0
  14. package/templates/create/astro/src/lib/prisma.ts.hbs +49 -43
  15. package/templates/create/astro/src/pages/api/users.ts.hbs +5 -12
  16. package/templates/create/astro/src/pages/index.astro.hbs +19 -21
  17. package/templates/create/elysia/.yarnrc.yml.hbs +3 -0
  18. package/templates/create/elysia/README.md.hbs +27 -18
  19. package/templates/create/elysia/deno.json.hbs +1 -1
  20. package/templates/create/elysia/prisma/contract.prisma.hbs +44 -0
  21. package/templates/create/elysia/prisma/contract.ts.hbs +85 -0
  22. package/templates/create/elysia/prisma-next.config.ts.hbs +13 -0
  23. package/templates/create/elysia/src/index.ts.hbs +12 -7
  24. package/templates/create/elysia/src/lib/prisma.ts.hbs +49 -46
  25. package/templates/create/elysia/tsconfig.json +1 -0
  26. package/templates/create/hono/README.md.hbs +27 -18
  27. package/templates/create/hono/deno.json.hbs +1 -1
  28. package/templates/create/hono/prisma/contract.prisma.hbs +44 -0
  29. package/templates/create/hono/prisma/contract.ts.hbs +85 -0
  30. package/templates/create/hono/prisma-next.config.ts.hbs +13 -0
  31. package/templates/create/hono/src/index.ts.hbs +8 -6
  32. package/templates/create/hono/src/lib/prisma.ts.hbs +49 -46
  33. package/templates/create/hono/tsconfig.json +1 -0
  34. package/templates/create/nest/README.md.hbs +28 -18
  35. package/templates/create/nest/deno.json.hbs +1 -1
  36. package/templates/create/nest/prisma/contract.prisma.hbs +44 -0
  37. package/templates/create/nest/prisma/contract.ts.hbs +85 -0
  38. package/templates/create/nest/prisma-next.config.ts.hbs +13 -0
  39. package/templates/create/nest/src/lib/prisma.ts.hbs +49 -48
  40. package/templates/create/nest/src/prisma.service.ts.hbs +6 -5
  41. package/templates/create/nest/src/users.service.ts.hbs +1 -6
  42. package/templates/create/nest/tsconfig.json +1 -0
  43. package/templates/create/next/README.md.hbs +22 -11
  44. package/templates/create/next/deno.json.hbs +1 -1
  45. package/templates/create/next/prisma/contract.prisma.hbs +44 -0
  46. package/templates/create/next/prisma/contract.ts.hbs +85 -0
  47. package/templates/create/next/prisma-next.config.ts.hbs +13 -0
  48. package/templates/create/next/src/app/page.tsx.hbs +21 -26
  49. package/templates/create/next/src/lib/prisma.ts.hbs +49 -43
  50. package/templates/create/next/tsconfig.json +1 -0
  51. package/templates/create/nuxt/README.md.hbs +22 -11
  52. package/templates/create/nuxt/app/pages/index.vue.hbs +14 -12
  53. package/templates/create/nuxt/deno.json.hbs +1 -1
  54. package/templates/create/nuxt/nuxt.config.ts +16 -0
  55. package/templates/create/nuxt/prisma/contract.prisma.hbs +44 -0
  56. package/templates/create/nuxt/prisma/contract.ts.hbs +85 -0
  57. package/templates/create/nuxt/prisma-next.config.ts.hbs +13 -0
  58. package/templates/create/nuxt/server/api/users.get.ts.hbs +3 -9
  59. package/templates/create/nuxt/server/utils/prisma.ts.hbs +49 -43
  60. package/templates/create/svelte/README.md.hbs +23 -12
  61. package/templates/create/svelte/deno.json.hbs +1 -1
  62. package/templates/create/svelte/prisma/contract.prisma.hbs +44 -0
  63. package/templates/create/svelte/prisma/contract.ts.hbs +85 -0
  64. package/templates/create/svelte/prisma-next.config.ts.hbs +13 -0
  65. package/templates/create/svelte/src/lib/server/prisma.ts.hbs +50 -44
  66. package/templates/create/svelte/src/routes/+page.server.ts.hbs +3 -9
  67. package/templates/create/svelte/src/routes/+page.svelte.hbs +21 -16
  68. package/templates/create/tanstack-start/README.md.hbs +22 -11
  69. package/templates/create/tanstack-start/deno.json.hbs +1 -2
  70. package/templates/create/tanstack-start/prisma/contract.prisma.hbs +44 -0
  71. package/templates/create/tanstack-start/prisma/contract.ts.hbs +85 -0
  72. package/templates/create/tanstack-start/prisma-next.config.ts.hbs +13 -0
  73. package/templates/create/tanstack-start/src/lib/prisma.server.ts.hbs +49 -43
  74. package/templates/create/tanstack-start/src/routes/__root.tsx.hbs +2 -3
  75. package/templates/create/tanstack-start/src/routes/index.tsx.hbs +27 -38
  76. package/templates/create/tanstack-start/tsconfig.json +1 -0
  77. package/templates/create/turborepo/README.md.hbs +25 -14
  78. package/templates/create/turborepo/apps/api/deno.json.hbs +6 -0
  79. package/templates/create/turborepo/apps/api/package.json.hbs +7 -0
  80. package/templates/create/turborepo/apps/api/src/index.ts.hbs +6 -13
  81. package/templates/create/turborepo/deno.json.hbs +5 -1
  82. package/templates/create/turborepo/package.json.hbs +12 -4
  83. package/templates/create/turborepo/packages/db/deno.json.hbs +6 -0
  84. package/templates/create/turborepo/packages/db/package.json.hbs +5 -0
  85. package/templates/create/turborepo/packages/db/prisma/contract.prisma.hbs +44 -0
  86. package/templates/create/turborepo/packages/db/prisma/contract.ts.hbs +85 -0
  87. package/templates/create/turborepo/packages/db/prisma-next.config.ts.hbs +13 -0
  88. package/templates/create/turborepo/packages/db/src/client.ts.hbs +56 -44
  89. package/templates/create/turborepo/packages/db/src/index.ts +1 -1
  90. package/templates/create/turborepo/packages/db/tsconfig.json +2 -1
  91. package/templates/create/turborepo/pnpm-workspace.yaml.hbs +5 -0
  92. package/templates/create/turborepo/turbo.json +9 -3
  93. package/templates/create/astro/prisma/schema.prisma.hbs +0 -21
  94. package/templates/create/astro/prisma/seed.ts.hbs +0 -38
  95. package/templates/create/astro/prisma.config.ts +0 -13
  96. package/templates/create/elysia/prisma/schema.prisma.hbs +0 -25
  97. package/templates/create/elysia/prisma/seed.ts.hbs +0 -42
  98. package/templates/create/elysia/prisma.config.ts.hbs +0 -15
  99. package/templates/create/hono/prisma/schema.prisma.hbs +0 -25
  100. package/templates/create/hono/prisma/seed.ts.hbs +0 -42
  101. package/templates/create/hono/prisma.config.ts.hbs +0 -15
  102. package/templates/create/nest/prisma/schema.prisma.hbs +0 -25
  103. package/templates/create/nest/prisma/seed.ts.hbs +0 -44
  104. package/templates/create/nest/prisma.config.ts.hbs +0 -15
  105. package/templates/create/next/prisma/schema.prisma.hbs +0 -21
  106. package/templates/create/next/prisma/seed.ts.hbs +0 -38
  107. package/templates/create/next/prisma.config.ts +0 -13
  108. package/templates/create/nuxt/prisma/schema.prisma.hbs +0 -21
  109. package/templates/create/nuxt/prisma/seed.ts.hbs +0 -38
  110. package/templates/create/nuxt/prisma.config.ts +0 -13
  111. package/templates/create/svelte/prisma/schema.prisma.hbs +0 -21
  112. package/templates/create/svelte/prisma/seed.ts.hbs +0 -87
  113. package/templates/create/svelte/prisma.config.ts +0 -13
  114. package/templates/create/tanstack-start/prisma/schema.prisma.hbs +0 -21
  115. package/templates/create/tanstack-start/prisma/seed.ts.hbs +0 -37
  116. package/templates/create/tanstack-start/prisma.config.ts +0 -13
  117. package/templates/create/turborepo/packages/db/prisma/schema.prisma.hbs +0 -21
  118. package/templates/create/turborepo/packages/db/prisma/seed.ts.hbs +0 -38
  119. package/templates/create/turborepo/packages/db/prisma.config.ts +0 -13
@@ -1,17 +1,133 @@
1
1
  #!/usr/bin/env node
2
- import { cancel, confirm, intro, isCancel, log, multiselect, outro, select, spinner, text } from "@clack/prompts";
2
+ import { cancel, confirm, intro, isCancel, log, note, outro, select, spinner, text } from "@clack/prompts";
3
3
  import fs from "fs-extra";
4
4
  import path from "node:path";
5
+ import { randomUUID } from "node:crypto";
6
+ import os from "node:os";
7
+ import { PostHog } from "posthog-node";
5
8
  import Handlebars from "handlebars";
6
9
  import { existsSync } from "node:fs";
7
10
  import { fileURLToPath } from "node:url";
8
11
  import { z } from "zod";
9
12
  import { execa } from "execa";
10
- import { randomUUID } from "node:crypto";
11
- import os from "node:os";
12
- import { PostHog } from "posthog-node";
13
13
  import { styleText } from "node:util";
14
14
 
15
+ //#region src/telemetry/client.ts
16
+ const TELEMETRY_API_KEY = "";
17
+ const TELEMETRY_HOST = "https://us.i.posthog.com";
18
+ const TELEMETRY_CONFIG_FILE = "telemetry.json";
19
+ 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;
20
+ function shouldDisableTelemetry() {
21
+ return true;
22
+ }
23
+ function getTelemetryConfigDir() {
24
+ if (process.platform === "darwin") return path.join(os.homedir(), "Library", "Application Support", "create-prisma");
25
+ if (process.platform === "win32") return path.join(process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming"), "create-prisma");
26
+ return path.join(process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config"), "create-prisma");
27
+ }
28
+ async function getAnonymousId() {
29
+ const telemetryConfigPath = path.join(getTelemetryConfigDir(), TELEMETRY_CONFIG_FILE);
30
+ try {
31
+ const config = await fs.readJSON(telemetryConfigPath);
32
+ if (typeof config.anonymousId === "string" && UUID_V4_REGEX.test(config.anonymousId)) return config.anonymousId;
33
+ } catch {}
34
+ const anonymousId = randomUUID();
35
+ try {
36
+ await fs.ensureDir(path.dirname(telemetryConfigPath));
37
+ await fs.writeJSON(telemetryConfigPath, { anonymousId }, { spaces: 2 });
38
+ } catch {}
39
+ return anonymousId;
40
+ }
41
+ function getCommonProperties() {
42
+ return {
43
+ "cli-version": "0.4.2-next.37.79.1",
44
+ "node-version": process.version,
45
+ platform: process.platform,
46
+ arch: process.arch
47
+ };
48
+ }
49
+ function sanitizeProperties(properties) {
50
+ return Object.fromEntries(Object.entries(properties).filter(([, value]) => value !== void 0));
51
+ }
52
+ async function trackCliTelemetry(event, properties) {
53
+ if (shouldDisableTelemetry()) return;
54
+ let client;
55
+ try {
56
+ const distinctId = await getAnonymousId();
57
+ const sanitizedProperties = sanitizeProperties({
58
+ ...getCommonProperties(),
59
+ ...properties,
60
+ $process_person_profile: false
61
+ });
62
+ client = new PostHog(TELEMETRY_API_KEY, {
63
+ host: TELEMETRY_HOST,
64
+ disableGeoip: true,
65
+ flushAt: 1,
66
+ flushInterval: 0
67
+ });
68
+ await client.captureImmediate({
69
+ distinctId,
70
+ event,
71
+ properties: sanitizedProperties,
72
+ disableGeoip: true
73
+ });
74
+ } catch {} finally {
75
+ if (client) await client.shutdown().catch(() => {});
76
+ }
77
+ }
78
+
79
+ //#endregion
80
+ //#region src/telemetry/create.ts
81
+ function getTargetDirectoryState(context) {
82
+ if (!context.targetPathState.exists) return "new";
83
+ if (context.targetPathState.isEmptyDirectory) return "empty_directory";
84
+ return "non_empty_directory";
85
+ }
86
+ function getBaseCreateProperties(input, context) {
87
+ return {
88
+ command: "create",
89
+ "uses-defaults": input.yes === true,
90
+ verbose: input.verbose === true,
91
+ force: input.force === true,
92
+ template: context?.template ?? input.template ?? null,
93
+ "database-provider": context?.prismaSetupContext.databaseProvider ?? input.provider ?? null,
94
+ "authoring-style": context?.prismaSetupContext.authoring ?? input.authoring ?? null,
95
+ "package-manager": context?.prismaSetupContext.packageManager ?? input.packageManager ?? null,
96
+ "schema-preset": context?.prismaSetupContext.schemaPreset ?? input.schemaPreset ?? null,
97
+ "should-install": context?.prismaSetupContext.shouldInstall ?? input.install ?? null,
98
+ "should-emit": context?.prismaSetupContext.shouldEmit ?? input.emit ?? null,
99
+ "uses-prisma-postgres": context?.prismaSetupContext.shouldUsePrismaPostgres ?? input.prismaPostgres ?? null,
100
+ "target-directory-state": context ? getTargetDirectoryState(context) : null
101
+ };
102
+ }
103
+ function getErrorName(error) {
104
+ if (error instanceof Error) return error.name;
105
+ return error === void 0 ? null : "UnknownError";
106
+ }
107
+ function getErrorCode(error) {
108
+ if (typeof error !== "object" || error === null) return null;
109
+ const exitCode = Reflect.get(error, "exitCode");
110
+ if (typeof exitCode === "number") return exitCode;
111
+ const code = Reflect.get(error, "code");
112
+ return typeof code === "number" || typeof code === "string" ? code : null;
113
+ }
114
+ async function trackCreateCompleted(params) {
115
+ await trackCliTelemetry("cli:create_command_completed", {
116
+ ...getBaseCreateProperties(params.input, params.context),
117
+ "duration-ms": params.durationMs
118
+ });
119
+ }
120
+ async function trackCreateFailed(params) {
121
+ await trackCliTelemetry("cli:create_command_failed", {
122
+ ...getBaseCreateProperties(params.input, params.context),
123
+ "duration-ms": params.durationMs,
124
+ "failure-stage": params.stage,
125
+ "error-name": getErrorName(params.error),
126
+ "error-code": getErrorCode(params.error)
127
+ });
128
+ }
129
+
130
+ //#endregion
15
131
  //#region src/utils/runtime.ts
16
132
  function usesNodeStyleRuntime(packageManager) {
17
133
  return packageManager !== void 0 && packageManager !== "bun" && packageManager !== "deno";
@@ -24,15 +140,23 @@ function requiresDotenvConfigImport(packageManager) {
24
140
  //#region src/constants/dependencies.ts
25
141
  const dependencyVersionMap = {
26
142
  "@elysiajs/node": "^1.4.5",
27
- "@prisma/client": "^7.4.0",
28
- "@prisma/adapter-pg": "^7.4.0",
29
- "@prisma/adapter-mariadb": "^7.4.0",
30
- "@prisma/adapter-better-sqlite3": "^7.4.0",
31
- "@prisma/adapter-mssql": "^7.4.0",
32
- "@types/node": "^24.3.0",
33
- dotenv: "^17.2.3",
34
- "node-gyp": "^11.5.0",
35
- prisma: "^7.4.0",
143
+ "@prisma-next/adapter-mongo": "0.4.4",
144
+ "@prisma-next/adapter-postgres": "0.4.4",
145
+ "@prisma-next/cli": "0.4.4",
146
+ "@prisma-next/contract": "0.4.4",
147
+ "@prisma-next/family-mongo": "0.4.4",
148
+ "@prisma-next/family-sql": "0.4.4",
149
+ "@prisma-next/mongo": "0.4.4",
150
+ "@prisma-next/mongo-contract": "0.4.4",
151
+ "@prisma-next/mongo-contract-ts": "0.4.4",
152
+ "@prisma-next/postgres": "0.4.4",
153
+ "@prisma-next/sql-contract": "0.4.4",
154
+ "@prisma-next/sql-contract-ts": "0.4.4",
155
+ "@prisma-next/target-mongo": "0.4.4",
156
+ "@prisma-next/target-postgres": "0.4.4",
157
+ "@types/node": "^25.6.2",
158
+ dotenv: "^17.4.2",
159
+ "prisma-next": "0.4.4",
36
160
  tsx: "^4.21.0"
37
161
  };
38
162
  function getWorkspaceDependencyVersion(packageManager) {
@@ -64,12 +188,11 @@ function getCreateTemplateDependencies(template, packageManager) {
64
188
 
65
189
  //#endregion
66
190
  //#region src/types.ts
67
- const databaseProviders = [
191
+ const databaseProviderInputs = [
192
+ "postgres",
68
193
  "postgresql",
69
- "mysql",
70
- "sqlite",
71
- "sqlserver",
72
- "cockroachdb"
194
+ "mongo",
195
+ "mongodb"
73
196
  ];
74
197
  const packageManagers = [
75
198
  "npm",
@@ -79,6 +202,7 @@ const packageManagers = [
79
202
  "deno"
80
203
  ];
81
204
  const schemaPresets = ["empty", "basic"];
205
+ const authoringStyles = ["psl", "typescript"];
82
206
  const createTemplates = [
83
207
  "hono",
84
208
  "elysia",
@@ -90,53 +214,35 @@ const createTemplates = [
90
214
  "tanstack-start",
91
215
  "turborepo"
92
216
  ];
93
- const createAddons = [
94
- "skills",
95
- "mcp",
96
- "extension"
97
- ];
98
- const addonInstallScopes = ["project", "global"];
99
- const extensionTargets = [
100
- "vscode",
101
- "cursor",
102
- "windsurf"
103
- ];
104
- const prismaSkillNames = [
105
- "prisma-cli",
106
- "prisma-client-api",
107
- "prisma-database-setup",
108
- "prisma-upgrade-v7",
109
- "prisma-postgres"
110
- ];
111
- const DatabaseProviderSchema = z.enum(databaseProviders);
217
+ function normalizeDatabaseProvider(value) {
218
+ if (value === "postgresql") return "postgres";
219
+ if (value === "mongodb") return "mongo";
220
+ return value;
221
+ }
222
+ const DatabaseProviderSchema = z.enum(databaseProviderInputs).transform(normalizeDatabaseProvider);
112
223
  const PackageManagerSchema = z.enum(packageManagers);
113
224
  const SchemaPresetSchema = z.enum(schemaPresets);
225
+ const AuthoringStyleSchema = z.enum(authoringStyles);
114
226
  const CreateTemplateSchema = z.enum(createTemplates);
115
- const CreateAddonSchema = z.enum(createAddons);
116
- const AddonInstallScopeSchema = z.enum(addonInstallScopes);
117
- const ExtensionTargetSchema = z.enum(extensionTargets);
118
- const PrismaSkillNameSchema = z.enum(prismaSkillNames);
119
227
  const DatabaseUrlSchema = z.string().trim().min(1, "Please enter a valid database URL");
120
228
  const CommonCommandOptionsSchema = z.object({
121
229
  yes: z.boolean().optional().describe("Skip prompts and accept default choices"),
122
230
  verbose: z.boolean().optional().describe("Show verbose command output during setup")
123
231
  });
124
232
  const PrismaSetupOptionsSchema = z.object({
125
- provider: DatabaseProviderSchema.optional().describe("Database provider"),
233
+ provider: DatabaseProviderSchema.optional().describe("Prisma Next database target: PostgreSQL relational models or MongoDB document models"),
234
+ authoring: AuthoringStyleSchema.optional().describe("Contract authoring style"),
126
235
  packageManager: PackageManagerSchema.optional().describe("Package manager used for dependency installation"),
127
- prismaPostgres: z.boolean().optional().describe("Provision Prisma Postgres with create-db when provider is postgresql"),
236
+ prismaPostgres: z.boolean().optional().describe("Provision Prisma Postgres with create-db when target is postgres"),
128
237
  databaseUrl: DatabaseUrlSchema.optional().describe("DATABASE_URL value"),
129
238
  install: z.boolean().optional().describe("Install dependencies with selected package manager"),
130
- generate: z.boolean().optional().describe("Generate Prisma Client after scaffolding"),
131
- schemaPreset: SchemaPresetSchema.optional().describe("Schema preset to scaffold in prisma/schema.prisma")
239
+ emit: z.boolean().optional().describe("Emit Prisma Next contract artifacts after scaffolding"),
240
+ schemaPreset: SchemaPresetSchema.optional().describe("Schema preset to scaffold in prisma/contract.prisma or prisma/contract.ts")
132
241
  });
133
242
  const PrismaSetupCommandInputSchema = CommonCommandOptionsSchema.extend(PrismaSetupOptionsSchema.shape);
134
243
  const CreateScaffoldOptionsSchema = z.object({
135
244
  name: z.string().trim().min(1, "Please enter a valid project name").optional().describe("Project name / directory"),
136
245
  template: CreateTemplateSchema.optional().describe("Project template"),
137
- skills: z.boolean().optional().describe("Enable skills addon"),
138
- mcp: z.boolean().optional().describe("Enable MCP addon"),
139
- extension: z.boolean().optional().describe("Enable extension addon"),
140
246
  force: z.boolean().optional().describe("Allow scaffolding into a non-empty target directory")
141
247
  });
142
248
  const CreateCommandInputSchema = PrismaSetupCommandInputSchema.extend(CreateScaffoldOptionsSchema.shape);
@@ -220,14 +326,11 @@ function getPackageManagerManifestValue(packageManager) {
220
326
  if (!packageManager || packageManager === "deno") return;
221
327
  return packageManagerManifestValues[packageManager];
222
328
  }
223
- function getDenoPrismaSpecifier() {
224
- return `npm:prisma@${dependencyVersionMap.prisma}`;
225
- }
226
329
  function getDenoAllowedScriptSpecifiers() {
227
330
  return [
228
- `npm:prisma@${dependencyVersionMap.prisma}`,
229
- `npm:@prisma/client@${dependencyVersionMap["@prisma/client"]}`,
230
- `npm:@prisma/engines@${dependencyVersionMap.prisma}`
331
+ `npm:prisma-next@${dependencyVersionMap["prisma-next"]}`,
332
+ `npm:@prisma-next/postgres@${dependencyVersionMap["@prisma-next/postgres"]}`,
333
+ `npm:@prisma-next/mongo@${dependencyVersionMap["@prisma-next/mongo"]}`
231
334
  ].join(",");
232
335
  }
233
336
  function getInstallCommand(packageManager) {
@@ -243,6 +346,19 @@ function getRunScriptCommand(packageManager, scriptName) {
243
346
  default: return `npm run ${scriptName}`;
244
347
  }
245
348
  }
349
+ function getRunScriptInDirectoryCommand(packageManager, directory, scriptName) {
350
+ switch (packageManager) {
351
+ case "deno": return `deno task --cwd ${directory} ${scriptName}`;
352
+ case "bun": return `bun run --cwd ${directory} ${scriptName}`;
353
+ case "pnpm": return `pnpm --dir ${directory} run ${scriptName}`;
354
+ case "yarn": return `yarn --cwd ${directory} run ${scriptName}`;
355
+ default: return `npm --prefix ${directory} run ${scriptName}`;
356
+ }
357
+ }
358
+ function getRunScriptInDirectoryCommandWithArgsPassthrough(packageManager, directory, scriptName) {
359
+ const command = getRunScriptInDirectoryCommand(packageManager, directory, scriptName);
360
+ return packageManager === "npm" ? `${command} --` : command;
361
+ }
246
362
  function joinCommandParts(parts) {
247
363
  return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
248
364
  }
@@ -326,26 +442,46 @@ function getPackageExecutionCommand(packageManager, commandArgs) {
326
442
  const execution = getPackageExecutionArgs(packageManager, commandArgs);
327
443
  return [execution.command, ...execution.args].join(" ");
328
444
  }
329
- function getPrismaCliArgs(packageManager, prismaArgs) {
330
- if (packageManager === "bun") return getPackageExecutionArgs(packageManager, [
331
- "--bun",
332
- "prisma",
333
- ...prismaArgs
334
- ]);
335
- if (packageManager === "deno") return {
336
- command: "deno",
337
- args: [
338
- "run",
339
- "-A",
340
- "--env-file=.env",
341
- getDenoPrismaSpecifier(),
342
- ...prismaArgs
343
- ]
344
- };
345
- return getPackageExecutionArgs(packageManager, ["prisma", ...prismaArgs]);
445
+ function getLocalPackageBinaryArgs(packageManager, binaryName, binaryArgs) {
446
+ switch (packageManager) {
447
+ case "pnpm": return {
448
+ command: "pnpm",
449
+ args: [
450
+ "exec",
451
+ binaryName,
452
+ ...binaryArgs
453
+ ]
454
+ };
455
+ case "yarn": return {
456
+ command: "yarn",
457
+ args: [binaryName, ...binaryArgs]
458
+ };
459
+ case "bun": return {
460
+ command: "bun",
461
+ args: [binaryName, ...binaryArgs]
462
+ };
463
+ case "deno": return {
464
+ command: "deno",
465
+ args: [
466
+ "run",
467
+ "-A",
468
+ `npm:${binaryName}`,
469
+ ...binaryArgs
470
+ ]
471
+ };
472
+ default: return {
473
+ command: "npm",
474
+ args: [
475
+ "exec",
476
+ binaryName,
477
+ "--",
478
+ ...binaryArgs
479
+ ]
480
+ };
481
+ }
346
482
  }
347
- function getPrismaCliCommand(packageManager, prismaArgs) {
348
- const execution = getPrismaCliArgs(packageManager, prismaArgs);
483
+ function getLocalPackageBinaryCommand(packageManager, binaryName, binaryArgs) {
484
+ const execution = getLocalPackageBinaryArgs(packageManager, binaryName, binaryArgs);
349
485
  return [execution.command, ...execution.args].join(" ");
350
486
  }
351
487
 
@@ -360,6 +496,8 @@ function getOptionalHashStringList(hash, key) {
360
496
  }
361
497
  Handlebars.registerHelper("eq", (left, right) => left === right);
362
498
  Handlebars.registerHelper("runScriptCommand", (packageManager, scriptName) => packageManager ? getRunScriptCommand(packageManager, scriptName) : "");
499
+ Handlebars.registerHelper("runScriptInDirectoryCommand", (packageManager, directory, scriptName) => packageManager ? getRunScriptInDirectoryCommand(packageManager, directory, scriptName) : "");
500
+ Handlebars.registerHelper("runScriptInDirectoryCommandWithArgsPassthrough", (packageManager, directory, scriptName) => packageManager ? getRunScriptInDirectoryCommandWithArgsPassthrough(packageManager, directory, scriptName) : "");
363
501
  Handlebars.registerHelper("packageManagerManifestValue", (packageManager) => getPackageManagerManifestValue(packageManager) ?? "");
364
502
  Handlebars.registerHelper("requiresDotenvConfigImport", (packageManager) => requiresDotenvConfigImport(packageManager));
365
503
  Handlebars.registerHelper("runtimeScript", (packageManager, kind, sourceEntrypoint, builtEntrypoint, options) => {
@@ -431,65 +569,81 @@ async function renderTemplateTree(opts) {
431
569
  function getCreateTemplateDir(template) {
432
570
  return resolveTemplatesDir(`templates/create/${template}`);
433
571
  }
434
- function createTemplateContext(projectName, provider, schemaPreset, packageManager) {
572
+ function getCreateSharedTemplateDir() {
573
+ return resolveTemplatesDir("templates/create/_shared");
574
+ }
575
+ function createTemplateContext(projectName, template, provider, authoring, schemaPreset, packageManager) {
435
576
  return {
436
577
  projectName,
578
+ template,
437
579
  provider,
580
+ authoring,
438
581
  schemaPreset,
439
582
  packageManager
440
583
  };
441
584
  }
442
585
  async function scaffoldCreateTemplate(opts) {
443
- const { projectDir, projectName, template, provider, schemaPreset, packageManager } = opts;
586
+ const { projectDir, projectName, template, provider, authoring, schemaPreset, packageManager } = opts;
587
+ const templateRoot = getCreateTemplateDir(template);
588
+ const sharedTemplateRoot = getCreateSharedTemplateDir();
589
+ const context = createTemplateContext(projectName, template, provider, authoring, schemaPreset, packageManager);
444
590
  await renderTemplateTree({
445
- templateRoot: getCreateTemplateDir(template),
591
+ templateRoot: sharedTemplateRoot,
446
592
  outputDir: projectDir,
447
- context: createTemplateContext(projectName, provider, schemaPreset, packageManager)
593
+ context
594
+ });
595
+ await renderTemplateTree({
596
+ templateRoot,
597
+ outputDir: projectDir,
598
+ context
448
599
  });
449
600
  }
450
601
 
451
602
  //#endregion
452
603
  //#region src/constants/db-packages.ts
453
- function getDbPackages(provider) {
604
+ function getDbPackages(provider, _packageManager) {
454
605
  switch (provider) {
455
- case "postgresql":
456
- case "cockroachdb": return "@prisma/adapter-pg";
457
- case "mysql": return "@prisma/adapter-mariadb";
458
- case "sqlite": return "@prisma/adapter-better-sqlite3";
459
- case "sqlserver": return "@prisma/adapter-mssql";
606
+ case "postgres": return "@prisma-next/postgres";
607
+ case "mongo": return "@prisma-next/mongo";
460
608
  default: {
461
609
  const exhaustiveCheck = provider;
462
- throw new Error(`Unsupported database provider: ${String(exhaustiveCheck)}`);
610
+ throw new Error(`Unsupported Prisma Next target: ${String(exhaustiveCheck)}`);
463
611
  }
464
612
  }
465
613
  }
466
614
 
467
615
  //#endregion
468
616
  //#region src/tasks/install.ts
469
- function getPrismaScriptMap(packageManager) {
617
+ function getPrismaNextScriptMap(packageManager) {
470
618
  if (packageManager === "deno") {
471
- const prismaSpecifier = getDenoPrismaSpecifier();
619
+ const prismaNextCli = `deno run -A --env-file=.env npm:prisma-next@${dependencyVersionMap["prisma-next"]}`;
472
620
  return {
473
- "db:generate": `deno run -A --env-file=.env ${prismaSpecifier} generate`,
474
- "db:push": `deno run -A --env-file=.env ${prismaSpecifier} db push`,
475
- "db:migrate": `deno run -A --env-file=.env ${prismaSpecifier} migrate dev`,
476
- "db:seed": `deno run -A --env-file=.env ${prismaSpecifier} db seed`
621
+ "contract:emit": `${prismaNextCli} contract emit`,
622
+ "db:init": `${prismaNextCli} db init`,
623
+ "db:update": `${prismaNextCli} db update`,
624
+ "db:seed": "deno run -A --env-file=.env prisma/seed.ts",
625
+ "migration:plan": `${prismaNextCli} migration plan`,
626
+ "migration:apply": `${prismaNextCli} migration apply`
477
627
  };
478
628
  }
479
629
  if (packageManager === "bun") {
480
- const prismaCli = "bun --env-file=.env ./node_modules/.bin/prisma";
630
+ const prismaNextCli = "bun prisma-next";
481
631
  return {
482
- "db:generate": `${prismaCli} generate`,
483
- "db:push": `${prismaCli} db push`,
484
- "db:migrate": `${prismaCli} migrate dev`,
485
- "db:seed": `${prismaCli} db seed`
632
+ "contract:emit": `${prismaNextCli} contract emit`,
633
+ "db:init": `${prismaNextCli} db init`,
634
+ "db:update": `${prismaNextCli} db update`,
635
+ "db:seed": "bun prisma/seed.ts",
636
+ "migration:plan": `${prismaNextCli} migration plan`,
637
+ "migration:apply": `${prismaNextCli} migration apply`
486
638
  };
487
639
  }
488
640
  return {
489
- "db:generate": "prisma generate",
490
- "db:push": "prisma db push",
491
- "db:migrate": "prisma migrate dev",
492
- "db:seed": "prisma db seed"
641
+ "contract:emit": "prisma-next contract emit",
642
+ "db:init": "prisma-next db init",
643
+ "db:update": "prisma-next db update",
644
+ "db:seed": "tsx prisma/seed.ts",
645
+ "migration:plan": "prisma-next migration plan",
646
+ "migration:apply": "prisma-next migration apply"
493
647
  };
494
648
  }
495
649
  function getVersion(packageName) {
@@ -501,24 +655,35 @@ function unique(items) {
501
655
  function sortRecord(record) {
502
656
  return Object.fromEntries(Object.entries(record).sort(([a], [b]) => a.localeCompare(b)));
503
657
  }
504
- async function projectContainsText(projectDir, text) {
505
- const directories = [projectDir];
506
- while (directories.length > 0) {
507
- const currentDirectory = directories.pop();
508
- if (!currentDirectory) continue;
509
- const entries = await fs.readdir(currentDirectory, { withFileTypes: true });
510
- for (const entry of entries) {
511
- if (entry.name === "node_modules" || entry.name === ".git") continue;
512
- const entryPath = path.join(currentDirectory, entry.name);
513
- if (entry.isDirectory()) {
514
- directories.push(entryPath);
515
- continue;
516
- }
517
- if (!entry.isFile() || !/\.(c|m)?[jt]sx?$/.test(entry.name)) continue;
518
- if ((await fs.readFile(entryPath, "utf8")).includes(text)) return true;
519
- }
520
- }
521
- return false;
658
+ function getGeneratedContractTypePackages(provider) {
659
+ if (provider === "mongo") return [
660
+ "@prisma-next/adapter-mongo",
661
+ "@prisma-next/contract",
662
+ "@prisma-next/mongo-contract"
663
+ ];
664
+ return [
665
+ "@prisma-next/adapter-postgres",
666
+ "@prisma-next/contract",
667
+ "@prisma-next/sql-contract",
668
+ "@prisma-next/target-postgres"
669
+ ];
670
+ }
671
+ function getTypeScriptContractPackages(provider) {
672
+ if (provider === "mongo") return [
673
+ ...getGeneratedContractTypePackages(provider),
674
+ "@prisma-next/family-mongo",
675
+ "@prisma-next/mongo-contract-ts",
676
+ "@prisma-next/target-mongo"
677
+ ];
678
+ return [
679
+ ...getGeneratedContractTypePackages(provider),
680
+ "@prisma-next/family-sql",
681
+ "@prisma-next/sql-contract-ts"
682
+ ];
683
+ }
684
+ function getMigrationPackages(provider) {
685
+ if (provider === "mongo") return ["@prisma-next/family-mongo", "@prisma-next/target-mongo"];
686
+ return ["@prisma-next/target-postgres"];
522
687
  }
523
688
  async function addPackageDependency(opts) {
524
689
  const { dependencies = [], devDependencies = [], customDependencies = {}, scripts = {}, scriptMode, projectDir } = opts;
@@ -550,16 +715,20 @@ async function addPackageDependency(opts) {
550
715
  pkgJson.devDependencies = sortRecord(pkgJson.devDependencies);
551
716
  await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
552
717
  }
553
- async function writePrismaDependencies(provider, packageManager, projectDir = process.cwd()) {
554
- const dependencies = ["@prisma/client"];
555
- const devDependencies = ["prisma"];
556
- dependencies.push(getDbPackages(provider));
557
- if (requiresDotenvConfigImport(packageManager) || await projectContainsText(projectDir, "dotenv/config")) dependencies.push("dotenv");
558
- if (provider === "sqlite" && packageManager === "deno") devDependencies.push("node-gyp");
718
+ async function writePrismaDependencies(provider, packageManager, authoring, projectDir = process.cwd()) {
719
+ const dependencies = [getDbPackages(provider, packageManager), "dotenv"];
720
+ const devDependencies = [
721
+ "prisma-next",
722
+ "@prisma-next/cli",
723
+ "@types/node"
724
+ ];
725
+ devDependencies.push(...getMigrationPackages(provider));
726
+ if (authoring === "typescript") devDependencies.push(...getTypeScriptContractPackages(provider));
727
+ else if (packageManager === "deno") devDependencies.push(...getGeneratedContractTypePackages(provider));
559
728
  await addPackageDependency({
560
729
  dependencies,
561
730
  devDependencies,
562
- scripts: getPrismaScriptMap(packageManager),
731
+ scripts: getPrismaNextScriptMap(packageManager),
563
732
  scriptMode: "if-missing",
564
733
  projectDir
565
734
  });
@@ -580,8 +749,10 @@ async function writeCreateTemplateDependencies(opts) {
580
749
  async function installProjectDependencies(packageManager, projectDir = process.cwd(), options = {}) {
581
750
  const verbose = options.verbose === true;
582
751
  const installCommand = getInstallArgs(packageManager);
752
+ const env = packageManager === "yarn" ? { YARN_ENABLE_IMMUTABLE_INSTALLS: "false" } : void 0;
583
753
  await execa(installCommand.command, installCommand.args, {
584
754
  cwd: projectDir,
755
+ env,
585
756
  stdio: verbose ? "inherit" : "pipe"
586
757
  });
587
758
  }
@@ -643,15 +814,45 @@ function getCreateDbCommand(packageManager) {
643
814
 
644
815
  //#endregion
645
816
  //#region src/tasks/setup-prisma.ts
646
- const DEFAULT_DATABASE_PROVIDER = "postgresql";
647
- const DEFAULT_SCHEMA_PRESET$1 = "empty";
648
- const DEFAULT_PRISMA_POSTGRES = true;
817
+ const DEFAULT_DATABASE_PROVIDER = "postgres";
818
+ const DEFAULT_AUTHORING = "psl";
819
+ const DEFAULT_SCHEMA_PRESET$1 = "basic";
649
820
  const DEFAULT_INSTALL = true;
650
- const DEFAULT_GENERATE = true;
821
+ const DEFAULT_EMIT = true;
822
+ const MONGO_DOCKER_COMPOSE = `services:
823
+ mongodb:
824
+ image: mongo:latest
825
+ command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
826
+ ports:
827
+ - "27017:27017"
828
+ volumes:
829
+ - mongodb-data:/data/db
830
+ healthcheck:
831
+ test:
832
+ [
833
+ "CMD-SHELL",
834
+ "mongosh --quiet --eval 'try { rs.status().members.some((member) => member.stateStr === \\"PRIMARY\\") } catch (error) { rs.initiate({_id: \\"rs0\\", members: [{ _id: 0, host: \\"localhost:27017\\" }] }); false }' | grep true",
835
+ ]
836
+ interval: 5s
837
+ timeout: 5s
838
+ retries: 30
839
+ start_period: 5s
840
+
841
+ volumes:
842
+ mongodb-data:
843
+ `;
844
+ const mongoDockerScripts = {
845
+ "db:up": "docker compose up -d --wait",
846
+ "db:down": "docker compose down"
847
+ };
651
848
  const requiredPrismaFileGroups = [
652
- ["prisma/schema.prisma", "packages/db/prisma/schema.prisma"],
653
- ["prisma/seed.ts", "packages/db/prisma/seed.ts"],
654
- ["prisma.config.ts", "packages/db/prisma.config.ts"],
849
+ [
850
+ "prisma/contract.prisma",
851
+ "prisma/contract.ts",
852
+ "packages/db/prisma/contract.prisma",
853
+ "packages/db/prisma/contract.ts"
854
+ ],
855
+ ["prisma-next.config.ts", "packages/db/prisma-next.config.ts"],
655
856
  [
656
857
  "src/lib/prisma.ts",
657
858
  "src/lib/prisma.server.ts",
@@ -662,36 +863,22 @@ const requiredPrismaFileGroups = [
662
863
  ];
663
864
  async function resolvePrismaProjectDir(projectDir) {
664
865
  const monorepoDbDir = path.join(projectDir, "packages/db");
665
- if (await fs.pathExists(path.join(monorepoDbDir, "prisma/schema.prisma"))) return monorepoDbDir;
866
+ if (await fs.pathExists(path.join(monorepoDbDir, "prisma/contract.prisma")) || await fs.pathExists(path.join(monorepoDbDir, "prisma/contract.ts"))) return monorepoDbDir;
666
867
  return projectDir;
667
868
  }
668
869
  async function promptForDatabaseProvider() {
669
870
  const databaseProvider = await select({
670
871
  message: "Select your database",
671
872
  initialValue: DEFAULT_DATABASE_PROVIDER,
672
- options: [
673
- {
674
- value: "postgresql",
675
- label: "PostgreSQL",
676
- hint: "Default"
677
- },
678
- {
679
- value: "mysql",
680
- label: "MySQL"
681
- },
682
- {
683
- value: "sqlite",
684
- label: "SQLite"
685
- },
686
- {
687
- value: "sqlserver",
688
- label: "SQL Server"
689
- },
690
- {
691
- value: "cockroachdb",
692
- label: "CockroachDB"
693
- }
694
- ]
873
+ options: [{
874
+ value: "postgres",
875
+ label: "PostgreSQL",
876
+ hint: "Relational models with typed ORM, relations, indexes, raw SQL"
877
+ }, {
878
+ value: "mongo",
879
+ label: "MongoDB",
880
+ hint: "Document models with typed ORM, indexes, aggregations"
881
+ }]
695
882
  });
696
883
  if (isCancel(databaseProvider)) {
697
884
  cancel("Operation cancelled.");
@@ -699,10 +886,35 @@ async function promptForDatabaseProvider() {
699
886
  }
700
887
  return DatabaseProviderSchema.parse(databaseProvider);
701
888
  }
889
+ async function promptForAuthoringStyle() {
890
+ const authoring = await select({
891
+ message: "Choose contract authoring style",
892
+ initialValue: DEFAULT_AUTHORING,
893
+ options: [{
894
+ value: "psl",
895
+ label: "PSL",
896
+ hint: "Schema syntax emits contract.json + types"
897
+ }, {
898
+ value: "typescript",
899
+ label: "TypeScript",
900
+ hint: "Builder API emits the same contract artifacts"
901
+ }]
902
+ });
903
+ if (isCancel(authoring)) {
904
+ cancel("Operation cancelled.");
905
+ return;
906
+ }
907
+ return AuthoringStyleSchema.parse(authoring);
908
+ }
702
909
  function getPackageManagerHint(option, detected) {
703
- if (option === detected) return "Detected";
704
- if (option === "bun") return "Fast runtime + package manager";
705
- if (option === "deno") return "Runtime + package manager";
910
+ const hint = {
911
+ npm: "Node.js default",
912
+ pnpm: "Fast, disk-efficient Node.js package manager",
913
+ yarn: "Yarn package manager",
914
+ bun: "Fast runtime + package manager",
915
+ deno: "Deno runtime + task runner"
916
+ }[option];
917
+ return option === detected ? `Detected; ${hint}` : hint;
706
918
  }
707
919
  async function promptForPackageManager(detectedPackageManager) {
708
920
  const packageManager = await select({
@@ -744,7 +956,9 @@ async function promptForPackageManager(detectedPackageManager) {
744
956
  }
745
957
  async function promptForDependencyInstall(packageManager) {
746
958
  const shouldInstall = await confirm({
747
- message: `Install dependencies now with ${getInstallCommand(packageManager)}?`,
959
+ message: `Install dependencies now with ${getInstallCommand(packageManager)}? You can run it later.`,
960
+ active: "Install now",
961
+ inactive: "Skip for now",
748
962
  initialValue: true
749
963
  });
750
964
  if (isCancel(shouldInstall)) {
@@ -753,17 +967,6 @@ async function promptForDependencyInstall(packageManager) {
753
967
  }
754
968
  return Boolean(shouldInstall);
755
969
  }
756
- async function promptForPrismaPostgres() {
757
- const shouldUsePrismaPostgres = await confirm({
758
- message: "Use Prisma Postgres and auto-generate DATABASE_URL with create-db?",
759
- initialValue: true
760
- });
761
- if (isCancel(shouldUsePrismaPostgres)) {
762
- cancel("Operation cancelled.");
763
- return;
764
- }
765
- return Boolean(shouldUsePrismaPostgres);
766
- }
767
970
  function getCommandErrorMessage(error) {
768
971
  if (error instanceof Error && "stderr" in error) {
769
972
  const stderr = String(error.stderr ?? "").trim();
@@ -775,16 +978,21 @@ async function collectPrismaSetupContext(input, options = {}) {
775
978
  const projectDir = path.resolve(options.projectDir ?? process.cwd());
776
979
  const useDefaults = input.yes === true;
777
980
  const verbose = input.verbose === true;
778
- const shouldGenerate = input.generate ?? DEFAULT_GENERATE;
981
+ const shouldEmit = input.emit ?? DEFAULT_EMIT;
779
982
  const databaseProvider = input.provider ?? (useDefaults ? DEFAULT_DATABASE_PROVIDER : await promptForDatabaseProvider());
780
983
  if (!databaseProvider) return;
984
+ const authoring = input.authoring ?? (useDefaults ? DEFAULT_AUTHORING : await promptForAuthoringStyle());
985
+ if (!authoring) return;
781
986
  const schemaPreset = input.schemaPreset ?? options.defaultSchemaPreset ?? DEFAULT_SCHEMA_PRESET$1;
782
987
  const databaseUrl = input.databaseUrl;
783
- let shouldUsePrismaPostgres = false;
784
- if (databaseProvider === "postgresql" && !databaseUrl) {
785
- const prismaPostgresChoice = input.prismaPostgres ?? (useDefaults ? DEFAULT_PRISMA_POSTGRES : await promptForPrismaPostgres());
786
- if (prismaPostgresChoice === void 0) return;
787
- shouldUsePrismaPostgres = prismaPostgresChoice;
988
+ const shouldUsePrismaPostgres = input.prismaPostgres === true;
989
+ if (shouldUsePrismaPostgres && databaseProvider !== "postgres") {
990
+ cancel("--prisma-postgres is only supported with --provider postgres.");
991
+ return;
992
+ }
993
+ if (shouldUsePrismaPostgres && databaseUrl) {
994
+ cancel("Use either --database-url or --prisma-postgres, not both.");
995
+ return;
788
996
  }
789
997
  const detectedPackageManager = await detectPackageManager(projectDir);
790
998
  const packageManager = input.packageManager ?? (useDefaults ? detectedPackageManager : await promptForPackageManager(detectedPackageManager));
@@ -794,8 +1002,9 @@ async function collectPrismaSetupContext(input, options = {}) {
794
1002
  return {
795
1003
  projectDir,
796
1004
  verbose,
797
- shouldGenerate,
1005
+ shouldEmit,
798
1006
  databaseProvider,
1007
+ authoring,
799
1008
  schemaPreset,
800
1009
  databaseUrl,
801
1010
  shouldUsePrismaPostgres,
@@ -805,14 +1014,11 @@ async function collectPrismaSetupContext(input, options = {}) {
805
1014
  }
806
1015
  function getDefaultDatabaseUrl(provider) {
807
1016
  switch (provider) {
808
- case "postgresql": return "postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public";
809
- case "cockroachdb": return "postgresql://johndoe:randompassword@localhost:26257/mydb?schema=public";
810
- case "mysql": return "mysql://johndoe:randompassword@localhost:3306/mydb";
811
- case "sqlite": return "file:./dev.db";
812
- case "sqlserver": return "sqlserver://localhost:1433;database=mydb;user=SA;password=randompassword;";
1017
+ case "postgres": return "postgresql://user:password@localhost:5432/mydb";
1018
+ case "mongo": return "mongodb://localhost:27017/mydb?replicaSet=rs0&directConnection=true";
813
1019
  default: {
814
1020
  const exhaustiveCheck = provider;
815
- throw new Error(`Unsupported provider: ${String(exhaustiveCheck)}`);
1021
+ throw new Error(`Unsupported Prisma Next target: ${String(exhaustiveCheck)}`);
816
1022
  }
817
1023
  }
818
1024
  }
@@ -882,6 +1088,34 @@ async function ensureGitignoreEntry(projectDir, entry) {
882
1088
  const separator = existingContent.endsWith("\n") ? "" : "\n";
883
1089
  await fs.appendFile(gitignorePath, `${separator}${entry}\n`, "utf8");
884
1090
  }
1091
+ async function ensurePackageScripts(projectDir, scripts) {
1092
+ const packageJsonPath = path.join(projectDir, "package.json");
1093
+ if (!await fs.pathExists(packageJsonPath)) return;
1094
+ const packageJson = await fs.readJson(packageJsonPath);
1095
+ if (!packageJson.scripts) packageJson.scripts = {};
1096
+ let didChange = false;
1097
+ for (const [scriptName, command] of Object.entries(scripts)) if (typeof packageJson.scripts[scriptName] !== "string" || packageJson.scripts[scriptName].trim().length === 0) {
1098
+ packageJson.scripts[scriptName] = command;
1099
+ didChange = true;
1100
+ }
1101
+ if (didChange) await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
1102
+ }
1103
+ async function ensureMongoDockerCompose(projectDir) {
1104
+ const composePath = path.join(projectDir, "docker-compose.yml");
1105
+ if (await fs.pathExists(composePath)) return;
1106
+ await fs.writeFile(composePath, MONGO_DOCKER_COMPOSE, "utf8");
1107
+ }
1108
+ async function writeMongoDockerHelpersForContext(context, projectDir) {
1109
+ if (context.databaseProvider !== "mongo" || context.databaseUrl) return true;
1110
+ try {
1111
+ await ensureMongoDockerCompose(projectDir);
1112
+ await ensurePackageScripts(projectDir, mongoDockerScripts);
1113
+ return true;
1114
+ } catch (error) {
1115
+ cancel(getCommandErrorMessage(error));
1116
+ return false;
1117
+ }
1118
+ }
885
1119
  async function ensureRequiredPrismaFiles(projectDir) {
886
1120
  const missingFiles = [];
887
1121
  for (const candidates of requiredPrismaFileGroups) {
@@ -895,13 +1129,12 @@ async function ensureRequiredPrismaFiles(projectDir) {
895
1129
  }
896
1130
  if (!foundCandidate) missingFiles.push(candidates.join(" or "));
897
1131
  }
898
- if (missingFiles.length > 0) throw new Error(`Template is missing required Prisma files: ${missingFiles.join(", ")}`);
1132
+ if (missingFiles.length > 0) throw new Error(`Template is missing required Prisma Next files: ${missingFiles.join(", ")}`);
899
1133
  }
900
1134
  async function finalizePrismaFiles(options) {
901
1135
  const projectDir = options.projectDir ?? process.cwd();
902
1136
  const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
903
1137
  await ensureRequiredPrismaFiles(projectDir);
904
- const generatedDir = await fs.pathExists(path.join(prismaProjectDir, "server/utils/prisma.ts")) ? "server/generated" : "src/generated";
905
1138
  await ensureEnvVarInEnv(prismaProjectDir, "DATABASE_URL", options.databaseUrl ?? getDefaultDatabaseUrl(options.provider), {
906
1139
  mode: options.databaseUrl ? "upsert" : "keep-existing",
907
1140
  comment: "Added by create-prisma"
@@ -913,7 +1146,7 @@ async function finalizePrismaFiles(options) {
913
1146
  });
914
1147
  await ensureEnvComment(prismaProjectDir, PRISMA_POSTGRES_TEMPORARY_NOTICE);
915
1148
  }
916
- await ensureGitignoreEntry(prismaProjectDir, generatedDir);
1149
+ await ensureGitignoreEntry(prismaProjectDir, ".env");
917
1150
  }
918
1151
  async function provisionPrismaPostgresIfNeeded(context, projectDir) {
919
1152
  if (!context.shouldUsePrismaPostgres) return { databaseUrl: context.databaseUrl };
@@ -939,7 +1172,7 @@ async function provisionPrismaPostgresIfNeeded(context, projectDir) {
939
1172
  async function writeDependenciesForContext(context, projectDir) {
940
1173
  const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
941
1174
  try {
942
- await writePrismaDependencies(context.databaseProvider, context.packageManager, prismaProjectDir);
1175
+ await writePrismaDependencies(context.databaseProvider, context.packageManager, context.authoring, prismaProjectDir);
943
1176
  return true;
944
1177
  } catch (error) {
945
1178
  cancel(getCommandErrorMessage(error));
@@ -974,7 +1207,7 @@ async function installDependenciesForContext(context, projectDir) {
974
1207
  }
975
1208
  async function finalizePrismaFilesForContext(context, projectDir, provisionResult) {
976
1209
  const initSpinner = spinner();
977
- initSpinner.start("Preparing Prisma files...");
1210
+ initSpinner.start("Preparing Prisma Next files...");
978
1211
  try {
979
1212
  await finalizePrismaFiles({
980
1213
  provider: context.databaseProvider,
@@ -982,55 +1215,106 @@ async function finalizePrismaFilesForContext(context, projectDir, provisionResul
982
1215
  claimUrl: provisionResult.claimUrl,
983
1216
  projectDir
984
1217
  });
985
- initSpinner.stop("Prisma files ready.");
1218
+ initSpinner.stop("Prisma Next files ready.");
986
1219
  return true;
987
1220
  } catch (error) {
988
- initSpinner.stop("Could not prepare Prisma files.");
1221
+ initSpinner.stop("Could not prepare Prisma Next files.");
989
1222
  cancel(getCommandErrorMessage(error));
990
1223
  return false;
991
1224
  }
992
1225
  }
993
- async function generatePrismaClientForContext(context, projectDir) {
1226
+ function getPrismaNextCliCommand(packageManager, prismaNextArgs) {
1227
+ if (packageManager === "deno") return `deno run -A --env-file=.env npm:prisma-next@${dependencyVersionMap["prisma-next"]} ${prismaNextArgs.join(" ")}`;
1228
+ return getLocalPackageBinaryCommand(packageManager, "prisma-next", prismaNextArgs);
1229
+ }
1230
+ function getPrismaNextCliArgs(packageManager, prismaNextArgs) {
1231
+ if (packageManager === "deno") return {
1232
+ command: "deno",
1233
+ args: [
1234
+ "run",
1235
+ "-A",
1236
+ "--env-file=.env",
1237
+ `npm:prisma-next@${dependencyVersionMap["prisma-next"]}`,
1238
+ ...prismaNextArgs
1239
+ ]
1240
+ };
1241
+ return getLocalPackageBinaryArgs(packageManager, "prisma-next", prismaNextArgs);
1242
+ }
1243
+ async function emitPrismaNextContractForContext(context, projectDir) {
994
1244
  const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
995
- if (!context.shouldGenerate) return { didGenerateClient: false };
996
- const generateCommand = getPrismaCliCommand(context.packageManager, ["generate"]);
997
- if (context.verbose) log.step(`Running ${generateCommand}`);
998
- const generateSpinner = context.verbose ? void 0 : spinner();
999
- generateSpinner?.start("Generating Prisma Client...");
1245
+ if (!context.shouldEmit) return { didEmitContract: false };
1246
+ if (!context.shouldInstall) return {
1247
+ didEmitContract: false,
1248
+ warning: "Skipped contract emit because dependencies were not installed."
1249
+ };
1250
+ const emitCommand = getPrismaNextCliCommand(context.packageManager, ["contract", "emit"]);
1251
+ if (context.verbose) log.step(`Running ${emitCommand}`);
1252
+ const emitSpinner = context.verbose ? void 0 : spinner();
1253
+ emitSpinner?.start("Emitting Prisma Next contract...");
1000
1254
  try {
1001
- const generateArgs = getPrismaCliArgs(context.packageManager, ["generate"]);
1002
- await execa(generateArgs.command, generateArgs.args, {
1255
+ const emitArgs = getPrismaNextCliArgs(context.packageManager, ["contract", "emit"]);
1256
+ await execa(emitArgs.command, emitArgs.args, {
1003
1257
  cwd: prismaProjectDir,
1004
1258
  stdio: context.verbose ? "inherit" : "pipe"
1005
1259
  });
1006
- if (context.verbose) log.success("Prisma Client generated.");
1007
- else generateSpinner?.stop("Prisma Client generated.");
1008
- return { didGenerateClient: true };
1260
+ if (context.verbose) log.success("Prisma Next contract emitted.");
1261
+ else emitSpinner?.stop("Prisma Next contract emitted.");
1262
+ return { didEmitContract: true };
1009
1263
  } catch (error) {
1010
- if (context.verbose) log.warn("Could not generate Prisma Client.");
1011
- else generateSpinner?.stop("Could not generate Prisma Client.");
1264
+ if (context.verbose) log.warn("Could not emit Prisma Next contract.");
1265
+ else emitSpinner?.stop("Could not emit Prisma Next contract.");
1012
1266
  return {
1013
- didGenerateClient: false,
1014
- warning: `Prisma generate failed: ${getCommandErrorMessage(error)}`
1267
+ didEmitContract: false,
1268
+ warning: `Contract emit failed: ${getCommandErrorMessage(error)}`
1015
1269
  };
1016
1270
  }
1017
1271
  }
1018
- function buildWarningLines(provisionWarning, generateWarning) {
1272
+ function buildWarningLines(provisionWarning, emitWarning) {
1019
1273
  const warningLines = [];
1020
1274
  if (provisionWarning) warningLines.push(`- ${provisionWarning}`);
1021
- if (generateWarning) warningLines.push(`- ${generateWarning}`);
1275
+ if (emitWarning) warningLines.push(`- ${emitWarning}`);
1022
1276
  return warningLines;
1023
1277
  }
1024
1278
  function buildNextStepsForContext(opts) {
1025
- const { context, options, didGenerateClient } = opts;
1279
+ const { context, options, didEmitContract } = opts;
1026
1280
  const nextSteps = [...options.prependNextSteps ?? []];
1027
- if (!context.shouldInstall) nextSteps.push(`- ${getInstallCommand(context.packageManager)}`);
1028
- if (!didGenerateClient || !context.shouldGenerate) nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "db:generate")}`);
1029
- nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "db:migrate")}`);
1030
- nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "db:seed")}`);
1031
- if (options.includeDevNextStep) nextSteps.push(`- ${getRunScriptCommand(context.packageManager, "dev")}`);
1281
+ if (!context.shouldInstall) nextSteps.push({
1282
+ command: getInstallCommand(context.packageManager),
1283
+ description: "Install the project dependencies."
1284
+ });
1285
+ if (!didEmitContract || !context.shouldEmit) nextSteps.push({
1286
+ command: getRunScriptCommand(context.packageManager, "contract:emit"),
1287
+ description: "Emit contract.json and TypeScript types from your Prisma Next contract."
1288
+ });
1289
+ if (context.databaseProvider === "postgres") nextSteps.push({
1290
+ command: getRunScriptCommand(context.packageManager, "db:init"),
1291
+ description: "Create the initial PostgreSQL database objects and sign the database."
1292
+ });
1293
+ if (context.databaseProvider === "mongo" && !context.databaseUrl) nextSteps.push({
1294
+ command: getRunScriptCommand(context.packageManager, "db:up"),
1295
+ description: "Start the local MongoDB replica set with Docker."
1296
+ });
1297
+ nextSteps.push({
1298
+ command: getRunScriptCommand(context.packageManager, "migration:plan"),
1299
+ description: "Compare the contract to the database and write a migration plan."
1300
+ });
1301
+ nextSteps.push({
1302
+ command: getRunScriptCommand(context.packageManager, "migration:apply"),
1303
+ description: "Apply the planned migration to the database."
1304
+ });
1305
+ if (context.schemaPreset === "basic") nextSteps.push({
1306
+ command: getRunScriptCommand(context.packageManager, "db:seed"),
1307
+ description: "Insert the sample user and post data from prisma/seed.ts."
1308
+ });
1309
+ if (options.includeDevNextStep) nextSteps.push({
1310
+ command: getRunScriptCommand(context.packageManager, "dev"),
1311
+ description: "Start the development server."
1312
+ });
1032
1313
  return nextSteps;
1033
1314
  }
1315
+ function formatNextSteps(nextSteps) {
1316
+ return nextSteps.map((step) => `${step.command}\n ${step.description}`).join("\n\n");
1317
+ }
1034
1318
  async function executePrismaSetupContext(context, options = {}) {
1035
1319
  const projectDir = path.resolve(options.projectDir ?? context.projectDir);
1036
1320
  const provisionResult = await provisionPrismaPostgresIfNeeded(context, projectDir);
@@ -1038,687 +1322,20 @@ async function executePrismaSetupContext(context, options = {}) {
1038
1322
  if (!await writeDependenciesForContext(context, projectDir)) return false;
1039
1323
  if (!await installDependenciesForContext(context, projectDir)) return false;
1040
1324
  if (!await finalizePrismaFilesForContext(context, projectDir, provisionResult)) return false;
1041
- const generateResult = await generatePrismaClientForContext(context, projectDir);
1042
- const warningLines = buildWarningLines(provisionResult.warning, generateResult.warning);
1325
+ if (!await writeMongoDockerHelpersForContext(context, projectDir)) return false;
1326
+ const emitResult = await emitPrismaNextContractForContext(context, projectDir);
1327
+ const warningLines = buildWarningLines(provisionResult.warning, emitResult.warning);
1043
1328
  const nextSteps = buildNextStepsForContext({
1044
1329
  context,
1045
1330
  options,
1046
- didGenerateClient: generateResult.didGenerateClient
1331
+ didEmitContract: emitResult.didEmitContract
1047
1332
  });
1048
- outro(`Setup complete.${warningLines.length > 0 ? `\n\n${warningLines.join("\n")}` : ""}
1049
-
1050
- Next steps:
1051
- ${nextSteps.join("\n")}`);
1333
+ if (warningLines.length > 0) note(warningLines.map((line) => line.replace(/^- /, "")).join("\n"), "Heads up");
1334
+ note(formatNextSteps(nextSteps), "Next steps");
1335
+ outro("Setup complete.");
1052
1336
  return true;
1053
1337
  }
1054
1338
 
1055
- //#endregion
1056
- //#region src/tasks/setup-addons.ts
1057
- const DEFAULT_ADDON_SCOPE = "project";
1058
- const DEFAULT_SKILLS_AGENTS = [
1059
- "claude-code",
1060
- "codex",
1061
- "cursor"
1062
- ];
1063
- const DEFAULT_MCP_AGENTS = [
1064
- "claude-code",
1065
- "codex",
1066
- "cursor"
1067
- ];
1068
- const DEFAULT_EXTENSION_TARGETS = ["vscode", "cursor"];
1069
- const PRISMA_MCP_SERVER = "https://mcp.prisma.io/mcp";
1070
- const ADDON_OPTIONS = [
1071
- {
1072
- value: "skills",
1073
- label: "Skills",
1074
- hint: "Install curated Prisma skills to your selected coding agents"
1075
- },
1076
- {
1077
- value: "mcp",
1078
- label: "MCP",
1079
- hint: "Configure Prisma MCP server in agent MCP config files"
1080
- },
1081
- {
1082
- value: "extension",
1083
- label: "IDE Extension",
1084
- hint: "Install Prisma extension in selected IDEs (VS Code, Cursor, Windsurf)"
1085
- }
1086
- ];
1087
- const SKILLS_AGENT_OPTIONS = [
1088
- {
1089
- value: "cursor",
1090
- label: "Cursor"
1091
- },
1092
- {
1093
- value: "claude-code",
1094
- label: "Claude Code"
1095
- },
1096
- {
1097
- value: "cline",
1098
- label: "Cline"
1099
- },
1100
- {
1101
- value: "github-copilot",
1102
- label: "GitHub Copilot"
1103
- },
1104
- {
1105
- value: "codex",
1106
- label: "Codex"
1107
- },
1108
- {
1109
- value: "opencode",
1110
- label: "OpenCode"
1111
- },
1112
- {
1113
- value: "windsurf",
1114
- label: "Windsurf"
1115
- },
1116
- {
1117
- value: "goose",
1118
- label: "Goose"
1119
- },
1120
- {
1121
- value: "roo",
1122
- label: "Roo Code"
1123
- },
1124
- {
1125
- value: "kilo",
1126
- label: "Kilo Code"
1127
- },
1128
- {
1129
- value: "gemini-cli",
1130
- label: "Gemini CLI"
1131
- },
1132
- {
1133
- value: "antigravity",
1134
- label: "Antigravity"
1135
- },
1136
- {
1137
- value: "openhands",
1138
- label: "OpenHands"
1139
- },
1140
- {
1141
- value: "trae",
1142
- label: "Trae"
1143
- },
1144
- {
1145
- value: "amp",
1146
- label: "Amp"
1147
- },
1148
- {
1149
- value: "pi",
1150
- label: "Pi"
1151
- },
1152
- {
1153
- value: "qoder",
1154
- label: "Qoder"
1155
- },
1156
- {
1157
- value: "qwen-code",
1158
- label: "Qwen Code"
1159
- },
1160
- {
1161
- value: "kiro-cli",
1162
- label: "Kiro CLI"
1163
- },
1164
- {
1165
- value: "droid",
1166
- label: "Droid"
1167
- },
1168
- {
1169
- value: "command-code",
1170
- label: "Command Code"
1171
- },
1172
- {
1173
- value: "clawdbot",
1174
- label: "Clawdbot"
1175
- },
1176
- {
1177
- value: "zencoder",
1178
- label: "Zencoder"
1179
- },
1180
- {
1181
- value: "neovate",
1182
- label: "Neovate"
1183
- },
1184
- {
1185
- value: "mcpjam",
1186
- label: "MCPJam"
1187
- }
1188
- ];
1189
- const MCP_AGENT_OPTIONS = [
1190
- {
1191
- value: "claude-code",
1192
- label: "Claude Code"
1193
- },
1194
- {
1195
- value: "codex",
1196
- label: "Codex"
1197
- },
1198
- {
1199
- value: "cursor",
1200
- label: "Cursor"
1201
- },
1202
- {
1203
- value: "vscode",
1204
- label: "VS Code"
1205
- },
1206
- {
1207
- value: "github-copilot-cli",
1208
- label: "GitHub Copilot CLI"
1209
- },
1210
- {
1211
- value: "opencode",
1212
- label: "OpenCode"
1213
- },
1214
- {
1215
- value: "gemini-cli",
1216
- label: "Gemini CLI"
1217
- },
1218
- {
1219
- value: "goose",
1220
- label: "Goose"
1221
- },
1222
- {
1223
- value: "zed",
1224
- label: "Zed"
1225
- },
1226
- {
1227
- value: "antigravity",
1228
- label: "Antigravity"
1229
- },
1230
- {
1231
- value: "cline",
1232
- label: "Cline VS Code Extension"
1233
- },
1234
- {
1235
- value: "cline-cli",
1236
- label: "Cline CLI"
1237
- },
1238
- {
1239
- value: "claude-desktop",
1240
- label: "Claude Desktop"
1241
- },
1242
- {
1243
- value: "mcporter",
1244
- label: "MCPorter"
1245
- }
1246
- ];
1247
- const SHARED_PRISMA_SKILLS = [
1248
- "prisma-cli",
1249
- "prisma-client-api",
1250
- "prisma-database-setup",
1251
- "prisma-upgrade-v7"
1252
- ];
1253
- function getAvailablePrismaSkills(provider) {
1254
- if (provider === "postgresql") return [...SHARED_PRISMA_SKILLS, "prisma-postgres"];
1255
- return [...SHARED_PRISMA_SKILLS];
1256
- }
1257
- function getSkillOptions(provider) {
1258
- const available = getAvailablePrismaSkills(provider);
1259
- const options = {
1260
- "prisma-cli": {
1261
- value: "prisma-cli",
1262
- label: "prisma-cli",
1263
- hint: "Prisma CLI reference"
1264
- },
1265
- "prisma-client-api": {
1266
- value: "prisma-client-api",
1267
- label: "prisma-client-api",
1268
- hint: "Prisma Client query patterns"
1269
- },
1270
- "prisma-database-setup": {
1271
- value: "prisma-database-setup",
1272
- label: "prisma-database-setup",
1273
- hint: "Database provider setup guides"
1274
- },
1275
- "prisma-upgrade-v7": {
1276
- value: "prisma-upgrade-v7",
1277
- label: "prisma-upgrade-v7",
1278
- hint: "v6 to v7 migration guide"
1279
- },
1280
- "prisma-postgres": {
1281
- value: "prisma-postgres",
1282
- label: "prisma-postgres",
1283
- hint: "Prisma Postgres workflows"
1284
- }
1285
- };
1286
- return available.map((skill) => options[skill]);
1287
- }
1288
- function collectAddonsFromInput(input) {
1289
- const addons = [];
1290
- if (input.skills === true) addons.push("skills");
1291
- if (input.mcp === true) addons.push("mcp");
1292
- if (input.extension === true) addons.push("extension");
1293
- return uniqueValues(addons);
1294
- }
1295
- const EXTENSION_TARGET_OPTIONS = [
1296
- {
1297
- value: "vscode",
1298
- label: "VS Code",
1299
- hint: "Uses the `code` CLI"
1300
- },
1301
- {
1302
- value: "cursor",
1303
- label: "Cursor",
1304
- hint: "Uses the `cursor` CLI"
1305
- },
1306
- {
1307
- value: "windsurf",
1308
- label: "Windsurf",
1309
- hint: "Uses the `windsurf` CLI"
1310
- }
1311
- ];
1312
- function uniqueValues(values) {
1313
- return Array.from(new Set(values));
1314
- }
1315
- function getRecommendedPrismaSkills(provider, shouldUsePrismaPostgres) {
1316
- const skills = [...getAvailablePrismaSkills(provider)];
1317
- if (!shouldUsePrismaPostgres) return skills.filter((skill) => skill !== "prisma-postgres");
1318
- return uniqueValues(skills);
1319
- }
1320
- async function promptForAddons() {
1321
- const selectedAddons = await multiselect({
1322
- message: "Select add-ons (optional)",
1323
- options: ADDON_OPTIONS,
1324
- required: false
1325
- });
1326
- if (isCancel(selectedAddons)) {
1327
- cancel("Operation cancelled.");
1328
- return;
1329
- }
1330
- return uniqueValues(selectedAddons);
1331
- }
1332
- async function promptForAddonScope() {
1333
- const selectedScope = await select({
1334
- message: "Where should add-ons write config?",
1335
- initialValue: DEFAULT_ADDON_SCOPE,
1336
- options: [{
1337
- value: "project",
1338
- label: "Project",
1339
- hint: "Recommended for teams (checked into the project when applicable)"
1340
- }, {
1341
- value: "global",
1342
- label: "Global",
1343
- hint: "Personal machine-level setup"
1344
- }]
1345
- });
1346
- if (isCancel(selectedScope)) {
1347
- cancel("Operation cancelled.");
1348
- return;
1349
- }
1350
- return selectedScope;
1351
- }
1352
- async function promptForPrismaSkills(provider, recommendedSkills) {
1353
- const options = getSkillOptions(provider);
1354
- const optionValues = new Set(options.map((option) => option.value));
1355
- const selectedSkills = await multiselect({
1356
- message: "Select Prisma skills",
1357
- options,
1358
- required: false,
1359
- initialValues: recommendedSkills.filter((skill) => optionValues.has(skill))
1360
- });
1361
- if (isCancel(selectedSkills)) {
1362
- cancel("Operation cancelled.");
1363
- return;
1364
- }
1365
- return uniqueValues(selectedSkills);
1366
- }
1367
- async function promptForSkillsAgents() {
1368
- const selectedAgents = await multiselect({
1369
- message: "Select agents for skills",
1370
- options: SKILLS_AGENT_OPTIONS,
1371
- required: false,
1372
- initialValues: [...DEFAULT_SKILLS_AGENTS]
1373
- });
1374
- if (isCancel(selectedAgents)) {
1375
- cancel("Operation cancelled.");
1376
- return;
1377
- }
1378
- return uniqueValues(selectedAgents);
1379
- }
1380
- async function promptForMcpAgents() {
1381
- const selectedAgents = await multiselect({
1382
- message: "Select agents for MCP",
1383
- options: MCP_AGENT_OPTIONS,
1384
- required: false,
1385
- initialValues: [...DEFAULT_MCP_AGENTS]
1386
- });
1387
- if (isCancel(selectedAgents)) {
1388
- cancel("Operation cancelled.");
1389
- return;
1390
- }
1391
- return uniqueValues(selectedAgents);
1392
- }
1393
- async function promptForExtensionTargets() {
1394
- const selectedTargets = await multiselect({
1395
- message: "Select IDEs for extension install",
1396
- options: EXTENSION_TARGET_OPTIONS,
1397
- required: false,
1398
- initialValues: DEFAULT_EXTENSION_TARGETS
1399
- });
1400
- if (isCancel(selectedTargets)) {
1401
- cancel("Operation cancelled.");
1402
- return;
1403
- }
1404
- return uniqueValues(selectedTargets);
1405
- }
1406
- async function collectCreateAddonSetupContext(input, options) {
1407
- const hasExplicitAddonSelection = input.skills !== void 0 || input.mcp !== void 0 || input.extension !== void 0;
1408
- const selectedFromInput = collectAddonsFromInput(input);
1409
- const selectedAddons = selectedFromInput.length > 0 ? selectedFromInput : hasExplicitAddonSelection ? [] : options.useDefaults ? [] : await promptForAddons();
1410
- if (!selectedAddons) return;
1411
- const addons = uniqueValues(selectedAddons);
1412
- if (addons.length === 0) return null;
1413
- const scope = addons.includes("skills") || addons.includes("mcp") ? options.useDefaults ? DEFAULT_ADDON_SCOPE : await promptForAddonScope() : DEFAULT_ADDON_SCOPE;
1414
- if (!scope) return;
1415
- const recommendedSkills = getRecommendedPrismaSkills(options.provider, options.shouldUsePrismaPostgres);
1416
- const skills = !addons.includes("skills") ? [] : options.useDefaults ? recommendedSkills : await promptForPrismaSkills(options.provider, recommendedSkills);
1417
- if (!skills) return;
1418
- const skillsAgents = !addons.includes("skills") ? [] : options.useDefaults ? [...DEFAULT_SKILLS_AGENTS] : await promptForSkillsAgents();
1419
- if (!skillsAgents) return;
1420
- const mcpAgents = !addons.includes("mcp") ? [] : options.useDefaults ? [...DEFAULT_MCP_AGENTS] : await promptForMcpAgents();
1421
- if (!mcpAgents) return;
1422
- const extensionTargets = !addons.includes("extension") ? [] : options.useDefaults ? [...DEFAULT_EXTENSION_TARGETS] : await promptForExtensionTargets();
1423
- if (!extensionTargets) return;
1424
- return {
1425
- addons,
1426
- scope,
1427
- skills,
1428
- skillsAgents: uniqueValues(skillsAgents),
1429
- mcpAgents: uniqueValues(mcpAgents),
1430
- extensionTargets: uniqueValues(extensionTargets)
1431
- };
1432
- }
1433
- async function executeExternalCommand(params) {
1434
- await execa(params.command, params.args, {
1435
- cwd: params.cwd,
1436
- stdio: params.verbose ? "inherit" : "pipe",
1437
- env: {
1438
- ...process.env,
1439
- CI: "true"
1440
- }
1441
- });
1442
- }
1443
- async function installSkillsAddon(params) {
1444
- if (params.agents.length === 0 || params.skills.length === 0) return "Skipped skills addon because no skills or agents were selected.";
1445
- const scopeArgs = params.scope === "global" ? ["-g"] : [];
1446
- const skillArgs = params.skills.flatMap((skill) => ["-s", skill]);
1447
- const agentArgs = params.agents.flatMap((agent) => ["-a", agent]);
1448
- const commandArgs = [
1449
- "skills@latest",
1450
- "add",
1451
- "prisma/skills",
1452
- ...scopeArgs,
1453
- ...skillArgs,
1454
- ...agentArgs,
1455
- "-y"
1456
- ];
1457
- const execution = getPackageExecutionArgs(params.packageManager, commandArgs);
1458
- try {
1459
- await executeExternalCommand({
1460
- command: execution.command,
1461
- args: execution.args,
1462
- cwd: params.projectDir,
1463
- verbose: params.verbose
1464
- });
1465
- return;
1466
- } catch (error) {
1467
- return `Skills addon failed: ${error instanceof Error ? error.message : String(error)}`;
1468
- }
1469
- }
1470
- async function installMcpAddon(params) {
1471
- if (params.agents.length === 0) return "Skipped MCP addon because no agents were selected.";
1472
- const scopeArgs = params.scope === "global" ? ["-g"] : [];
1473
- const agentArgs = params.agents.flatMap((agent) => ["-a", agent]);
1474
- const commandArgs = [
1475
- "add-mcp@latest",
1476
- PRISMA_MCP_SERVER,
1477
- ...scopeArgs,
1478
- ...agentArgs,
1479
- "--name",
1480
- "prisma",
1481
- "--gitignore",
1482
- "-y"
1483
- ];
1484
- const execution = getPackageExecutionArgs(params.packageManager, commandArgs);
1485
- try {
1486
- await executeExternalCommand({
1487
- command: execution.command,
1488
- args: execution.args,
1489
- cwd: params.projectDir,
1490
- verbose: params.verbose
1491
- });
1492
- return;
1493
- } catch (error) {
1494
- return `MCP addon failed: ${error instanceof Error ? error.message : String(error)}`;
1495
- }
1496
- }
1497
- function getExtensionInstallBinary(target) {
1498
- switch (target) {
1499
- case "vscode": return "code";
1500
- case "cursor": return "cursor";
1501
- case "windsurf": return "windsurf";
1502
- default: {
1503
- const exhaustiveCheck = target;
1504
- throw new Error(`Unsupported extension target: ${String(exhaustiveCheck)}`);
1505
- }
1506
- }
1507
- }
1508
- async function installExtensionAddon(params) {
1509
- if (params.targets.length === 0) return ["Skipped extension addon because no IDE targets were selected."];
1510
- const warnings = [];
1511
- for (const target of params.targets) {
1512
- const binary = getExtensionInstallBinary(target);
1513
- try {
1514
- await executeExternalCommand({
1515
- command: binary,
1516
- args: ["--version"],
1517
- cwd: params.projectDir,
1518
- verbose: false
1519
- });
1520
- } catch {
1521
- warnings.push(`Skipped ${target} extension install because the \`${binary}\` CLI is not available.`);
1522
- continue;
1523
- }
1524
- try {
1525
- await executeExternalCommand({
1526
- command: binary,
1527
- args: [
1528
- "--install-extension",
1529
- "Prisma.prisma",
1530
- "--force"
1531
- ],
1532
- cwd: params.projectDir,
1533
- verbose: params.verbose
1534
- });
1535
- } catch (error) {
1536
- warnings.push(`${target} extension install failed: ${error instanceof Error ? error.message : String(error)}`);
1537
- }
1538
- }
1539
- return warnings;
1540
- }
1541
- async function executeCreateAddonSetupContext(params) {
1542
- const { context, packageManager, projectDir, verbose } = params;
1543
- const addonSpinner = spinner();
1544
- addonSpinner.start("Applying selected add-ons...");
1545
- const warnings = [];
1546
- if (context.addons.includes("skills")) {
1547
- const warning = await installSkillsAddon({
1548
- packageManager,
1549
- projectDir,
1550
- scope: context.scope,
1551
- skills: context.skills,
1552
- agents: context.skillsAgents,
1553
- verbose
1554
- });
1555
- if (warning) warnings.push(warning);
1556
- }
1557
- if (context.addons.includes("mcp")) {
1558
- const warning = await installMcpAddon({
1559
- packageManager,
1560
- projectDir,
1561
- scope: context.scope,
1562
- agents: context.mcpAgents,
1563
- verbose
1564
- });
1565
- if (warning) warnings.push(warning);
1566
- }
1567
- if (context.addons.includes("extension")) {
1568
- const extensionWarnings = await installExtensionAddon({
1569
- projectDir,
1570
- verbose,
1571
- targets: context.extensionTargets
1572
- });
1573
- warnings.push(...extensionWarnings);
1574
- }
1575
- if (warnings.length > 0) {
1576
- addonSpinner.stop("Add-ons applied with warnings.");
1577
- for (const warning of warnings) log.warn(warning);
1578
- return;
1579
- }
1580
- addonSpinner.stop("Add-ons applied.");
1581
- }
1582
-
1583
- //#endregion
1584
- //#region src/telemetry/client.ts
1585
- const TELEMETRY_API_KEY = "phc_cmc85avbWyuJ2JyKdGPdv7dxXli8xLdWDBPbvIXWJfs";
1586
- const TELEMETRY_HOST = "https://us.i.posthog.com";
1587
- const TELEMETRY_CONFIG_FILE = "telemetry.json";
1588
- 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;
1589
- function isTruthyEnvValue(value) {
1590
- return [
1591
- "1",
1592
- "true",
1593
- "yes",
1594
- "on"
1595
- ].includes(String(value ?? "").trim().toLowerCase());
1596
- }
1597
- function shouldDisableTelemetry() {
1598
- if (isTruthyEnvValue(process.env.CI) || isTruthyEnvValue(process.env.GITHUB_ACTIONS)) return true;
1599
- return process.env.CREATE_PRISMA_DISABLE_TELEMETRY !== void 0 || process.env.CREATE_PRISMA_TELEMETRY_DISABLED !== void 0 || process.env.DO_NOT_TRACK !== void 0;
1600
- }
1601
- function getTelemetryConfigDir() {
1602
- if (process.platform === "darwin") return path.join(os.homedir(), "Library", "Application Support", "create-prisma");
1603
- if (process.platform === "win32") return path.join(process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming"), "create-prisma");
1604
- return path.join(process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config"), "create-prisma");
1605
- }
1606
- async function getAnonymousId() {
1607
- const telemetryConfigPath = path.join(getTelemetryConfigDir(), TELEMETRY_CONFIG_FILE);
1608
- try {
1609
- const config = await fs.readJSON(telemetryConfigPath);
1610
- if (typeof config.anonymousId === "string" && UUID_V4_REGEX.test(config.anonymousId)) return config.anonymousId;
1611
- } catch {}
1612
- const anonymousId = randomUUID();
1613
- try {
1614
- await fs.ensureDir(path.dirname(telemetryConfigPath));
1615
- await fs.writeJSON(telemetryConfigPath, { anonymousId }, { spaces: 2 });
1616
- } catch {}
1617
- return anonymousId;
1618
- }
1619
- function getCommonProperties() {
1620
- return {
1621
- "cli-version": "0.4.1",
1622
- "node-version": process.version,
1623
- platform: process.platform,
1624
- arch: process.arch
1625
- };
1626
- }
1627
- function sanitizeProperties(properties) {
1628
- return Object.fromEntries(Object.entries(properties).filter(([, value]) => value !== void 0));
1629
- }
1630
- async function trackCliTelemetry(event, properties) {
1631
- if (shouldDisableTelemetry()) return;
1632
- let client;
1633
- try {
1634
- const distinctId = await getAnonymousId();
1635
- const sanitizedProperties = sanitizeProperties({
1636
- ...getCommonProperties(),
1637
- ...properties,
1638
- $process_person_profile: false
1639
- });
1640
- client = new PostHog(TELEMETRY_API_KEY, {
1641
- host: TELEMETRY_HOST,
1642
- disableGeoip: true,
1643
- flushAt: 1,
1644
- flushInterval: 0
1645
- });
1646
- await client.captureImmediate({
1647
- distinctId,
1648
- event,
1649
- properties: sanitizedProperties,
1650
- disableGeoip: true
1651
- });
1652
- } catch {} finally {
1653
- if (client) await client.shutdown().catch(() => {});
1654
- }
1655
- }
1656
-
1657
- //#endregion
1658
- //#region src/telemetry/create.ts
1659
- function getRequestedAddons(input) {
1660
- const addons = [];
1661
- if (input.skills === true) addons.push("skills");
1662
- if (input.mcp === true) addons.push("mcp");
1663
- if (input.extension === true) addons.push("extension");
1664
- return addons;
1665
- }
1666
- function getTargetDirectoryState(context) {
1667
- if (!context.targetPathState.exists) return "new";
1668
- if (context.targetPathState.isEmptyDirectory) return "empty_directory";
1669
- return "non_empty_directory";
1670
- }
1671
- function getBaseCreateProperties(input, context) {
1672
- const resolvedAddons = context?.addonSetupContext?.addons ?? getRequestedAddons(input);
1673
- return {
1674
- command: "create",
1675
- "uses-defaults": input.yes === true,
1676
- verbose: input.verbose === true,
1677
- force: input.force === true,
1678
- template: context?.template ?? input.template ?? null,
1679
- "database-provider": context?.prismaSetupContext.databaseProvider ?? input.provider ?? null,
1680
- "package-manager": context?.prismaSetupContext.packageManager ?? input.packageManager ?? null,
1681
- "schema-preset": context?.prismaSetupContext.schemaPreset ?? input.schemaPreset ?? null,
1682
- "should-install": context?.prismaSetupContext.shouldInstall ?? input.install ?? null,
1683
- "should-generate": context?.prismaSetupContext.shouldGenerate ?? input.generate ?? null,
1684
- "uses-prisma-postgres": context?.prismaSetupContext.shouldUsePrismaPostgres ?? input.prismaPostgres ?? null,
1685
- addons: resolvedAddons,
1686
- "addon-count": resolvedAddons.length,
1687
- "addon-scope": context?.addonSetupContext?.scope ?? null,
1688
- "skills-count": context?.addonSetupContext?.skills.length ?? null,
1689
- "skills-agents-count": context?.addonSetupContext?.skillsAgents.length ?? null,
1690
- "mcp-agents-count": context?.addonSetupContext?.mcpAgents.length ?? null,
1691
- "extension-target-count": context?.addonSetupContext?.extensionTargets.length ?? null,
1692
- "target-directory-state": context ? getTargetDirectoryState(context) : null
1693
- };
1694
- }
1695
- function getErrorName(error) {
1696
- if (error instanceof Error) return error.name;
1697
- return error === void 0 ? null : "UnknownError";
1698
- }
1699
- function getErrorCode(error) {
1700
- if (typeof error !== "object" || error === null) return null;
1701
- const exitCode = Reflect.get(error, "exitCode");
1702
- if (typeof exitCode === "number") return exitCode;
1703
- const code = Reflect.get(error, "code");
1704
- return typeof code === "number" || typeof code === "string" ? code : null;
1705
- }
1706
- async function trackCreateCompleted(params) {
1707
- await trackCliTelemetry("cli:create_command_completed", {
1708
- ...getBaseCreateProperties(params.input, params.context),
1709
- "duration-ms": params.durationMs
1710
- });
1711
- }
1712
- async function trackCreateFailed(params) {
1713
- await trackCliTelemetry("cli:create_command_failed", {
1714
- ...getBaseCreateProperties(params.input, params.context),
1715
- "duration-ms": params.durationMs,
1716
- "failure-stage": params.stage,
1717
- "error-name": getErrorName(params.error),
1718
- "error-code": getErrorCode(params.error)
1719
- });
1720
- }
1721
-
1722
1339
  //#endregion
1723
1340
  //#region src/ui/branding.ts
1724
1341
  const prismaTitle = `${styleText(["bold", "cyan"], "Create")} ${styleText(["bold", "magenta"], "Prisma")}`;
@@ -1764,7 +1381,7 @@ async function promptForCreateTemplate() {
1764
1381
  {
1765
1382
  value: "hono",
1766
1383
  label: "Hono",
1767
- hint: "TypeScript API starter"
1384
+ hint: "Default TypeScript API starter"
1768
1385
  },
1769
1386
  {
1770
1387
  value: "elysia",
@@ -1872,8 +1489,8 @@ async function runCreateCommand(rawInput = {}) {
1872
1489
  }
1873
1490
  }
1874
1491
  async function collectCreateContext(input) {
1875
- const useDefaults = input.yes === true;
1876
1492
  const force = input.force === true;
1493
+ const useDefaults = input.yes === true;
1877
1494
  const projectNameInput = input.name ?? (useDefaults ? DEFAULT_PROJECT_NAME : await promptForProjectName());
1878
1495
  if (projectNameInput === void 0) return;
1879
1496
  const projectName = String(projectNameInput).trim();
@@ -1899,20 +1516,13 @@ async function collectCreateContext(input) {
1899
1516
  defaultSchemaPreset: DEFAULT_SCHEMA_PRESET
1900
1517
  });
1901
1518
  if (!prismaSetupContext) return;
1902
- const addonSetupContext = await collectCreateAddonSetupContext(input, {
1903
- useDefaults,
1904
- provider: prismaSetupContext.databaseProvider,
1905
- shouldUsePrismaPostgres: prismaSetupContext.shouldUsePrismaPostgres
1906
- });
1907
- if (addonSetupContext === void 0) return;
1908
1519
  return {
1909
1520
  targetDirectory,
1910
1521
  targetPathState,
1911
1522
  force,
1912
1523
  template,
1913
1524
  projectPackageName: toPackageName(path.basename(targetDirectory)),
1914
- prismaSetupContext,
1915
- addonSetupContext: addonSetupContext ?? void 0
1525
+ prismaSetupContext
1916
1526
  };
1917
1527
  }
1918
1528
  async function executeCreateContext(context) {
@@ -1925,6 +1535,7 @@ async function executeCreateContext(context) {
1925
1535
  template: context.template,
1926
1536
  schemaPreset: context.prismaSetupContext.schemaPreset,
1927
1537
  provider: context.prismaSetupContext.databaseProvider,
1538
+ authoring: context.prismaSetupContext.authoring,
1928
1539
  packageManager: context.prismaSetupContext.packageManager
1929
1540
  });
1930
1541
  scaffoldSpinner.stop("Project files scaffolded.");
@@ -1950,21 +1561,10 @@ async function executeCreateContext(context) {
1950
1561
  };
1951
1562
  }
1952
1563
  if (context.targetPathState.exists && !context.targetPathState.isEmptyDirectory && context.force) log.warn(`Used --force in non-empty directory ${formatPathForDisplay(context.targetDirectory)}.`);
1953
- const nextSteps = formatPathForDisplay(context.targetDirectory) === "." ? [] : [`- cd ${formatPathForDisplay(context.targetDirectory)}`];
1954
- if (context.addonSetupContext) try {
1955
- await executeCreateAddonSetupContext({
1956
- context: context.addonSetupContext,
1957
- packageManager: context.prismaSetupContext.packageManager,
1958
- projectDir: context.targetDirectory,
1959
- verbose: context.prismaSetupContext.verbose
1960
- });
1961
- } catch (error) {
1962
- return {
1963
- ok: false,
1964
- stage: "addons",
1965
- error
1966
- };
1967
- }
1564
+ const nextSteps = formatPathForDisplay(context.targetDirectory) === "." ? [] : [{
1565
+ command: `cd ${formatPathForDisplay(context.targetDirectory)}`,
1566
+ description: "Enter your new project directory."
1567
+ }];
1968
1568
  try {
1969
1569
  if (!await executePrismaSetupContext(context.prismaSetupContext, {
1970
1570
  prependNextSteps: nextSteps,
@@ -1985,4 +1585,4 @@ async function executeCreateContext(context) {
1985
1585
  }
1986
1586
 
1987
1587
  //#endregion
1988
- export { DatabaseUrlSchema as a, DatabaseProviderSchema as i, CreateCommandInputSchema as n, PackageManagerSchema as o, CreateTemplateSchema as r, SchemaPresetSchema as s, runCreateCommand as t };
1588
+ export { DatabaseProviderSchema as a, SchemaPresetSchema as c, CreateTemplateSchema as i, AuthoringStyleSchema as n, DatabaseUrlSchema as o, CreateCommandInputSchema as r, PackageManagerSchema as s, runCreateCommand as t };