create-better-t-stack 2.49.0 → 2.49.1-canary.206d95c1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/{src-DXyLKhXK.js → src-CRbLnM5h.js} +395 -157
  4. package/package.json +2 -1
  5. package/templates/api/orpc/server/base/_gitignore +34 -0
  6. package/templates/api/orpc/server/base/package.json.hbs +24 -0
  7. package/templates/{backend/server/server-base → api/orpc/server/base}/src/routers/index.ts.hbs +2 -2
  8. package/templates/api/orpc/server/base/tsconfig.json.hbs +10 -0
  9. package/templates/api/orpc/server/base/tsdown.config.ts.hbs +7 -0
  10. package/templates/api/orpc/server/{base/src/lib → rest/src}/context.ts.hbs +5 -5
  11. package/templates/api/orpc/web/nuxt/app/plugins/orpc.ts.hbs +1 -1
  12. package/templates/api/orpc/web/react/base/src/utils/orpc.ts.hbs +1 -1
  13. package/templates/api/orpc/web/solid/src/utils/orpc.ts.hbs +1 -1
  14. package/templates/api/orpc/web/svelte/src/lib/orpc.ts.hbs +1 -1
  15. package/templates/api/trpc/server/base/_gitignore +34 -0
  16. package/templates/api/trpc/server/base/package.json.hbs +23 -0
  17. package/templates/api/trpc/server/base/src/routers/index.ts.hbs +55 -0
  18. package/templates/api/trpc/server/base/tsconfig.json.hbs +13 -0
  19. package/templates/api/trpc/server/base/tsdown.config.ts.hbs +7 -0
  20. package/templates/api/trpc/server/{base/src/lib → rest/src}/context.ts.hbs +5 -5
  21. package/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs +2 -2
  22. package/templates/auth/better-auth/server/base/_gitignore +34 -0
  23. package/templates/auth/better-auth/server/base/package.json.hbs +24 -0
  24. package/templates/auth/better-auth/server/base/src/{lib/auth.ts.hbs → index.ts.hbs} +6 -6
  25. package/templates/auth/better-auth/server/base/tsconfig.json.hbs +13 -0
  26. package/templates/auth/better-auth/server/base/tsdown.config.ts.hbs +7 -0
  27. package/templates/backend/server/{server-base → base}/package.json.hbs +0 -1
  28. package/templates/backend/server/{server-base → base}/tsconfig.json.hbs +5 -10
  29. package/templates/backend/server/base/tsdown.config.ts.hbs +14 -0
  30. package/templates/backend/server/elysia/src/index.ts.hbs +5 -5
  31. package/templates/backend/server/express/src/index.ts.hbs +5 -5
  32. package/templates/backend/server/fastify/src/index.ts.hbs +5 -5
  33. package/templates/backend/server/hono/src/index.ts.hbs +5 -5
  34. package/templates/base/_gitignore +47 -1
  35. package/templates/base/package.json.hbs +1 -3
  36. package/templates/base/tsconfig.base.json +23 -0
  37. package/templates/db/base/_gitignore +34 -0
  38. package/templates/db/base/package.json.hbs +23 -0
  39. package/templates/db/base/tsconfig.json.hbs +13 -0
  40. package/templates/db/base/tsdown.config.ts.hbs +7 -0
  41. package/templates/db/drizzle/mysql/drizzle.config.ts.hbs +7 -2
  42. package/templates/db/drizzle/postgres/drizzle.config.ts.hbs +7 -2
  43. package/templates/db/drizzle/sqlite/drizzle.config.ts.hbs +7 -2
  44. package/templates/db/prisma/mongodb/prisma.config.ts.hbs +5 -1
  45. package/templates/db/prisma/mongodb/src/index.ts.hbs +5 -0
  46. package/templates/db/prisma/mysql/prisma.config.ts.hbs +5 -1
  47. package/templates/db/prisma/mysql/src/{db/index.ts.hbs → index.ts.hbs} +1 -1
  48. package/templates/db/prisma/postgres/prisma.config.ts.hbs +7 -3
  49. package/templates/db/prisma/postgres/src/{db/index.ts.hbs → index.ts.hbs} +1 -1
  50. package/templates/db/prisma/sqlite/prisma.config.ts.hbs +5 -1
  51. package/templates/db/prisma/sqlite/src/{db/index.ts.hbs → index.ts.hbs} +3 -3
  52. package/templates/examples/todo/server/drizzle/base/src/routers/todo.ts.hbs +6 -6
  53. package/templates/examples/todo/server/mongoose/base/src/routers/todo.ts.hbs +4 -4
  54. package/templates/examples/todo/server/prisma/base/src/routers/todo.ts.hbs +4 -4
  55. package/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs +1 -1
  56. package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +1 -1
  57. package/templates/db/prisma/mongodb/src/db/index.ts.hbs +0 -5
  58. /package/templates/api/orpc/server/{base/src/lib/orpc.ts.hbs → rest/src/index.ts.hbs} +0 -0
  59. /package/templates/api/trpc/server/{base/src/lib/trpc.ts.hbs → rest/src/index.ts.hbs} +0 -0
  60. /package/templates/auth/better-auth/server/db/drizzle/mysql/src/{db/schema → schema}/auth.ts +0 -0
  61. /package/templates/auth/better-auth/server/db/drizzle/postgres/src/{db/schema → schema}/auth.ts +0 -0
  62. /package/templates/auth/better-auth/server/db/drizzle/sqlite/src/{db/schema → schema}/auth.ts +0 -0
  63. /package/templates/auth/better-auth/server/db/mongoose/mongodb/src/{db/models → models}/auth.model.ts +0 -0
  64. /package/templates/backend/server/{server-base → base}/_gitignore +0 -0
  65. /package/templates/db/drizzle/mysql/src/{db/index.ts.hbs → index.ts.hbs} +0 -0
  66. /package/templates/db/drizzle/postgres/src/{db/index.ts.hbs → index.ts.hbs} +0 -0
  67. /package/templates/db/drizzle/sqlite/src/{db/index.ts.hbs → index.ts.hbs} +0 -0
  68. /package/templates/db/mongoose/mongodb/src/{db/index.ts.hbs → index.ts.hbs} +0 -0
  69. /package/templates/examples/todo/server/mongoose/mongodb/src/db/models/{todo.model.ts → todo.model.ts.hbs} +0 -0
  70. /package/templates/examples/todo/server/prisma/mongodb/prisma/schema/{todo.prisma → todo.prisma.hbs} +0 -0
  71. /package/templates/examples/todo/server/prisma/mysql/prisma/schema/{todo.prisma → todo.prisma.hbs} +0 -0
  72. /package/templates/examples/todo/server/prisma/postgres/prisma/schema/{todo.prisma → todo.prisma.hbs} +0 -0
  73. /package/templates/examples/todo/server/prisma/sqlite/prisma/schema/{todo.prisma → todo.prisma.hbs} +0 -0
@@ -15,6 +15,7 @@ import { IndentationText, Node, Project, QuoteKind, SyntaxKind } from "ts-morph"
15
15
  import { glob } from "tinyglobby";
16
16
  import handlebars from "handlebars";
17
17
  import { Biome } from "@biomejs/js-api/nodejs";
18
+ import yaml from "yaml";
18
19
  import os$1 from "node:os";
19
20
 
20
21
  //#region src/utils/get-package-manager.ts
@@ -71,6 +72,7 @@ const dependencyVersionMap = {
71
72
  "drizzle-kit": "^0.31.2",
72
73
  "@planetscale/database": "^1.19.0",
73
74
  "@libsql/client": "^0.15.9",
75
+ libsql: "^0.5.22",
74
76
  "@neondatabase/serverless": "^1.0.1",
75
77
  pg: "^8.14.1",
76
78
  "@types/pg": "^8.11.11",
@@ -146,7 +148,9 @@ const dependencyVersionMap = {
146
148
  "@cloudflare/workers-types": "^4.20250822.0",
147
149
  alchemy: "^0.67.0",
148
150
  nitropack: "^2.12.4",
149
- dotenv: "^17.2.1",
151
+ dotenv: "^17.2.2",
152
+ tsdown: "^0.15.5",
153
+ zod: "^4.1.11",
150
154
  "@polar-sh/better-auth": "^1.1.3",
151
155
  "@polar-sh/sdk": "^0.34.16"
152
156
  };
@@ -1375,7 +1379,7 @@ const getLatestCLIVersion = () => {
1375
1379
  */
1376
1380
  function isTelemetryEnabled() {
1377
1381
  const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
1378
- const BTS_TELEMETRY = "1";
1382
+ const BTS_TELEMETRY = "0";
1379
1383
  if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
1380
1384
  if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
1381
1385
  return true;
@@ -1383,8 +1387,8 @@ function isTelemetryEnabled() {
1383
1387
 
1384
1388
  //#endregion
1385
1389
  //#region src/utils/analytics.ts
1386
- const POSTHOG_API_KEY = "phc_8ZUxEwwfKMajJLvxz1daGd931dYbQrwKNficBmsdIrs";
1387
- const POSTHOG_HOST = "https://us.i.posthog.com";
1390
+ const POSTHOG_API_KEY = "random";
1391
+ const POSTHOG_HOST = "random";
1388
1392
  function generateSessionId() {
1389
1393
  const rand = Math.random().toString(36).slice(2);
1390
1394
  return `cli_${Date.now().toString(36)}${rand}`;
@@ -1992,15 +1996,17 @@ const addPackageDependency = async (opts) => {
1992
1996
  if (!pkgJson.dependencies) pkgJson.dependencies = {};
1993
1997
  if (!pkgJson.devDependencies) pkgJson.devDependencies = {};
1994
1998
  for (const pkgName of dependencies) {
1995
- const version = customDependencies[pkgName] || dependencyVersionMap[pkgName];
1999
+ const version = dependencyVersionMap[pkgName];
1996
2000
  if (version) pkgJson.dependencies[pkgName] = version;
1997
2001
  else console.warn(`Warning: Dependency ${pkgName} not found in version map.`);
1998
2002
  }
1999
2003
  for (const pkgName of devDependencies) {
2000
- const version = customDevDependencies[pkgName] || dependencyVersionMap[pkgName];
2004
+ const version = dependencyVersionMap[pkgName];
2001
2005
  if (version) pkgJson.devDependencies[pkgName] = version;
2002
2006
  else console.warn(`Warning: Dev dependency ${pkgName} not found in version map.`);
2003
2007
  }
2008
+ for (const [pkgName, version] of Object.entries(customDependencies)) pkgJson.dependencies[pkgName] = version;
2009
+ for (const [pkgName, version] of Object.entries(customDevDependencies)) pkgJson.devDependencies[pkgName] = version;
2004
2010
  await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
2005
2011
  };
2006
2012
 
@@ -2770,23 +2776,28 @@ async function setupBackendFramework(projectDir, context) {
2770
2776
  return;
2771
2777
  }
2772
2778
  await fs.ensureDir(serverAppDir);
2773
- const serverBaseDir = path.join(PKG_ROOT, "templates/backend/server/server-base");
2779
+ const serverBaseDir = path.join(PKG_ROOT, "templates/backend/server/base");
2774
2780
  if (await fs.pathExists(serverBaseDir)) await processAndCopyFiles("**/*", serverBaseDir, serverAppDir, context);
2775
2781
  const frameworkSrcDir = path.join(PKG_ROOT, `templates/backend/server/${context.backend}`);
2776
2782
  if (await fs.pathExists(frameworkSrcDir)) await processAndCopyFiles("**/*", frameworkSrcDir, serverAppDir, context, true);
2777
2783
  if (context.api !== "none") {
2784
+ const apiPackageDir = path.join(projectDir, "packages/api");
2785
+ await fs.ensureDir(apiPackageDir);
2778
2786
  const apiServerBaseDir = path.join(PKG_ROOT, `templates/api/${context.api}/server/base`);
2779
- if (await fs.pathExists(apiServerBaseDir)) await processAndCopyFiles("**/*", apiServerBaseDir, serverAppDir, context, true);
2780
- const apiServerFrameworkDir = path.join(PKG_ROOT, `templates/api/${context.api}/server/${context.backend}`);
2781
- if (await fs.pathExists(apiServerFrameworkDir)) await processAndCopyFiles("**/*", apiServerFrameworkDir, serverAppDir, context, true);
2787
+ if (await fs.pathExists(apiServerBaseDir)) await processAndCopyFiles("**/*", apiServerBaseDir, apiPackageDir, context);
2788
+ let apiServerFrameworkDir = "";
2789
+ if (context.backend === "next") apiServerFrameworkDir = path.join(PKG_ROOT, `templates/api/${context.api}/server/${context.backend}`);
2790
+ else apiServerFrameworkDir = path.join(PKG_ROOT, `templates/api/${context.api}/server/rest`);
2791
+ if (await fs.pathExists(apiServerFrameworkDir)) await processAndCopyFiles("**/*", apiServerFrameworkDir, apiPackageDir, context, true);
2792
+ }
2793
+ if (context.database !== "none" && context.orm !== "none") {
2794
+ const dbPackageDir = path.join(projectDir, "packages/db");
2795
+ await fs.ensureDir(dbPackageDir);
2796
+ const dbBaseDir = path.join(PKG_ROOT, "templates/db/base");
2797
+ if (await fs.pathExists(dbBaseDir)) await processAndCopyFiles("**/*", dbBaseDir, dbPackageDir, context);
2798
+ const dbOrmSrcDir = path.join(PKG_ROOT, `templates/db/${context.orm}/${context.database}`);
2799
+ if (await fs.pathExists(dbOrmSrcDir)) await processAndCopyFiles("**/*", dbOrmSrcDir, dbPackageDir, context);
2782
2800
  }
2783
- }
2784
- async function setupDbOrmTemplates(projectDir, context) {
2785
- if (context.backend === "convex" || context.orm === "none" || context.database === "none") return;
2786
- const serverAppDir = path.join(projectDir, "apps/server");
2787
- await fs.ensureDir(serverAppDir);
2788
- const dbOrmSrcDir = path.join(PKG_ROOT, `templates/db/${context.orm}/${context.database}`);
2789
- if (await fs.pathExists(dbOrmSrcDir)) await processAndCopyFiles("**/*", dbOrmSrcDir, serverAppDir, context);
2790
2801
  }
2791
2802
  async function setupAuthTemplate(projectDir, context) {
2792
2803
  if (!context.auth || context.auth === "none") return;
@@ -2867,20 +2878,24 @@ async function setupAuthTemplate(projectDir, context) {
2867
2878
  return;
2868
2879
  }
2869
2880
  if (serverAppDirExists && context.backend !== "convex") {
2881
+ const authPackageDir = path.join(projectDir, "packages/auth");
2882
+ await fs.ensureDir(authPackageDir);
2870
2883
  const authServerBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/base`);
2871
- if (await fs.pathExists(authServerBaseSrc)) await processAndCopyFiles("**/*", authServerBaseSrc, serverAppDir, context);
2884
+ if (await fs.pathExists(authServerBaseSrc)) await processAndCopyFiles("**/*", authServerBaseSrc, authPackageDir, context);
2872
2885
  if (context.backend === "next") {
2873
2886
  const authServerNextSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/next`);
2874
- if (await fs.pathExists(authServerNextSrc)) await processAndCopyFiles("**/*", authServerNextSrc, serverAppDir, context);
2887
+ if (await fs.pathExists(authServerNextSrc)) await processAndCopyFiles("**/*", authServerNextSrc, authPackageDir, context);
2875
2888
  }
2876
2889
  if (context.orm !== "none" && context.database !== "none") {
2890
+ const dbPackageDir = path.join(projectDir, "packages/db");
2891
+ await fs.ensureDir(dbPackageDir);
2877
2892
  const orm = context.orm;
2878
2893
  const db = context.database;
2879
2894
  let authDbSrc = "";
2880
2895
  if (orm === "drizzle") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/drizzle/${db}`);
2881
2896
  else if (orm === "prisma") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/prisma/${db}`);
2882
2897
  else if (orm === "mongoose") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/mongoose/${db}`);
2883
- if (authDbSrc && await fs.pathExists(authDbSrc)) await processAndCopyFiles("**/*", authDbSrc, serverAppDir, context);
2898
+ if (authDbSrc && await fs.pathExists(authDbSrc)) await processAndCopyFiles("**/*", authDbSrc, dbPackageDir, context);
2884
2899
  }
2885
2900
  }
2886
2901
  if ((hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) && webAppDirExists) {
@@ -2927,8 +2942,10 @@ async function setupPaymentsTemplate(projectDir, context) {
2927
2942
  const serverAppDirExists = await fs.pathExists(serverAppDir);
2928
2943
  const webAppDirExists = await fs.pathExists(webAppDir);
2929
2944
  if (serverAppDirExists && context.backend !== "convex") {
2945
+ const authPackageDir = path.join(projectDir, "packages/auth");
2946
+ await fs.ensureDir(authPackageDir);
2930
2947
  const paymentsServerSrc = path.join(PKG_ROOT, `templates/payments/${context.payments}/server/base`);
2931
- if (await fs.pathExists(paymentsServerSrc)) await processAndCopyFiles("**/*", paymentsServerSrc, serverAppDir, context);
2948
+ if (await fs.pathExists(paymentsServerSrc)) await processAndCopyFiles("**/*", paymentsServerSrc, authPackageDir, context);
2932
2949
  }
2933
2950
  const hasReactWeb = context.frontend.some((f) => [
2934
2951
  "tanstack-router",
@@ -3006,15 +3023,21 @@ async function setupExamplesTemplate(projectDir, context) {
3006
3023
  const exampleBaseDir = path.join(PKG_ROOT, `templates/examples/${example}`);
3007
3024
  if (serverAppDirExists && context.backend !== "convex" && context.backend !== "none") {
3008
3025
  const exampleServerSrc = path.join(exampleBaseDir, "server");
3009
- if (example === "ai" && context.backend === "next") {
3010
- const aiNextServerSrc = path.join(exampleServerSrc, "next");
3011
- if (await fs.pathExists(aiNextServerSrc)) await processAndCopyFiles("**/*", aiNextServerSrc, serverAppDir, context, false);
3026
+ if (context.api !== "none") {
3027
+ const apiPackageDir = path.join(projectDir, "packages/api");
3028
+ await fs.ensureDir(apiPackageDir);
3029
+ const exampleOrmBaseSrc = path.join(exampleServerSrc, context.orm, "base");
3030
+ if (await fs.pathExists(exampleOrmBaseSrc)) await processAndCopyFiles("**/*", exampleOrmBaseSrc, apiPackageDir, context, false);
3012
3031
  }
3013
3032
  if (context.orm !== "none" && context.database !== "none") {
3014
- const exampleOrmBaseSrc = path.join(exampleServerSrc, context.orm, "base");
3015
- if (await fs.pathExists(exampleOrmBaseSrc)) await processAndCopyFiles("**/*", exampleOrmBaseSrc, serverAppDir, context, false);
3033
+ const dbPackageDir = path.join(projectDir, "packages/db");
3034
+ await fs.ensureDir(dbPackageDir);
3016
3035
  const exampleDbSchemaSrc = path.join(exampleServerSrc, context.orm, context.database);
3017
- if (await fs.pathExists(exampleDbSchemaSrc)) await processAndCopyFiles("**/*", exampleDbSchemaSrc, serverAppDir, context, false);
3036
+ if (await fs.pathExists(exampleDbSchemaSrc)) await processAndCopyFiles("**/*", exampleDbSchemaSrc, dbPackageDir, context, false);
3037
+ }
3038
+ if (example === "ai" && context.backend === "next") {
3039
+ const aiNextServerSrc = path.join(exampleServerSrc, "next");
3040
+ if (await fs.pathExists(aiNextServerSrc)) await processAndCopyFiles("**/*", aiNextServerSrc, serverAppDir, context, false);
3018
3041
  }
3019
3042
  }
3020
3043
  if (webAppDirExists) {
@@ -3081,9 +3104,9 @@ async function handleExtras(projectDir, context) {
3081
3104
  }
3082
3105
  async function setupDockerComposeTemplates(projectDir, context) {
3083
3106
  if (context.dbSetup !== "docker" || context.database === "none") return;
3084
- const serverAppDir = path.join(projectDir, "apps/server");
3107
+ const dbPackageDir = path.join(projectDir, "packages/db");
3085
3108
  const dockerSrcDir = path.join(PKG_ROOT, `templates/db-setup/docker-compose/${context.database}`);
3086
- if (await fs.pathExists(dockerSrcDir)) await processAndCopyFiles("**/*", dockerSrcDir, serverAppDir, context);
3109
+ if (await fs.pathExists(dockerSrcDir)) await processAndCopyFiles("**/*", dockerSrcDir, dbPackageDir, context);
3087
3110
  }
3088
3111
  async function setupDeploymentTemplates(projectDir, context) {
3089
3112
  if (context.webDeploy === "alchemy" || context.serverDeploy === "alchemy") if (context.webDeploy === "alchemy" && context.serverDeploy === "alchemy") {
@@ -3955,6 +3978,110 @@ async function addDeploymentToProject(input) {
3955
3978
  }
3956
3979
  }
3957
3980
 
3981
+ //#endregion
3982
+ //#region src/utils/setup-catalogs.ts
3983
+ async function setupCatalogs(projectDir, options) {
3984
+ if (options.packageManager === "npm") return;
3985
+ const packagePaths = [
3986
+ "apps/server",
3987
+ "apps/web",
3988
+ "packages/api",
3989
+ "packages/db",
3990
+ "packages/auth",
3991
+ "packages/backend"
3992
+ ];
3993
+ const packagesInfo = [];
3994
+ for (const pkgPath of packagePaths) {
3995
+ const fullPath = path.join(projectDir, pkgPath);
3996
+ const pkgJsonPath = path.join(fullPath, "package.json");
3997
+ if (await fs.pathExists(pkgJsonPath)) {
3998
+ const pkgJson = await fs.readJson(pkgJsonPath);
3999
+ packagesInfo.push({
4000
+ path: fullPath,
4001
+ dependencies: pkgJson.dependencies || {},
4002
+ devDependencies: pkgJson.devDependencies || {}
4003
+ });
4004
+ }
4005
+ }
4006
+ const catalog = findDuplicateDependencies(packagesInfo, options.projectName);
4007
+ if (Object.keys(catalog).length === 0) return;
4008
+ if (options.packageManager === "bun") await setupBunCatalogs(projectDir, catalog);
4009
+ else if (options.packageManager === "pnpm") await setupPnpmCatalogs(projectDir, catalog);
4010
+ await updatePackageJsonsWithCatalogs(packagesInfo, catalog);
4011
+ }
4012
+ function findDuplicateDependencies(packagesInfo, projectName) {
4013
+ const depCount = /* @__PURE__ */ new Map();
4014
+ const projectScope = `@${projectName}/`;
4015
+ for (const pkg of packagesInfo) {
4016
+ const allDeps = {
4017
+ ...pkg.dependencies,
4018
+ ...pkg.devDependencies
4019
+ };
4020
+ for (const [depName, version] of Object.entries(allDeps)) {
4021
+ if (depName.startsWith(projectScope)) continue;
4022
+ if (version.startsWith("workspace:")) continue;
4023
+ const existing = depCount.get(depName);
4024
+ if (existing) existing.packages.push(pkg.path);
4025
+ else depCount.set(depName, {
4026
+ version,
4027
+ packages: [pkg.path]
4028
+ });
4029
+ }
4030
+ }
4031
+ const catalog = {};
4032
+ for (const [depName, info] of depCount.entries()) if (info.packages.length > 1) catalog[depName] = info.version;
4033
+ return catalog;
4034
+ }
4035
+ async function setupBunCatalogs(projectDir, catalog) {
4036
+ const rootPkgJsonPath = path.join(projectDir, "package.json");
4037
+ const rootPkgJson = await fs.readJson(rootPkgJsonPath);
4038
+ if (!rootPkgJson.workspaces) rootPkgJson.workspaces = {};
4039
+ if (Array.isArray(rootPkgJson.workspaces)) rootPkgJson.workspaces = {
4040
+ packages: rootPkgJson.workspaces,
4041
+ catalog
4042
+ };
4043
+ else if (typeof rootPkgJson.workspaces === "object") {
4044
+ if (!rootPkgJson.workspaces.catalog) rootPkgJson.workspaces.catalog = {};
4045
+ rootPkgJson.workspaces.catalog = {
4046
+ ...rootPkgJson.workspaces.catalog,
4047
+ ...catalog
4048
+ };
4049
+ }
4050
+ await fs.writeJson(rootPkgJsonPath, rootPkgJson, { spaces: 2 });
4051
+ }
4052
+ async function setupPnpmCatalogs(projectDir, catalog) {
4053
+ const workspaceYamlPath = path.join(projectDir, "pnpm-workspace.yaml");
4054
+ if (!await fs.pathExists(workspaceYamlPath)) return;
4055
+ const workspaceContent = await fs.readFile(workspaceYamlPath, "utf-8");
4056
+ const workspaceYaml = yaml.parse(workspaceContent);
4057
+ if (!workspaceYaml.catalog) workspaceYaml.catalog = {};
4058
+ workspaceYaml.catalog = {
4059
+ ...workspaceYaml.catalog,
4060
+ ...catalog
4061
+ };
4062
+ await fs.writeFile(workspaceYamlPath, yaml.stringify(workspaceYaml));
4063
+ }
4064
+ async function updatePackageJsonsWithCatalogs(packagesInfo, catalog) {
4065
+ for (const pkg of packagesInfo) {
4066
+ const pkgJsonPath = path.join(pkg.path, "package.json");
4067
+ const pkgJson = await fs.readJson(pkgJsonPath);
4068
+ let updated = false;
4069
+ if (pkgJson.dependencies) {
4070
+ for (const depName of Object.keys(pkgJson.dependencies)) if (catalog[depName]) {
4071
+ pkgJson.dependencies[depName] = "catalog:";
4072
+ updated = true;
4073
+ }
4074
+ }
4075
+ if (pkgJson.devDependencies) {
4076
+ for (const depName of Object.keys(pkgJson.devDependencies)) if (catalog[depName]) {
4077
+ pkgJson.devDependencies[depName] = "catalog:";
4078
+ updated = true;
4079
+ }
4080
+ }
4081
+ if (updated) await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
4082
+ }
4083
+ }
4084
+
3958
4085
  //#endregion
3959
4086
  //#region src/helpers/addons/examples-setup.ts
3960
4087
  async function setupExamples(config) {
@@ -3963,10 +4090,10 @@ async function setupExamples(config) {
3963
4090
  if (examples.includes("ai")) {
3964
4091
  const webClientDir = path.join(projectDir, "apps/web");
3965
4092
  const nativeClientDir = path.join(projectDir, "apps/native");
3966
- const serverDir = path.join(projectDir, "apps/server");
4093
+ const apiDir = path.join(projectDir, "packages/api");
3967
4094
  const webClientDirExists = await fs.pathExists(webClientDir);
3968
4095
  const nativeClientDirExists = await fs.pathExists(nativeClientDir);
3969
- const serverDirExists = await fs.pathExists(serverDir);
4096
+ const apiDirExists = await fs.pathExists(apiDir);
3970
4097
  const hasNuxt = frontend.includes("nuxt");
3971
4098
  const hasSvelte = frontend.includes("svelte");
3972
4099
  const hasReactWeb = frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("next") || frontend.includes("tanstack-start");
@@ -3987,9 +4114,9 @@ async function setupExamples(config) {
3987
4114
  dependencies: ["ai", "@ai-sdk/react"],
3988
4115
  projectDir: nativeClientDir
3989
4116
  });
3990
- if (serverDirExists && backend !== "none") await addPackageDependency({
4117
+ if (apiDirExists && backend !== "none") await addPackageDependency({
3991
4118
  dependencies: ["ai", "@ai-sdk/google"],
3992
- projectDir: serverDir
4119
+ projectDir: apiDir
3993
4120
  });
3994
4121
  }
3995
4122
  }
@@ -4105,32 +4232,54 @@ function getConvexDependencies(frontend) {
4105
4232
  return deps;
4106
4233
  }
4107
4234
  async function setupApi(config) {
4108
- const { api, projectName, frontend, backend, packageManager, projectDir } = config;
4235
+ const { api, projectName, frontend, backend, packageManager, projectDir, auth } = config;
4109
4236
  const isConvex = backend === "convex";
4110
4237
  const webDir = path.join(projectDir, "apps/web");
4111
4238
  const nativeDir = path.join(projectDir, "apps/native");
4112
4239
  const serverDir = path.join(projectDir, "apps/server");
4113
4240
  const webDirExists = await fs.pathExists(webDir);
4114
4241
  const nativeDirExists = await fs.pathExists(nativeDir);
4115
- const serverDirExists = await fs.pathExists(serverDir);
4242
+ await fs.pathExists(serverDir);
4116
4243
  const frontendType = getFrontendType(frontend);
4117
4244
  if (!isConvex && api !== "none") {
4118
4245
  const apiDeps = getApiDependencies(api, frontendType);
4119
- if (serverDirExists && apiDeps.server) {
4246
+ const apiPackageDir = path.join(projectDir, "packages/api");
4247
+ if (apiDeps.server) {
4120
4248
  await addPackageDependency({
4121
4249
  dependencies: apiDeps.server.dependencies,
4122
- projectDir: serverDir
4250
+ projectDir: apiPackageDir
4251
+ });
4252
+ const frameworkDeps = [];
4253
+ if (backend === "hono") frameworkDeps.push("hono");
4254
+ else if (backend === "elysia") frameworkDeps.push("elysia");
4255
+ else if (backend === "express") frameworkDeps.push("express", "@types/express");
4256
+ else if (backend === "fastify") frameworkDeps.push("fastify");
4257
+ if (frameworkDeps.length > 0) await addPackageDependency({
4258
+ dependencies: frameworkDeps,
4259
+ projectDir: apiPackageDir
4123
4260
  });
4124
4261
  if (api === "trpc") {
4125
4262
  if (backend === "hono") await addPackageDependency({
4126
4263
  dependencies: ["@hono/trpc-server"],
4127
- projectDir: serverDir
4264
+ projectDir: apiPackageDir
4128
4265
  });
4129
4266
  else if (backend === "elysia") await addPackageDependency({
4130
4267
  dependencies: ["@elysiajs/trpc"],
4131
- projectDir: serverDir
4268
+ projectDir: apiPackageDir
4269
+ });
4270
+ else if (backend === "express") await addPackageDependency({
4271
+ dependencies: ["@trpc/server"],
4272
+ projectDir: apiPackageDir
4273
+ });
4274
+ else if (backend === "fastify") await addPackageDependency({
4275
+ dependencies: ["@trpc/server"],
4276
+ projectDir: apiPackageDir
4132
4277
  });
4133
4278
  }
4279
+ if (auth === "better-auth") await addPackageDependency({
4280
+ dependencies: ["better-auth"],
4281
+ projectDir: apiPackageDir
4282
+ });
4134
4283
  }
4135
4284
  if (webDirExists && apiDeps.web) await addPackageDependency({
4136
4285
  dependencies: apiDeps.web.dependencies,
@@ -4174,7 +4323,7 @@ async function setupApi(config) {
4174
4323
  //#endregion
4175
4324
  //#region src/helpers/core/backend-setup.ts
4176
4325
  async function setupBackendDependencies(config) {
4177
- const { backend, runtime, api, projectDir } = config;
4326
+ const { backend, runtime, api, auth, examples, projectDir } = config;
4178
4327
  if (backend === "convex") return;
4179
4328
  const framework = backend;
4180
4329
  const serverDir = path.join(projectDir, "apps/server");
@@ -4202,6 +4351,13 @@ async function setupBackendDependencies(config) {
4202
4351
  dependencies.push("fastify", "@fastify/cors");
4203
4352
  if (runtime === "node") devDependencies.push("tsx", "@types/node");
4204
4353
  }
4354
+ if (api === "trpc") {
4355
+ if (framework === "express") dependencies.push("@trpc/server");
4356
+ else if (framework === "fastify") dependencies.push("@trpc/server");
4357
+ else if (runtime === "workers") dependencies.push("@trpc/server");
4358
+ } else if (api === "orpc") dependencies.push("@orpc/server", "@orpc/openapi", "@orpc/zod");
4359
+ if (auth === "better-auth") dependencies.push("better-auth");
4360
+ if (examples.includes("ai")) dependencies.push("ai", "@ai-sdk/google");
4205
4361
  if (runtime === "bun") devDependencies.push("@types/bun");
4206
4362
  if (dependencies.length > 0 || devDependencies.length > 0) await addPackageDependency({
4207
4363
  dependencies,
@@ -4220,7 +4376,7 @@ async function setupAuth(config) {
4220
4376
  const nativeDir = path.join(projectDir, "apps/native");
4221
4377
  const clientDirExists = await fs.pathExists(clientDir);
4222
4378
  const nativeDirExists = await fs.pathExists(nativeDir);
4223
- const serverDirExists = await fs.pathExists(serverDir);
4379
+ await fs.pathExists(serverDir);
4224
4380
  try {
4225
4381
  if (backend === "convex") {
4226
4382
  if (auth === "clerk" && clientDirExists) {
@@ -4276,9 +4432,11 @@ async function setupAuth(config) {
4276
4432
  });
4277
4433
  return;
4278
4434
  }
4279
- if (serverDirExists && auth === "better-auth") await addPackageDependency({
4435
+ const authPackageDir = path.join(projectDir, "packages/auth");
4436
+ const authPackageDirExists = await fs.pathExists(authPackageDir);
4437
+ if (authPackageDirExists && auth === "better-auth") await addPackageDependency({
4280
4438
  dependencies: ["better-auth"],
4281
- projectDir: serverDir
4439
+ projectDir: authPackageDir
4282
4440
  });
4283
4441
  if (frontend.some((f) => [
4284
4442
  "react-router",
@@ -4300,9 +4458,9 @@ async function setupAuth(config) {
4300
4458
  dependencies: ["better-auth", "@better-auth/expo"],
4301
4459
  projectDir: nativeDir
4302
4460
  });
4303
- if (serverDirExists) await addPackageDependency({
4461
+ if (authPackageDirExists) await addPackageDependency({
4304
4462
  dependencies: ["@better-auth/expo"],
4305
- projectDir: serverDir
4463
+ projectDir: authPackageDir
4306
4464
  });
4307
4465
  }
4308
4466
  }
@@ -4485,8 +4643,6 @@ async function setupEnvironmentVariables(config) {
4485
4643
  return;
4486
4644
  }
4487
4645
  const serverDir = path.join(projectDir, "apps/server");
4488
- if (!await fs.pathExists(serverDir)) return;
4489
- const envPath = path.join(serverDir, ".env");
4490
4646
  let corsOrigin = "http://localhost:3001";
4491
4647
  if (hasReactRouter || hasSvelte) corsOrigin = "http://localhost:5173";
4492
4648
  let databaseUrl = null;
@@ -4502,47 +4658,50 @@ async function setupEnvironmentVariables(config) {
4502
4658
  break;
4503
4659
  case "sqlite":
4504
4660
  if (config.runtime === "workers") databaseUrl = "http://127.0.0.1:8080";
4505
- else databaseUrl = "file:./local.db";
4661
+ else databaseUrl = `file:${path.join(config.projectDir, "apps/server", "local.db")}`;
4506
4662
  break;
4507
4663
  }
4508
- const serverVars = [
4509
- {
4510
- key: "CORS_ORIGIN",
4511
- value: corsOrigin,
4512
- condition: true
4513
- },
4514
- {
4515
- key: "BETTER_AUTH_SECRET",
4516
- value: generateAuthSecret(),
4517
- condition: !!auth
4518
- },
4519
- {
4520
- key: "BETTER_AUTH_URL",
4521
- value: "http://localhost:3000",
4522
- condition: !!auth
4523
- },
4524
- {
4525
- key: "DATABASE_URL",
4526
- value: databaseUrl,
4527
- condition: database !== "none" && dbSetup === "none"
4528
- },
4529
- {
4530
- key: "GOOGLE_GENERATIVE_AI_API_KEY",
4531
- value: "",
4532
- condition: examples?.includes("ai") || false
4533
- },
4534
- {
4535
- key: "POLAR_ACCESS_TOKEN",
4536
- value: "",
4537
- condition: config.payments === "polar"
4538
- },
4539
- {
4540
- key: "POLAR_SUCCESS_URL",
4541
- value: `${corsOrigin}/success?checkout_id={CHECKOUT_ID}`,
4542
- condition: config.payments === "polar"
4543
- }
4544
- ];
4545
- await addEnvVariablesToFile(envPath, serverVars);
4664
+ if (await fs.pathExists(serverDir)) {
4665
+ const serverEnvPath = path.join(serverDir, ".env");
4666
+ const serverVars = [
4667
+ {
4668
+ key: "BETTER_AUTH_SECRET",
4669
+ value: generateAuthSecret(),
4670
+ condition: !!auth
4671
+ },
4672
+ {
4673
+ key: "BETTER_AUTH_URL",
4674
+ value: "http://localhost:3000",
4675
+ condition: !!auth
4676
+ },
4677
+ {
4678
+ key: "POLAR_ACCESS_TOKEN",
4679
+ value: "",
4680
+ condition: config.payments === "polar"
4681
+ },
4682
+ {
4683
+ key: "POLAR_SUCCESS_URL",
4684
+ value: `${corsOrigin}/success?checkout_id={CHECKOUT_ID}`,
4685
+ condition: config.payments === "polar"
4686
+ },
4687
+ {
4688
+ key: "CORS_ORIGIN",
4689
+ value: corsOrigin,
4690
+ condition: true
4691
+ },
4692
+ {
4693
+ key: "GOOGLE_GENERATIVE_AI_API_KEY",
4694
+ value: "",
4695
+ condition: examples?.includes("ai") || false
4696
+ },
4697
+ {
4698
+ key: "DATABASE_URL",
4699
+ value: databaseUrl,
4700
+ condition: database !== "none" && dbSetup === "none"
4701
+ }
4702
+ ];
4703
+ await addEnvVariablesToFile(serverEnvPath, serverVars);
4704
+ }
4546
4705
  const isUnifiedAlchemy = webDeploy === "alchemy" && serverDeploy === "alchemy";
4547
4706
  const isIndividualAlchemy = webDeploy === "alchemy" || serverDeploy === "alchemy";
4548
4707
  if (isUnifiedAlchemy) {
@@ -4561,14 +4720,11 @@ async function setupEnvironmentVariables(config) {
4561
4720
  condition: true
4562
4721
  }]);
4563
4722
  }
4564
- if (serverDeploy === "alchemy") {
4565
- const serverDir$1 = path.join(projectDir, "apps/server");
4566
- if (await fs.pathExists(serverDir$1)) await addEnvVariablesToFile(path.join(serverDir$1, ".env"), [{
4567
- key: "ALCHEMY_PASSWORD",
4568
- value: "please-change-this",
4569
- condition: true
4570
- }]);
4571
- }
4723
+ if (serverDeploy === "alchemy") await addEnvVariablesToFile(path.join(serverDir, ".env"), [{
4724
+ key: "ALCHEMY_PASSWORD",
4725
+ value: "please-change-this",
4726
+ condition: true
4727
+ }]);
4572
4728
  }
4573
4729
  }
4574
4730
 
@@ -4603,7 +4759,7 @@ async function setupCloudflareD1(config) {
4603
4759
  const envPath = path.join(projectDir, "apps/server", ".env");
4604
4760
  const variables = [{
4605
4761
  key: "DATABASE_URL",
4606
- value: "file:./local.db",
4762
+ value: `file:${path.join(projectDir, "apps/server", "local.db")}`,
4607
4763
  condition: true
4608
4764
  }];
4609
4765
  try {
@@ -5133,9 +5289,9 @@ async function writeEnvFile$1(projectDir, config) {
5133
5289
  }
5134
5290
  async function addDotenvImportToPrismaConfig(projectDir) {
5135
5291
  try {
5136
- const prismaConfigPath = path.join(projectDir, "apps/server/prisma.config.ts");
5292
+ const prismaConfigPath = path.join(projectDir, "packages/db/prisma.config.ts");
5137
5293
  let content = await fs.readFile(prismaConfigPath, "utf8");
5138
- content = `import "dotenv/config";\n${content}`;
5294
+ content = `import dotenv from "dotenv";\ndotenv.config({ path: "../../apps/server/.env" });\n${content}`;
5139
5295
  await fs.writeFile(prismaConfigPath, content);
5140
5296
  } catch (_error) {
5141
5297
  consola$1.error("Failed to update prisma.config.ts");
@@ -5151,11 +5307,12 @@ function displayManualSetupInstructions$1() {
5151
5307
 
5152
5308
  DATABASE_URL="your_database_url"`);
5153
5309
  }
5154
- async function addPrismaAccelerateExtension(serverDir) {
5310
+ async function addPrismaAccelerateExtension(projectDir) {
5155
5311
  try {
5312
+ const dbPackageDir = path.join(projectDir, "packages/db");
5156
5313
  await addPackageDependency({
5157
5314
  dependencies: ["@prisma/extension-accelerate"],
5158
- projectDir: serverDir
5315
+ projectDir: dbPackageDir
5159
5316
  });
5160
5317
  return true;
5161
5318
  } catch (_error) {
@@ -5216,7 +5373,7 @@ async function setupPrismaPostgres(config, cliInput) {
5216
5373
  await writeEnvFile$1(projectDir, prismaConfig);
5217
5374
  if (orm === "prisma") {
5218
5375
  await addDotenvImportToPrismaConfig(projectDir);
5219
- await addPrismaAccelerateExtension(serverDir);
5376
+ await addPrismaAccelerateExtension(projectDir);
5220
5377
  }
5221
5378
  const connectionType = orm === "drizzle" ? "direct connection" : "Prisma Accelerate";
5222
5379
  log.success(pc.green(`Prisma Postgres database configured successfully with ${connectionType}!`));
@@ -5316,18 +5473,18 @@ function displayManualSupabaseInstructions(output) {
5316
5473
  log.info(`"Manual Supabase Setup Instructions:"
5317
5474
  1. Ensure Docker is installed and running.
5318
5475
  2. Install the Supabase CLI (e.g., \`npm install -g supabase\`).
5319
- 3. Run \`supabase init\` in your project's \`apps/server\` directory.
5320
- 4. Run \`supabase start\` in your project's \`apps/server\` directory.
5476
+ 3. Run \`supabase init\` in your project's \`packages/db\` directory.
5477
+ 4. Run \`supabase start\` in your project's \`packages/db\` directory.
5321
5478
  5. Copy the 'DB URL' from the output.${output ? `
5322
5479
  ${pc.bold("Relevant output from `supabase start`:")}
5323
5480
  ${pc.dim(output)}` : ""}
5324
- 6. Add the DB URL to the .env file in \`apps/server/.env\` as \`DATABASE_URL\`:
5481
+ 6. Add the DB URL to the .env file in \`packages/db/.env\` as \`DATABASE_URL\`:
5325
5482
  ${pc.gray("DATABASE_URL=\"your_supabase_db_url\"")}`);
5326
5483
  }
5327
5484
  async function setupSupabase(config, cliInput) {
5328
5485
  const { projectDir, packageManager } = config;
5329
5486
  const manualDb = cliInput?.manualDb ?? false;
5330
- const serverDir = path.join(projectDir, "apps", "server");
5487
+ const serverDir = path.join(projectDir, "packages", "db");
5331
5488
  try {
5332
5489
  await fs.ensureDir(serverDir);
5333
5490
  if (manualDb) {
@@ -5610,15 +5767,15 @@ async function setupDatabase(config, cliInput) {
5610
5767
  const { database, orm, dbSetup, backend, projectDir } = config;
5611
5768
  if (backend === "convex" || database === "none") {
5612
5769
  if (backend !== "convex") {
5613
- const serverDir$1 = path.join(projectDir, "apps/server");
5614
- const serverDbDir = path.join(serverDir$1, "src/db");
5770
+ const serverDir = path.join(projectDir, "apps/server");
5771
+ const serverDbDir = path.join(serverDir, "src/db");
5615
5772
  if (await fs.pathExists(serverDbDir)) await fs.remove(serverDbDir);
5616
5773
  }
5617
5774
  return;
5618
5775
  }
5619
5776
  const s = spinner();
5620
- const serverDir = path.join(projectDir, "apps/server");
5621
- if (!await fs.pathExists(serverDir)) return;
5777
+ const dbPackageDir = path.join(projectDir, "packages/db");
5778
+ if (!await fs.pathExists(dbPackageDir)) return;
5622
5779
  try {
5623
5780
  if (orm === "prisma") if (database === "mysql" && dbSetup === "planetscale") await addPackageDependency({
5624
5781
  dependencies: [
@@ -5627,23 +5784,27 @@ async function setupDatabase(config, cliInput) {
5627
5784
  "@planetscale/database"
5628
5785
  ],
5629
5786
  devDependencies: ["prisma"],
5630
- projectDir: serverDir
5787
+ projectDir: dbPackageDir
5631
5788
  });
5632
5789
  else if (database === "sqlite" && dbSetup === "turso") await addPackageDependency({
5633
5790
  dependencies: ["@prisma/client", "@prisma/adapter-libsql"],
5634
5791
  devDependencies: ["prisma"],
5635
- projectDir: serverDir
5792
+ projectDir: dbPackageDir
5636
5793
  });
5637
5794
  else await addPackageDependency({
5638
5795
  dependencies: ["@prisma/client"],
5639
5796
  devDependencies: ["prisma"],
5640
- projectDir: serverDir
5797
+ projectDir: dbPackageDir
5641
5798
  });
5642
5799
  else if (orm === "drizzle") {
5643
5800
  if (database === "sqlite") await addPackageDependency({
5644
- dependencies: ["drizzle-orm", "@libsql/client"],
5801
+ dependencies: [
5802
+ "drizzle-orm",
5803
+ "@libsql/client",
5804
+ "libsql"
5805
+ ],
5645
5806
  devDependencies: ["drizzle-kit"],
5646
- projectDir: serverDir
5807
+ projectDir: dbPackageDir
5647
5808
  });
5648
5809
  else if (database === "postgres") if (dbSetup === "neon") await addPackageDependency({
5649
5810
  dependencies: [
@@ -5652,32 +5813,32 @@ async function setupDatabase(config, cliInput) {
5652
5813
  "ws"
5653
5814
  ],
5654
5815
  devDependencies: ["drizzle-kit", "@types/ws"],
5655
- projectDir: serverDir
5816
+ projectDir: dbPackageDir
5656
5817
  });
5657
5818
  else if (dbSetup === "planetscale") await addPackageDependency({
5658
5819
  dependencies: ["drizzle-orm", "pg"],
5659
5820
  devDependencies: ["drizzle-kit", "@types/pg"],
5660
- projectDir: serverDir
5821
+ projectDir: dbPackageDir
5661
5822
  });
5662
5823
  else await addPackageDependency({
5663
5824
  dependencies: ["drizzle-orm", "pg"],
5664
5825
  devDependencies: ["drizzle-kit", "@types/pg"],
5665
- projectDir: serverDir
5826
+ projectDir: dbPackageDir
5666
5827
  });
5667
5828
  else if (database === "mysql") if (dbSetup === "planetscale") await addPackageDependency({
5668
5829
  dependencies: ["drizzle-orm", "@planetscale/database"],
5669
5830
  devDependencies: ["drizzle-kit"],
5670
- projectDir: serverDir
5831
+ projectDir: dbPackageDir
5671
5832
  });
5672
5833
  else await addPackageDependency({
5673
5834
  dependencies: ["drizzle-orm", "mysql2"],
5674
5835
  devDependencies: ["drizzle-kit"],
5675
- projectDir: serverDir
5836
+ projectDir: dbPackageDir
5676
5837
  });
5677
5838
  } else if (orm === "mongoose") await addPackageDependency({
5678
5839
  dependencies: ["mongoose"],
5679
5840
  devDependencies: [],
5680
- projectDir: serverDir
5841
+ projectDir: dbPackageDir
5681
5842
  });
5682
5843
  if (dbSetup === "docker") await setupDockerCompose(config);
5683
5844
  else if (database === "sqlite" && dbSetup === "turso") await setupTurso(config, cliInput);
@@ -6043,7 +6204,7 @@ SERVER_URL={your-production-server-domain}
6043
6204
  CORS_ORIGIN={your-production-web-domain}
6044
6205
  BETTER_AUTH_URL={your-production-server-domain}
6045
6206
  \`\`\`
6046
- - In \`apps/server/lib/auth.ts\`, uncomment the \`session.cookieCache\` and \`advanced.crossSubDomainCookies\` sections and replace \`<your-workers-subdomain>\` with your actual workers subdomain. These settings are required to ensure cookies are transferred properly between your web and server domains.
6207
+ - In \`apps/server/src/lib/auth.ts\`, uncomment the \`session.cookieCache\` and \`advanced.crossSubDomainCookies\` sections and replace \`<your-workers-subdomain>\` with your actual workers subdomain. These settings are required to ensure cookies are transferred properly between your web and server domains.
6047
6208
  `;
6048
6209
  }
6049
6210
  function generateDeploymentCommands(packageManagerRunCmd, webDeploy, serverDeploy) {
@@ -6334,12 +6495,66 @@ function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy) {
6334
6495
  return instructions.length ? `\n${instructions.join("\n")}` : "";
6335
6496
  }
6336
6497
 
6498
+ //#endregion
6499
+ //#region src/helpers/core/workspace-setup.ts
6500
+ async function setupWorkspaceDependencies(projectDir, options) {
6501
+ const projectName = options.projectName;
6502
+ const workspaceVersion = options.packageManager === "npm" ? "*" : "workspace:*";
6503
+ const commonDeps = ["dotenv", "zod"];
6504
+ const commonDevDeps = ["tsdown"];
6505
+ const dbPackageDir = path.join(projectDir, "packages/db");
6506
+ if (await fs.pathExists(dbPackageDir)) await addPackageDependency({
6507
+ dependencies: commonDeps,
6508
+ devDependencies: commonDevDeps,
6509
+ projectDir: dbPackageDir
6510
+ });
6511
+ const authPackageDir = path.join(projectDir, "packages/auth");
6512
+ if (await fs.pathExists(authPackageDir)) await addPackageDependency({
6513
+ dependencies: commonDeps,
6514
+ devDependencies: commonDevDeps,
6515
+ customDependencies: { [`@${projectName}/db`]: workspaceVersion },
6516
+ projectDir: authPackageDir
6517
+ });
6518
+ const apiPackageDir = path.join(projectDir, "packages/api");
6519
+ if (await fs.pathExists(apiPackageDir)) await addPackageDependency({
6520
+ dependencies: commonDeps,
6521
+ devDependencies: commonDevDeps,
6522
+ customDependencies: {
6523
+ [`@${projectName}/auth`]: workspaceVersion,
6524
+ [`@${projectName}/db`]: workspaceVersion
6525
+ },
6526
+ projectDir: apiPackageDir
6527
+ });
6528
+ const serverPackageDir = path.join(projectDir, "apps/server");
6529
+ if (await fs.pathExists(serverPackageDir)) await addPackageDependency({
6530
+ dependencies: commonDeps,
6531
+ devDependencies: commonDevDeps,
6532
+ customDependencies: {
6533
+ [`@${projectName}/api`]: workspaceVersion,
6534
+ [`@${projectName}/auth`]: workspaceVersion,
6535
+ [`@${projectName}/db`]: workspaceVersion
6536
+ },
6537
+ projectDir: serverPackageDir
6538
+ });
6539
+ if (options.api && options.api !== "none") {
6540
+ const webPackageDir = path.join(projectDir, "apps/web");
6541
+ if (await fs.pathExists(webPackageDir)) await addPackageDependency({
6542
+ customDependencies: { [`@${projectName}/api`]: workspaceVersion },
6543
+ projectDir: webPackageDir
6544
+ });
6545
+ }
6546
+ }
6547
+
6337
6548
  //#endregion
6338
6549
  //#region src/helpers/core/project-config.ts
6339
6550
  async function updatePackageConfigurations(projectDir, options) {
6340
6551
  await updateRootPackageJson(projectDir, options);
6341
- if (options.backend !== "convex") await updateServerPackageJson(projectDir, options);
6342
- else await updateConvexPackageJson(projectDir, options);
6552
+ if (options.backend !== "convex") {
6553
+ await updateServerPackageJson(projectDir, options);
6554
+ await updateAuthPackageJson(projectDir, options);
6555
+ await updateApiPackageJson(projectDir, options);
6556
+ await setupWorkspaceDependencies(projectDir, options);
6557
+ } else await updateConvexPackageJson(projectDir, options);
6343
6558
  }
6344
6559
  async function updateRootPackageJson(projectDir, options) {
6345
6560
  const rootPackageJsonPath = path.join(projectDir, "package.json");
@@ -6349,6 +6564,7 @@ async function updateRootPackageJson(projectDir, options) {
6349
6564
  if (!packageJson.scripts) packageJson.scripts = {};
6350
6565
  const scripts = packageJson.scripts;
6351
6566
  const backendPackageName = options.backend === "convex" ? `@${options.projectName}/backend` : "server";
6567
+ const dbPackageName = `@${options.projectName}/db`;
6352
6568
  let serverDevScript = "";
6353
6569
  if (options.addons.includes("turborepo")) serverDevScript = `turbo -F ${backendPackageName} dev`;
6354
6570
  else if (options.packageManager === "bun") serverDevScript = `bun run --filter ${backendPackageName} dev`;
@@ -6368,14 +6584,14 @@ async function updateRootPackageJson(projectDir, options) {
6368
6584
  scripts["dev:server"] = serverDevScript;
6369
6585
  if (options.backend === "convex") scripts["dev:setup"] = `turbo -F ${backendPackageName} dev:setup`;
6370
6586
  if (needsDbScripts) {
6371
- scripts["db:push"] = `turbo -F ${backendPackageName} db:push`;
6372
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `turbo -F ${backendPackageName} db:studio`;
6587
+ scripts["db:push"] = `turbo -F ${dbPackageName} db:push`;
6588
+ if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `turbo -F ${dbPackageName} db:studio`;
6373
6589
  if (options.orm === "prisma") {
6374
- scripts["db:generate"] = `turbo -F ${backendPackageName} db:generate`;
6375
- scripts["db:migrate"] = `turbo -F ${backendPackageName} db:migrate`;
6590
+ scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
6591
+ scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
6376
6592
  } else if (options.orm === "drizzle") {
6377
- scripts["db:generate"] = `turbo -F ${backendPackageName} db:generate`;
6378
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${backendPackageName} db:migrate`;
6593
+ scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
6594
+ if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
6379
6595
  }
6380
6596
  }
6381
6597
  if (options.dbSetup === "docker") {
@@ -6393,14 +6609,14 @@ async function updateRootPackageJson(projectDir, options) {
6393
6609
  scripts["dev:server"] = serverDevScript;
6394
6610
  if (options.backend === "convex") scripts["dev:setup"] = `pnpm --filter ${backendPackageName} dev:setup`;
6395
6611
  if (needsDbScripts) {
6396
- scripts["db:push"] = `pnpm --filter ${backendPackageName} db:push`;
6397
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${backendPackageName} db:studio`;
6612
+ scripts["db:push"] = `pnpm --filter ${dbPackageName} db:push`;
6613
+ if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${dbPackageName} db:studio`;
6398
6614
  if (options.orm === "prisma") {
6399
- scripts["db:generate"] = `pnpm --filter ${backendPackageName} db:generate`;
6400
- scripts["db:migrate"] = `pnpm --filter ${backendPackageName} db:migrate`;
6615
+ scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
6616
+ scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
6401
6617
  } else if (options.orm === "drizzle") {
6402
- scripts["db:generate"] = `pnpm --filter ${backendPackageName} db:generate`;
6403
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${backendPackageName} db:migrate`;
6618
+ scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
6619
+ if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
6404
6620
  }
6405
6621
  }
6406
6622
  if (options.dbSetup === "docker") {
@@ -6418,14 +6634,14 @@ async function updateRootPackageJson(projectDir, options) {
6418
6634
  scripts["dev:server"] = serverDevScript;
6419
6635
  if (options.backend === "convex") scripts["dev:setup"] = `npm run dev:setup --workspace ${backendPackageName}`;
6420
6636
  if (needsDbScripts) {
6421
- scripts["db:push"] = `npm run db:push --workspace ${backendPackageName}`;
6422
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `npm run db:studio --workspace ${backendPackageName}`;
6637
+ scripts["db:push"] = `npm run db:push --workspace ${dbPackageName}`;
6638
+ if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `npm run db:studio --workspace ${dbPackageName}`;
6423
6639
  if (options.orm === "prisma") {
6424
- scripts["db:generate"] = `npm run db:generate --workspace ${backendPackageName}`;
6425
- scripts["db:migrate"] = `npm run db:migrate --workspace ${backendPackageName}`;
6640
+ scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
6641
+ scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
6426
6642
  } else if (options.orm === "drizzle") {
6427
- scripts["db:generate"] = `npm run db:generate --workspace ${backendPackageName}`;
6428
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `npm run db:migrate --workspace ${backendPackageName}`;
6643
+ scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
6644
+ if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
6429
6645
  }
6430
6646
  }
6431
6647
  if (options.dbSetup === "docker") {
@@ -6443,14 +6659,14 @@ async function updateRootPackageJson(projectDir, options) {
6443
6659
  scripts["dev:server"] = serverDevScript;
6444
6660
  if (options.backend === "convex") scripts["dev:setup"] = `bun run --filter ${backendPackageName} dev:setup`;
6445
6661
  if (needsDbScripts) {
6446
- scripts["db:push"] = `bun run --filter ${backendPackageName} db:push`;
6447
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${backendPackageName} db:studio`;
6662
+ scripts["db:push"] = `bun run --filter ${dbPackageName} db:push`;
6663
+ if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${dbPackageName} db:studio`;
6448
6664
  if (options.orm === "prisma") {
6449
- scripts["db:generate"] = `bun run --filter ${backendPackageName} db:generate`;
6450
- scripts["db:migrate"] = `bun run --filter ${backendPackageName} db:migrate`;
6665
+ scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
6666
+ scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
6451
6667
  } else if (options.orm === "drizzle") {
6452
- scripts["db:generate"] = `bun run --filter ${backendPackageName} db:generate`;
6453
- if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `bun run --filter ${backendPackageName} db:migrate`;
6668
+ scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
6669
+ if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
6454
6670
  }
6455
6671
  }
6456
6672
  if (options.dbSetup === "docker") {
@@ -6483,6 +6699,22 @@ async function updateServerPackageJson(projectDir, options) {
6483
6699
  const serverPackageJson = await fs.readJson(serverPackageJsonPath);
6484
6700
  if (!serverPackageJson.scripts) serverPackageJson.scripts = {};
6485
6701
  const scripts = serverPackageJson.scripts;
6702
+ if (options.dbSetup === "docker") {
6703
+ scripts["db:start"] = "docker compose up -d";
6704
+ scripts["db:watch"] = "docker compose up";
6705
+ scripts["db:stop"] = "docker compose stop";
6706
+ scripts["db:down"] = "docker compose down";
6707
+ }
6708
+ await fs.writeJson(serverPackageJsonPath, serverPackageJson, { spaces: 2 });
6709
+ await updateDbPackageJson(projectDir, options);
6710
+ }
6711
+ async function updateDbPackageJson(projectDir, options) {
6712
+ const dbPackageJsonPath = path.join(projectDir, "packages/db/package.json");
6713
+ if (!await fs.pathExists(dbPackageJsonPath)) return;
6714
+ const dbPackageJson = await fs.readJson(dbPackageJsonPath);
6715
+ dbPackageJson.name = `@${options.projectName}/db`;
6716
+ if (!dbPackageJson.scripts) dbPackageJson.scripts = {};
6717
+ const scripts = dbPackageJson.scripts;
6486
6718
  if (options.database !== "none") {
6487
6719
  if (options.database === "sqlite" && options.orm === "drizzle" && options.dbSetup !== "d1") scripts["db:local"] = "turso dev --db-file local.db";
6488
6720
  if (options.orm === "prisma") {
@@ -6497,13 +6729,21 @@ async function updateServerPackageJson(projectDir, options) {
6497
6729
  if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = "drizzle-kit migrate";
6498
6730
  }
6499
6731
  }
6500
- if (options.dbSetup === "docker") {
6501
- scripts["db:start"] = "docker compose up -d";
6502
- scripts["db:watch"] = "docker compose up";
6503
- scripts["db:stop"] = "docker compose stop";
6504
- scripts["db:down"] = "docker compose down";
6505
- }
6506
- await fs.writeJson(serverPackageJsonPath, serverPackageJson, { spaces: 2 });
6732
+ await fs.writeJson(dbPackageJsonPath, dbPackageJson, { spaces: 2 });
6733
+ }
6734
+ async function updateAuthPackageJson(projectDir, options) {
6735
+ const authPackageJsonPath = path.join(projectDir, "packages/auth/package.json");
6736
+ if (!await fs.pathExists(authPackageJsonPath)) return;
6737
+ const authPackageJson = await fs.readJson(authPackageJsonPath);
6738
+ authPackageJson.name = `@${options.projectName}/auth`;
6739
+ await fs.writeJson(authPackageJsonPath, authPackageJson, { spaces: 2 });
6740
+ }
6741
+ async function updateApiPackageJson(projectDir, options) {
6742
+ const apiPackageJsonPath = path.join(projectDir, "packages/api/package.json");
6743
+ if (!await fs.pathExists(apiPackageJsonPath)) return;
6744
+ const apiPackageJson = await fs.readJson(apiPackageJsonPath);
6745
+ apiPackageJson.name = `@${options.projectName}/api`;
6746
+ await fs.writeJson(apiPackageJsonPath, apiPackageJson, { spaces: 2 });
6507
6747
  }
6508
6748
  async function updateConvexPackageJson(projectDir, options) {
6509
6749
  const convexPackageJsonPath = path.join(projectDir, "packages/backend/package.json");
@@ -6524,10 +6764,7 @@ async function createProject(options, cliInput) {
6524
6764
  await copyBaseTemplate(projectDir, options);
6525
6765
  await setupFrontendTemplates(projectDir, options);
6526
6766
  await setupBackendFramework(projectDir, options);
6527
- if (!isConvex) {
6528
- await setupDbOrmTemplates(projectDir, options);
6529
- await setupDockerComposeTemplates(projectDir, options);
6530
- }
6767
+ if (!isConvex) await setupDockerComposeTemplates(projectDir, options);
6531
6768
  await setupAuthTemplate(projectDir, options);
6532
6769
  if (options.payments && options.payments !== "none") await setupPaymentsTemplate(projectDir, options);
6533
6770
  if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamplesTemplate(projectDir, options);
@@ -6546,6 +6783,7 @@ async function createProject(options, cliInput) {
6546
6783
  await handleExtras(projectDir, options);
6547
6784
  await setupEnvironmentVariables(options);
6548
6785
  await updatePackageConfigurations(projectDir, options);
6786
+ await setupCatalogs(projectDir, options);
6549
6787
  await setupWebDeploy(options);
6550
6788
  await setupServerDeploy(options);
6551
6789
  await createReadme(projectDir, options);