create-prisma 0.4.1 → 0.4.2-next.37.80.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-CfH21J9-.mjs} +529 -914
  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.80.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);
590
+ await renderTemplateTree({
591
+ templateRoot: sharedTemplateRoot,
592
+ outputDir: projectDir,
593
+ context
594
+ });
444
595
  await renderTemplateTree({
445
- templateRoot: getCreateTemplateDir(template),
596
+ templateRoot,
446
597
  outputDir: projectDir,
447
- context: createTemplateContext(projectName, provider, schemaPreset, packageManager)
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,46 @@ 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 DEFAULT_PRISMA_POSTGRES = false;
823
+ const MONGO_DOCKER_COMPOSE = `services:
824
+ mongodb:
825
+ image: mongo:latest
826
+ command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
827
+ ports:
828
+ - "27017:27017"
829
+ volumes:
830
+ - mongodb-data:/data/db
831
+ healthcheck:
832
+ test:
833
+ [
834
+ "CMD-SHELL",
835
+ "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",
836
+ ]
837
+ interval: 5s
838
+ timeout: 5s
839
+ retries: 30
840
+ start_period: 5s
841
+
842
+ volumes:
843
+ mongodb-data:
844
+ `;
845
+ const mongoDockerScripts = {
846
+ "db:up": "docker compose up -d --wait",
847
+ "db:down": "docker compose down"
848
+ };
651
849
  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"],
850
+ [
851
+ "prisma/contract.prisma",
852
+ "prisma/contract.ts",
853
+ "packages/db/prisma/contract.prisma",
854
+ "packages/db/prisma/contract.ts"
855
+ ],
856
+ ["prisma-next.config.ts", "packages/db/prisma-next.config.ts"],
655
857
  [
656
858
  "src/lib/prisma.ts",
657
859
  "src/lib/prisma.server.ts",
@@ -662,36 +864,22 @@ const requiredPrismaFileGroups = [
662
864
  ];
663
865
  async function resolvePrismaProjectDir(projectDir) {
664
866
  const monorepoDbDir = path.join(projectDir, "packages/db");
665
- if (await fs.pathExists(path.join(monorepoDbDir, "prisma/schema.prisma"))) return monorepoDbDir;
867
+ if (await fs.pathExists(path.join(monorepoDbDir, "prisma/contract.prisma")) || await fs.pathExists(path.join(monorepoDbDir, "prisma/contract.ts"))) return monorepoDbDir;
666
868
  return projectDir;
667
869
  }
668
870
  async function promptForDatabaseProvider() {
669
871
  const databaseProvider = await select({
670
872
  message: "Select your database",
671
873
  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
- ]
874
+ options: [{
875
+ value: "postgres",
876
+ label: "PostgreSQL",
877
+ hint: "Relational models with typed ORM, relations, indexes, raw SQL"
878
+ }, {
879
+ value: "mongo",
880
+ label: "MongoDB",
881
+ hint: "Document models with typed ORM, indexes, aggregations"
882
+ }]
695
883
  });
696
884
  if (isCancel(databaseProvider)) {
697
885
  cancel("Operation cancelled.");
@@ -699,10 +887,48 @@ async function promptForDatabaseProvider() {
699
887
  }
700
888
  return DatabaseProviderSchema.parse(databaseProvider);
701
889
  }
890
+ async function promptForAuthoringStyle() {
891
+ const authoring = await select({
892
+ message: "Choose contract authoring style",
893
+ initialValue: DEFAULT_AUTHORING,
894
+ options: [{
895
+ value: "psl",
896
+ label: "PSL",
897
+ hint: "Schema syntax emits contract.json + types"
898
+ }, {
899
+ value: "typescript",
900
+ label: "TypeScript",
901
+ hint: "Builder API emits the same contract artifacts"
902
+ }]
903
+ });
904
+ if (isCancel(authoring)) {
905
+ cancel("Operation cancelled.");
906
+ return;
907
+ }
908
+ return AuthoringStyleSchema.parse(authoring);
909
+ }
910
+ async function promptForPrismaPostgres() {
911
+ const shouldUsePrismaPostgres = await confirm({
912
+ message: "Provision a Prisma Postgres database?",
913
+ active: "Provision Prisma Postgres",
914
+ inactive: "Use my own database",
915
+ initialValue: DEFAULT_PRISMA_POSTGRES
916
+ });
917
+ if (isCancel(shouldUsePrismaPostgres)) {
918
+ cancel("Operation cancelled.");
919
+ return;
920
+ }
921
+ return Boolean(shouldUsePrismaPostgres);
922
+ }
702
923
  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";
924
+ const hint = {
925
+ npm: "Node.js default",
926
+ pnpm: "Fast, disk-efficient Node.js package manager",
927
+ yarn: "Yarn package manager",
928
+ bun: "Fast runtime + package manager",
929
+ deno: "Deno runtime + task runner"
930
+ }[option];
931
+ return option === detected ? `Detected; ${hint}` : hint;
706
932
  }
707
933
  async function promptForPackageManager(detectedPackageManager) {
708
934
  const packageManager = await select({
@@ -744,7 +970,9 @@ async function promptForPackageManager(detectedPackageManager) {
744
970
  }
745
971
  async function promptForDependencyInstall(packageManager) {
746
972
  const shouldInstall = await confirm({
747
- message: `Install dependencies now with ${getInstallCommand(packageManager)}?`,
973
+ message: `Install dependencies now with ${getInstallCommand(packageManager)}? You can run it later.`,
974
+ active: "Install now",
975
+ inactive: "Skip for now",
748
976
  initialValue: true
749
977
  });
750
978
  if (isCancel(shouldInstall)) {
@@ -753,17 +981,6 @@ async function promptForDependencyInstall(packageManager) {
753
981
  }
754
982
  return Boolean(shouldInstall);
755
983
  }
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
984
  function getCommandErrorMessage(error) {
768
985
  if (error instanceof Error && "stderr" in error) {
769
986
  const stderr = String(error.stderr ?? "").trim();
@@ -775,17 +992,23 @@ async function collectPrismaSetupContext(input, options = {}) {
775
992
  const projectDir = path.resolve(options.projectDir ?? process.cwd());
776
993
  const useDefaults = input.yes === true;
777
994
  const verbose = input.verbose === true;
778
- const shouldGenerate = input.generate ?? DEFAULT_GENERATE;
995
+ const shouldEmit = input.emit ?? DEFAULT_EMIT;
779
996
  const databaseProvider = input.provider ?? (useDefaults ? DEFAULT_DATABASE_PROVIDER : await promptForDatabaseProvider());
780
997
  if (!databaseProvider) return;
781
- const schemaPreset = input.schemaPreset ?? options.defaultSchemaPreset ?? DEFAULT_SCHEMA_PRESET$1;
782
998
  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;
999
+ const shouldUsePrismaPostgres = input.prismaPostgres ?? (databaseProvider === "postgres" && !databaseUrl && !useDefaults ? await promptForPrismaPostgres() : DEFAULT_PRISMA_POSTGRES);
1000
+ if (shouldUsePrismaPostgres === void 0) return;
1001
+ if (shouldUsePrismaPostgres && databaseProvider !== "postgres") {
1002
+ cancel("--prisma-postgres is only supported with --provider postgres.");
1003
+ return;
1004
+ }
1005
+ if (shouldUsePrismaPostgres && databaseUrl) {
1006
+ cancel("Use either --database-url or --prisma-postgres, not both.");
1007
+ return;
788
1008
  }
1009
+ const authoring = input.authoring ?? (useDefaults ? DEFAULT_AUTHORING : await promptForAuthoringStyle());
1010
+ if (!authoring) return;
1011
+ const schemaPreset = input.schemaPreset ?? options.defaultSchemaPreset ?? DEFAULT_SCHEMA_PRESET$1;
789
1012
  const detectedPackageManager = await detectPackageManager(projectDir);
790
1013
  const packageManager = input.packageManager ?? (useDefaults ? detectedPackageManager : await promptForPackageManager(detectedPackageManager));
791
1014
  if (!packageManager) return;
@@ -794,8 +1017,9 @@ async function collectPrismaSetupContext(input, options = {}) {
794
1017
  return {
795
1018
  projectDir,
796
1019
  verbose,
797
- shouldGenerate,
1020
+ shouldEmit,
798
1021
  databaseProvider,
1022
+ authoring,
799
1023
  schemaPreset,
800
1024
  databaseUrl,
801
1025
  shouldUsePrismaPostgres,
@@ -805,14 +1029,11 @@ async function collectPrismaSetupContext(input, options = {}) {
805
1029
  }
806
1030
  function getDefaultDatabaseUrl(provider) {
807
1031
  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;";
1032
+ case "postgres": return "postgresql://user:password@localhost:5432/mydb";
1033
+ case "mongo": return "mongodb://localhost:27017/mydb?replicaSet=rs0&directConnection=true";
813
1034
  default: {
814
1035
  const exhaustiveCheck = provider;
815
- throw new Error(`Unsupported provider: ${String(exhaustiveCheck)}`);
1036
+ throw new Error(`Unsupported Prisma Next target: ${String(exhaustiveCheck)}`);
816
1037
  }
817
1038
  }
818
1039
  }
@@ -882,6 +1103,34 @@ async function ensureGitignoreEntry(projectDir, entry) {
882
1103
  const separator = existingContent.endsWith("\n") ? "" : "\n";
883
1104
  await fs.appendFile(gitignorePath, `${separator}${entry}\n`, "utf8");
884
1105
  }
1106
+ async function ensurePackageScripts(projectDir, scripts) {
1107
+ const packageJsonPath = path.join(projectDir, "package.json");
1108
+ if (!await fs.pathExists(packageJsonPath)) return;
1109
+ const packageJson = await fs.readJson(packageJsonPath);
1110
+ if (!packageJson.scripts) packageJson.scripts = {};
1111
+ let didChange = false;
1112
+ for (const [scriptName, command] of Object.entries(scripts)) if (typeof packageJson.scripts[scriptName] !== "string" || packageJson.scripts[scriptName].trim().length === 0) {
1113
+ packageJson.scripts[scriptName] = command;
1114
+ didChange = true;
1115
+ }
1116
+ if (didChange) await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
1117
+ }
1118
+ async function ensureMongoDockerCompose(projectDir) {
1119
+ const composePath = path.join(projectDir, "docker-compose.yml");
1120
+ if (await fs.pathExists(composePath)) return;
1121
+ await fs.writeFile(composePath, MONGO_DOCKER_COMPOSE, "utf8");
1122
+ }
1123
+ async function writeMongoDockerHelpersForContext(context, projectDir) {
1124
+ if (context.databaseProvider !== "mongo" || context.databaseUrl) return true;
1125
+ try {
1126
+ await ensureMongoDockerCompose(projectDir);
1127
+ await ensurePackageScripts(projectDir, mongoDockerScripts);
1128
+ return true;
1129
+ } catch (error) {
1130
+ cancel(getCommandErrorMessage(error));
1131
+ return false;
1132
+ }
1133
+ }
885
1134
  async function ensureRequiredPrismaFiles(projectDir) {
886
1135
  const missingFiles = [];
887
1136
  for (const candidates of requiredPrismaFileGroups) {
@@ -895,13 +1144,12 @@ async function ensureRequiredPrismaFiles(projectDir) {
895
1144
  }
896
1145
  if (!foundCandidate) missingFiles.push(candidates.join(" or "));
897
1146
  }
898
- if (missingFiles.length > 0) throw new Error(`Template is missing required Prisma files: ${missingFiles.join(", ")}`);
1147
+ if (missingFiles.length > 0) throw new Error(`Template is missing required Prisma Next files: ${missingFiles.join(", ")}`);
899
1148
  }
900
1149
  async function finalizePrismaFiles(options) {
901
1150
  const projectDir = options.projectDir ?? process.cwd();
902
1151
  const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
903
1152
  await ensureRequiredPrismaFiles(projectDir);
904
- const generatedDir = await fs.pathExists(path.join(prismaProjectDir, "server/utils/prisma.ts")) ? "server/generated" : "src/generated";
905
1153
  await ensureEnvVarInEnv(prismaProjectDir, "DATABASE_URL", options.databaseUrl ?? getDefaultDatabaseUrl(options.provider), {
906
1154
  mode: options.databaseUrl ? "upsert" : "keep-existing",
907
1155
  comment: "Added by create-prisma"
@@ -913,7 +1161,7 @@ async function finalizePrismaFiles(options) {
913
1161
  });
914
1162
  await ensureEnvComment(prismaProjectDir, PRISMA_POSTGRES_TEMPORARY_NOTICE);
915
1163
  }
916
- await ensureGitignoreEntry(prismaProjectDir, generatedDir);
1164
+ await ensureGitignoreEntry(prismaProjectDir, ".env");
917
1165
  }
918
1166
  async function provisionPrismaPostgresIfNeeded(context, projectDir) {
919
1167
  if (!context.shouldUsePrismaPostgres) return { databaseUrl: context.databaseUrl };
@@ -939,7 +1187,7 @@ async function provisionPrismaPostgresIfNeeded(context, projectDir) {
939
1187
  async function writeDependenciesForContext(context, projectDir) {
940
1188
  const prismaProjectDir = await resolvePrismaProjectDir(projectDir);
941
1189
  try {
942
- await writePrismaDependencies(context.databaseProvider, context.packageManager, prismaProjectDir);
1190
+ await writePrismaDependencies(context.databaseProvider, context.packageManager, context.authoring, prismaProjectDir);
943
1191
  return true;
944
1192
  } catch (error) {
945
1193
  cancel(getCommandErrorMessage(error));
@@ -974,7 +1222,7 @@ async function installDependenciesForContext(context, projectDir) {
974
1222
  }
975
1223
  async function finalizePrismaFilesForContext(context, projectDir, provisionResult) {
976
1224
  const initSpinner = spinner();
977
- initSpinner.start("Preparing Prisma files...");
1225
+ initSpinner.start("Preparing Prisma Next files...");
978
1226
  try {
979
1227
  await finalizePrismaFiles({
980
1228
  provider: context.databaseProvider,
@@ -982,55 +1230,106 @@ async function finalizePrismaFilesForContext(context, projectDir, provisionResul
982
1230
  claimUrl: provisionResult.claimUrl,
983
1231
  projectDir
984
1232
  });
985
- initSpinner.stop("Prisma files ready.");
1233
+ initSpinner.stop("Prisma Next files ready.");
986
1234
  return true;
987
1235
  } catch (error) {
988
- initSpinner.stop("Could not prepare Prisma files.");
1236
+ initSpinner.stop("Could not prepare Prisma Next files.");
989
1237
  cancel(getCommandErrorMessage(error));
990
1238
  return false;
991
1239
  }
992
1240
  }
993
- async function generatePrismaClientForContext(context, projectDir) {
1241
+ function getPrismaNextCliCommand(packageManager, prismaNextArgs) {
1242
+ if (packageManager === "deno") return `deno run -A --env-file=.env npm:prisma-next@${dependencyVersionMap["prisma-next"]} ${prismaNextArgs.join(" ")}`;
1243
+ return getLocalPackageBinaryCommand(packageManager, "prisma-next", prismaNextArgs);
1244
+ }
1245
+ function getPrismaNextCliArgs(packageManager, prismaNextArgs) {
1246
+ if (packageManager === "deno") return {
1247
+ command: "deno",
1248
+ args: [
1249
+ "run",
1250
+ "-A",
1251
+ "--env-file=.env",
1252
+ `npm:prisma-next@${dependencyVersionMap["prisma-next"]}`,
1253
+ ...prismaNextArgs
1254
+ ]
1255
+ };
1256
+ return getLocalPackageBinaryArgs(packageManager, "prisma-next", prismaNextArgs);
1257
+ }
1258
+ async function emitPrismaNextContractForContext(context, projectDir) {
994
1259
  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...");
1260
+ if (!context.shouldEmit) return { didEmitContract: false };
1261
+ if (!context.shouldInstall) return {
1262
+ didEmitContract: false,
1263
+ warning: "Skipped contract emit because dependencies were not installed."
1264
+ };
1265
+ const emitCommand = getPrismaNextCliCommand(context.packageManager, ["contract", "emit"]);
1266
+ if (context.verbose) log.step(`Running ${emitCommand}`);
1267
+ const emitSpinner = context.verbose ? void 0 : spinner();
1268
+ emitSpinner?.start("Emitting Prisma Next contract...");
1000
1269
  try {
1001
- const generateArgs = getPrismaCliArgs(context.packageManager, ["generate"]);
1002
- await execa(generateArgs.command, generateArgs.args, {
1270
+ const emitArgs = getPrismaNextCliArgs(context.packageManager, ["contract", "emit"]);
1271
+ await execa(emitArgs.command, emitArgs.args, {
1003
1272
  cwd: prismaProjectDir,
1004
1273
  stdio: context.verbose ? "inherit" : "pipe"
1005
1274
  });
1006
- if (context.verbose) log.success("Prisma Client generated.");
1007
- else generateSpinner?.stop("Prisma Client generated.");
1008
- return { didGenerateClient: true };
1275
+ if (context.verbose) log.success("Prisma Next contract emitted.");
1276
+ else emitSpinner?.stop("Prisma Next contract emitted.");
1277
+ return { didEmitContract: true };
1009
1278
  } catch (error) {
1010
- if (context.verbose) log.warn("Could not generate Prisma Client.");
1011
- else generateSpinner?.stop("Could not generate Prisma Client.");
1279
+ if (context.verbose) log.warn("Could not emit Prisma Next contract.");
1280
+ else emitSpinner?.stop("Could not emit Prisma Next contract.");
1012
1281
  return {
1013
- didGenerateClient: false,
1014
- warning: `Prisma generate failed: ${getCommandErrorMessage(error)}`
1282
+ didEmitContract: false,
1283
+ warning: `Contract emit failed: ${getCommandErrorMessage(error)}`
1015
1284
  };
1016
1285
  }
1017
1286
  }
1018
- function buildWarningLines(provisionWarning, generateWarning) {
1287
+ function buildWarningLines(provisionWarning, emitWarning) {
1019
1288
  const warningLines = [];
1020
1289
  if (provisionWarning) warningLines.push(`- ${provisionWarning}`);
1021
- if (generateWarning) warningLines.push(`- ${generateWarning}`);
1290
+ if (emitWarning) warningLines.push(`- ${emitWarning}`);
1022
1291
  return warningLines;
1023
1292
  }
1024
1293
  function buildNextStepsForContext(opts) {
1025
- const { context, options, didGenerateClient } = opts;
1294
+ const { context, options, didEmitContract } = opts;
1026
1295
  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")}`);
1296
+ if (!context.shouldInstall) nextSteps.push({
1297
+ command: getInstallCommand(context.packageManager),
1298
+ description: "Install the project dependencies."
1299
+ });
1300
+ if (!didEmitContract || !context.shouldEmit) nextSteps.push({
1301
+ command: getRunScriptCommand(context.packageManager, "contract:emit"),
1302
+ description: "Emit contract.json and TypeScript types from your Prisma Next contract."
1303
+ });
1304
+ if (context.databaseProvider === "postgres") nextSteps.push({
1305
+ command: getRunScriptCommand(context.packageManager, "db:init"),
1306
+ description: "Create the initial PostgreSQL database objects and sign the database."
1307
+ });
1308
+ if (context.databaseProvider === "mongo" && !context.databaseUrl) nextSteps.push({
1309
+ command: getRunScriptCommand(context.packageManager, "db:up"),
1310
+ description: "Start the local MongoDB replica set with Docker."
1311
+ });
1312
+ nextSteps.push({
1313
+ command: getRunScriptCommand(context.packageManager, "migration:plan"),
1314
+ description: "Compare the contract to the database and write a migration plan."
1315
+ });
1316
+ nextSteps.push({
1317
+ command: getRunScriptCommand(context.packageManager, "migration:apply"),
1318
+ description: "Apply the planned migration to the database."
1319
+ });
1320
+ if (context.schemaPreset === "basic") nextSteps.push({
1321
+ command: getRunScriptCommand(context.packageManager, "db:seed"),
1322
+ description: "Insert the sample user and post data from prisma/seed.ts."
1323
+ });
1324
+ if (options.includeDevNextStep) nextSteps.push({
1325
+ command: getRunScriptCommand(context.packageManager, "dev"),
1326
+ description: "Start the development server."
1327
+ });
1032
1328
  return nextSteps;
1033
1329
  }
1330
+ function formatNextSteps(nextSteps) {
1331
+ return nextSteps.map((step) => `${step.command}\n ${step.description}`).join("\n\n");
1332
+ }
1034
1333
  async function executePrismaSetupContext(context, options = {}) {
1035
1334
  const projectDir = path.resolve(options.projectDir ?? context.projectDir);
1036
1335
  const provisionResult = await provisionPrismaPostgresIfNeeded(context, projectDir);
@@ -1038,687 +1337,20 @@ async function executePrismaSetupContext(context, options = {}) {
1038
1337
  if (!await writeDependenciesForContext(context, projectDir)) return false;
1039
1338
  if (!await installDependenciesForContext(context, projectDir)) return false;
1040
1339
  if (!await finalizePrismaFilesForContext(context, projectDir, provisionResult)) return false;
1041
- const generateResult = await generatePrismaClientForContext(context, projectDir);
1042
- const warningLines = buildWarningLines(provisionResult.warning, generateResult.warning);
1340
+ if (!await writeMongoDockerHelpersForContext(context, projectDir)) return false;
1341
+ const emitResult = await emitPrismaNextContractForContext(context, projectDir);
1342
+ const warningLines = buildWarningLines(provisionResult.warning, emitResult.warning);
1043
1343
  const nextSteps = buildNextStepsForContext({
1044
1344
  context,
1045
1345
  options,
1046
- didGenerateClient: generateResult.didGenerateClient
1346
+ didEmitContract: emitResult.didEmitContract
1047
1347
  });
1048
- outro(`Setup complete.${warningLines.length > 0 ? `\n\n${warningLines.join("\n")}` : ""}
1049
-
1050
- Next steps:
1051
- ${nextSteps.join("\n")}`);
1348
+ if (warningLines.length > 0) note(warningLines.map((line) => line.replace(/^- /, "")).join("\n"), "Heads up");
1349
+ note(formatNextSteps(nextSteps), "Next steps");
1350
+ outro("Setup complete.");
1052
1351
  return true;
1053
1352
  }
1054
1353
 
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
1354
  //#endregion
1723
1355
  //#region src/ui/branding.ts
1724
1356
  const prismaTitle = `${styleText(["bold", "cyan"], "Create")} ${styleText(["bold", "magenta"], "Prisma")}`;
@@ -1764,7 +1396,7 @@ async function promptForCreateTemplate() {
1764
1396
  {
1765
1397
  value: "hono",
1766
1398
  label: "Hono",
1767
- hint: "TypeScript API starter"
1399
+ hint: "Default TypeScript API starter"
1768
1400
  },
1769
1401
  {
1770
1402
  value: "elysia",
@@ -1872,8 +1504,8 @@ async function runCreateCommand(rawInput = {}) {
1872
1504
  }
1873
1505
  }
1874
1506
  async function collectCreateContext(input) {
1875
- const useDefaults = input.yes === true;
1876
1507
  const force = input.force === true;
1508
+ const useDefaults = input.yes === true;
1877
1509
  const projectNameInput = input.name ?? (useDefaults ? DEFAULT_PROJECT_NAME : await promptForProjectName());
1878
1510
  if (projectNameInput === void 0) return;
1879
1511
  const projectName = String(projectNameInput).trim();
@@ -1899,20 +1531,13 @@ async function collectCreateContext(input) {
1899
1531
  defaultSchemaPreset: DEFAULT_SCHEMA_PRESET
1900
1532
  });
1901
1533
  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
1534
  return {
1909
1535
  targetDirectory,
1910
1536
  targetPathState,
1911
1537
  force,
1912
1538
  template,
1913
1539
  projectPackageName: toPackageName(path.basename(targetDirectory)),
1914
- prismaSetupContext,
1915
- addonSetupContext: addonSetupContext ?? void 0
1540
+ prismaSetupContext
1916
1541
  };
1917
1542
  }
1918
1543
  async function executeCreateContext(context) {
@@ -1925,6 +1550,7 @@ async function executeCreateContext(context) {
1925
1550
  template: context.template,
1926
1551
  schemaPreset: context.prismaSetupContext.schemaPreset,
1927
1552
  provider: context.prismaSetupContext.databaseProvider,
1553
+ authoring: context.prismaSetupContext.authoring,
1928
1554
  packageManager: context.prismaSetupContext.packageManager
1929
1555
  });
1930
1556
  scaffoldSpinner.stop("Project files scaffolded.");
@@ -1950,21 +1576,10 @@ async function executeCreateContext(context) {
1950
1576
  };
1951
1577
  }
1952
1578
  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
- }
1579
+ const nextSteps = formatPathForDisplay(context.targetDirectory) === "." ? [] : [{
1580
+ command: `cd ${formatPathForDisplay(context.targetDirectory)}`,
1581
+ description: "Enter your new project directory."
1582
+ }];
1968
1583
  try {
1969
1584
  if (!await executePrismaSetupContext(context.prismaSetupContext, {
1970
1585
  prependNextSteps: nextSteps,
@@ -1985,4 +1600,4 @@ async function executeCreateContext(context) {
1985
1600
  }
1986
1601
 
1987
1602
  //#endregion
1988
- export { DatabaseUrlSchema as a, DatabaseProviderSchema as i, CreateCommandInputSchema as n, PackageManagerSchema as o, CreateTemplateSchema as r, SchemaPresetSchema as s, runCreateCommand as t };
1603
+ 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 };