create-prisma 0.9.2 → 0.9.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.
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import "./create-DPrHKEg5.mjs";
2
+ import "./create-CJa0JTWf.mjs";
3
3
  import { createCreatePrismaCli } from "./index.mjs";
4
4
 
5
5
  //#region src/cli.ts
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { z } from "zod";
3
- import { cancel, confirm, intro, isCancel, log, note, outro, select, spinner, text } from "@clack/prompts";
3
+ import { cancel, confirm, intro, isCancel, log, note, outro, select, spinner, taskLog, text } from "@clack/prompts";
4
4
  import fs from "fs-extra";
5
5
  import path from "node:path";
6
6
  import { randomUUID } from "node:crypto";
@@ -10,6 +10,7 @@ import Handlebars from "handlebars";
10
10
  import { existsSync } from "node:fs";
11
11
  import { fileURLToPath } from "node:url";
12
12
  import { execa } from "execa";
13
+ import { createInterface } from "node:readline";
13
14
  import { styleText } from "node:util";
14
15
 
15
16
  //#region src/telemetry/client.ts
@@ -49,7 +50,7 @@ async function getAnonymousId() {
49
50
  }
50
51
  function getCommonProperties() {
51
52
  return {
52
- "cli-version": "0.9.2",
53
+ "cli-version": "0.9.3",
53
54
  "node-version": process.version,
54
55
  platform: process.platform,
55
56
  arch: process.arch
@@ -668,7 +669,7 @@ async function installProjectDependencies(packageManager, projectDir = process.c
668
669
  //#endregion
669
670
  //#region src/tasks/deploy-with-composer.ts
670
671
  function redactSecrets(message) {
671
- return message.replace(/\b((?:prisma\+)?postgres(?:ql)?:\/\/)[^\s'"]+/gi, "$1<redacted>").replace(/\b([A-Z0-9_]*(?:DATABASE_URL|TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE_KEY)[A-Z0-9_]*=)[^\s]+/g, "$1<redacted>");
672
+ 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>");
672
673
  }
673
674
  function getErrorMessage(error) {
674
675
  if (error instanceof Error) return redactSecrets(error.message);
@@ -703,12 +704,16 @@ async function runPrismaJsonCommand(options) {
703
704
  "--json",
704
705
  "--no-interactive"
705
706
  ]);
706
- const result = await execa(invocation.command, invocation.args, {
707
+ const subprocess = execa(invocation.command, invocation.args, {
707
708
  cwd: options.projectDir,
708
709
  env: process.env,
709
710
  reject: false
710
711
  });
711
- if (options.forwardStderr && result.stderr) process.stderr.write(result.stderr.endsWith("\n") ? result.stderr : `${result.stderr}\n`);
712
+ const stderrLines = options.onStderrLine && subprocess.stderr ? (async () => {
713
+ const lines = createInterface({ input: subprocess.stderr });
714
+ for await (const line of lines) if (line.trim()) options.onStderrLine?.(line);
715
+ })() : Promise.resolve();
716
+ const [result] = await Promise.all([subprocess, stderrLines]);
712
717
  let envelope;
713
718
  try {
714
719
  envelope = parsePrismaCliEnvelope(result.stdout);
@@ -722,6 +727,19 @@ async function runPrismaJsonCommand(options) {
722
727
  }
723
728
  return envelope.result;
724
729
  }
730
+ function findProjectNameCollisions(projects, appName) {
731
+ return projects.filter((project) => project.name === appName);
732
+ }
733
+ async function ensureProjectNameAvailable(options) {
734
+ const collisions = findProjectNameCollisions((await runPrismaJsonCommand({
735
+ packageManager: options.packageManager,
736
+ projectDir: options.projectDir,
737
+ args: ["project", "list"]
738
+ })).items, options.appName);
739
+ if (collisions.length === 0) return;
740
+ const projectIds = collisions.map((project) => project.id).join(", ");
741
+ throw new Error(`A Prisma project named "${options.appName}" already exists in workspace ${workspaceLabel(options.workspace)} (${options.workspace.id}). Choose a different project name or delete the existing project (${projectIds}) in Prisma Console, then retry.`);
742
+ }
725
743
  async function ensureAuthentication(packageManager, projectDir, beforeInteractiveLogin) {
726
744
  const whoami = () => runPrismaJsonCommand({
727
745
  packageManager,
@@ -843,8 +861,13 @@ async function getProjectDetails(options) {
843
861
  return;
844
862
  }
845
863
  }
846
- async function deployWithComposer(options) {
864
+ /**
865
+ * Performs the optional one-shot deployment at the end of a create-prisma scaffold.
866
+ * Generated projects use their own `deploy` script for every subsequent deployment.
867
+ */
868
+ async function deployNewProjectWithComposer(options) {
847
869
  const progress = options.verbose ? void 0 : spinner();
870
+ let deploymentLog;
848
871
  let progressRunning = false;
849
872
  const showProgress = (message) => {
850
873
  if (!progress) return;
@@ -875,6 +898,14 @@ async function deployWithComposer(options) {
875
898
  ...options.workspace ? { workspace: options.workspace } : {}
876
899
  });
877
900
  if (!selectedWorkspace) return;
901
+ showProgress("Checking Prisma project name...");
902
+ if (options.verbose) log.step("Checking Prisma project name.");
903
+ await ensureProjectNameAvailable({
904
+ appName: options.appName,
905
+ packageManager: options.packageManager,
906
+ projectDir: options.projectDir,
907
+ workspace: selectedWorkspace
908
+ });
878
909
  showProgress("Building for deployment...");
879
910
  if (options.verbose) log.step("Building for deployment.");
880
911
  const build = getRunScriptArgs(options.packageManager, "build");
@@ -883,22 +914,40 @@ async function deployWithComposer(options) {
883
914
  env: process.env,
884
915
  stdio: options.verbose ? "inherit" : "pipe"
885
916
  });
886
- showProgress("Deploying to Prisma...");
887
- if (options.verbose) log.step("Deploying to Prisma.");
917
+ clearProgress();
918
+ const deployCommand = getPackageExecutionCommand(options.packageManager, [
919
+ PRISMA_PLATFORM_CLI_PACKAGE,
920
+ "deploy",
921
+ "module.ts"
922
+ ]);
923
+ if (options.verbose) log.step(`Deploying to Prisma with ${deployCommand}.`);
924
+ else {
925
+ deploymentLog = taskLog({
926
+ title: "Deploying to Prisma...",
927
+ limit: 10
928
+ });
929
+ deploymentLog.message(`$ ${deployCommand}`);
930
+ }
888
931
  const deployment = parseComposerDeployResult(await runPrismaJsonCommand({
889
932
  packageManager: options.packageManager,
890
933
  projectDir: options.projectDir,
891
934
  args: ["deploy", "module.ts"],
892
- forwardStderr: options.verbose
935
+ onStderrLine: (line) => {
936
+ const redactedLine = redactSecrets(line);
937
+ if (options.verbose) process.stderr.write(`${redactedLine}\n`);
938
+ else deploymentLog?.message(redactedLine);
939
+ }
893
940
  }));
894
941
  const appName = deployment?.appName ?? options.appName;
895
- showProgress("Loading deployment details...");
942
+ if (options.verbose) log.step("Loading deployment details.");
943
+ else deploymentLog?.message("Loading deployment details...");
896
944
  const details = await getProjectDetails({
897
945
  packageManager: options.packageManager,
898
946
  projectDir: options.projectDir,
899
947
  appName
900
948
  });
901
- progress?.stop("Deployed to Prisma.");
949
+ deploymentLog?.success("Deployed to Prisma.");
950
+ deploymentLog = void 0;
902
951
  progressRunning = false;
903
952
  if (options.verbose) log.success("Deployed to Prisma.");
904
953
  const workspace = details?.workspace ?? selectedWorkspace;
@@ -909,13 +958,73 @@ async function deployWithComposer(options) {
909
958
  project: details?.project ?? { name: appName }
910
959
  };
911
960
  } catch (error) {
912
- progress?.error("Deployment failed.");
961
+ if (deploymentLog) {
962
+ deploymentLog.error("Deployment failed.");
963
+ deploymentLog = void 0;
964
+ } else progress?.error("Deployment failed.");
913
965
  progressRunning = false;
914
966
  log.error(`Deploy failed: ${getErrorMessage(error)}`);
915
967
  return;
916
968
  }
917
969
  }
918
970
 
971
+ //#endregion
972
+ //#region src/tasks/initialize-git.ts
973
+ function errorMessage(error) {
974
+ if (error instanceof Error && "stderr" in error) {
975
+ const stderr = String(error.stderr ?? "").trim();
976
+ if (stderr) return stderr;
977
+ }
978
+ return error instanceof Error ? error.message : String(error);
979
+ }
980
+ /**
981
+ * Initializes a standalone scaffold as a Git repository and records its generated files.
982
+ * Projects created inside an existing repository remain part of that repository.
983
+ */
984
+ async function initializeGitRepository(projectDir, env = process.env) {
985
+ try {
986
+ const existing = await execa("git", ["rev-parse", "--is-inside-work-tree"], {
987
+ cwd: projectDir,
988
+ env,
989
+ reject: false
990
+ });
991
+ if (existing.exitCode === 0 && existing.stdout.trim() === "true") return { status: "already-in-repository" };
992
+ } catch (error) {
993
+ return {
994
+ status: "skipped",
995
+ reason: errorMessage(error)
996
+ };
997
+ }
998
+ let initialized = false;
999
+ try {
1000
+ await execa("git", ["init"], {
1001
+ cwd: projectDir,
1002
+ env
1003
+ });
1004
+ initialized = true;
1005
+ await execa("git", ["add", "--all"], {
1006
+ cwd: projectDir,
1007
+ env
1008
+ });
1009
+ await execa("git", [
1010
+ "commit",
1011
+ "--no-verify",
1012
+ "-m",
1013
+ "Initial commit from create-prisma"
1014
+ ], {
1015
+ cwd: projectDir,
1016
+ env
1017
+ });
1018
+ return { status: "initialized" };
1019
+ } catch (error) {
1020
+ if (initialized) await fs.remove(path.join(projectDir, ".git"));
1021
+ return {
1022
+ status: "skipped",
1023
+ reason: errorMessage(error)
1024
+ };
1025
+ }
1026
+ }
1027
+
919
1028
  //#endregion
920
1029
  //#region src/tasks/setup-prisma.ts
921
1030
  const DEFAULT_DATABASE_PROVIDER = "postgres";
@@ -1166,7 +1275,9 @@ async function executePrismaSetupContext(context, options = {}) {
1166
1275
  const projectName = options.projectName ?? path.basename(projectDir);
1167
1276
  const template = options.template ?? "minimal";
1168
1277
  const progress = context.verbose ? void 0 : options.progressSpinner ?? spinner();
1169
- if (progress !== void 0 && !options.progressSpinner) progress.start("Creating Prisma 8 project...");
1278
+ const ownsProgress = progress !== void 0 && !options.progressSpinner;
1279
+ let gitInitialization;
1280
+ if (ownsProgress) progress.start("Creating Prisma 8 project...");
1170
1281
  try {
1171
1282
  progress?.message("Preparing Prisma 8 project files...");
1172
1283
  await runPrismaInit(context, projectDir);
@@ -1181,13 +1292,23 @@ async function executePrismaSetupContext(context, options = {}) {
1181
1292
  await writePrismaDependencies(context.databaseProvider, context.packageManager, context.authoring, projectDir);
1182
1293
  await ensureComposerTypeScriptOptions(projectDir);
1183
1294
  if (context.databaseProvider === "mongo") await ensureMongoEnvironment(projectDir);
1295
+ if (context.packageManager !== "deno") {
1296
+ await ensureGitignoreEntry(projectDir, "/.alchemy");
1297
+ await ensureGitignoreEntry(projectDir, "/.prisma-composer");
1298
+ }
1184
1299
  progress?.message(`Installing dependencies with ${getInstallCommand(context.packageManager)}...`);
1185
1300
  await installProjectDependencies(context.packageManager, projectDir, { verbose: context.verbose });
1186
1301
  progress?.message("Installing Prisma agent skills...");
1187
1302
  await initializeAgentSkills(context, projectDir);
1188
1303
  progress?.message("Generating Prisma 8 contract artifacts...");
1189
1304
  await emitContract(context, projectDir);
1305
+ if (options.initializeGit) {
1306
+ progress?.message("Initializing Git repository...");
1307
+ gitInitialization = await initializeGitRepository(projectDir);
1308
+ }
1190
1309
  progress?.stop("Prisma 8 project ready.");
1310
+ if (gitInitialization?.status === "initialized" && context.verbose) log.success("Initialized Git repository with an initial commit.");
1311
+ else if (gitInitialization?.status === "skipped") log.warn(`Could not initialize Git repository: ${gitInitialization.reason}`);
1191
1312
  } catch (error) {
1192
1313
  progress?.error("Could not create Prisma 8 project.");
1193
1314
  cancel(getCommandErrorMessage(error));
@@ -1195,7 +1316,7 @@ async function executePrismaSetupContext(context, options = {}) {
1195
1316
  }
1196
1317
  let deployment;
1197
1318
  if (context.shouldDeploy) {
1198
- deployment = await deployWithComposer({
1319
+ deployment = await deployNewProjectWithComposer({
1199
1320
  appName: projectName,
1200
1321
  packageManager: context.packageManager,
1201
1322
  projectDir,
@@ -1490,6 +1611,7 @@ async function executeCreateContext(context) {
1490
1611
  template: context.template,
1491
1612
  createdProjectPath: context.targetDirectory,
1492
1613
  includeDevNextStep: true,
1614
+ initializeGit: !context.targetPathState.exists || context.targetPathState.isEmptyDirectory,
1493
1615
  progressSpinner: createSpinner
1494
1616
  })) return {
1495
1617
  ok: false,
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { a as DatabaseProviderSchema, i as CreateTemplateSchema, n as AuthoringStyleSchema, o as PackageManagerSchema, r as CreateCommandInputSchema, t as runCreateCommand } from "./create-DPrHKEg5.mjs";
2
+ import { a as DatabaseProviderSchema, i as CreateTemplateSchema, n as AuthoringStyleSchema, o as PackageManagerSchema, r as CreateCommandInputSchema, t as runCreateCommand } from "./create-CJa0JTWf.mjs";
3
3
  import { os } from "@orpc/server";
4
4
  import { createCli } from "trpc-cli";
5
5
  import { z } from "zod";
6
6
 
7
7
  //#region src/index.ts
8
- const CLI_VERSION = "0.9.2";
8
+ const CLI_VERSION = "0.9.3";
9
9
  const CreateCliInputSchema = z.tuple([z.string().trim().min(1, "Please enter a valid project name").optional().describe("Project name / directory"), CreateCommandInputSchema]);
10
10
  function normalizeCreateCliInput(input) {
11
11
  const [projectName, options] = input;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-prisma",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "private": false,
5
5
  "description": "Create Prisma 8 projects with first-party templates and great DX.",
6
6
  "homepage": "https://github.com/prisma/create-prisma",
@@ -37,7 +37,7 @@
37
37
  "dev": "tsdown --watch",
38
38
  "start": "bun run ./dist/cli.mjs",
39
39
  "test": "bun run test:unit && bun run test:e2e",
40
- "test:unit": "bun test ./tests/dependencies.test.ts ./tests/deploy-with-composer.test.ts ./tests/install.test.ts ./tests/node-version.test.ts ./tests/setup-prisma.test.ts ./tests/telemetry.test.ts",
40
+ "test:unit": "bun test ./tests/dependencies.test.ts ./tests/deploy-with-composer.test.ts ./tests/initialize-git.test.ts ./tests/install.test.ts ./tests/node-version.test.ts ./tests/setup-prisma.test.ts ./tests/telemetry.test.ts",
41
41
  "test:e2e": "bun test --timeout 180000 ./tests/e2e/create-prisma.e2e.test.ts",
42
42
  "check": "bun run format:check && bun run lint",
43
43
  "lint": "oxlint . --deny-warnings",