create-prisma 0.11.2 → 0.11.3

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