create-better-t-stack 3.7.2 → 3.7.3-canary.3bd96a3b

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.
@@ -3,11 +3,12 @@ import { autocompleteMultiselect, cancel, confirm, group, groupMultiselect, intr
3
3
  import { createRouterClient, os } from "@orpc/server";
4
4
  import pc from "picocolors";
5
5
  import { createCli } from "trpc-cli";
6
- import z$1, { z } from "zod";
6
+ import z from "zod";
7
7
  import path from "node:path";
8
8
  import consola, { consola as consola$1 } from "consola";
9
9
  import fs from "fs-extra";
10
10
  import { fileURLToPath } from "node:url";
11
+ import { APISchema, AddonsSchema, AuthSchema, BackendSchema, DatabaseSchema, DatabaseSetupSchema, DirectoryConflictSchema, ExamplesSchema, FrontendSchema, ORMSchema, PackageManagerSchema, PaymentsSchema, ProjectNameSchema, RuntimeSchema, ServerDeploySchema, TemplateSchema, WebDeploySchema } from "@better-t-stack/types";
11
12
  import gradient from "gradient-string";
12
13
  import * as JSONC from "jsonc-parser";
13
14
  import { $, execa } from "execa";
@@ -62,6 +63,7 @@ function getDefaultConfig() {
62
63
  }
63
64
  const DEFAULT_CONFIG = getDefaultConfig();
64
65
  const dependencyVersionMap = {
66
+ typescript: "^5",
65
67
  "better-auth": "^1.4.5",
66
68
  "@better-auth/expo": "^1.4.5",
67
69
  "@clerk/nextjs": "^6.31.5",
@@ -98,7 +100,7 @@ const dependencyVersionMap = {
98
100
  "lint-staged": "^16.1.2",
99
101
  tsx: "^4.19.2",
100
102
  "@types/node": "^22.13.11",
101
- "@types/bun": "^1.2.6",
103
+ "@types/bun": "^1.3.4",
102
104
  "@elysiajs/node": "^1.3.1",
103
105
  "@elysiajs/cors": "^1.3.3",
104
106
  "@elysiajs/trpc": "^1.1.0",
@@ -128,7 +130,7 @@ const dependencyVersionMap = {
128
130
  "@trpc/tanstack-react-query": "^11.5.0",
129
131
  "@trpc/server": "^11.5.0",
130
132
  "@trpc/client": "^11.5.0",
131
- next: "15.5.4",
133
+ next: "^16.0.7",
132
134
  convex: "^1.29.3",
133
135
  "@convex-dev/react-query": "^0.1.0",
134
136
  "convex-svelte": "^0.0.12",
@@ -153,7 +155,7 @@ const dependencyVersionMap = {
153
155
  alchemy: "^0.77.0",
154
156
  dotenv: "^17.2.2",
155
157
  tsdown: "^0.16.5",
156
- zod: "^4.1.11",
158
+ zod: "^4.1.13",
157
159
  srvx: "0.8.15",
158
160
  "@polar-sh/better-auth": "^1.1.3",
159
161
  "@polar-sh/sdk": "^0.34.16"
@@ -184,121 +186,6 @@ const ADDON_COMPATIBILITY = {
184
186
  none: []
185
187
  };
186
188
 
187
- //#endregion
188
- //#region src/types.ts
189
- const DatabaseSchema = z.enum([
190
- "none",
191
- "sqlite",
192
- "postgres",
193
- "mysql",
194
- "mongodb"
195
- ]).describe("Database type");
196
- const ORMSchema = z.enum([
197
- "drizzle",
198
- "prisma",
199
- "mongoose",
200
- "none"
201
- ]).describe("ORM type");
202
- const BackendSchema = z.enum([
203
- "hono",
204
- "express",
205
- "fastify",
206
- "elysia",
207
- "convex",
208
- "self",
209
- "none"
210
- ]).describe("Backend framework");
211
- const RuntimeSchema = z.enum([
212
- "bun",
213
- "node",
214
- "workers",
215
- "none"
216
- ]).describe("Runtime environment");
217
- const FrontendSchema = z.enum([
218
- "tanstack-router",
219
- "react-router",
220
- "tanstack-start",
221
- "next",
222
- "nuxt",
223
- "native-bare",
224
- "native-uniwind",
225
- "native-unistyles",
226
- "svelte",
227
- "solid",
228
- "none"
229
- ]).describe("Frontend framework");
230
- const AddonsSchema = z.enum([
231
- "pwa",
232
- "tauri",
233
- "starlight",
234
- "biome",
235
- "husky",
236
- "ruler",
237
- "turborepo",
238
- "fumadocs",
239
- "ultracite",
240
- "oxlint",
241
- "none"
242
- ]).describe("Additional addons");
243
- const ExamplesSchema = z.enum([
244
- "todo",
245
- "ai",
246
- "none"
247
- ]).describe("Example templates to include");
248
- const PackageManagerSchema = z.enum([
249
- "npm",
250
- "pnpm",
251
- "bun"
252
- ]).describe("Package manager");
253
- const DatabaseSetupSchema = z.enum([
254
- "turso",
255
- "neon",
256
- "prisma-postgres",
257
- "planetscale",
258
- "mongodb-atlas",
259
- "supabase",
260
- "d1",
261
- "docker",
262
- "none"
263
- ]).describe("Database hosting setup");
264
- const APISchema = z.enum([
265
- "trpc",
266
- "orpc",
267
- "none"
268
- ]).describe("API type");
269
- const AuthSchema = z.enum([
270
- "better-auth",
271
- "clerk",
272
- "none"
273
- ]).describe("Authentication provider");
274
- const PaymentsSchema = z.enum(["polar", "none"]).describe("Payments provider");
275
- const ProjectNameSchema = z.string().min(1, "Project name cannot be empty").max(255, "Project name must be less than 255 characters").refine((name) => name === "." || !name.startsWith("."), "Project name cannot start with a dot (except for '.')").refine((name) => name === "." || !name.startsWith("-"), "Project name cannot start with a dash").refine((name) => {
276
- return ![
277
- "<",
278
- ">",
279
- ":",
280
- "\"",
281
- "|",
282
- "?",
283
- "*"
284
- ].some((char) => name.includes(char));
285
- }, "Project name contains invalid characters").refine((name) => name.toLowerCase() !== "node_modules", "Project name is reserved").describe("Project name or path");
286
- const WebDeploySchema = z.enum(["alchemy", "none"]).describe("Web deployment");
287
- const ServerDeploySchema = z.enum(["alchemy", "none"]).describe("Server deployment");
288
- const DirectoryConflictSchema = z.enum([
289
- "merge",
290
- "overwrite",
291
- "increment",
292
- "error"
293
- ]).describe("How to handle existing directory conflicts");
294
- const TemplateSchema = z.enum([
295
- "mern",
296
- "pern",
297
- "t3",
298
- "uniwind",
299
- "none"
300
- ]).describe("Predefined project template");
301
-
302
189
  //#endregion
303
190
  //#region src/utils/compatibility.ts
304
191
  const WEB_FRAMEWORKS = [
@@ -1346,7 +1233,7 @@ const getLatestCLIVersion = () => {
1346
1233
  */
1347
1234
  function isTelemetryEnabled() {
1348
1235
  const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
1349
- const BTS_TELEMETRY = "1";
1236
+ const BTS_TELEMETRY = "0";
1350
1237
  if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
1351
1238
  if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
1352
1239
  return true;
@@ -3863,6 +3750,7 @@ async function addDeploymentToProject(input) {
3863
3750
  async function setupCatalogs(projectDir, options) {
3864
3751
  if (options.packageManager === "npm") return;
3865
3752
  const packagePaths = [
3753
+ ".",
3866
3754
  "apps/server",
3867
3755
  "apps/web",
3868
3756
  "apps/native",
@@ -3871,7 +3759,8 @@ async function setupCatalogs(projectDir, options) {
3871
3759
  "packages/api",
3872
3760
  "packages/db",
3873
3761
  "packages/auth",
3874
- "packages/backend"
3762
+ "packages/backend",
3763
+ "packages/config"
3875
3764
  ];
3876
3765
  const packagesInfo = [];
3877
3766
  for (const pkgPath of packagePaths) {
@@ -3970,15 +3859,18 @@ async function updatePackageJsonsWithCatalogs(packagesInfo, catalog) {
3970
3859
  //#endregion
3971
3860
  //#region src/helpers/addons/examples-setup.ts
3972
3861
  async function setupExamples(config) {
3973
- const { examples, frontend, backend, projectDir, orm } = config;
3862
+ const { examples, frontend, backend, projectDir, orm, database } = config;
3974
3863
  if (backend === "convex" || !examples || examples.length === 0 || examples[0] === "none") return;
3975
3864
  const apiDir = path.join(projectDir, "packages/api");
3976
3865
  if (await fs.pathExists(apiDir) && backend !== "none") {
3977
- if (orm === "drizzle") await addPackageDependency({
3978
- dependencies: ["drizzle-orm"],
3979
- projectDir: apiDir
3980
- });
3981
- else if (orm === "prisma") await addPackageDependency({
3866
+ if (orm === "drizzle") {
3867
+ const dependencies = ["drizzle-orm"];
3868
+ if (database === "postgres") dependencies.push("@types/pg");
3869
+ await addPackageDependency({
3870
+ dependencies,
3871
+ projectDir: apiDir
3872
+ });
3873
+ } else if (orm === "prisma") await addPackageDependency({
3982
3874
  dependencies: ["@prisma/client"],
3983
3875
  projectDir: apiDir
3984
3876
  });
@@ -4027,15 +3919,6 @@ async function setupExamples(config) {
4027
3919
 
4028
3920
  //#endregion
4029
3921
  //#region src/helpers/core/api-setup.ts
4030
- async function addBackendWorkspaceDependency(projectDir, backendPackageName, workspaceVersion) {
4031
- const pkgJsonPath = path.join(projectDir, "package.json");
4032
- try {
4033
- const pkgJson = await fs.readJson(pkgJsonPath);
4034
- if (!pkgJson.dependencies) pkgJson.dependencies = {};
4035
- pkgJson.dependencies[backendPackageName] = workspaceVersion;
4036
- await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
4037
- } catch {}
4038
- }
4039
3922
  function getFrontendType(frontend) {
4040
3923
  const reactBasedFrontends = [
4041
3924
  "tanstack-router",
@@ -4153,7 +4036,7 @@ function getConvexDependencies(frontend) {
4153
4036
  return deps;
4154
4037
  }
4155
4038
  async function setupApi(config) {
4156
- const { api, projectName, frontend, backend, packageManager, projectDir } = config;
4039
+ const { api, frontend, backend, projectDir } = config;
4157
4040
  const isConvex = backend === "convex";
4158
4041
  const webDir = path.join(projectDir, "apps/web");
4159
4042
  const nativeDir = path.join(projectDir, "apps/native");
@@ -4223,10 +4106,6 @@ async function setupApi(config) {
4223
4106
  dependencies: convexDeps.native.dependencies,
4224
4107
  projectDir: nativeDir
4225
4108
  });
4226
- const backendPackageName = `@${projectName}/backend`;
4227
- const backendWorkspaceVersion = packageManager === "npm" ? "*" : "workspace:*";
4228
- if (webDirExists) await addBackendWorkspaceDependency(webDir, backendPackageName, backendWorkspaceVersion);
4229
- if (nativeDirExists) await addBackendWorkspaceDependency(nativeDir, backendPackageName, backendWorkspaceVersion);
4230
4109
  }
4231
4110
  }
4232
4111
 
@@ -6431,93 +6310,113 @@ function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend)
6431
6310
  //#endregion
6432
6311
  //#region src/helpers/core/workspace-setup.ts
6433
6312
  async function setupWorkspaceDependencies(projectDir, options) {
6434
- const projectName = options.projectName;
6435
- const workspaceVersion = options.packageManager === "npm" ? "*" : "workspace:*";
6313
+ const { projectName, packageManager, database, auth, api, runtime, backend } = options;
6314
+ const workspaceVersion = packageManager === "npm" ? "*" : "workspace:*";
6436
6315
  const commonDeps = ["dotenv", "zod"];
6437
- const commonDevDeps = [];
6438
- const configPackageDir = path.join(projectDir, "packages/config");
6439
- const configDep = {};
6440
- if (await fs.pathExists(configPackageDir)) configDep[`@${projectName}/config`] = workspaceVersion;
6441
- const dbPackageDir = path.join(projectDir, "packages/db");
6442
- if (await fs.pathExists(dbPackageDir)) await addPackageDependency({
6316
+ const commonDevDeps = ["typescript"];
6317
+ const configDir = path.join(projectDir, "packages/config");
6318
+ const dbDir = path.join(projectDir, "packages/db");
6319
+ const authDir = path.join(projectDir, "packages/auth");
6320
+ const apiDir = path.join(projectDir, "packages/api");
6321
+ const backendDir = path.join(projectDir, "packages/backend");
6322
+ const serverDir = path.join(projectDir, "apps/server");
6323
+ const webDir = path.join(projectDir, "apps/web");
6324
+ const nativeDir = path.join(projectDir, "apps/native");
6325
+ const [configExists, dbExists, authExists, apiExists, backendExists, serverExists, webExists, nativeExists] = await Promise.all([
6326
+ fs.pathExists(configDir),
6327
+ fs.pathExists(dbDir),
6328
+ fs.pathExists(authDir),
6329
+ fs.pathExists(apiDir),
6330
+ fs.pathExists(backendDir),
6331
+ fs.pathExists(serverDir),
6332
+ fs.pathExists(webDir),
6333
+ fs.pathExists(nativeDir)
6334
+ ]);
6335
+ const configDep = configExists ? { [`@${projectName}/config`]: workspaceVersion } : {};
6336
+ if (dbExists) await addPackageDependency({
6443
6337
  dependencies: commonDeps,
6444
6338
  devDependencies: commonDevDeps,
6445
6339
  customDevDependencies: configDep,
6446
- projectDir: dbPackageDir
6340
+ projectDir: dbDir
6447
6341
  });
6448
- const authPackageDir = path.join(projectDir, "packages/auth");
6449
- if (await fs.pathExists(authPackageDir)) {
6342
+ if (authExists) {
6450
6343
  const authDeps = {};
6451
- if (options.database !== "none" && await fs.pathExists(dbPackageDir)) authDeps[`@${projectName}/db`] = workspaceVersion;
6344
+ if (database !== "none" && dbExists) authDeps[`@${projectName}/db`] = workspaceVersion;
6452
6345
  await addPackageDependency({
6453
6346
  dependencies: commonDeps,
6454
6347
  devDependencies: commonDevDeps,
6455
6348
  customDependencies: authDeps,
6456
6349
  customDevDependencies: configDep,
6457
- projectDir: authPackageDir
6350
+ projectDir: authDir
6458
6351
  });
6459
6352
  }
6460
- const apiPackageDir = path.join(projectDir, "packages/api");
6461
- if (await fs.pathExists(apiPackageDir)) {
6353
+ if (apiExists) {
6462
6354
  const apiDeps = {};
6463
- if (options.auth !== "none" && await fs.pathExists(authPackageDir)) apiDeps[`@${projectName}/auth`] = workspaceVersion;
6464
- if (options.database !== "none" && await fs.pathExists(dbPackageDir)) apiDeps[`@${projectName}/db`] = workspaceVersion;
6355
+ if (auth !== "none" && authExists) apiDeps[`@${projectName}/auth`] = workspaceVersion;
6356
+ if (database !== "none" && dbExists) apiDeps[`@${projectName}/db`] = workspaceVersion;
6465
6357
  await addPackageDependency({
6466
6358
  dependencies: commonDeps,
6467
6359
  devDependencies: commonDevDeps,
6468
6360
  customDependencies: apiDeps,
6469
6361
  customDevDependencies: configDep,
6470
- projectDir: apiPackageDir
6362
+ projectDir: apiDir
6471
6363
  });
6472
6364
  }
6473
- const serverPackageDir = path.join(projectDir, "apps/server");
6474
- if (await fs.pathExists(serverPackageDir)) {
6365
+ if (backendExists) await addPackageDependency({
6366
+ dependencies: commonDeps,
6367
+ devDependencies: commonDevDeps,
6368
+ customDevDependencies: configDep,
6369
+ projectDir: backendDir
6370
+ });
6371
+ if (serverExists) {
6475
6372
  const serverDeps = {};
6476
- if (options.api !== "none" && await fs.pathExists(apiPackageDir)) serverDeps[`@${projectName}/api`] = workspaceVersion;
6477
- if (options.auth !== "none" && await fs.pathExists(authPackageDir)) serverDeps[`@${projectName}/auth`] = workspaceVersion;
6478
- if (options.database !== "none" && await fs.pathExists(dbPackageDir)) serverDeps[`@${projectName}/db`] = workspaceVersion;
6373
+ if (api !== "none" && apiExists) serverDeps[`@${projectName}/api`] = workspaceVersion;
6374
+ if (auth !== "none" && authExists) serverDeps[`@${projectName}/auth`] = workspaceVersion;
6375
+ if (database !== "none" && dbExists) serverDeps[`@${projectName}/db`] = workspaceVersion;
6479
6376
  await addPackageDependency({
6480
6377
  dependencies: commonDeps,
6481
6378
  devDependencies: [...commonDevDeps, "tsdown"],
6482
6379
  customDependencies: serverDeps,
6483
6380
  customDevDependencies: configDep,
6484
- projectDir: serverPackageDir
6381
+ projectDir: serverDir
6485
6382
  });
6486
6383
  }
6487
- const webPackageDir = path.join(projectDir, "apps/web");
6488
- if (await fs.pathExists(webPackageDir)) {
6384
+ if (webExists) {
6489
6385
  const webDeps = {};
6490
- if (options.api !== "none" && await fs.pathExists(apiPackageDir)) webDeps[`@${projectName}/api`] = workspaceVersion;
6491
- if (options.auth !== "none" && await fs.pathExists(authPackageDir)) webDeps[`@${projectName}/auth`] = workspaceVersion;
6492
- if (Object.keys(webDeps).length > 0) await addPackageDependency({
6386
+ if (api !== "none" && apiExists) webDeps[`@${projectName}/api`] = workspaceVersion;
6387
+ if (auth !== "none" && authExists) webDeps[`@${projectName}/auth`] = workspaceVersion;
6388
+ if (backend === "convex" && backendExists) webDeps[`@${projectName}/backend`] = workspaceVersion;
6389
+ await addPackageDependency({
6390
+ dependencies: commonDeps,
6391
+ devDependencies: commonDevDeps,
6493
6392
  customDependencies: webDeps,
6494
6393
  customDevDependencies: configDep,
6495
- projectDir: webPackageDir
6394
+ projectDir: webDir
6496
6395
  });
6497
6396
  }
6498
- const nativePackageDir = path.join(projectDir, "apps/native");
6499
- if (await fs.pathExists(nativePackageDir)) {
6397
+ if (nativeExists) {
6500
6398
  const nativeDeps = {};
6501
- if (options.api !== "none" && await fs.pathExists(apiPackageDir)) nativeDeps[`@${projectName}/api`] = workspaceVersion;
6502
- if (Object.keys(nativeDeps).length > 0) await addPackageDependency({
6399
+ if (api !== "none" && apiExists) nativeDeps[`@${projectName}/api`] = workspaceVersion;
6400
+ if (backend === "convex" && backendExists) nativeDeps[`@${projectName}/backend`] = workspaceVersion;
6401
+ await addPackageDependency({
6402
+ dependencies: commonDeps,
6403
+ devDependencies: commonDevDeps,
6503
6404
  customDependencies: nativeDeps,
6504
6405
  customDevDependencies: configDep,
6505
- projectDir: nativePackageDir
6406
+ projectDir: nativeDir
6506
6407
  });
6507
6408
  }
6508
- const runtimeDevDeps = getRuntimeDevDeps(options);
6409
+ const runtimeDevDeps = getRuntimeDevDeps(runtime, backend);
6509
6410
  await addPackageDependency({
6510
6411
  dependencies: commonDeps,
6511
6412
  devDependencies: [...commonDevDeps, ...runtimeDevDeps],
6512
6413
  projectDir
6513
6414
  });
6514
6415
  }
6515
- function getRuntimeDevDeps(options) {
6516
- const { runtime, backend } = options;
6416
+ function getRuntimeDevDeps(runtime, backend) {
6517
6417
  if (runtime === "none" && backend === "self") return ["@types/node"];
6518
- if (runtime === "node") return ["@types/node"];
6418
+ if (runtime === "node" || runtime === "workers") return ["@types/node"];
6519
6419
  if (runtime === "bun") return ["@types/bun"];
6520
- if (runtime === "workers") return ["@types/node"];
6521
6420
  return [];
6522
6421
  }
6523
6422
 
@@ -6526,185 +6425,130 @@ function getRuntimeDevDeps(options) {
6526
6425
  async function updatePackageConfigurations(projectDir, options) {
6527
6426
  await updateRootPackageJson(projectDir, options);
6528
6427
  if (options.backend === "convex") await updateConvexPackageJson(projectDir, options);
6529
- else if (options.backend === "self") {
6428
+ else if (options.backend !== "none") {
6530
6429
  await updateDbPackageJson(projectDir, options);
6531
6430
  await updateAuthPackageJson(projectDir, options);
6532
6431
  await updateApiPackageJson(projectDir, options);
6533
- await setupWorkspaceDependencies(projectDir, options);
6534
- } else if (options.backend !== "none") {
6535
- await updateServerPackageJson(projectDir, options);
6536
- await updateAuthPackageJson(projectDir, options);
6537
- await updateApiPackageJson(projectDir, options);
6538
- await setupWorkspaceDependencies(projectDir, options);
6432
+ if (options.backend !== "self") await updateServerPackageJson(projectDir, options);
6539
6433
  }
6434
+ await setupWorkspaceDependencies(projectDir, options);
6540
6435
  }
6541
6436
  async function updateRootPackageJson(projectDir, options) {
6542
6437
  const rootPackageJsonPath = path.join(projectDir, "package.json");
6543
6438
  if (!await fs.pathExists(rootPackageJsonPath)) return;
6544
6439
  const packageJson = await fs.readJson(rootPackageJsonPath);
6545
6440
  packageJson.name = options.projectName;
6546
- if (!packageJson.scripts) packageJson.scripts = {};
6441
+ packageJson.scripts = packageJson.scripts || {};
6442
+ packageJson.workspaces = packageJson.workspaces || [];
6547
6443
  const scripts = packageJson.scripts;
6548
- const backendPackageName = options.backend === "convex" ? `@${options.projectName}/backend` : "server";
6549
- const dbPackageName = `@${options.projectName}/db`;
6550
- let serverDevScript = "";
6551
- if (options.addons.includes("turborepo")) serverDevScript = `turbo -F ${backendPackageName} dev`;
6552
- else if (options.packageManager === "bun") serverDevScript = `bun run --filter ${backendPackageName} dev`;
6553
- else if (options.packageManager === "pnpm") serverDevScript = `pnpm --filter ${backendPackageName} dev`;
6554
- else if (options.packageManager === "npm") serverDevScript = `npm run dev --workspace ${backendPackageName}`;
6555
- let devScript = "";
6556
- if (options.packageManager === "pnpm") devScript = "pnpm -r dev";
6557
- else if (options.packageManager === "npm") devScript = "npm run dev --workspaces";
6558
- else if (options.packageManager === "bun") devScript = "bun run --filter '*' dev";
6559
- const needsDbScripts = options.backend !== "convex" && options.database !== "none" && options.orm !== "none" && options.orm !== "mongoose";
6560
- if (options.addons.includes("turborepo")) {
6561
- scripts.dev = "turbo dev";
6562
- scripts.build = "turbo build";
6563
- scripts["check-types"] = "turbo check-types";
6564
- scripts["dev:native"] = "turbo -F native dev";
6565
- scripts["dev:web"] = "turbo -F web dev";
6566
- if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
6567
- if (options.backend === "convex") scripts["dev:setup"] = `turbo -F ${backendPackageName} dev:setup`;
6568
- if (needsDbScripts) {
6569
- scripts["db:push"] = `turbo -F ${dbPackageName} db:push`;
6570
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `turbo -F ${dbPackageName} db:studio`;
6571
- if (options.orm === "prisma") {
6572
- scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
6573
- scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
6574
- } else if (options.orm === "drizzle") {
6575
- scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
6576
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
6577
- }
6578
- }
6579
- if (options.dbSetup === "docker") {
6580
- scripts["db:start"] = `turbo -F ${dbPackageName} db:start`;
6581
- scripts["db:watch"] = `turbo -F ${dbPackageName} db:watch`;
6582
- scripts["db:stop"] = `turbo -F ${dbPackageName} db:stop`;
6583
- scripts["db:down"] = `turbo -F ${dbPackageName} db:down`;
6584
- }
6585
- } else if (options.packageManager === "pnpm") {
6586
- scripts.dev = devScript;
6587
- scripts.build = "pnpm -r build";
6588
- scripts["check-types"] = "pnpm -r check-types";
6589
- scripts["dev:native"] = "pnpm --filter native dev";
6590
- scripts["dev:web"] = "pnpm --filter web dev";
6591
- if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
6592
- if (options.backend === "convex") scripts["dev:setup"] = `pnpm --filter ${backendPackageName} dev:setup`;
6593
- if (needsDbScripts) {
6594
- scripts["db:push"] = `pnpm --filter ${dbPackageName} db:push`;
6595
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${dbPackageName} db:studio`;
6596
- if (options.orm === "prisma") {
6597
- scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
6598
- scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
6599
- } else if (options.orm === "drizzle") {
6600
- scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
6601
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
6602
- }
6603
- }
6604
- if (options.dbSetup === "docker") {
6605
- scripts["db:start"] = `pnpm --filter ${dbPackageName} db:start`;
6606
- scripts["db:watch"] = `pnpm --filter ${dbPackageName} db:watch`;
6607
- scripts["db:stop"] = `pnpm --filter ${dbPackageName} db:stop`;
6608
- scripts["db:down"] = `pnpm --filter ${dbPackageName} db:down`;
6609
- }
6610
- } else if (options.packageManager === "npm") {
6611
- scripts.dev = devScript;
6612
- scripts.build = "npm run build --workspaces";
6613
- scripts["check-types"] = "npm run check-types --workspaces";
6614
- scripts["dev:native"] = "npm run dev --workspace native";
6615
- scripts["dev:web"] = "npm run dev --workspace web";
6616
- if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
6617
- if (options.backend === "convex") scripts["dev:setup"] = `npm run dev:setup --workspace ${backendPackageName}`;
6618
- if (needsDbScripts) {
6619
- scripts["db:push"] = `npm run db:push --workspace ${dbPackageName}`;
6620
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `npm run db:studio --workspace ${dbPackageName}`;
6621
- if (options.orm === "prisma") {
6622
- scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
6623
- scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
6624
- } else if (options.orm === "drizzle") {
6625
- scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
6626
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
6627
- }
6628
- }
6629
- if (options.dbSetup === "docker") {
6630
- scripts["db:start"] = `npm run db:start --workspace ${dbPackageName}`;
6631
- scripts["db:watch"] = `npm run db:watch --workspace ${dbPackageName}`;
6632
- scripts["db:stop"] = `npm run db:stop --workspace ${dbPackageName}`;
6633
- scripts["db:down"] = `npm run db:down --workspace ${dbPackageName}`;
6634
- }
6635
- } else if (options.packageManager === "bun") {
6636
- scripts.dev = devScript;
6637
- scripts.build = "bun run --filter '*' build";
6638
- scripts["check-types"] = "bun run --filter '*' check-types";
6639
- scripts["dev:native"] = "bun run --filter native dev";
6640
- scripts["dev:web"] = "bun run --filter web dev";
6641
- if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
6642
- if (options.backend === "convex") scripts["dev:setup"] = `bun run --filter ${backendPackageName} dev:setup`;
6643
- if (needsDbScripts) {
6644
- scripts["db:push"] = `bun run --filter ${dbPackageName} db:push`;
6645
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${dbPackageName} db:studio`;
6646
- if (options.orm === "prisma") {
6647
- scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
6648
- scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
6649
- } else if (options.orm === "drizzle") {
6650
- scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
6651
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
6652
- }
6653
- }
6654
- if (options.dbSetup === "docker") {
6655
- scripts["db:start"] = `bun run --filter ${dbPackageName} db:start`;
6656
- scripts["db:watch"] = `bun run --filter ${dbPackageName} db:watch`;
6657
- scripts["db:stop"] = `bun run --filter ${dbPackageName} db:stop`;
6658
- scripts["db:down"] = `bun run --filter ${dbPackageName} db:down`;
6444
+ const workspaces = packageJson.workspaces;
6445
+ const { projectName, packageManager, backend, database, orm, dbSetup, serverDeploy, addons } = options;
6446
+ const backendPackageName = backend === "convex" ? `@${projectName}/backend` : "server";
6447
+ const dbPackageName = `@${projectName}/db`;
6448
+ const hasTurborepo = addons.includes("turborepo");
6449
+ const needsDbScripts = backend !== "convex" && database !== "none" && orm !== "none" && orm !== "mongoose";
6450
+ const isD1Alchemy = dbSetup === "d1" && serverDeploy === "alchemy";
6451
+ const pmConfig = getPackageManagerConfig(packageManager, hasTurborepo);
6452
+ scripts.dev = pmConfig.dev;
6453
+ scripts.build = pmConfig.build;
6454
+ scripts["check-types"] = pmConfig.checkTypes;
6455
+ scripts["dev:native"] = pmConfig.filter("native", "dev");
6456
+ scripts["dev:web"] = pmConfig.filter("web", "dev");
6457
+ if (backend !== "self" && backend !== "none") scripts["dev:server"] = pmConfig.filter(backendPackageName, "dev");
6458
+ if (backend === "convex") scripts["dev:setup"] = pmConfig.filter(backendPackageName, "dev:setup");
6459
+ if (needsDbScripts) {
6460
+ scripts["db:push"] = pmConfig.filter(dbPackageName, "db:push");
6461
+ if (!isD1Alchemy) scripts["db:studio"] = pmConfig.filter(dbPackageName, "db:studio");
6462
+ if (orm === "prisma") {
6463
+ scripts["db:generate"] = pmConfig.filter(dbPackageName, "db:generate");
6464
+ scripts["db:migrate"] = pmConfig.filter(dbPackageName, "db:migrate");
6465
+ } else if (orm === "drizzle") {
6466
+ scripts["db:generate"] = pmConfig.filter(dbPackageName, "db:generate");
6467
+ if (!isD1Alchemy) scripts["db:migrate"] = pmConfig.filter(dbPackageName, "db:migrate");
6659
6468
  }
6660
6469
  }
6470
+ if (dbSetup === "docker") {
6471
+ scripts["db:start"] = pmConfig.filter(dbPackageName, "db:start");
6472
+ scripts["db:watch"] = pmConfig.filter(dbPackageName, "db:watch");
6473
+ scripts["db:stop"] = pmConfig.filter(dbPackageName, "db:stop");
6474
+ scripts["db:down"] = pmConfig.filter(dbPackageName, "db:down");
6475
+ }
6661
6476
  try {
6662
- const { stdout } = await execa(options.packageManager, ["-v"], { cwd: projectDir });
6663
- packageJson.packageManager = `${options.packageManager}@${stdout.trim()}`;
6477
+ const { stdout } = await execa(packageManager, ["-v"], { cwd: projectDir });
6478
+ packageJson.packageManager = `${packageManager}@${stdout.trim()}`;
6664
6479
  } catch {
6665
- log.warn(`Could not determine ${options.packageManager} version.`);
6480
+ log.warn(`Could not determine ${packageManager} version.`);
6666
6481
  }
6667
- if (!packageJson.workspaces) packageJson.workspaces = [];
6668
- const workspaces = packageJson.workspaces;
6669
- if (options.backend === "convex") {
6482
+ if (backend === "convex") {
6670
6483
  if (!workspaces.includes("packages/*")) workspaces.push("packages/*");
6671
- if ((options.frontend.length > 0 || options.addons.includes("starlight")) && !workspaces.includes("apps/*")) workspaces.push("apps/*");
6484
+ if ((options.frontend.length > 0 || addons.includes("starlight")) && !workspaces.includes("apps/*")) workspaces.push("apps/*");
6672
6485
  } else {
6673
6486
  if (!workspaces.includes("apps/*")) workspaces.push("apps/*");
6674
6487
  if (!workspaces.includes("packages/*")) workspaces.push("packages/*");
6675
6488
  }
6676
6489
  await fs.writeJson(rootPackageJsonPath, packageJson, { spaces: 2 });
6677
6490
  }
6678
- async function updateServerPackageJson(projectDir, options) {
6491
+ function getPackageManagerConfig(packageManager, hasTurborepo) {
6492
+ if (hasTurborepo) return {
6493
+ dev: "turbo dev",
6494
+ build: "turbo build",
6495
+ checkTypes: "turbo check-types",
6496
+ filter: (workspace, script) => `turbo -F ${workspace} ${script}`
6497
+ };
6498
+ switch (packageManager) {
6499
+ case "pnpm": return {
6500
+ dev: "pnpm -r dev",
6501
+ build: "pnpm -r build",
6502
+ checkTypes: "pnpm -r check-types",
6503
+ filter: (workspace, script) => `pnpm --filter ${workspace} ${script}`
6504
+ };
6505
+ case "npm": return {
6506
+ dev: "npm run dev --workspaces",
6507
+ build: "npm run build --workspaces",
6508
+ checkTypes: "npm run check-types --workspaces",
6509
+ filter: (workspace, script) => `npm run ${script} --workspace ${workspace}`
6510
+ };
6511
+ case "bun": return {
6512
+ dev: "bun run --filter '*' dev",
6513
+ build: "bun run --filter '*' build",
6514
+ checkTypes: "bun run --filter '*' check-types",
6515
+ filter: (workspace, script) => `bun run --filter ${workspace} ${script}`
6516
+ };
6517
+ }
6518
+ }
6519
+ async function updateServerPackageJson(projectDir, _options) {
6679
6520
  const serverPackageJsonPath = path.join(projectDir, "apps/server/package.json");
6680
6521
  if (!await fs.pathExists(serverPackageJsonPath)) return;
6681
6522
  const serverPackageJson = await fs.readJson(serverPackageJsonPath);
6682
- if (!serverPackageJson.scripts) serverPackageJson.scripts = {};
6523
+ serverPackageJson.scripts = serverPackageJson.scripts || {};
6683
6524
  await fs.writeJson(serverPackageJsonPath, serverPackageJson, { spaces: 2 });
6684
- await updateDbPackageJson(projectDir, options);
6685
6525
  }
6686
6526
  async function updateDbPackageJson(projectDir, options) {
6687
6527
  const dbPackageJsonPath = path.join(projectDir, "packages/db/package.json");
6688
6528
  if (!await fs.pathExists(dbPackageJsonPath)) return;
6689
6529
  const dbPackageJson = await fs.readJson(dbPackageJsonPath);
6690
6530
  dbPackageJson.name = `@${options.projectName}/db`;
6691
- if (!dbPackageJson.scripts) dbPackageJson.scripts = {};
6531
+ dbPackageJson.scripts = dbPackageJson.scripts || {};
6692
6532
  const scripts = dbPackageJson.scripts;
6693
- if (options.database !== "none") {
6694
- if (options.database === "sqlite" && options.orm === "drizzle" && options.dbSetup !== "d1") scripts["db:local"] = "turso dev --db-file local.db";
6695
- if (options.orm === "prisma") {
6533
+ const { database, orm, dbSetup, serverDeploy } = options;
6534
+ const isD1Alchemy = dbSetup === "d1" && serverDeploy === "alchemy";
6535
+ if (database !== "none") {
6536
+ if (database === "sqlite" && orm === "drizzle" && dbSetup !== "d1") scripts["db:local"] = "turso dev --db-file local.db";
6537
+ if (orm === "prisma") {
6696
6538
  scripts["db:push"] = "prisma db push";
6697
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = "prisma studio";
6698
6539
  scripts["db:generate"] = "prisma generate";
6699
6540
  scripts["db:migrate"] = "prisma migrate dev";
6700
- } else if (options.orm === "drizzle") {
6541
+ if (!isD1Alchemy) scripts["db:studio"] = "prisma studio";
6542
+ } else if (orm === "drizzle") {
6701
6543
  scripts["db:push"] = "drizzle-kit push";
6702
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = "drizzle-kit studio";
6703
6544
  scripts["db:generate"] = "drizzle-kit generate";
6704
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = "drizzle-kit migrate";
6545
+ if (!isD1Alchemy) {
6546
+ scripts["db:studio"] = "drizzle-kit studio";
6547
+ scripts["db:migrate"] = "drizzle-kit migrate";
6548
+ }
6705
6549
  }
6706
6550
  }
6707
- if (options.dbSetup === "docker") {
6551
+ if (dbSetup === "docker") {
6708
6552
  scripts["db:start"] = "docker compose up -d";
6709
6553
  scripts["db:watch"] = "docker compose up";
6710
6554
  scripts["db:stop"] = "docker compose stop";
@@ -6731,7 +6575,7 @@ async function updateConvexPackageJson(projectDir, options) {
6731
6575
  if (!await fs.pathExists(convexPackageJsonPath)) return;
6732
6576
  const convexPackageJson = await fs.readJson(convexPackageJsonPath);
6733
6577
  convexPackageJson.name = `@${options.projectName}/backend`;
6734
- if (!convexPackageJson.scripts) convexPackageJson.scripts = {};
6578
+ convexPackageJson.scripts = convexPackageJson.scripts || {};
6735
6579
  await fs.writeJson(convexPackageJsonPath, convexPackageJson, { spaces: 2 });
6736
6580
  }
6737
6581
 
@@ -7094,21 +6938,21 @@ const router = os.router({
7094
6938
  description: "Create a new Better-T-Stack project",
7095
6939
  default: true,
7096
6940
  negateBooleans: true
7097
- }).input(z$1.tuple([ProjectNameSchema.optional(), z$1.object({
6941
+ }).input(z.tuple([ProjectNameSchema.optional(), z.object({
7098
6942
  template: TemplateSchema.optional().describe("Use a predefined template"),
7099
- yes: z$1.boolean().optional().default(false).describe("Use default configuration"),
7100
- yolo: z$1.boolean().optional().default(false).describe("(WARNING - NOT RECOMMENDED) Bypass validations and compatibility checks"),
7101
- verbose: z$1.boolean().optional().default(false).describe("Show detailed result information"),
6943
+ yes: z.boolean().optional().default(false).describe("Use default configuration"),
6944
+ yolo: z.boolean().optional().default(false).describe("(WARNING - NOT RECOMMENDED) Bypass validations and compatibility checks"),
6945
+ verbose: z.boolean().optional().default(false).describe("Show detailed result information"),
7102
6946
  database: DatabaseSchema.optional(),
7103
6947
  orm: ORMSchema.optional(),
7104
6948
  auth: AuthSchema.optional(),
7105
6949
  payments: PaymentsSchema.optional(),
7106
- frontend: z$1.array(FrontendSchema).optional(),
7107
- addons: z$1.array(AddonsSchema).optional(),
7108
- examples: z$1.array(ExamplesSchema).optional(),
7109
- git: z$1.boolean().optional(),
6950
+ frontend: z.array(FrontendSchema).optional(),
6951
+ addons: z.array(AddonsSchema).optional(),
6952
+ examples: z.array(ExamplesSchema).optional(),
6953
+ git: z.boolean().optional(),
7110
6954
  packageManager: PackageManagerSchema.optional(),
7111
- install: z$1.boolean().optional(),
6955
+ install: z.boolean().optional(),
7112
6956
  dbSetup: DatabaseSetupSchema.optional(),
7113
6957
  backend: BackendSchema.optional(),
7114
6958
  runtime: RuntimeSchema.optional(),
@@ -7116,9 +6960,9 @@ const router = os.router({
7116
6960
  webDeploy: WebDeploySchema.optional(),
7117
6961
  serverDeploy: ServerDeploySchema.optional(),
7118
6962
  directoryConflict: DirectoryConflictSchema.optional(),
7119
- renderTitle: z$1.boolean().optional(),
7120
- disableAnalytics: z$1.boolean().optional().default(false).describe("Disable analytics"),
7121
- manualDb: z$1.boolean().optional().default(false).describe("Skip automatic/manual database setup prompt and use manual setup")
6963
+ renderTitle: z.boolean().optional(),
6964
+ disableAnalytics: z.boolean().optional().default(false).describe("Disable analytics"),
6965
+ manualDb: z.boolean().optional().default(false).describe("Skip automatic/manual database setup prompt and use manual setup")
7122
6966
  })])).handler(async ({ input }) => {
7123
6967
  const [projectName, options] = input;
7124
6968
  const result = await createProjectHandler({
@@ -7127,12 +6971,12 @@ const router = os.router({
7127
6971
  });
7128
6972
  if (options.verbose) return result;
7129
6973
  }),
7130
- add: os.meta({ description: "Add addons or deployment configurations to an existing Better-T-Stack project" }).input(z$1.tuple([z$1.object({
7131
- addons: z$1.array(AddonsSchema).optional().default([]),
6974
+ add: os.meta({ description: "Add addons or deployment configurations to an existing Better-T-Stack project" }).input(z.tuple([z.object({
6975
+ addons: z.array(AddonsSchema).optional().default([]),
7132
6976
  webDeploy: WebDeploySchema.optional(),
7133
6977
  serverDeploy: ServerDeploySchema.optional(),
7134
- projectDir: z$1.string().optional(),
7135
- install: z$1.boolean().optional().default(false).describe("Install dependencies after adding addons or deployment"),
6978
+ projectDir: z.string().optional(),
6979
+ install: z.boolean().optional().default(false).describe("Install dependencies after adding addons or deployment"),
7136
6980
  packageManager: PackageManagerSchema.optional()
7137
6981
  })])).handler(async ({ input }) => {
7138
6982
  const [options] = input;