create-better-t-stack 2.50.0 → 2.50.1-canary.7ebd503f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +8 -9
- package/dist/index.js +1 -1
- package/dist/{src-BFx0Xu3C.js → src-DG05Vcnx.js} +696 -343
- package/package.json +2 -1
- package/templates/api/orpc/fullstack/next/src/app/api/rpc/[[...rest]]/route.ts.hbs +50 -0
- package/templates/api/orpc/server/_gitignore +34 -0
- package/templates/api/orpc/server/package.json.hbs +24 -0
- package/templates/api/orpc/server/{base/src/lib → src}/context.ts.hbs +6 -6
- package/templates/{backend/server/server-base → api/orpc/server}/src/routers/index.ts.hbs +2 -2
- package/templates/api/orpc/server/tsconfig.json.hbs +10 -0
- package/templates/api/orpc/server/tsdown.config.ts.hbs +7 -0
- package/templates/api/orpc/web/nuxt/app/plugins/orpc.ts.hbs +1 -1
- package/templates/api/orpc/web/react/base/src/utils/orpc.ts.hbs +4 -2
- package/templates/api/orpc/web/solid/src/utils/orpc.ts.hbs +1 -1
- package/templates/api/orpc/web/svelte/src/lib/orpc.ts.hbs +1 -1
- package/templates/api/trpc/fullstack/next/src/app/api/trpc/[trpc]/route.ts.hbs +14 -0
- package/templates/api/trpc/server/_gitignore +34 -0
- package/templates/api/trpc/server/package.json.hbs +23 -0
- package/templates/api/trpc/server/{base/src/lib → src}/context.ts.hbs +6 -6
- package/templates/api/trpc/server/src/routers/index.ts.hbs +55 -0
- package/templates/api/trpc/server/tsconfig.json.hbs +13 -0
- package/templates/api/trpc/server/tsdown.config.ts.hbs +7 -0
- package/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs +6 -4
- package/templates/auth/better-auth/{server/next/src/app/api/auth/[...all]/route.ts → fullstack/next/src/app/api/auth/[...all]/route.ts.hbs} +1 -1
- package/templates/auth/better-auth/server/base/_gitignore +34 -0
- package/templates/auth/better-auth/server/base/package.json.hbs +24 -0
- package/templates/auth/better-auth/server/base/src/{lib/auth.ts.hbs → index.ts.hbs} +12 -12
- package/templates/auth/better-auth/server/base/tsconfig.json.hbs +13 -0
- package/templates/auth/better-auth/server/base/tsdown.config.ts.hbs +7 -0
- package/templates/auth/better-auth/web/react/base/src/lib/auth-client.ts.hbs +2 -0
- package/templates/auth/better-auth/web/react/next/src/app/dashboard/page.tsx.hbs +31 -0
- package/templates/backend/server/{server-base → base}/package.json.hbs +1 -5
- package/templates/backend/server/{server-base → base}/tsconfig.json.hbs +5 -10
- package/templates/backend/server/base/tsdown.config.ts.hbs +9 -0
- package/templates/backend/server/elysia/src/index.ts.hbs +6 -6
- package/templates/backend/server/express/src/index.ts.hbs +6 -6
- package/templates/backend/server/fastify/src/index.ts.hbs +6 -6
- package/templates/backend/server/hono/src/index.ts.hbs +7 -7
- package/templates/base/_gitignore +47 -1
- package/templates/base/package.json.hbs +1 -3
- package/templates/base/tsconfig.base.json.hbs +23 -0
- package/templates/base/tsconfig.json.hbs +3 -0
- package/templates/db/base/_gitignore +34 -0
- package/templates/db/base/package.json.hbs +23 -0
- package/templates/db/base/tsconfig.json.hbs +13 -0
- package/templates/db/base/tsdown.config.ts.hbs +7 -0
- package/templates/db/drizzle/mysql/drizzle.config.ts.hbs +11 -2
- package/templates/db/drizzle/mysql/src/{db/index.ts.hbs → index.ts.hbs} +1 -1
- package/templates/db/drizzle/postgres/drizzle.config.ts.hbs +11 -2
- package/templates/db/drizzle/postgres/src/{db/index.ts.hbs → index.ts.hbs} +1 -1
- package/templates/db/drizzle/sqlite/drizzle.config.ts.hbs +11 -2
- package/templates/db/drizzle/sqlite/src/{db/index.ts.hbs → index.ts.hbs} +1 -1
- package/templates/db/prisma/mongodb/prisma.config.ts.hbs +9 -1
- package/templates/db/prisma/mongodb/src/index.ts.hbs +5 -0
- package/templates/db/prisma/mysql/prisma.config.ts.hbs +9 -1
- package/templates/db/prisma/mysql/src/{db/index.ts.hbs → index.ts.hbs} +1 -1
- package/templates/db/prisma/postgres/prisma.config.ts.hbs +11 -3
- package/templates/db/prisma/postgres/src/{db/index.ts.hbs → index.ts.hbs} +1 -1
- package/templates/db/prisma/sqlite/prisma.config.ts.hbs +9 -1
- package/templates/db/prisma/sqlite/src/{db/index.ts.hbs → index.ts.hbs} +3 -3
- package/templates/deploy/alchemy/alchemy.run.ts.hbs +3 -3
- package/templates/examples/ai/fullstack/next/src/app/api/ai/route.ts.hbs +15 -0
- package/templates/examples/todo/server/drizzle/base/src/routers/todo.ts.hbs +6 -6
- package/templates/examples/todo/server/mongoose/base/src/routers/todo.ts.hbs +4 -4
- package/templates/examples/todo/server/prisma/base/src/routers/todo.ts.hbs +4 -4
- package/templates/frontend/native/nativewind/tsconfig.json.hbs +1 -6
- package/templates/frontend/native/unistyles/tsconfig.json.hbs +1 -6
- package/templates/frontend/nuxt/tsconfig.json.hbs +0 -4
- package/templates/frontend/react/next/package.json.hbs +1 -1
- package/templates/frontend/react/next/tsconfig.json.hbs +0 -7
- package/templates/frontend/react/react-router/tsconfig.json.hbs +1 -6
- package/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs +1 -1
- package/templates/frontend/react/tanstack-router/tsconfig.json.hbs +1 -6
- package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +1 -1
- package/templates/frontend/react/tanstack-start/tsconfig.json.hbs +1 -6
- package/templates/frontend/solid/tsconfig.json.hbs +1 -6
- package/templates/frontend/svelte/tsconfig.json.hbs +1 -6
- package/templates/api/orpc/server/next/src/app/rpc/[...all]/route.ts.hbs +0 -52
- package/templates/api/trpc/server/next/src/app/trpc/[trpc]/route.ts +0 -14
- package/templates/backend/server/next/next-env.d.ts +0 -5
- package/templates/backend/server/next/next.config.ts +0 -7
- package/templates/backend/server/next/package.json.hbs +0 -27
- package/templates/backend/server/next/src/app/route.ts +0 -5
- package/templates/backend/server/next/src/middleware.ts +0 -19
- package/templates/backend/server/next/tsconfig.json.hbs +0 -33
- package/templates/db/prisma/mongodb/src/db/index.ts.hbs +0 -5
- package/templates/examples/ai/server/next/src/app/ai/route.ts.hbs +0 -15
- /package/templates/api/orpc/server/{base/src/lib/orpc.ts.hbs → src/index.ts.hbs} +0 -0
- /package/templates/api/trpc/server/{base/src/lib/trpc.ts.hbs → src/index.ts.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/drizzle/mysql/src/{db/schema/auth.ts → schema/auth.ts.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/drizzle/postgres/src/{db/schema/auth.ts → schema/auth.ts.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/drizzle/sqlite/src/{db/schema/auth.ts → schema/auth.ts.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/mongoose/mongodb/src/{db/models/auth.model.ts → models/auth.model.ts.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/prisma/mongodb/prisma/schema/{auth.prisma → auth.prisma.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/prisma/mysql/prisma/schema/{auth.prisma → auth.prisma.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/prisma/postgres/prisma/schema/{auth.prisma → auth.prisma.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/prisma/sqlite/prisma/schema/{auth.prisma → auth.prisma.hbs} +0 -0
- /package/templates/auth/better-auth/web/nuxt/app/middleware/{auth.ts → auth.ts.hbs} +0 -0
- /package/templates/backend/server/{server-base → base}/_gitignore +0 -0
- /package/templates/db/mongoose/mongodb/src/{db/index.ts.hbs → index.ts.hbs} +0 -0
- /package/templates/examples/todo/server/drizzle/mysql/src/{db/schema → schema}/todo.ts +0 -0
- /package/templates/examples/todo/server/drizzle/postgres/src/{db/schema → schema}/todo.ts +0 -0
- /package/templates/examples/todo/server/drizzle/sqlite/src/{db/schema → schema}/todo.ts +0 -0
- /package/templates/examples/todo/server/mongoose/mongodb/src/{db/models/todo.model.ts → models/todo.model.ts.hbs} +0 -0
- /package/templates/examples/todo/server/prisma/mongodb/prisma/schema/{todo.prisma → todo.prisma.hbs} +0 -0
- /package/templates/examples/todo/server/prisma/mysql/prisma/schema/{todo.prisma → todo.prisma.hbs} +0 -0
- /package/templates/examples/todo/server/prisma/postgres/prisma/schema/{todo.prisma → todo.prisma.hbs} +0 -0
- /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
|
|
@@ -70,7 +71,7 @@ const dependencyVersionMap = {
|
|
|
70
71
|
"drizzle-orm": "^0.44.2",
|
|
71
72
|
"drizzle-kit": "^0.31.2",
|
|
72
73
|
"@planetscale/database": "^1.19.0",
|
|
73
|
-
"@libsql/client": "^0.
|
|
74
|
+
"@libsql/client": "^0.14.0",
|
|
74
75
|
"@neondatabase/serverless": "^1.0.1",
|
|
75
76
|
pg: "^8.14.1",
|
|
76
77
|
"@types/pg": "^8.11.11",
|
|
@@ -123,6 +124,7 @@ const dependencyVersionMap = {
|
|
|
123
124
|
"@trpc/tanstack-react-query": "^11.5.0",
|
|
124
125
|
"@trpc/server": "^11.5.0",
|
|
125
126
|
"@trpc/client": "^11.5.0",
|
|
127
|
+
next: "15.5.4",
|
|
126
128
|
convex: "^1.27.0",
|
|
127
129
|
"@convex-dev/react-query": "^0.0.0-alpha.8",
|
|
128
130
|
"convex-svelte": "^0.0.11",
|
|
@@ -146,7 +148,9 @@ const dependencyVersionMap = {
|
|
|
146
148
|
"@cloudflare/workers-types": "^4.20250822.0",
|
|
147
149
|
alchemy: "^0.70.0",
|
|
148
150
|
nitropack: "^2.12.4",
|
|
149
|
-
dotenv: "^17.2.
|
|
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
|
};
|
|
@@ -195,9 +199,9 @@ const BackendSchema = z.enum([
|
|
|
195
199
|
"hono",
|
|
196
200
|
"express",
|
|
197
201
|
"fastify",
|
|
198
|
-
"next",
|
|
199
202
|
"elysia",
|
|
200
203
|
"convex",
|
|
204
|
+
"self",
|
|
201
205
|
"none"
|
|
202
206
|
]).describe("Backend framework");
|
|
203
207
|
const RuntimeSchema = z.enum([
|
|
@@ -343,6 +347,22 @@ function ensureSingleWebAndNative(frontends) {
|
|
|
343
347
|
if (web.length > 1) exitWithError("Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte, solid");
|
|
344
348
|
if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-nativewind, native-unistyles");
|
|
345
349
|
}
|
|
350
|
+
const FULLSTACK_FRONTENDS$1 = [
|
|
351
|
+
"next",
|
|
352
|
+
"nuxt",
|
|
353
|
+
"svelte",
|
|
354
|
+
"tanstack-start"
|
|
355
|
+
];
|
|
356
|
+
function validateSelfBackendCompatibility(providedFlags, options, config) {
|
|
357
|
+
const backend = config.backend || options.backend;
|
|
358
|
+
const frontends = config.frontend || options.frontend || [];
|
|
359
|
+
if (backend === "self") {
|
|
360
|
+
if (!frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f))) exitWithError("Backend 'self' (fullstack) requires a fullstack-capable frontend. Please use --frontend with one of: next, nuxt, svelte, tanstack-start");
|
|
361
|
+
if (frontends.length > 1) exitWithError("Backend 'self' (fullstack) can only be used with a single frontend framework.");
|
|
362
|
+
}
|
|
363
|
+
const hasFullstackFrontend = frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f));
|
|
364
|
+
if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") exitWithError("Backend 'self' (fullstack) is only compatible with fullstack-capable frontends: next, nuxt, svelte, tanstack-start. Please choose a different backend or use a fullstack frontend.");
|
|
365
|
+
}
|
|
346
366
|
function validateWorkersCompatibility(providedFlags, options, config) {
|
|
347
367
|
if (providedFlags.has("runtime") && options.runtime === "workers" && config.backend && config.backend !== "hono") exitWithError(`Cloudflare Workers runtime (--runtime workers) is only supported with Hono backend (--backend hono). Current backend: ${config.backend}. Please use '--backend hono' or choose a different runtime.`);
|
|
348
368
|
if (providedFlags.has("backend") && config.backend && config.backend !== "hono" && config.runtime === "workers") exitWithError(`Backend '${config.backend}' is not compatible with Cloudflare Workers runtime. Cloudflare Workers runtime is only supported with Hono backend. Please use '--backend hono' or choose a different runtime.`);
|
|
@@ -664,36 +684,39 @@ async function getAuthChoice(auth, hasDatabase, backend, frontend) {
|
|
|
664
684
|
|
|
665
685
|
//#endregion
|
|
666
686
|
//#region src/prompts/backend.ts
|
|
687
|
+
const FULLSTACK_FRONTENDS = [
|
|
688
|
+
"next",
|
|
689
|
+
"nuxt",
|
|
690
|
+
"svelte",
|
|
691
|
+
"tanstack-start"
|
|
692
|
+
];
|
|
667
693
|
async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
668
694
|
if (backendFramework !== void 0) return backendFramework;
|
|
669
695
|
const hasIncompatibleFrontend = frontends?.some((f) => f === "solid");
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
hint: "Ergonomic web framework for building backend servers"
|
|
695
|
-
}
|
|
696
|
-
];
|
|
696
|
+
const hasFullstackFrontend = frontends?.some((f) => FULLSTACK_FRONTENDS.includes(f));
|
|
697
|
+
const backendOptions = [];
|
|
698
|
+
if (hasFullstackFrontend) backendOptions.push({
|
|
699
|
+
value: "self",
|
|
700
|
+
label: "Self (Fullstack)",
|
|
701
|
+
hint: "Use frontend's built-in api routes"
|
|
702
|
+
});
|
|
703
|
+
backendOptions.push({
|
|
704
|
+
value: "hono",
|
|
705
|
+
label: "Hono",
|
|
706
|
+
hint: "Lightweight, ultrafast web framework"
|
|
707
|
+
}, {
|
|
708
|
+
value: "express",
|
|
709
|
+
label: "Express",
|
|
710
|
+
hint: "Fast, unopinionated, minimalist web framework for Node.js"
|
|
711
|
+
}, {
|
|
712
|
+
value: "fastify",
|
|
713
|
+
label: "Fastify",
|
|
714
|
+
hint: "Fast, low-overhead web framework for Node.js"
|
|
715
|
+
}, {
|
|
716
|
+
value: "elysia",
|
|
717
|
+
label: "Elysia",
|
|
718
|
+
hint: "Ergonomic web framework for building backend servers"
|
|
719
|
+
});
|
|
697
720
|
if (!hasIncompatibleFrontend) backendOptions.push({
|
|
698
721
|
value: "convex",
|
|
699
722
|
label: "Convex",
|
|
@@ -707,7 +730,7 @@ async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
|
707
730
|
const response = await select({
|
|
708
731
|
message: "Select backend",
|
|
709
732
|
options: backendOptions,
|
|
710
|
-
initialValue: DEFAULT_CONFIG.backend
|
|
733
|
+
initialValue: hasFullstackFrontend ? "self" : DEFAULT_CONFIG.backend
|
|
711
734
|
});
|
|
712
735
|
if (isCancel(response)) return exitCancelled("Operation cancelled");
|
|
713
736
|
return response;
|
|
@@ -1086,9 +1109,8 @@ async function getPaymentsChoice(payments, auth, backend, frontends) {
|
|
|
1086
1109
|
//#endregion
|
|
1087
1110
|
//#region src/prompts/runtime.ts
|
|
1088
1111
|
async function getRuntimeChoice(runtime, backend) {
|
|
1089
|
-
if (backend === "convex" || backend === "none") return "none";
|
|
1112
|
+
if (backend === "convex" || backend === "none" || backend === "self") return "none";
|
|
1090
1113
|
if (runtime !== void 0) return runtime;
|
|
1091
|
-
if (backend === "next") return "node";
|
|
1092
1114
|
const runtimeOptions = [{
|
|
1093
1115
|
value: "bun",
|
|
1094
1116
|
label: "Bun",
|
|
@@ -1375,7 +1397,7 @@ const getLatestCLIVersion = () => {
|
|
|
1375
1397
|
*/
|
|
1376
1398
|
function isTelemetryEnabled() {
|
|
1377
1399
|
const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
|
|
1378
|
-
const BTS_TELEMETRY = "
|
|
1400
|
+
const BTS_TELEMETRY = "0";
|
|
1379
1401
|
if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
|
|
1380
1402
|
if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
|
|
1381
1403
|
return true;
|
|
@@ -1383,8 +1405,8 @@ function isTelemetryEnabled() {
|
|
|
1383
1405
|
|
|
1384
1406
|
//#endregion
|
|
1385
1407
|
//#region src/utils/analytics.ts
|
|
1386
|
-
const POSTHOG_API_KEY = "
|
|
1387
|
-
const POSTHOG_HOST = "
|
|
1408
|
+
const POSTHOG_API_KEY = "random";
|
|
1409
|
+
const POSTHOG_HOST = "random";
|
|
1388
1410
|
function generateSessionId() {
|
|
1389
1411
|
const rand = Math.random().toString(36).slice(2);
|
|
1390
1412
|
return `cli_${Date.now().toString(36)}${rand}`;
|
|
@@ -1765,8 +1787,8 @@ function validateBackendConstraints(config, providedFlags, options) {
|
|
|
1765
1787
|
].includes(f));
|
|
1766
1788
|
if (incompatibleFrontends.length > 0) exitWithError(`Clerk authentication is not compatible with the following frontends: ${incompatibleFrontends.join(", ")}. Please choose a different frontend or auth provider.`);
|
|
1767
1789
|
}
|
|
1768
|
-
if (providedFlags.has("backend") && backend && backend !== "convex" && backend !== "none") {
|
|
1769
|
-
if (providedFlags.has("runtime") && options.runtime === "none") exitWithError("'--runtime none' is only supported with '--backend convex' or '--backend
|
|
1790
|
+
if (providedFlags.has("backend") && backend && backend !== "convex" && backend !== "none" && backend !== "self") {
|
|
1791
|
+
if (providedFlags.has("runtime") && options.runtime === "none") exitWithError("'--runtime none' is only supported with '--backend convex', '--backend none', or '--backend self'. Please choose 'bun', 'node', or remove the --runtime flag.");
|
|
1770
1792
|
}
|
|
1771
1793
|
if (backend === "convex" && providedFlags.has("frontend") && options.frontend) {
|
|
1772
1794
|
const incompatibleFrontends = options.frontend.filter((f) => f === "solid");
|
|
@@ -1796,6 +1818,7 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
1796
1818
|
validateFrontendConstraints(config, providedFlags);
|
|
1797
1819
|
validateApiConstraints(config, options);
|
|
1798
1820
|
validateServerDeployRequiresBackend(config.serverDeploy, config.backend);
|
|
1821
|
+
validateSelfBackendCompatibility(providedFlags, options, config);
|
|
1799
1822
|
validateWorkersCompatibility(providedFlags, options, config);
|
|
1800
1823
|
if (config.runtime === "workers" && config.serverDeploy === "none") exitWithError("Cloudflare Workers runtime requires a server deployment. Please choose 'wrangler' or 'alchemy' for --server-deploy.");
|
|
1801
1824
|
if (config.addons && config.addons.length > 0) {
|
|
@@ -1849,6 +1872,7 @@ const CORE_STACK_FLAGS = new Set([
|
|
|
1849
1872
|
"examples",
|
|
1850
1873
|
"auth",
|
|
1851
1874
|
"dbSetup",
|
|
1875
|
+
"payments",
|
|
1852
1876
|
"api",
|
|
1853
1877
|
"webDeploy",
|
|
1854
1878
|
"serverDeploy"
|
|
@@ -1992,15 +2016,17 @@ const addPackageDependency = async (opts) => {
|
|
|
1992
2016
|
if (!pkgJson.dependencies) pkgJson.dependencies = {};
|
|
1993
2017
|
if (!pkgJson.devDependencies) pkgJson.devDependencies = {};
|
|
1994
2018
|
for (const pkgName of dependencies) {
|
|
1995
|
-
const version =
|
|
2019
|
+
const version = dependencyVersionMap[pkgName];
|
|
1996
2020
|
if (version) pkgJson.dependencies[pkgName] = version;
|
|
1997
2021
|
else console.warn(`Warning: Dependency ${pkgName} not found in version map.`);
|
|
1998
2022
|
}
|
|
1999
2023
|
for (const pkgName of devDependencies) {
|
|
2000
|
-
const version =
|
|
2024
|
+
const version = dependencyVersionMap[pkgName];
|
|
2001
2025
|
if (version) pkgJson.devDependencies[pkgName] = version;
|
|
2002
2026
|
else console.warn(`Warning: Dev dependency ${pkgName} not found in version map.`);
|
|
2003
2027
|
}
|
|
2028
|
+
for (const [pkgName, version] of Object.entries(customDependencies)) pkgJson.dependencies[pkgName] = version;
|
|
2029
|
+
for (const [pkgName, version] of Object.entries(customDevDependencies)) pkgJson.devDependencies[pkgName] = version;
|
|
2004
2030
|
await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
2005
2031
|
};
|
|
2006
2032
|
|
|
@@ -2062,11 +2088,14 @@ async function setupFumadocs(config) {
|
|
|
2062
2088
|
if (isCancel(template)) return exitCancelled("Operation cancelled");
|
|
2063
2089
|
const commandWithArgs = `create-fumadocs-app@latest fumadocs --template ${TEMPLATES[template].value} --src --no-install --pm ${packageManager} --no-eslint --no-git`;
|
|
2064
2090
|
const fumadocsInitCommand = getPackageExecutionCommand(packageManager, commandWithArgs);
|
|
2091
|
+
const s = spinner();
|
|
2092
|
+
s.start("Setting up Fumadocs...");
|
|
2065
2093
|
await execa(fumadocsInitCommand, {
|
|
2066
2094
|
cwd: path.join(projectDir, "apps"),
|
|
2067
2095
|
env: { CI: "true" },
|
|
2068
2096
|
shell: true
|
|
2069
2097
|
});
|
|
2098
|
+
s.stop("Fumadocs setup complete!");
|
|
2070
2099
|
const fumadocsDir = path.join(projectDir, "apps", "fumadocs");
|
|
2071
2100
|
const packageJsonPath = path.join(fumadocsDir, "package.json");
|
|
2072
2101
|
if (await fs.pathExists(packageJsonPath)) {
|
|
@@ -2307,11 +2336,14 @@ async function setupUltracite(config, hasHusky) {
|
|
|
2307
2336
|
if (hasHusky) ultraciteArgs.push("--integrations", "husky", "lint-staged");
|
|
2308
2337
|
const commandWithArgs = `ultracite@latest ${ultraciteArgs.join(" ")} --skip-install`;
|
|
2309
2338
|
const ultraciteInitCommand = getPackageExecutionCommand(packageManager, commandWithArgs);
|
|
2339
|
+
const s = spinner();
|
|
2340
|
+
s.start("Setting up Ultracite...");
|
|
2310
2341
|
await execa(ultraciteInitCommand, {
|
|
2311
2342
|
cwd: projectDir,
|
|
2312
2343
|
env: { CI: "true" },
|
|
2313
2344
|
shell: true
|
|
2314
2345
|
});
|
|
2346
|
+
s.stop("Ultracite setup complete!");
|
|
2315
2347
|
if (hasHusky) await addPackageDependency({
|
|
2316
2348
|
devDependencies: ["husky", "lint-staged"],
|
|
2317
2349
|
projectDir
|
|
@@ -2655,8 +2687,12 @@ async function processTemplate(srcPath, destPath, context) {
|
|
|
2655
2687
|
}
|
|
2656
2688
|
handlebars.registerHelper("eq", (a, b) => a === b);
|
|
2657
2689
|
handlebars.registerHelper("ne", (a, b) => a !== b);
|
|
2658
|
-
handlebars.registerHelper("and", (
|
|
2659
|
-
|
|
2690
|
+
handlebars.registerHelper("and", (...args) => {
|
|
2691
|
+
return args.slice(0, -1).every((value) => value);
|
|
2692
|
+
});
|
|
2693
|
+
handlebars.registerHelper("or", (...args) => {
|
|
2694
|
+
return args.slice(0, -1).some((value) => value);
|
|
2695
|
+
});
|
|
2660
2696
|
handlebars.registerHelper("includes", (array, value) => Array.isArray(array) && array.includes(value));
|
|
2661
2697
|
|
|
2662
2698
|
//#endregion
|
|
@@ -2718,6 +2754,10 @@ async function setupFrontendTemplates(projectDir, context) {
|
|
|
2718
2754
|
const apiWebBaseDir = path.join(PKG_ROOT, `templates/api/${context.api}/web/react/base`);
|
|
2719
2755
|
if (await fs.pathExists(apiWebBaseDir)) await processAndCopyFiles("**/*", apiWebBaseDir, webAppDir, context);
|
|
2720
2756
|
}
|
|
2757
|
+
if (context.backend === "self" && reactFramework === "next" && context.api !== "none") {
|
|
2758
|
+
const apiFullstackDir = path.join(PKG_ROOT, `templates/api/${context.api}/fullstack/next`);
|
|
2759
|
+
if (await fs.pathExists(apiFullstackDir)) await processAndCopyFiles("**/*", apiFullstackDir, webAppDir, context);
|
|
2760
|
+
}
|
|
2721
2761
|
}
|
|
2722
2762
|
} else if (hasNuxtWeb) {
|
|
2723
2763
|
const nuxtBaseDir = path.join(PKG_ROOT, "templates/frontend/nuxt");
|
|
@@ -2758,35 +2798,52 @@ async function setupFrontendTemplates(projectDir, context) {
|
|
|
2758
2798
|
}
|
|
2759
2799
|
}
|
|
2760
2800
|
}
|
|
2761
|
-
async function
|
|
2762
|
-
if (context.
|
|
2801
|
+
async function setupApiPackage(projectDir, context) {
|
|
2802
|
+
if (context.api === "none") return;
|
|
2803
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
2804
|
+
await fs.ensureDir(apiPackageDir);
|
|
2805
|
+
const apiServerDir = path.join(PKG_ROOT, `templates/api/${context.api}/server`);
|
|
2806
|
+
if (await fs.pathExists(apiServerDir)) await processAndCopyFiles("**/*", apiServerDir, apiPackageDir, context);
|
|
2807
|
+
}
|
|
2808
|
+
async function setupDbPackage(projectDir, context) {
|
|
2809
|
+
if (context.database === "none" || context.orm === "none") return;
|
|
2810
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
2811
|
+
await fs.ensureDir(dbPackageDir);
|
|
2812
|
+
const dbBaseDir = path.join(PKG_ROOT, "templates/db/base");
|
|
2813
|
+
if (await fs.pathExists(dbBaseDir)) await processAndCopyFiles("**/*", dbBaseDir, dbPackageDir, context);
|
|
2814
|
+
const dbOrmSrcDir = path.join(PKG_ROOT, `templates/db/${context.orm}/${context.database}`);
|
|
2815
|
+
if (await fs.pathExists(dbOrmSrcDir)) await processAndCopyFiles("**/*", dbOrmSrcDir, dbPackageDir, context);
|
|
2816
|
+
}
|
|
2817
|
+
async function setupConvexBackend(projectDir, context) {
|
|
2818
|
+
const serverAppDir = path.join(projectDir, "apps/server");
|
|
2819
|
+
if (await fs.pathExists(serverAppDir)) await fs.remove(serverAppDir);
|
|
2820
|
+
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
|
2821
|
+
const convexSrcDir = path.join(PKG_ROOT, "templates/backend/convex/packages/backend");
|
|
2822
|
+
await fs.ensureDir(convexBackendDestDir);
|
|
2823
|
+
if (await fs.pathExists(convexSrcDir)) await processAndCopyFiles("**/*", convexSrcDir, convexBackendDestDir, context);
|
|
2824
|
+
}
|
|
2825
|
+
async function setupServerApp(projectDir, context) {
|
|
2763
2826
|
const serverAppDir = path.join(projectDir, "apps/server");
|
|
2764
|
-
if (context.backend === "convex") {
|
|
2765
|
-
if (await fs.pathExists(serverAppDir)) await fs.remove(serverAppDir);
|
|
2766
|
-
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
|
2767
|
-
const convexSrcDir = path.join(PKG_ROOT, "templates/backend/convex/packages/backend");
|
|
2768
|
-
await fs.ensureDir(convexBackendDestDir);
|
|
2769
|
-
if (await fs.pathExists(convexSrcDir)) await processAndCopyFiles("**/*", convexSrcDir, convexBackendDestDir, context);
|
|
2770
|
-
return;
|
|
2771
|
-
}
|
|
2772
2827
|
await fs.ensureDir(serverAppDir);
|
|
2773
|
-
const serverBaseDir = path.join(PKG_ROOT, "templates/backend/server/
|
|
2828
|
+
const serverBaseDir = path.join(PKG_ROOT, "templates/backend/server/base");
|
|
2774
2829
|
if (await fs.pathExists(serverBaseDir)) await processAndCopyFiles("**/*", serverBaseDir, serverAppDir, context);
|
|
2775
2830
|
const frameworkSrcDir = path.join(PKG_ROOT, `templates/backend/server/${context.backend}`);
|
|
2776
2831
|
if (await fs.pathExists(frameworkSrcDir)) await processAndCopyFiles("**/*", frameworkSrcDir, serverAppDir, context, true);
|
|
2777
|
-
if (context.api !== "none") {
|
|
2778
|
-
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);
|
|
2782
|
-
}
|
|
2783
2832
|
}
|
|
2784
|
-
async function
|
|
2785
|
-
if (context.backend === "
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2833
|
+
async function setupBackendFramework(projectDir, context) {
|
|
2834
|
+
if (context.backend === "none") return;
|
|
2835
|
+
if (context.backend === "convex") {
|
|
2836
|
+
await setupConvexBackend(projectDir, context);
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
if (context.backend === "self") {
|
|
2840
|
+
await setupApiPackage(projectDir, context);
|
|
2841
|
+
await setupDbPackage(projectDir, context);
|
|
2842
|
+
return;
|
|
2843
|
+
}
|
|
2844
|
+
await setupServerApp(projectDir, context);
|
|
2845
|
+
await setupApiPackage(projectDir, context);
|
|
2846
|
+
await setupDbPackage(projectDir, context);
|
|
2790
2847
|
}
|
|
2791
2848
|
async function setupAuthTemplate(projectDir, context) {
|
|
2792
2849
|
if (!context.auth || context.auth === "none") return;
|
|
@@ -2866,21 +2923,21 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2866
2923
|
}
|
|
2867
2924
|
return;
|
|
2868
2925
|
}
|
|
2869
|
-
if (serverAppDirExists && context.backend !== "convex") {
|
|
2926
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex") {
|
|
2927
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
2928
|
+
await fs.ensureDir(authPackageDir);
|
|
2870
2929
|
const authServerBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/base`);
|
|
2871
|
-
if (await fs.pathExists(authServerBaseSrc)) await processAndCopyFiles("**/*", authServerBaseSrc,
|
|
2872
|
-
if (context.backend === "next") {
|
|
2873
|
-
const authServerNextSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/next`);
|
|
2874
|
-
if (await fs.pathExists(authServerNextSrc)) await processAndCopyFiles("**/*", authServerNextSrc, serverAppDir, context);
|
|
2875
|
-
}
|
|
2930
|
+
if (await fs.pathExists(authServerBaseSrc)) await processAndCopyFiles("**/*", authServerBaseSrc, authPackageDir, context);
|
|
2876
2931
|
if (context.orm !== "none" && context.database !== "none") {
|
|
2932
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
2933
|
+
await fs.ensureDir(dbPackageDir);
|
|
2877
2934
|
const orm = context.orm;
|
|
2878
2935
|
const db = context.database;
|
|
2879
2936
|
let authDbSrc = "";
|
|
2880
2937
|
if (orm === "drizzle") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/drizzle/${db}`);
|
|
2881
2938
|
else if (orm === "prisma") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/prisma/${db}`);
|
|
2882
2939
|
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,
|
|
2940
|
+
if (authDbSrc && await fs.pathExists(authDbSrc)) await processAndCopyFiles("**/*", authDbSrc, dbPackageDir, context);
|
|
2884
2941
|
}
|
|
2885
2942
|
}
|
|
2886
2943
|
if ((hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) && webAppDirExists) {
|
|
@@ -2896,6 +2953,10 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2896
2953
|
if (reactFramework) {
|
|
2897
2954
|
const authWebFrameworkSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/react/${reactFramework}`);
|
|
2898
2955
|
if (await fs.pathExists(authWebFrameworkSrc)) await processAndCopyFiles("**/*", authWebFrameworkSrc, webAppDir, context);
|
|
2956
|
+
if (context.backend === "self" && reactFramework === "next") {
|
|
2957
|
+
const authFullstackSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/fullstack/next`);
|
|
2958
|
+
if (await fs.pathExists(authFullstackSrc)) await processAndCopyFiles("**/*", authFullstackSrc, webAppDir, context);
|
|
2959
|
+
}
|
|
2899
2960
|
}
|
|
2900
2961
|
} else if (hasNuxtWeb) {
|
|
2901
2962
|
const authWebNuxtSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/nuxt`);
|
|
@@ -2926,9 +2987,11 @@ async function setupPaymentsTemplate(projectDir, context) {
|
|
|
2926
2987
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
2927
2988
|
const serverAppDirExists = await fs.pathExists(serverAppDir);
|
|
2928
2989
|
const webAppDirExists = await fs.pathExists(webAppDir);
|
|
2929
|
-
if (serverAppDirExists && context.backend !== "convex") {
|
|
2990
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex") {
|
|
2991
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
2992
|
+
await fs.ensureDir(authPackageDir);
|
|
2930
2993
|
const paymentsServerSrc = path.join(PKG_ROOT, `templates/payments/${context.payments}/server/base`);
|
|
2931
|
-
if (await fs.pathExists(paymentsServerSrc)) await processAndCopyFiles("**/*", paymentsServerSrc,
|
|
2994
|
+
if (await fs.pathExists(paymentsServerSrc)) await processAndCopyFiles("**/*", paymentsServerSrc, authPackageDir, context);
|
|
2932
2995
|
}
|
|
2933
2996
|
const hasReactWeb = context.frontend.some((f) => [
|
|
2934
2997
|
"tanstack-router",
|
|
@@ -3004,17 +3067,19 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3004
3067
|
for (const example of context.examples) {
|
|
3005
3068
|
if (example === "none") continue;
|
|
3006
3069
|
const exampleBaseDir = path.join(PKG_ROOT, `templates/examples/${example}`);
|
|
3007
|
-
if (serverAppDirExists && context.backend !== "convex" && context.backend !== "none") {
|
|
3070
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex" && context.backend !== "none") {
|
|
3008
3071
|
const exampleServerSrc = path.join(exampleBaseDir, "server");
|
|
3009
|
-
if (
|
|
3010
|
-
const
|
|
3011
|
-
|
|
3072
|
+
if (context.api !== "none") {
|
|
3073
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
3074
|
+
await fs.ensureDir(apiPackageDir);
|
|
3075
|
+
const exampleOrmBaseSrc = path.join(exampleServerSrc, context.orm, "base");
|
|
3076
|
+
if (await fs.pathExists(exampleOrmBaseSrc)) await processAndCopyFiles("**/*", exampleOrmBaseSrc, apiPackageDir, context, false);
|
|
3012
3077
|
}
|
|
3013
3078
|
if (context.orm !== "none" && context.database !== "none") {
|
|
3014
|
-
const
|
|
3015
|
-
|
|
3079
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
3080
|
+
await fs.ensureDir(dbPackageDir);
|
|
3016
3081
|
const exampleDbSchemaSrc = path.join(exampleServerSrc, context.orm, context.database);
|
|
3017
|
-
if (await fs.pathExists(exampleDbSchemaSrc)) await processAndCopyFiles("**/*", exampleDbSchemaSrc,
|
|
3082
|
+
if (await fs.pathExists(exampleDbSchemaSrc)) await processAndCopyFiles("**/*", exampleDbSchemaSrc, dbPackageDir, context, false);
|
|
3018
3083
|
}
|
|
3019
3084
|
}
|
|
3020
3085
|
if (webAppDirExists) {
|
|
@@ -3034,6 +3099,10 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3034
3099
|
if (reactFramework) {
|
|
3035
3100
|
const exampleWebFrameworkSrc = path.join(exampleWebSrc, reactFramework);
|
|
3036
3101
|
if (await fs.pathExists(exampleWebFrameworkSrc)) await processAndCopyFiles("**/*", exampleWebFrameworkSrc, webAppDir, context, false);
|
|
3102
|
+
if (context.backend === "self" && reactFramework === "next") {
|
|
3103
|
+
const exampleFullstackSrc = path.join(exampleBaseDir, "fullstack/next");
|
|
3104
|
+
if (await fs.pathExists(exampleFullstackSrc)) await processAndCopyFiles("**/*", exampleFullstackSrc, webAppDir, context, false);
|
|
3105
|
+
}
|
|
3037
3106
|
}
|
|
3038
3107
|
}
|
|
3039
3108
|
} else if (hasNuxtWeb) {
|
|
@@ -3081,9 +3150,9 @@ async function handleExtras(projectDir, context) {
|
|
|
3081
3150
|
}
|
|
3082
3151
|
async function setupDockerComposeTemplates(projectDir, context) {
|
|
3083
3152
|
if (context.dbSetup !== "docker" || context.database === "none") return;
|
|
3084
|
-
const
|
|
3153
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
3085
3154
|
const dockerSrcDir = path.join(PKG_ROOT, `templates/db-setup/docker-compose/${context.database}`);
|
|
3086
|
-
if (await fs.pathExists(dockerSrcDir)) await processAndCopyFiles("**/*", dockerSrcDir,
|
|
3155
|
+
if (await fs.pathExists(dockerSrcDir)) await processAndCopyFiles("**/*", dockerSrcDir, dbPackageDir, context);
|
|
3087
3156
|
}
|
|
3088
3157
|
async function setupDeploymentTemplates(projectDir, context) {
|
|
3089
3158
|
if (context.webDeploy === "alchemy" || context.serverDeploy === "alchemy") if (context.webDeploy === "alchemy" && context.serverDeploy === "alchemy") {
|
|
@@ -3244,7 +3313,6 @@ async function setupAlchemyServerDeploy(serverDir, _packageManager) {
|
|
|
3244
3313
|
"alchemy",
|
|
3245
3314
|
"wrangler",
|
|
3246
3315
|
"@types/node",
|
|
3247
|
-
"dotenv",
|
|
3248
3316
|
"@cloudflare/workers-types"
|
|
3249
3317
|
],
|
|
3250
3318
|
projectDir: serverDir
|
|
@@ -3271,7 +3339,6 @@ async function setupNextAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3271
3339
|
dependencies: ["@opennextjs/cloudflare"],
|
|
3272
3340
|
devDependencies: [
|
|
3273
3341
|
"alchemy",
|
|
3274
|
-
"dotenv",
|
|
3275
3342
|
"wrangler",
|
|
3276
3343
|
"@cloudflare/workers-types"
|
|
3277
3344
|
],
|
|
@@ -3307,7 +3374,6 @@ async function setupNuxtAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3307
3374
|
devDependencies: [
|
|
3308
3375
|
"alchemy",
|
|
3309
3376
|
"nitro-cloudflare-dev",
|
|
3310
|
-
"dotenv",
|
|
3311
3377
|
"wrangler"
|
|
3312
3378
|
],
|
|
3313
3379
|
projectDir: webAppDir
|
|
@@ -3370,7 +3436,7 @@ async function setupReactRouterAlchemyDeploy(projectDir, _packageManager, option
|
|
|
3370
3436
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3371
3437
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3372
3438
|
await addPackageDependency({
|
|
3373
|
-
devDependencies: ["alchemy"
|
|
3439
|
+
devDependencies: ["alchemy"],
|
|
3374
3440
|
projectDir: webAppDir
|
|
3375
3441
|
});
|
|
3376
3442
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
@@ -3391,7 +3457,7 @@ async function setupSolidAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3391
3457
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3392
3458
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3393
3459
|
await addPackageDependency({
|
|
3394
|
-
devDependencies: ["alchemy"
|
|
3460
|
+
devDependencies: ["alchemy"],
|
|
3395
3461
|
projectDir: webAppDir
|
|
3396
3462
|
});
|
|
3397
3463
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
@@ -3412,11 +3478,7 @@ async function setupSvelteAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3412
3478
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3413
3479
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3414
3480
|
await addPackageDependency({
|
|
3415
|
-
devDependencies: [
|
|
3416
|
-
"alchemy",
|
|
3417
|
-
"@sveltejs/adapter-cloudflare",
|
|
3418
|
-
"dotenv"
|
|
3419
|
-
],
|
|
3481
|
+
devDependencies: ["alchemy", "@sveltejs/adapter-cloudflare"],
|
|
3420
3482
|
projectDir: webAppDir
|
|
3421
3483
|
});
|
|
3422
3484
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
@@ -3481,7 +3543,7 @@ async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager, opt
|
|
|
3481
3543
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3482
3544
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3483
3545
|
await addPackageDependency({
|
|
3484
|
-
devDependencies: ["alchemy"
|
|
3546
|
+
devDependencies: ["alchemy"],
|
|
3485
3547
|
projectDir: webAppDir
|
|
3486
3548
|
});
|
|
3487
3549
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
@@ -3502,11 +3564,7 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3502
3564
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3503
3565
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3504
3566
|
await addPackageDependency({
|
|
3505
|
-
devDependencies: [
|
|
3506
|
-
"alchemy",
|
|
3507
|
-
"dotenv",
|
|
3508
|
-
"@cloudflare/vite-plugin"
|
|
3509
|
-
],
|
|
3567
|
+
devDependencies: ["alchemy", "@cloudflare/vite-plugin"],
|
|
3510
3568
|
projectDir: webAppDir
|
|
3511
3569
|
});
|
|
3512
3570
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
@@ -3561,7 +3619,7 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3561
3619
|
//#region src/helpers/deployment/alchemy/alchemy-combined-setup.ts
|
|
3562
3620
|
async function setupCombinedAlchemyDeploy(projectDir, packageManager, config) {
|
|
3563
3621
|
await addPackageDependency({
|
|
3564
|
-
devDependencies: ["alchemy"
|
|
3622
|
+
devDependencies: ["alchemy"],
|
|
3565
3623
|
projectDir
|
|
3566
3624
|
});
|
|
3567
3625
|
const rootPkgPath = path.join(projectDir, "package.json");
|
|
@@ -3901,18 +3959,137 @@ async function addDeploymentToProject(input) {
|
|
|
3901
3959
|
}
|
|
3902
3960
|
}
|
|
3903
3961
|
|
|
3962
|
+
//#endregion
|
|
3963
|
+
//#region src/utils/setup-catalogs.ts
|
|
3964
|
+
async function setupCatalogs(projectDir, options) {
|
|
3965
|
+
if (options.packageManager === "npm") return;
|
|
3966
|
+
const packagePaths = [
|
|
3967
|
+
"apps/server",
|
|
3968
|
+
"apps/web",
|
|
3969
|
+
"packages/api",
|
|
3970
|
+
"packages/db",
|
|
3971
|
+
"packages/auth",
|
|
3972
|
+
"packages/backend"
|
|
3973
|
+
];
|
|
3974
|
+
const packagesInfo = [];
|
|
3975
|
+
for (const pkgPath of packagePaths) {
|
|
3976
|
+
const fullPath = path.join(projectDir, pkgPath);
|
|
3977
|
+
const pkgJsonPath = path.join(fullPath, "package.json");
|
|
3978
|
+
if (await fs.pathExists(pkgJsonPath)) {
|
|
3979
|
+
const pkgJson = await fs.readJson(pkgJsonPath);
|
|
3980
|
+
packagesInfo.push({
|
|
3981
|
+
path: fullPath,
|
|
3982
|
+
dependencies: pkgJson.dependencies || {},
|
|
3983
|
+
devDependencies: pkgJson.devDependencies || {}
|
|
3984
|
+
});
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
const catalog = findDuplicateDependencies(packagesInfo, options.projectName);
|
|
3988
|
+
if (Object.keys(catalog).length === 0) return;
|
|
3989
|
+
if (options.packageManager === "bun") await setupBunCatalogs(projectDir, catalog);
|
|
3990
|
+
else if (options.packageManager === "pnpm") await setupPnpmCatalogs(projectDir, catalog);
|
|
3991
|
+
await updatePackageJsonsWithCatalogs(packagesInfo, catalog);
|
|
3992
|
+
}
|
|
3993
|
+
function findDuplicateDependencies(packagesInfo, projectName) {
|
|
3994
|
+
const depCount = /* @__PURE__ */ new Map();
|
|
3995
|
+
const projectScope = `@${projectName}/`;
|
|
3996
|
+
for (const pkg of packagesInfo) {
|
|
3997
|
+
const allDeps = {
|
|
3998
|
+
...pkg.dependencies,
|
|
3999
|
+
...pkg.devDependencies
|
|
4000
|
+
};
|
|
4001
|
+
for (const [depName, version] of Object.entries(allDeps)) {
|
|
4002
|
+
if (depName.startsWith(projectScope)) continue;
|
|
4003
|
+
if (version.startsWith("workspace:")) continue;
|
|
4004
|
+
const existing = depCount.get(depName);
|
|
4005
|
+
if (existing) existing.packages.push(pkg.path);
|
|
4006
|
+
else depCount.set(depName, {
|
|
4007
|
+
version,
|
|
4008
|
+
packages: [pkg.path]
|
|
4009
|
+
});
|
|
4010
|
+
}
|
|
4011
|
+
}
|
|
4012
|
+
const catalog = {};
|
|
4013
|
+
for (const [depName, info] of depCount.entries()) if (info.packages.length > 1) catalog[depName] = info.version;
|
|
4014
|
+
return catalog;
|
|
4015
|
+
}
|
|
4016
|
+
async function setupBunCatalogs(projectDir, catalog) {
|
|
4017
|
+
const rootPkgJsonPath = path.join(projectDir, "package.json");
|
|
4018
|
+
const rootPkgJson = await fs.readJson(rootPkgJsonPath);
|
|
4019
|
+
if (!rootPkgJson.workspaces) rootPkgJson.workspaces = {};
|
|
4020
|
+
if (Array.isArray(rootPkgJson.workspaces)) rootPkgJson.workspaces = {
|
|
4021
|
+
packages: rootPkgJson.workspaces,
|
|
4022
|
+
catalog
|
|
4023
|
+
};
|
|
4024
|
+
else if (typeof rootPkgJson.workspaces === "object") {
|
|
4025
|
+
if (!rootPkgJson.workspaces.catalog) rootPkgJson.workspaces.catalog = {};
|
|
4026
|
+
rootPkgJson.workspaces.catalog = {
|
|
4027
|
+
...rootPkgJson.workspaces.catalog,
|
|
4028
|
+
...catalog
|
|
4029
|
+
};
|
|
4030
|
+
}
|
|
4031
|
+
await fs.writeJson(rootPkgJsonPath, rootPkgJson, { spaces: 2 });
|
|
4032
|
+
}
|
|
4033
|
+
async function setupPnpmCatalogs(projectDir, catalog) {
|
|
4034
|
+
const workspaceYamlPath = path.join(projectDir, "pnpm-workspace.yaml");
|
|
4035
|
+
if (!await fs.pathExists(workspaceYamlPath)) return;
|
|
4036
|
+
const workspaceContent = await fs.readFile(workspaceYamlPath, "utf-8");
|
|
4037
|
+
const workspaceYaml = yaml.parse(workspaceContent);
|
|
4038
|
+
if (!workspaceYaml.catalog) workspaceYaml.catalog = {};
|
|
4039
|
+
workspaceYaml.catalog = {
|
|
4040
|
+
...workspaceYaml.catalog,
|
|
4041
|
+
...catalog
|
|
4042
|
+
};
|
|
4043
|
+
await fs.writeFile(workspaceYamlPath, yaml.stringify(workspaceYaml));
|
|
4044
|
+
}
|
|
4045
|
+
async function updatePackageJsonsWithCatalogs(packagesInfo, catalog) {
|
|
4046
|
+
for (const pkg of packagesInfo) {
|
|
4047
|
+
const pkgJsonPath = path.join(pkg.path, "package.json");
|
|
4048
|
+
const pkgJson = await fs.readJson(pkgJsonPath);
|
|
4049
|
+
let updated = false;
|
|
4050
|
+
if (pkgJson.dependencies) {
|
|
4051
|
+
for (const depName of Object.keys(pkgJson.dependencies)) if (catalog[depName]) {
|
|
4052
|
+
pkgJson.dependencies[depName] = "catalog:";
|
|
4053
|
+
updated = true;
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
if (pkgJson.devDependencies) {
|
|
4057
|
+
for (const depName of Object.keys(pkgJson.devDependencies)) if (catalog[depName]) {
|
|
4058
|
+
pkgJson.devDependencies[depName] = "catalog:";
|
|
4059
|
+
updated = true;
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
if (updated) await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
|
|
3904
4066
|
//#endregion
|
|
3905
4067
|
//#region src/helpers/addons/examples-setup.ts
|
|
3906
4068
|
async function setupExamples(config) {
|
|
3907
|
-
const { examples, frontend, backend, projectDir } = config;
|
|
4069
|
+
const { examples, frontend, backend, projectDir, orm } = config;
|
|
3908
4070
|
if (backend === "convex" || !examples || examples.length === 0 || examples[0] === "none") return;
|
|
4071
|
+
const apiDir = path.join(projectDir, "packages/api");
|
|
4072
|
+
if (await fs.pathExists(apiDir) && backend !== "none") {
|
|
4073
|
+
if (orm === "drizzle") await addPackageDependency({
|
|
4074
|
+
dependencies: ["drizzle-orm"],
|
|
4075
|
+
projectDir: apiDir
|
|
4076
|
+
});
|
|
4077
|
+
else if (orm === "prisma") await addPackageDependency({
|
|
4078
|
+
dependencies: ["@prisma/client"],
|
|
4079
|
+
projectDir: apiDir
|
|
4080
|
+
});
|
|
4081
|
+
else if (orm === "mongoose") await addPackageDependency({
|
|
4082
|
+
dependencies: ["mongoose"],
|
|
4083
|
+
projectDir: apiDir
|
|
4084
|
+
});
|
|
4085
|
+
}
|
|
3909
4086
|
if (examples.includes("ai")) {
|
|
3910
4087
|
const webClientDir = path.join(projectDir, "apps/web");
|
|
3911
4088
|
const nativeClientDir = path.join(projectDir, "apps/native");
|
|
3912
|
-
const
|
|
4089
|
+
const apiDir$1 = path.join(projectDir, "packages/api");
|
|
3913
4090
|
const webClientDirExists = await fs.pathExists(webClientDir);
|
|
3914
4091
|
const nativeClientDirExists = await fs.pathExists(nativeClientDir);
|
|
3915
|
-
const
|
|
4092
|
+
const apiDirExists = await fs.pathExists(apiDir$1);
|
|
3916
4093
|
const hasNuxt = frontend.includes("nuxt");
|
|
3917
4094
|
const hasSvelte = frontend.includes("svelte");
|
|
3918
4095
|
const hasReactWeb = frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("next") || frontend.includes("tanstack-start");
|
|
@@ -3933,9 +4110,13 @@ async function setupExamples(config) {
|
|
|
3933
4110
|
dependencies: ["ai", "@ai-sdk/react"],
|
|
3934
4111
|
projectDir: nativeClientDir
|
|
3935
4112
|
});
|
|
3936
|
-
if (
|
|
4113
|
+
if (apiDirExists && backend !== "none") await addPackageDependency({
|
|
3937
4114
|
dependencies: ["ai", "@ai-sdk/google"],
|
|
3938
|
-
projectDir:
|
|
4115
|
+
projectDir: apiDir$1
|
|
4116
|
+
});
|
|
4117
|
+
if (backend === "self" && webClientDirExists) await addPackageDependency({
|
|
4118
|
+
dependencies: ["ai", "@ai-sdk/google"],
|
|
4119
|
+
projectDir: webClientDir
|
|
3939
4120
|
});
|
|
3940
4121
|
}
|
|
3941
4122
|
}
|
|
@@ -4051,32 +4232,61 @@ function getConvexDependencies(frontend) {
|
|
|
4051
4232
|
return deps;
|
|
4052
4233
|
}
|
|
4053
4234
|
async function setupApi(config) {
|
|
4054
|
-
const { api, projectName, frontend, backend, packageManager, projectDir } = config;
|
|
4235
|
+
const { api, projectName, frontend, backend, packageManager, projectDir, auth } = config;
|
|
4055
4236
|
const isConvex = backend === "convex";
|
|
4056
4237
|
const webDir = path.join(projectDir, "apps/web");
|
|
4057
4238
|
const nativeDir = path.join(projectDir, "apps/native");
|
|
4058
4239
|
const serverDir = path.join(projectDir, "apps/server");
|
|
4059
4240
|
const webDirExists = await fs.pathExists(webDir);
|
|
4060
4241
|
const nativeDirExists = await fs.pathExists(nativeDir);
|
|
4061
|
-
|
|
4242
|
+
await fs.pathExists(serverDir);
|
|
4062
4243
|
const frontendType = getFrontendType(frontend);
|
|
4063
4244
|
if (!isConvex && api !== "none") {
|
|
4064
4245
|
const apiDeps = getApiDependencies(api, frontendType);
|
|
4065
|
-
|
|
4246
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
4247
|
+
if (apiDeps.server) {
|
|
4066
4248
|
await addPackageDependency({
|
|
4067
4249
|
dependencies: apiDeps.server.dependencies,
|
|
4068
|
-
projectDir:
|
|
4250
|
+
projectDir: apiPackageDir
|
|
4251
|
+
});
|
|
4252
|
+
if (backend === "self" && webDirExists) await addPackageDependency({
|
|
4253
|
+
dependencies: apiDeps.server.dependencies,
|
|
4254
|
+
projectDir: webDir
|
|
4255
|
+
});
|
|
4256
|
+
const frameworkDeps = [];
|
|
4257
|
+
if (backend === "hono") frameworkDeps.push("hono");
|
|
4258
|
+
else if (backend === "elysia") frameworkDeps.push("elysia");
|
|
4259
|
+
else if (backend === "express") frameworkDeps.push("express", "@types/express");
|
|
4260
|
+
else if (backend === "fastify") frameworkDeps.push("fastify");
|
|
4261
|
+
else if (backend === "self") {
|
|
4262
|
+
if (frontend.includes("next")) frameworkDeps.push("next");
|
|
4263
|
+
}
|
|
4264
|
+
if (frameworkDeps.length > 0) await addPackageDependency({
|
|
4265
|
+
dependencies: frameworkDeps,
|
|
4266
|
+
projectDir: apiPackageDir
|
|
4069
4267
|
});
|
|
4070
4268
|
if (api === "trpc") {
|
|
4071
4269
|
if (backend === "hono") await addPackageDependency({
|
|
4072
4270
|
dependencies: ["@hono/trpc-server"],
|
|
4073
|
-
projectDir:
|
|
4271
|
+
projectDir: apiPackageDir
|
|
4074
4272
|
});
|
|
4075
4273
|
else if (backend === "elysia") await addPackageDependency({
|
|
4076
4274
|
dependencies: ["@elysiajs/trpc"],
|
|
4077
|
-
projectDir:
|
|
4275
|
+
projectDir: apiPackageDir
|
|
4276
|
+
});
|
|
4277
|
+
else if (backend === "express") await addPackageDependency({
|
|
4278
|
+
dependencies: ["@trpc/server"],
|
|
4279
|
+
projectDir: apiPackageDir
|
|
4280
|
+
});
|
|
4281
|
+
else if (backend === "fastify") await addPackageDependency({
|
|
4282
|
+
dependencies: ["@trpc/server"],
|
|
4283
|
+
projectDir: apiPackageDir
|
|
4078
4284
|
});
|
|
4079
4285
|
}
|
|
4286
|
+
if (auth === "better-auth") await addPackageDependency({
|
|
4287
|
+
dependencies: ["better-auth"],
|
|
4288
|
+
projectDir: apiPackageDir
|
|
4289
|
+
});
|
|
4080
4290
|
}
|
|
4081
4291
|
if (webDirExists && apiDeps.web) await addPackageDependency({
|
|
4082
4292
|
dependencies: apiDeps.web.dependencies,
|
|
@@ -4120,7 +4330,7 @@ async function setupApi(config) {
|
|
|
4120
4330
|
//#endregion
|
|
4121
4331
|
//#region src/helpers/core/backend-setup.ts
|
|
4122
4332
|
async function setupBackendDependencies(config) {
|
|
4123
|
-
const { backend, runtime, api, projectDir } = config;
|
|
4333
|
+
const { backend, runtime, api, auth, examples, projectDir } = config;
|
|
4124
4334
|
if (backend === "convex") return;
|
|
4125
4335
|
const framework = backend;
|
|
4126
4336
|
const serverDir = path.join(projectDir, "apps/server");
|
|
@@ -4148,6 +4358,13 @@ async function setupBackendDependencies(config) {
|
|
|
4148
4358
|
dependencies.push("fastify", "@fastify/cors");
|
|
4149
4359
|
if (runtime === "node") devDependencies.push("tsx", "@types/node");
|
|
4150
4360
|
}
|
|
4361
|
+
if (api === "trpc") {
|
|
4362
|
+
if (framework === "express") dependencies.push("@trpc/server");
|
|
4363
|
+
else if (framework === "fastify") dependencies.push("@trpc/server");
|
|
4364
|
+
else if (runtime === "workers") dependencies.push("@trpc/server");
|
|
4365
|
+
} else if (api === "orpc") dependencies.push("@orpc/server", "@orpc/openapi", "@orpc/zod");
|
|
4366
|
+
if (auth === "better-auth") dependencies.push("better-auth");
|
|
4367
|
+
if (examples.includes("ai")) dependencies.push("ai", "@ai-sdk/google");
|
|
4151
4368
|
if (runtime === "bun") devDependencies.push("@types/bun");
|
|
4152
4369
|
if (dependencies.length > 0 || devDependencies.length > 0) await addPackageDependency({
|
|
4153
4370
|
dependencies,
|
|
@@ -4166,7 +4383,7 @@ async function setupAuth(config) {
|
|
|
4166
4383
|
const nativeDir = path.join(projectDir, "apps/native");
|
|
4167
4384
|
const clientDirExists = await fs.pathExists(clientDir);
|
|
4168
4385
|
const nativeDirExists = await fs.pathExists(nativeDir);
|
|
4169
|
-
|
|
4386
|
+
await fs.pathExists(serverDir);
|
|
4170
4387
|
try {
|
|
4171
4388
|
if (backend === "convex") {
|
|
4172
4389
|
if (auth === "clerk" && clientDirExists) {
|
|
@@ -4222,9 +4439,11 @@ async function setupAuth(config) {
|
|
|
4222
4439
|
});
|
|
4223
4440
|
return;
|
|
4224
4441
|
}
|
|
4225
|
-
|
|
4442
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
4443
|
+
const authPackageDirExists = await fs.pathExists(authPackageDir);
|
|
4444
|
+
if (authPackageDirExists && auth === "better-auth") await addPackageDependency({
|
|
4226
4445
|
dependencies: ["better-auth"],
|
|
4227
|
-
projectDir:
|
|
4446
|
+
projectDir: authPackageDir
|
|
4228
4447
|
});
|
|
4229
4448
|
if (frontend.some((f) => [
|
|
4230
4449
|
"react-router",
|
|
@@ -4246,9 +4465,9 @@ async function setupAuth(config) {
|
|
|
4246
4465
|
dependencies: ["better-auth", "@better-auth/expo"],
|
|
4247
4466
|
projectDir: nativeDir
|
|
4248
4467
|
});
|
|
4249
|
-
if (
|
|
4468
|
+
if (authPackageDirExists) await addPackageDependency({
|
|
4250
4469
|
dependencies: ["@better-auth/expo"],
|
|
4251
|
-
projectDir:
|
|
4470
|
+
projectDir: authPackageDir
|
|
4252
4471
|
});
|
|
4253
4472
|
}
|
|
4254
4473
|
}
|
|
@@ -4267,6 +4486,34 @@ function generateAuthSecret(length = 32) {
|
|
|
4267
4486
|
|
|
4268
4487
|
//#endregion
|
|
4269
4488
|
//#region src/helpers/core/env-setup.ts
|
|
4489
|
+
function getClientServerVar(frontend, backend) {
|
|
4490
|
+
const hasNextJs = frontend.includes("next");
|
|
4491
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
4492
|
+
const hasSvelte = frontend.includes("svelte");
|
|
4493
|
+
if (backend === "self") return {
|
|
4494
|
+
key: "",
|
|
4495
|
+
value: "",
|
|
4496
|
+
write: false
|
|
4497
|
+
};
|
|
4498
|
+
let key = "VITE_SERVER_URL";
|
|
4499
|
+
if (hasNextJs) key = "NEXT_PUBLIC_SERVER_URL";
|
|
4500
|
+
else if (hasNuxt) key = "NUXT_PUBLIC_SERVER_URL";
|
|
4501
|
+
else if (hasSvelte) key = "PUBLIC_SERVER_URL";
|
|
4502
|
+
return {
|
|
4503
|
+
key,
|
|
4504
|
+
value: "http://localhost:3000",
|
|
4505
|
+
write: true
|
|
4506
|
+
};
|
|
4507
|
+
}
|
|
4508
|
+
function getConvexVar(frontend) {
|
|
4509
|
+
const hasNextJs = frontend.includes("next");
|
|
4510
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
4511
|
+
const hasSvelte = frontend.includes("svelte");
|
|
4512
|
+
if (hasNextJs) return "NEXT_PUBLIC_CONVEX_URL";
|
|
4513
|
+
if (hasNuxt) return "NUXT_PUBLIC_CONVEX_URL";
|
|
4514
|
+
if (hasSvelte) return "PUBLIC_CONVEX_URL";
|
|
4515
|
+
return "VITE_CONVEX_URL";
|
|
4516
|
+
}
|
|
4270
4517
|
async function addEnvVariablesToFile(filePath, variables) {
|
|
4271
4518
|
await fs.ensureDir(path.dirname(filePath));
|
|
4272
4519
|
let envContent = "";
|
|
@@ -4325,22 +4572,13 @@ async function setupEnvironmentVariables(config) {
|
|
|
4325
4572
|
if (hasReactRouter || hasTanStackRouter || hasTanStackStart || hasNextJs || hasNuxt || hasSolid || hasSvelte) {
|
|
4326
4573
|
const clientDir = path.join(projectDir, "apps/web");
|
|
4327
4574
|
if (await fs.pathExists(clientDir)) {
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
else if (hasNuxt) envVarName = "NUXT_PUBLIC_SERVER_URL";
|
|
4332
|
-
else if (hasSvelte) envVarName = "PUBLIC_SERVER_URL";
|
|
4333
|
-
if (backend === "convex") {
|
|
4334
|
-
if (hasNextJs) envVarName = "NEXT_PUBLIC_CONVEX_URL";
|
|
4335
|
-
else if (hasNuxt) envVarName = "NUXT_PUBLIC_CONVEX_URL";
|
|
4336
|
-
else if (hasSvelte) envVarName = "PUBLIC_CONVEX_URL";
|
|
4337
|
-
else envVarName = "VITE_CONVEX_URL";
|
|
4338
|
-
serverUrl = "https://<YOUR_CONVEX_URL>";
|
|
4339
|
-
}
|
|
4575
|
+
const baseVar = getClientServerVar(frontend, backend);
|
|
4576
|
+
const envVarName = backend === "convex" ? getConvexVar(frontend) : baseVar.key;
|
|
4577
|
+
const serverUrl = backend === "convex" ? "https://<YOUR_CONVEX_URL>" : baseVar.value;
|
|
4340
4578
|
const clientVars = [{
|
|
4341
4579
|
key: envVarName,
|
|
4342
4580
|
value: serverUrl,
|
|
4343
|
-
condition: true
|
|
4581
|
+
condition: backend === "convex" ? true : baseVar.write
|
|
4344
4582
|
}];
|
|
4345
4583
|
if (backend === "convex" && auth === "clerk") {
|
|
4346
4584
|
if (hasNextJs) clientVars.push({
|
|
@@ -4431,10 +4669,9 @@ async function setupEnvironmentVariables(config) {
|
|
|
4431
4669
|
return;
|
|
4432
4670
|
}
|
|
4433
4671
|
const serverDir = path.join(projectDir, "apps/server");
|
|
4434
|
-
if (!await fs.pathExists(serverDir)) return;
|
|
4435
|
-
const envPath = path.join(serverDir, ".env");
|
|
4436
4672
|
let corsOrigin = "http://localhost:3001";
|
|
4437
|
-
if (
|
|
4673
|
+
if (backend === "self") corsOrigin = "http://localhost:3001";
|
|
4674
|
+
else if (hasReactRouter || hasSvelte) corsOrigin = "http://localhost:5173";
|
|
4438
4675
|
let databaseUrl = null;
|
|
4439
4676
|
if (database !== "none" && dbSetup === "none") switch (database) {
|
|
4440
4677
|
case "postgres":
|
|
@@ -4448,15 +4685,13 @@ async function setupEnvironmentVariables(config) {
|
|
|
4448
4685
|
break;
|
|
4449
4686
|
case "sqlite":
|
|
4450
4687
|
if (config.runtime === "workers") databaseUrl = "http://127.0.0.1:8080";
|
|
4451
|
-
else
|
|
4688
|
+
else {
|
|
4689
|
+
const dbAppDir = backend === "self" ? "apps/web" : "apps/server";
|
|
4690
|
+
databaseUrl = `file:${path.join(config.projectDir, dbAppDir, "local.db")}`;
|
|
4691
|
+
}
|
|
4452
4692
|
break;
|
|
4453
4693
|
}
|
|
4454
4694
|
const serverVars = [
|
|
4455
|
-
{
|
|
4456
|
-
key: "CORS_ORIGIN",
|
|
4457
|
-
value: corsOrigin,
|
|
4458
|
-
condition: true
|
|
4459
|
-
},
|
|
4460
4695
|
{
|
|
4461
4696
|
key: "BETTER_AUTH_SECRET",
|
|
4462
4697
|
value: generateAuthSecret(),
|
|
@@ -4464,19 +4699,9 @@ async function setupEnvironmentVariables(config) {
|
|
|
4464
4699
|
},
|
|
4465
4700
|
{
|
|
4466
4701
|
key: "BETTER_AUTH_URL",
|
|
4467
|
-
value: "http://localhost:3000",
|
|
4702
|
+
value: backend === "self" ? "http://localhost:3001" : "http://localhost:3000",
|
|
4468
4703
|
condition: !!auth
|
|
4469
4704
|
},
|
|
4470
|
-
{
|
|
4471
|
-
key: "DATABASE_URL",
|
|
4472
|
-
value: databaseUrl,
|
|
4473
|
-
condition: database !== "none" && dbSetup === "none"
|
|
4474
|
-
},
|
|
4475
|
-
{
|
|
4476
|
-
key: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
4477
|
-
value: "",
|
|
4478
|
-
condition: examples?.includes("ai") || false
|
|
4479
|
-
},
|
|
4480
4705
|
{
|
|
4481
4706
|
key: "POLAR_ACCESS_TOKEN",
|
|
4482
4707
|
value: "",
|
|
@@ -4486,9 +4711,27 @@ async function setupEnvironmentVariables(config) {
|
|
|
4486
4711
|
key: "POLAR_SUCCESS_URL",
|
|
4487
4712
|
value: `${corsOrigin}/success?checkout_id={CHECKOUT_ID}`,
|
|
4488
4713
|
condition: config.payments === "polar"
|
|
4714
|
+
},
|
|
4715
|
+
{
|
|
4716
|
+
key: "CORS_ORIGIN",
|
|
4717
|
+
value: corsOrigin,
|
|
4718
|
+
condition: true
|
|
4719
|
+
},
|
|
4720
|
+
{
|
|
4721
|
+
key: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
4722
|
+
value: "",
|
|
4723
|
+
condition: examples?.includes("ai") || false
|
|
4724
|
+
},
|
|
4725
|
+
{
|
|
4726
|
+
key: "DATABASE_URL",
|
|
4727
|
+
value: databaseUrl,
|
|
4728
|
+
condition: database !== "none" && dbSetup === "none"
|
|
4489
4729
|
}
|
|
4490
4730
|
];
|
|
4491
|
-
|
|
4731
|
+
if (backend === "self") {
|
|
4732
|
+
const webDir = path.join(projectDir, "apps/web");
|
|
4733
|
+
if (await fs.pathExists(webDir)) await addEnvVariablesToFile(path.join(webDir, ".env"), serverVars);
|
|
4734
|
+
} else if (await fs.pathExists(serverDir)) await addEnvVariablesToFile(path.join(serverDir, ".env"), serverVars);
|
|
4492
4735
|
const isUnifiedAlchemy = webDeploy === "alchemy" && serverDeploy === "alchemy";
|
|
4493
4736
|
const isIndividualAlchemy = webDeploy === "alchemy" || serverDeploy === "alchemy";
|
|
4494
4737
|
if (isUnifiedAlchemy) {
|
|
@@ -4508,12 +4751,15 @@ async function setupEnvironmentVariables(config) {
|
|
|
4508
4751
|
}]);
|
|
4509
4752
|
}
|
|
4510
4753
|
if (serverDeploy === "alchemy") {
|
|
4511
|
-
const
|
|
4512
|
-
if (await fs.pathExists(serverDir$1)) await addEnvVariablesToFile(path.join(serverDir$1, ".env"), [{
|
|
4754
|
+
const serverAlchemyVars = [{
|
|
4513
4755
|
key: "ALCHEMY_PASSWORD",
|
|
4514
4756
|
value: "please-change-this",
|
|
4515
4757
|
condition: true
|
|
4516
|
-
}]
|
|
4758
|
+
}];
|
|
4759
|
+
if (backend === "self") {
|
|
4760
|
+
const webDir = path.join(projectDir, "apps/web");
|
|
4761
|
+
if (await fs.pathExists(webDir)) await addEnvVariablesToFile(path.join(webDir, ".env"), serverAlchemyVars);
|
|
4762
|
+
} else await addEnvVariablesToFile(path.join(serverDir, ".env"), serverAlchemyVars);
|
|
4517
4763
|
}
|
|
4518
4764
|
}
|
|
4519
4765
|
}
|
|
@@ -4521,9 +4767,10 @@ async function setupEnvironmentVariables(config) {
|
|
|
4521
4767
|
//#endregion
|
|
4522
4768
|
//#region src/helpers/database-providers/d1-setup.ts
|
|
4523
4769
|
async function setupCloudflareD1(config) {
|
|
4524
|
-
const { projectDir, serverDeploy, orm } = config;
|
|
4770
|
+
const { projectDir, serverDeploy, orm, backend } = config;
|
|
4525
4771
|
if (serverDeploy === "wrangler") {
|
|
4526
|
-
const
|
|
4772
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
4773
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4527
4774
|
const variables = [
|
|
4528
4775
|
{
|
|
4529
4776
|
key: "CLOUDFLARE_ACCOUNT_ID",
|
|
@@ -4546,16 +4793,17 @@ async function setupCloudflareD1(config) {
|
|
|
4546
4793
|
} catch (_err) {}
|
|
4547
4794
|
}
|
|
4548
4795
|
if ((serverDeploy === "wrangler" || serverDeploy === "alchemy") && orm === "prisma") {
|
|
4549
|
-
const
|
|
4796
|
+
const targetApp2 = backend === "self" ? "apps/web" : "apps/server";
|
|
4797
|
+
const envPath = path.join(projectDir, targetApp2, ".env");
|
|
4550
4798
|
const variables = [{
|
|
4551
4799
|
key: "DATABASE_URL",
|
|
4552
|
-
value: "
|
|
4800
|
+
value: `file:${path.join(projectDir, "apps/server", "local.db")}`,
|
|
4553
4801
|
condition: true
|
|
4554
4802
|
}];
|
|
4555
4803
|
try {
|
|
4556
4804
|
await addEnvVariablesToFile(envPath, variables);
|
|
4557
4805
|
} catch (_err) {}
|
|
4558
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
4806
|
+
const serverDir = path.join(projectDir, backend === "self" ? "apps/web" : "apps/server");
|
|
4559
4807
|
await addPackageDependency({
|
|
4560
4808
|
dependencies: ["@prisma/adapter-d1"],
|
|
4561
4809
|
projectDir: serverDir
|
|
@@ -4606,14 +4854,13 @@ async function commandExists(command) {
|
|
|
4606
4854
|
//#endregion
|
|
4607
4855
|
//#region src/helpers/database-providers/mongodb-atlas-setup.ts
|
|
4608
4856
|
async function checkAtlasCLI() {
|
|
4609
|
-
const s = spinner();
|
|
4610
|
-
s.start("Checking for MongoDB Atlas CLI...");
|
|
4611
4857
|
try {
|
|
4612
4858
|
const exists = await commandExists("atlas");
|
|
4613
|
-
|
|
4859
|
+
if (exists) log.info("MongoDB Atlas CLI found");
|
|
4860
|
+
else log.warn(pc.yellow("MongoDB Atlas CLI not found"));
|
|
4614
4861
|
return exists;
|
|
4615
4862
|
} catch (_error) {
|
|
4616
|
-
|
|
4863
|
+
log.error(pc.red("Error checking MongoDB Atlas CLI"));
|
|
4617
4864
|
return false;
|
|
4618
4865
|
}
|
|
4619
4866
|
}
|
|
@@ -4624,12 +4871,13 @@ async function initMongoDBAtlas(serverDir) {
|
|
|
4624
4871
|
log.info(pc.yellow("Please install it from: https://www.mongodb.com/docs/atlas/cli/current/install-atlas-cli/"));
|
|
4625
4872
|
return null;
|
|
4626
4873
|
}
|
|
4627
|
-
log.info(
|
|
4874
|
+
log.info("Running MongoDB Atlas setup...");
|
|
4628
4875
|
await execa("atlas", ["deployments", "setup"], {
|
|
4629
4876
|
cwd: serverDir,
|
|
4877
|
+
shell: true,
|
|
4630
4878
|
stdio: "inherit"
|
|
4631
4879
|
});
|
|
4632
|
-
log.
|
|
4880
|
+
log.success("MongoDB Atlas deployment ready");
|
|
4633
4881
|
const connectionString = await text({
|
|
4634
4882
|
message: "Enter your MongoDB connection string:",
|
|
4635
4883
|
placeholder: "mongodb+srv://username:password@cluster.mongodb.net/database",
|
|
@@ -4648,9 +4896,10 @@ async function initMongoDBAtlas(serverDir) {
|
|
|
4648
4896
|
return null;
|
|
4649
4897
|
}
|
|
4650
4898
|
}
|
|
4651
|
-
async function writeEnvFile$3(projectDir, config) {
|
|
4899
|
+
async function writeEnvFile$3(projectDir, backend, config) {
|
|
4652
4900
|
try {
|
|
4653
|
-
const
|
|
4901
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
4902
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4654
4903
|
const variables = [{
|
|
4655
4904
|
key: "DATABASE_URL",
|
|
4656
4905
|
value: config?.connectionString ?? "mongodb://localhost:27017/mydb",
|
|
@@ -4679,16 +4928,14 @@ ${pc.green("MongoDB Atlas Manual Setup Instructions:")}
|
|
|
4679
4928
|
`);
|
|
4680
4929
|
}
|
|
4681
4930
|
async function setupMongoDBAtlas(config, cliInput) {
|
|
4682
|
-
const { projectDir } = config;
|
|
4931
|
+
const { projectDir, backend } = config;
|
|
4683
4932
|
const manualDb = cliInput?.manualDb ?? false;
|
|
4684
|
-
const
|
|
4685
|
-
mainSpinner.start("Setting up MongoDB Atlas...");
|
|
4686
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
4933
|
+
const serverDir = path.join(projectDir, "packages/db");
|
|
4687
4934
|
try {
|
|
4688
4935
|
await fs.ensureDir(serverDir);
|
|
4689
4936
|
if (manualDb) {
|
|
4690
|
-
|
|
4691
|
-
await writeEnvFile$3(projectDir);
|
|
4937
|
+
log.info("MongoDB Atlas manual setup selected");
|
|
4938
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4692
4939
|
displayManualSetupInstructions$3();
|
|
4693
4940
|
return;
|
|
4694
4941
|
}
|
|
@@ -4707,26 +4954,24 @@ async function setupMongoDBAtlas(config, cliInput) {
|
|
|
4707
4954
|
});
|
|
4708
4955
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
4709
4956
|
if (mode === "manual") {
|
|
4710
|
-
|
|
4711
|
-
await writeEnvFile$3(projectDir);
|
|
4957
|
+
log.info("MongoDB Atlas manual setup selected");
|
|
4958
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4712
4959
|
displayManualSetupInstructions$3();
|
|
4713
4960
|
return;
|
|
4714
4961
|
}
|
|
4715
|
-
mainSpinner.stop("MongoDB Atlas setup ready");
|
|
4716
4962
|
const config$1 = await initMongoDBAtlas(serverDir);
|
|
4717
4963
|
if (config$1) {
|
|
4718
|
-
await writeEnvFile$3(projectDir, config$1);
|
|
4964
|
+
await writeEnvFile$3(projectDir, backend, config$1);
|
|
4719
4965
|
log.success(pc.green("MongoDB Atlas setup complete! Connection saved to .env file."));
|
|
4720
4966
|
} else {
|
|
4721
4967
|
log.warn(pc.yellow("Falling back to local MongoDB configuration"));
|
|
4722
|
-
await writeEnvFile$3(projectDir);
|
|
4968
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4723
4969
|
displayManualSetupInstructions$3();
|
|
4724
4970
|
}
|
|
4725
4971
|
} catch (error) {
|
|
4726
|
-
mainSpinner.stop(pc.red("MongoDB Atlas setup failed"));
|
|
4727
4972
|
consola.error(pc.red(`Error during MongoDB Atlas setup: ${error instanceof Error ? error.message : String(error)}`));
|
|
4728
4973
|
try {
|
|
4729
|
-
await writeEnvFile$3(projectDir);
|
|
4974
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4730
4975
|
displayManualSetupInstructions$3();
|
|
4731
4976
|
} catch {}
|
|
4732
4977
|
}
|
|
@@ -4783,7 +5028,7 @@ async function executeNeonCommand(packageManager, commandArgsString, spinnerText
|
|
|
4783
5028
|
}
|
|
4784
5029
|
async function createNeonProject(projectName, regionId, packageManager) {
|
|
4785
5030
|
try {
|
|
4786
|
-
const commandArgsString = `neonctl projects create --name ${projectName} --region-id ${regionId} --output json`;
|
|
5031
|
+
const commandArgsString = `neonctl@latest projects create --name ${projectName} --region-id ${regionId} --output json`;
|
|
4787
5032
|
const { stdout } = await executeNeonCommand(packageManager, commandArgsString, `Creating Neon project "${projectName}"...`);
|
|
4788
5033
|
const response = JSON.parse(stdout);
|
|
4789
5034
|
if (response.project && response.connection_uris && response.connection_uris.length > 0) {
|
|
@@ -4803,8 +5048,9 @@ async function createNeonProject(projectName, regionId, packageManager) {
|
|
|
4803
5048
|
consola$1.error(pc.red("Failed to create Neon project"));
|
|
4804
5049
|
}
|
|
4805
5050
|
}
|
|
4806
|
-
async function writeEnvFile$2(projectDir, config) {
|
|
4807
|
-
const
|
|
5051
|
+
async function writeEnvFile$2(projectDir, backend, config) {
|
|
5052
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5053
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4808
5054
|
const variables = [{
|
|
4809
5055
|
key: "DATABASE_URL",
|
|
4810
5056
|
value: config?.connectionString ?? "postgresql://postgres:postgres@localhost:5432/mydb?schema=public",
|
|
@@ -4813,16 +5059,17 @@ async function writeEnvFile$2(projectDir, config) {
|
|
|
4813
5059
|
await addEnvVariablesToFile(envPath, variables);
|
|
4814
5060
|
return true;
|
|
4815
5061
|
}
|
|
4816
|
-
async function setupWithNeonDb(projectDir, packageManager) {
|
|
5062
|
+
async function setupWithNeonDb(projectDir, packageManager, backend) {
|
|
4817
5063
|
try {
|
|
4818
5064
|
const s = spinner();
|
|
4819
5065
|
s.start("Creating Neon database using neondb...");
|
|
4820
|
-
const
|
|
4821
|
-
|
|
4822
|
-
|
|
5066
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5067
|
+
const targetDir = path.join(projectDir, targetApp);
|
|
5068
|
+
await fs.ensureDir(targetDir);
|
|
5069
|
+
const packageCmd = getPackageExecutionCommand(packageManager, "neondb@latest --yes");
|
|
4823
5070
|
await execa(packageCmd, {
|
|
4824
5071
|
shell: true,
|
|
4825
|
-
cwd:
|
|
5072
|
+
cwd: targetDir
|
|
4826
5073
|
});
|
|
4827
5074
|
s.stop(pc.green("Neon database created successfully!"));
|
|
4828
5075
|
return true;
|
|
@@ -4831,23 +5078,23 @@ async function setupWithNeonDb(projectDir, packageManager) {
|
|
|
4831
5078
|
throw error;
|
|
4832
5079
|
}
|
|
4833
5080
|
}
|
|
4834
|
-
function displayManualSetupInstructions$2() {
|
|
5081
|
+
function displayManualSetupInstructions$2(target) {
|
|
4835
5082
|
log.info(`Manual Neon PostgreSQL Setup Instructions:
|
|
4836
5083
|
|
|
4837
5084
|
1. Visit https://neon.tech and create an account
|
|
4838
5085
|
2. Create a new project from the dashboard
|
|
4839
5086
|
3. Get your connection string
|
|
4840
|
-
4. Add the database URL to the .env file in
|
|
5087
|
+
4. Add the database URL to the .env file in ${target}/.env
|
|
4841
5088
|
|
|
4842
5089
|
DATABASE_URL="your_connection_string"`);
|
|
4843
5090
|
}
|
|
4844
5091
|
async function setupNeonPostgres(config, cliInput) {
|
|
4845
|
-
const { packageManager, projectDir } = config;
|
|
5092
|
+
const { packageManager, projectDir, backend } = config;
|
|
4846
5093
|
const manualDb = cliInput?.manualDb ?? false;
|
|
4847
5094
|
try {
|
|
4848
5095
|
if (manualDb) {
|
|
4849
|
-
await writeEnvFile$2(projectDir);
|
|
4850
|
-
displayManualSetupInstructions$2();
|
|
5096
|
+
await writeEnvFile$2(projectDir, backend);
|
|
5097
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
4851
5098
|
return;
|
|
4852
5099
|
}
|
|
4853
5100
|
const mode = await select({
|
|
@@ -4865,8 +5112,8 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
4865
5112
|
});
|
|
4866
5113
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
4867
5114
|
if (mode === "manual") {
|
|
4868
|
-
await writeEnvFile$2(projectDir);
|
|
4869
|
-
displayManualSetupInstructions$2();
|
|
5115
|
+
await writeEnvFile$2(projectDir, backend);
|
|
5116
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
4870
5117
|
return;
|
|
4871
5118
|
}
|
|
4872
5119
|
const setupMethod = await select({
|
|
@@ -4883,7 +5130,7 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
4883
5130
|
initialValue: "neondb"
|
|
4884
5131
|
});
|
|
4885
5132
|
if (isCancel(setupMethod)) return exitCancelled("Operation cancelled");
|
|
4886
|
-
if (setupMethod === "neondb") await setupWithNeonDb(projectDir, packageManager);
|
|
5133
|
+
if (setupMethod === "neondb") await setupWithNeonDb(projectDir, packageManager, backend);
|
|
4887
5134
|
else {
|
|
4888
5135
|
const suggestedProjectName = path.basename(projectDir);
|
|
4889
5136
|
const projectName = await text({
|
|
@@ -4901,22 +5148,22 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
4901
5148
|
if (!neonConfig) throw new Error("Failed to create project - couldn't get connection information");
|
|
4902
5149
|
const finalSpinner = spinner();
|
|
4903
5150
|
finalSpinner.start("Configuring database connection");
|
|
4904
|
-
await
|
|
4905
|
-
await writeEnvFile$2(projectDir, neonConfig);
|
|
5151
|
+
await writeEnvFile$2(projectDir, backend, neonConfig);
|
|
4906
5152
|
finalSpinner.stop("Neon database configured!");
|
|
4907
5153
|
}
|
|
4908
5154
|
} catch (error) {
|
|
4909
5155
|
if (error instanceof Error) consola$1.error(pc.red(error.message));
|
|
4910
|
-
await writeEnvFile$2(projectDir);
|
|
4911
|
-
displayManualSetupInstructions$2();
|
|
5156
|
+
await writeEnvFile$2(projectDir, backend);
|
|
5157
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
4912
5158
|
}
|
|
4913
5159
|
}
|
|
4914
5160
|
|
|
4915
5161
|
//#endregion
|
|
4916
5162
|
//#region src/helpers/database-providers/planetscale-setup.ts
|
|
4917
5163
|
async function setupPlanetScale(config) {
|
|
4918
|
-
const { projectDir, database, orm } = config;
|
|
4919
|
-
const
|
|
5164
|
+
const { projectDir, database, orm, backend } = config;
|
|
5165
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5166
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4920
5167
|
if (database === "mysql" && orm === "drizzle") {
|
|
4921
5168
|
const variables = [
|
|
4922
5169
|
{
|
|
@@ -4940,7 +5187,7 @@ async function setupPlanetScale(config) {
|
|
|
4940
5187
|
condition: true
|
|
4941
5188
|
}
|
|
4942
5189
|
];
|
|
4943
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5190
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
4944
5191
|
await addEnvVariablesToFile(envPath, variables);
|
|
4945
5192
|
}
|
|
4946
5193
|
if (database === "postgres" && orm === "prisma") {
|
|
@@ -4949,7 +5196,7 @@ async function setupPlanetScale(config) {
|
|
|
4949
5196
|
value: "postgresql://username:password@host/database?sslaccept=strict",
|
|
4950
5197
|
condition: true
|
|
4951
5198
|
}];
|
|
4952
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5199
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
4953
5200
|
await addEnvVariablesToFile(envPath, variables);
|
|
4954
5201
|
}
|
|
4955
5202
|
if (database === "postgres" && orm === "drizzle") {
|
|
@@ -4958,7 +5205,7 @@ async function setupPlanetScale(config) {
|
|
|
4958
5205
|
value: "postgresql://username:password@host/database?sslmode=verify-full",
|
|
4959
5206
|
condition: true
|
|
4960
5207
|
}];
|
|
4961
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5208
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
4962
5209
|
await addEnvVariablesToFile(envPath, variables);
|
|
4963
5210
|
}
|
|
4964
5211
|
if (database === "mysql" && orm === "prisma") {
|
|
@@ -4967,7 +5214,7 @@ async function setupPlanetScale(config) {
|
|
|
4967
5214
|
value: "mysql://username:password@host/database?sslaccept=strict",
|
|
4968
5215
|
condition: true
|
|
4969
5216
|
}];
|
|
4970
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5217
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
4971
5218
|
await addEnvVariablesToFile(envPath, variables);
|
|
4972
5219
|
}
|
|
4973
5220
|
}
|
|
@@ -5037,7 +5284,7 @@ async function initPrismaDatabase(serverDir, packageManager) {
|
|
|
5037
5284
|
try {
|
|
5038
5285
|
const prismaDir = path.join(serverDir, "prisma");
|
|
5039
5286
|
await fs.ensureDir(prismaDir);
|
|
5040
|
-
log.info("Starting Prisma PostgreSQL setup.
|
|
5287
|
+
log.info("Starting Prisma PostgreSQL setup.");
|
|
5041
5288
|
const prismaInitCommand = getPackageExecutionCommand(packageManager, "prisma init --db");
|
|
5042
5289
|
await execa(prismaInitCommand, {
|
|
5043
5290
|
cwd: serverDir,
|
|
@@ -5059,9 +5306,10 @@ async function initPrismaDatabase(serverDir, packageManager) {
|
|
|
5059
5306
|
return null;
|
|
5060
5307
|
}
|
|
5061
5308
|
}
|
|
5062
|
-
async function writeEnvFile$1(projectDir, config) {
|
|
5309
|
+
async function writeEnvFile$1(projectDir, backend, config) {
|
|
5063
5310
|
try {
|
|
5064
|
-
const
|
|
5311
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5312
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5065
5313
|
const variables = [{
|
|
5066
5314
|
key: "DATABASE_URL",
|
|
5067
5315
|
value: config?.databaseUrl ?? "postgresql://postgres:postgres@localhost:5432/mydb?schema=public",
|
|
@@ -5077,31 +5325,32 @@ async function writeEnvFile$1(projectDir, config) {
|
|
|
5077
5325
|
consola$1.error("Failed to update environment configuration");
|
|
5078
5326
|
}
|
|
5079
5327
|
}
|
|
5080
|
-
async function addDotenvImportToPrismaConfig(projectDir) {
|
|
5328
|
+
async function addDotenvImportToPrismaConfig(projectDir, backend) {
|
|
5081
5329
|
try {
|
|
5082
|
-
const prismaConfigPath = path.join(projectDir, "
|
|
5330
|
+
const prismaConfigPath = path.join(projectDir, "packages/db/prisma.config.ts");
|
|
5083
5331
|
let content = await fs.readFile(prismaConfigPath, "utf8");
|
|
5084
|
-
content = `import "dotenv
|
|
5332
|
+
content = `import dotenv from "dotenv";\ndotenv.config({ path: "${backend === "self" ? "../../apps/web/.env" : "../../apps/server/.env"}" });\n${content}`;
|
|
5085
5333
|
await fs.writeFile(prismaConfigPath, content);
|
|
5086
5334
|
} catch (_error) {
|
|
5087
5335
|
consola$1.error("Failed to update prisma.config.ts");
|
|
5088
5336
|
}
|
|
5089
5337
|
}
|
|
5090
|
-
function displayManualSetupInstructions$1() {
|
|
5338
|
+
function displayManualSetupInstructions$1(target) {
|
|
5091
5339
|
log.info(`Manual Prisma PostgreSQL Setup Instructions:
|
|
5092
5340
|
|
|
5093
5341
|
1. Visit https://console.prisma.io and create an account
|
|
5094
5342
|
2. Create a new PostgreSQL database from the dashboard
|
|
5095
5343
|
3. Get your database URL
|
|
5096
|
-
4. Add the database URL to the .env file in
|
|
5344
|
+
4. Add the database URL to the .env file in ${target}/.env
|
|
5097
5345
|
|
|
5098
5346
|
DATABASE_URL="your_database_url"`);
|
|
5099
5347
|
}
|
|
5100
|
-
async function addPrismaAccelerateExtension(
|
|
5348
|
+
async function addPrismaAccelerateExtension(projectDir) {
|
|
5101
5349
|
try {
|
|
5350
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
5102
5351
|
await addPackageDependency({
|
|
5103
5352
|
dependencies: ["@prisma/extension-accelerate"],
|
|
5104
|
-
projectDir:
|
|
5353
|
+
projectDir: dbPackageDir
|
|
5105
5354
|
});
|
|
5106
5355
|
return true;
|
|
5107
5356
|
} catch (_error) {
|
|
@@ -5110,14 +5359,14 @@ async function addPrismaAccelerateExtension(serverDir) {
|
|
|
5110
5359
|
}
|
|
5111
5360
|
}
|
|
5112
5361
|
async function setupPrismaPostgres(config, cliInput) {
|
|
5113
|
-
const { packageManager, projectDir, orm } = config;
|
|
5362
|
+
const { packageManager, projectDir, orm, backend } = config;
|
|
5114
5363
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5115
|
-
const
|
|
5364
|
+
const dbDir = path.join(projectDir, "packages/db");
|
|
5116
5365
|
try {
|
|
5117
|
-
await fs.ensureDir(
|
|
5366
|
+
await fs.ensureDir(dbDir);
|
|
5118
5367
|
if (manualDb) {
|
|
5119
|
-
await writeEnvFile$1(projectDir);
|
|
5120
|
-
displayManualSetupInstructions$1();
|
|
5368
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5369
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5121
5370
|
return;
|
|
5122
5371
|
}
|
|
5123
5372
|
const mode = await select({
|
|
@@ -5135,8 +5384,8 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5135
5384
|
});
|
|
5136
5385
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5137
5386
|
if (mode === "manual") {
|
|
5138
|
-
await writeEnvFile$1(projectDir);
|
|
5139
|
-
displayManualSetupInstructions$1();
|
|
5387
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5388
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5140
5389
|
return;
|
|
5141
5390
|
}
|
|
5142
5391
|
const setupOptions = [{
|
|
@@ -5156,26 +5405,26 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5156
5405
|
});
|
|
5157
5406
|
if (isCancel(setupMethod)) return exitCancelled("Operation cancelled");
|
|
5158
5407
|
let prismaConfig = null;
|
|
5159
|
-
if (setupMethod === "create-db") prismaConfig = await setupWithCreateDb(
|
|
5160
|
-
else prismaConfig = await initPrismaDatabase(
|
|
5408
|
+
if (setupMethod === "create-db") prismaConfig = await setupWithCreateDb(dbDir, packageManager, orm);
|
|
5409
|
+
else prismaConfig = await initPrismaDatabase(dbDir, packageManager);
|
|
5161
5410
|
if (prismaConfig) {
|
|
5162
|
-
await writeEnvFile$1(projectDir, prismaConfig);
|
|
5411
|
+
await writeEnvFile$1(projectDir, backend, prismaConfig);
|
|
5163
5412
|
if (orm === "prisma") {
|
|
5164
|
-
await addDotenvImportToPrismaConfig(projectDir);
|
|
5165
|
-
await addPrismaAccelerateExtension(
|
|
5413
|
+
await addDotenvImportToPrismaConfig(projectDir, backend);
|
|
5414
|
+
await addPrismaAccelerateExtension(projectDir);
|
|
5166
5415
|
}
|
|
5167
5416
|
const connectionType = orm === "drizzle" ? "direct connection" : "Prisma Accelerate";
|
|
5168
5417
|
log.success(pc.green(`Prisma Postgres database configured successfully with ${connectionType}!`));
|
|
5169
5418
|
if (prismaConfig.claimUrl) log.info(pc.blue(`Claim URL saved to .env: ${prismaConfig.claimUrl}`));
|
|
5170
5419
|
} else {
|
|
5171
|
-
await writeEnvFile$1(projectDir);
|
|
5172
|
-
displayManualSetupInstructions$1();
|
|
5420
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5421
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5173
5422
|
}
|
|
5174
5423
|
} catch (error) {
|
|
5175
5424
|
consola$1.error(pc.red(`Error during Prisma Postgres setup: ${error instanceof Error ? error.message : String(error)}`));
|
|
5176
5425
|
try {
|
|
5177
|
-
await writeEnvFile$1(projectDir);
|
|
5178
|
-
displayManualSetupInstructions$1();
|
|
5426
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5427
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5179
5428
|
} catch {}
|
|
5180
5429
|
log.info("Setup completed with manual configuration required.");
|
|
5181
5430
|
}
|
|
@@ -5183,9 +5432,10 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5183
5432
|
|
|
5184
5433
|
//#endregion
|
|
5185
5434
|
//#region src/helpers/database-providers/supabase-setup.ts
|
|
5186
|
-
async function writeSupabaseEnvFile(projectDir, databaseUrl) {
|
|
5435
|
+
async function writeSupabaseEnvFile(projectDir, backend, databaseUrl) {
|
|
5187
5436
|
try {
|
|
5188
|
-
const
|
|
5437
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5438
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5189
5439
|
const dbUrlToUse = databaseUrl || "postgresql://postgres:postgres@127.0.0.1:54322/postgres";
|
|
5190
5440
|
await addEnvVariablesToFile(envPath, [{
|
|
5191
5441
|
key: "DATABASE_URL",
|
|
@@ -5262,23 +5512,23 @@ function displayManualSupabaseInstructions(output) {
|
|
|
5262
5512
|
log.info(`"Manual Supabase Setup Instructions:"
|
|
5263
5513
|
1. Ensure Docker is installed and running.
|
|
5264
5514
|
2. Install the Supabase CLI (e.g., \`npm install -g supabase\`).
|
|
5265
|
-
3. Run \`supabase init\` in your project's \`
|
|
5266
|
-
4. Run \`supabase start\` in your project's \`
|
|
5515
|
+
3. Run \`supabase init\` in your project's \`packages/db\` directory.
|
|
5516
|
+
4. Run \`supabase start\` in your project's \`packages/db\` directory.
|
|
5267
5517
|
5. Copy the 'DB URL' from the output.${output ? `
|
|
5268
5518
|
${pc.bold("Relevant output from `supabase start`:")}
|
|
5269
5519
|
${pc.dim(output)}` : ""}
|
|
5270
|
-
6. Add the DB URL to the .env file in \`
|
|
5520
|
+
6. Add the DB URL to the .env file in \`packages/db/.env\` as \`DATABASE_URL\`:
|
|
5271
5521
|
${pc.gray("DATABASE_URL=\"your_supabase_db_url\"")}`);
|
|
5272
5522
|
}
|
|
5273
5523
|
async function setupSupabase(config, cliInput) {
|
|
5274
|
-
const { projectDir, packageManager } = config;
|
|
5524
|
+
const { projectDir, packageManager, backend } = config;
|
|
5275
5525
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5276
|
-
const serverDir = path.join(projectDir, "
|
|
5526
|
+
const serverDir = path.join(projectDir, "packages", "db");
|
|
5277
5527
|
try {
|
|
5278
5528
|
await fs.ensureDir(serverDir);
|
|
5279
5529
|
if (manualDb) {
|
|
5280
5530
|
displayManualSupabaseInstructions();
|
|
5281
|
-
await writeSupabaseEnvFile(projectDir, "");
|
|
5531
|
+
await writeSupabaseEnvFile(projectDir, backend, "");
|
|
5282
5532
|
return;
|
|
5283
5533
|
}
|
|
5284
5534
|
const mode = await select({
|
|
@@ -5297,7 +5547,7 @@ async function setupSupabase(config, cliInput) {
|
|
|
5297
5547
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5298
5548
|
if (mode === "manual") {
|
|
5299
5549
|
displayManualSupabaseInstructions();
|
|
5300
|
-
await writeSupabaseEnvFile(projectDir, "");
|
|
5550
|
+
await writeSupabaseEnvFile(projectDir, backend, "");
|
|
5301
5551
|
return;
|
|
5302
5552
|
}
|
|
5303
5553
|
if (!await initializeSupabase(serverDir, packageManager)) {
|
|
@@ -5310,7 +5560,7 @@ async function setupSupabase(config, cliInput) {
|
|
|
5310
5560
|
return;
|
|
5311
5561
|
}
|
|
5312
5562
|
const dbUrl = extractDbUrl(supabaseOutput);
|
|
5313
|
-
if (dbUrl) if (await writeSupabaseEnvFile(projectDir, dbUrl)) log.success(pc.green("Supabase local development setup ready!"));
|
|
5563
|
+
if (dbUrl) if (await writeSupabaseEnvFile(projectDir, backend, dbUrl)) log.success(pc.green("Supabase local development setup ready!"));
|
|
5314
5564
|
else {
|
|
5315
5565
|
log.error(pc.red("Supabase setup completed, but failed to update .env automatically."));
|
|
5316
5566
|
displayManualSupabaseInstructions(supabaseOutput);
|
|
@@ -5438,8 +5688,9 @@ async function createTursoDatabase(dbName, groupName) {
|
|
|
5438
5688
|
s.stop(pc.red("Failed to retrieve database connection details"));
|
|
5439
5689
|
}
|
|
5440
5690
|
}
|
|
5441
|
-
async function writeEnvFile(projectDir, config) {
|
|
5442
|
-
const
|
|
5691
|
+
async function writeEnvFile(projectDir, backend, config) {
|
|
5692
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5693
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5443
5694
|
const variables = [{
|
|
5444
5695
|
key: "DATABASE_URL",
|
|
5445
5696
|
value: config?.dbUrl ?? "",
|
|
@@ -5463,12 +5714,12 @@ DATABASE_URL=your_database_url
|
|
|
5463
5714
|
DATABASE_AUTH_TOKEN=your_auth_token`);
|
|
5464
5715
|
}
|
|
5465
5716
|
async function setupTurso(config, cliInput) {
|
|
5466
|
-
const { orm, projectDir } = config;
|
|
5717
|
+
const { orm, projectDir, backend } = config;
|
|
5467
5718
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5468
5719
|
const setupSpinner = spinner();
|
|
5469
5720
|
try {
|
|
5470
5721
|
if (manualDb) {
|
|
5471
|
-
await writeEnvFile(projectDir);
|
|
5722
|
+
await writeEnvFile(projectDir, backend);
|
|
5472
5723
|
displayManualSetupInstructions();
|
|
5473
5724
|
return;
|
|
5474
5725
|
}
|
|
@@ -5487,7 +5738,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5487
5738
|
});
|
|
5488
5739
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5489
5740
|
if (mode === "manual") {
|
|
5490
|
-
await writeEnvFile(projectDir);
|
|
5741
|
+
await writeEnvFile(projectDir, backend);
|
|
5491
5742
|
displayManualSetupInstructions();
|
|
5492
5743
|
return;
|
|
5493
5744
|
}
|
|
@@ -5497,7 +5748,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5497
5748
|
if (platform === "win32") {
|
|
5498
5749
|
if (setupSpinner) setupSpinner.stop(pc.yellow("Turso setup not supported on Windows"));
|
|
5499
5750
|
log.warn(pc.yellow("Automatic Turso setup is not supported on Windows."));
|
|
5500
|
-
await writeEnvFile(projectDir);
|
|
5751
|
+
await writeEnvFile(projectDir, backend);
|
|
5501
5752
|
displayManualSetupInstructions();
|
|
5502
5753
|
return;
|
|
5503
5754
|
}
|
|
@@ -5509,7 +5760,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5509
5760
|
});
|
|
5510
5761
|
if (isCancel(shouldInstall)) return exitCancelled("Operation cancelled");
|
|
5511
5762
|
if (!shouldInstall) {
|
|
5512
|
-
await writeEnvFile(projectDir);
|
|
5763
|
+
await writeEnvFile(projectDir, backend);
|
|
5513
5764
|
displayManualSetupInstructions();
|
|
5514
5765
|
return;
|
|
5515
5766
|
}
|
|
@@ -5531,7 +5782,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5531
5782
|
dbName = dbNameResponse;
|
|
5532
5783
|
try {
|
|
5533
5784
|
const config$1 = await createTursoDatabase(dbName, selectedGroup);
|
|
5534
|
-
await writeEnvFile(projectDir, config$1);
|
|
5785
|
+
await writeEnvFile(projectDir, backend, config$1);
|
|
5535
5786
|
success = true;
|
|
5536
5787
|
} catch (error) {
|
|
5537
5788
|
if (error instanceof Error && error.message === "DATABASE_EXISTS") {
|
|
@@ -5544,7 +5795,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5544
5795
|
} catch (error) {
|
|
5545
5796
|
if (setupSpinner) setupSpinner.stop(pc.red("Turso CLI availability check failed"));
|
|
5546
5797
|
consola.error(pc.red(`Error during Turso setup: ${error instanceof Error ? error.message : String(error)}`));
|
|
5547
|
-
await writeEnvFile(projectDir);
|
|
5798
|
+
await writeEnvFile(projectDir, backend);
|
|
5548
5799
|
displayManualSetupInstructions();
|
|
5549
5800
|
log.success("Setup completed with manual configuration required.");
|
|
5550
5801
|
}
|
|
@@ -5556,40 +5807,48 @@ async function setupDatabase(config, cliInput) {
|
|
|
5556
5807
|
const { database, orm, dbSetup, backend, projectDir } = config;
|
|
5557
5808
|
if (backend === "convex" || database === "none") {
|
|
5558
5809
|
if (backend !== "convex") {
|
|
5559
|
-
const serverDir
|
|
5560
|
-
const serverDbDir = path.join(serverDir
|
|
5810
|
+
const serverDir = path.join(projectDir, "apps/server");
|
|
5811
|
+
const serverDbDir = path.join(serverDir, "src/db");
|
|
5561
5812
|
if (await fs.pathExists(serverDbDir)) await fs.remove(serverDbDir);
|
|
5562
5813
|
}
|
|
5563
5814
|
return;
|
|
5564
5815
|
}
|
|
5565
5816
|
const s = spinner();
|
|
5566
|
-
const
|
|
5567
|
-
if (!await fs.pathExists(
|
|
5817
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
5818
|
+
if (!await fs.pathExists(dbPackageDir)) return;
|
|
5568
5819
|
try {
|
|
5569
|
-
if (orm === "prisma")
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5820
|
+
if (orm === "prisma") {
|
|
5821
|
+
if (database === "mysql" && dbSetup === "planetscale") await addPackageDependency({
|
|
5822
|
+
dependencies: [
|
|
5823
|
+
"@prisma/client",
|
|
5824
|
+
"@prisma/adapter-planetscale",
|
|
5825
|
+
"@planetscale/database"
|
|
5826
|
+
],
|
|
5827
|
+
devDependencies: ["prisma"],
|
|
5828
|
+
projectDir: dbPackageDir
|
|
5829
|
+
});
|
|
5830
|
+
else if (database === "sqlite" && dbSetup === "turso") await addPackageDependency({
|
|
5831
|
+
dependencies: ["@prisma/client", "@prisma/adapter-libsql"],
|
|
5832
|
+
devDependencies: ["prisma"],
|
|
5833
|
+
projectDir: dbPackageDir
|
|
5834
|
+
});
|
|
5835
|
+
else await addPackageDependency({
|
|
5836
|
+
dependencies: ["@prisma/client"],
|
|
5837
|
+
devDependencies: ["prisma"],
|
|
5838
|
+
projectDir: dbPackageDir
|
|
5839
|
+
});
|
|
5840
|
+
if (backend === "self") {
|
|
5841
|
+
const webDir = path.join(projectDir, "apps/web");
|
|
5842
|
+
if (await fs.pathExists(webDir)) await addPackageDependency({
|
|
5843
|
+
dependencies: ["@prisma/client"],
|
|
5844
|
+
projectDir: webDir
|
|
5845
|
+
});
|
|
5846
|
+
}
|
|
5847
|
+
} else if (orm === "drizzle") {
|
|
5589
5848
|
if (database === "sqlite") await addPackageDependency({
|
|
5590
5849
|
dependencies: ["drizzle-orm", "@libsql/client"],
|
|
5591
5850
|
devDependencies: ["drizzle-kit"],
|
|
5592
|
-
projectDir:
|
|
5851
|
+
projectDir: dbPackageDir
|
|
5593
5852
|
});
|
|
5594
5853
|
else if (database === "postgres") if (dbSetup === "neon") await addPackageDependency({
|
|
5595
5854
|
dependencies: [
|
|
@@ -5598,32 +5857,32 @@ async function setupDatabase(config, cliInput) {
|
|
|
5598
5857
|
"ws"
|
|
5599
5858
|
],
|
|
5600
5859
|
devDependencies: ["drizzle-kit", "@types/ws"],
|
|
5601
|
-
projectDir:
|
|
5860
|
+
projectDir: dbPackageDir
|
|
5602
5861
|
});
|
|
5603
5862
|
else if (dbSetup === "planetscale") await addPackageDependency({
|
|
5604
5863
|
dependencies: ["drizzle-orm", "pg"],
|
|
5605
5864
|
devDependencies: ["drizzle-kit", "@types/pg"],
|
|
5606
|
-
projectDir:
|
|
5865
|
+
projectDir: dbPackageDir
|
|
5607
5866
|
});
|
|
5608
5867
|
else await addPackageDependency({
|
|
5609
5868
|
dependencies: ["drizzle-orm", "pg"],
|
|
5610
5869
|
devDependencies: ["drizzle-kit", "@types/pg"],
|
|
5611
|
-
projectDir:
|
|
5870
|
+
projectDir: dbPackageDir
|
|
5612
5871
|
});
|
|
5613
5872
|
else if (database === "mysql") if (dbSetup === "planetscale") await addPackageDependency({
|
|
5614
5873
|
dependencies: ["drizzle-orm", "@planetscale/database"],
|
|
5615
5874
|
devDependencies: ["drizzle-kit"],
|
|
5616
|
-
projectDir:
|
|
5875
|
+
projectDir: dbPackageDir
|
|
5617
5876
|
});
|
|
5618
5877
|
else await addPackageDependency({
|
|
5619
5878
|
dependencies: ["drizzle-orm", "mysql2"],
|
|
5620
5879
|
devDependencies: ["drizzle-kit"],
|
|
5621
|
-
projectDir:
|
|
5880
|
+
projectDir: dbPackageDir
|
|
5622
5881
|
});
|
|
5623
5882
|
} else if (orm === "mongoose") await addPackageDependency({
|
|
5624
5883
|
dependencies: ["mongoose"],
|
|
5625
5884
|
devDependencies: [],
|
|
5626
|
-
projectDir:
|
|
5885
|
+
projectDir: dbPackageDir
|
|
5627
5886
|
});
|
|
5628
5887
|
if (dbSetup === "docker") await setupDockerCompose(config);
|
|
5629
5888
|
else if (database === "sqlite" && dbSetup === "turso") await setupTurso(config, cliInput);
|
|
@@ -5646,7 +5905,7 @@ async function setupDatabase(config, cliInput) {
|
|
|
5646
5905
|
//#region src/helpers/core/runtime-setup.ts
|
|
5647
5906
|
async function setupRuntime(config) {
|
|
5648
5907
|
const { runtime, backend, projectDir } = config;
|
|
5649
|
-
if (backend === "convex" || backend === "
|
|
5908
|
+
if (backend === "convex" || backend === "self" || runtime === "none") return;
|
|
5650
5909
|
const serverDir = path.join(projectDir, "apps/server");
|
|
5651
5910
|
if (!await fs.pathExists(serverDir)) return;
|
|
5652
5911
|
if (runtime === "bun") await setupBunRuntime(serverDir, backend);
|
|
@@ -6035,15 +6294,14 @@ async function initializeGit(projectDir, useGit) {
|
|
|
6035
6294
|
async function setupPayments(config) {
|
|
6036
6295
|
const { payments, projectDir, frontend } = config;
|
|
6037
6296
|
if (!payments || payments === "none") return;
|
|
6038
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
6039
6297
|
const clientDir = path.join(projectDir, "apps/web");
|
|
6040
|
-
const
|
|
6298
|
+
const authDir = path.join(projectDir, "packages/auth");
|
|
6041
6299
|
const clientDirExists = await fs.pathExists(clientDir);
|
|
6042
|
-
|
|
6300
|
+
const authDirExists = await fs.pathExists(authDir);
|
|
6043
6301
|
if (payments === "polar") {
|
|
6044
|
-
await addPackageDependency({
|
|
6302
|
+
if (authDirExists) await addPackageDependency({
|
|
6045
6303
|
dependencies: ["@polar-sh/better-auth", "@polar-sh/sdk"],
|
|
6046
|
-
projectDir:
|
|
6304
|
+
projectDir: authDir
|
|
6047
6305
|
});
|
|
6048
6306
|
if (clientDirExists) {
|
|
6049
6307
|
if (frontend.some((f) => [
|
|
@@ -6166,7 +6424,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6166
6424
|
else if (!hasNative && !addons?.includes("starlight")) output += `${pc.yellow("NOTE:")} You are creating a backend-only app\n (no frontend selected)\n`;
|
|
6167
6425
|
if (!isConvex) {
|
|
6168
6426
|
output += `${pc.cyan("•")} Backend API: http://localhost:3000\n`;
|
|
6169
|
-
if (api === "orpc") if (backend === "
|
|
6427
|
+
if (api === "orpc") if (backend === "self") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/rpc/api\n`;
|
|
6170
6428
|
else output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/api\n`;
|
|
6171
6429
|
}
|
|
6172
6430
|
if (addons?.includes("starlight")) output += `${pc.cyan("•")} Docs: http://localhost:4321\n`;
|
|
@@ -6280,12 +6538,81 @@ function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy) {
|
|
|
6280
6538
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
6281
6539
|
}
|
|
6282
6540
|
|
|
6541
|
+
//#endregion
|
|
6542
|
+
//#region src/helpers/core/workspace-setup.ts
|
|
6543
|
+
async function setupWorkspaceDependencies(projectDir, options) {
|
|
6544
|
+
const projectName = options.projectName;
|
|
6545
|
+
const workspaceVersion = options.packageManager === "npm" ? "*" : "workspace:*";
|
|
6546
|
+
const commonDeps = ["dotenv", "zod"];
|
|
6547
|
+
const commonDevDeps = ["tsdown"];
|
|
6548
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
6549
|
+
if (await fs.pathExists(dbPackageDir)) await addPackageDependency({
|
|
6550
|
+
dependencies: commonDeps,
|
|
6551
|
+
devDependencies: commonDevDeps,
|
|
6552
|
+
projectDir: dbPackageDir
|
|
6553
|
+
});
|
|
6554
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
6555
|
+
if (await fs.pathExists(authPackageDir)) await addPackageDependency({
|
|
6556
|
+
dependencies: commonDeps,
|
|
6557
|
+
devDependencies: commonDevDeps,
|
|
6558
|
+
customDependencies: { [`@${projectName}/db`]: workspaceVersion },
|
|
6559
|
+
projectDir: authPackageDir
|
|
6560
|
+
});
|
|
6561
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
6562
|
+
if (await fs.pathExists(apiPackageDir)) await addPackageDependency({
|
|
6563
|
+
dependencies: commonDeps,
|
|
6564
|
+
devDependencies: commonDevDeps,
|
|
6565
|
+
customDependencies: {
|
|
6566
|
+
[`@${projectName}/auth`]: workspaceVersion,
|
|
6567
|
+
[`@${projectName}/db`]: workspaceVersion
|
|
6568
|
+
},
|
|
6569
|
+
projectDir: apiPackageDir
|
|
6570
|
+
});
|
|
6571
|
+
const serverPackageDir = path.join(projectDir, "apps/server");
|
|
6572
|
+
if (await fs.pathExists(serverPackageDir)) await addPackageDependency({
|
|
6573
|
+
dependencies: commonDeps,
|
|
6574
|
+
devDependencies: commonDevDeps,
|
|
6575
|
+
customDependencies: {
|
|
6576
|
+
[`@${projectName}/api`]: workspaceVersion,
|
|
6577
|
+
[`@${projectName}/auth`]: workspaceVersion,
|
|
6578
|
+
[`@${projectName}/db`]: workspaceVersion
|
|
6579
|
+
},
|
|
6580
|
+
projectDir: serverPackageDir
|
|
6581
|
+
});
|
|
6582
|
+
const webPackageDir = path.join(projectDir, "apps/web");
|
|
6583
|
+
if (await fs.pathExists(webPackageDir)) {
|
|
6584
|
+
const webDeps = {};
|
|
6585
|
+
webDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6586
|
+
webDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
6587
|
+
webDeps[`@${projectName}/db`] = workspaceVersion;
|
|
6588
|
+
if (Object.keys(webDeps).length > 0) await addPackageDependency({
|
|
6589
|
+
customDependencies: webDeps,
|
|
6590
|
+
projectDir: webPackageDir
|
|
6591
|
+
});
|
|
6592
|
+
}
|
|
6593
|
+
await addPackageDependency({
|
|
6594
|
+
dependencies: commonDeps,
|
|
6595
|
+
devDependencies: commonDevDeps,
|
|
6596
|
+
projectDir
|
|
6597
|
+
});
|
|
6598
|
+
}
|
|
6599
|
+
|
|
6283
6600
|
//#endregion
|
|
6284
6601
|
//#region src/helpers/core/project-config.ts
|
|
6285
6602
|
async function updatePackageConfigurations(projectDir, options) {
|
|
6286
6603
|
await updateRootPackageJson(projectDir, options);
|
|
6287
|
-
if (options.backend
|
|
6288
|
-
else
|
|
6604
|
+
if (options.backend === "convex") await updateConvexPackageJson(projectDir, options);
|
|
6605
|
+
else if (options.backend === "self") {
|
|
6606
|
+
await updateDbPackageJson(projectDir, options);
|
|
6607
|
+
await updateAuthPackageJson(projectDir, options);
|
|
6608
|
+
await updateApiPackageJson(projectDir, options);
|
|
6609
|
+
await setupWorkspaceDependencies(projectDir, options);
|
|
6610
|
+
} else if (options.backend !== "none") {
|
|
6611
|
+
await updateServerPackageJson(projectDir, options);
|
|
6612
|
+
await updateAuthPackageJson(projectDir, options);
|
|
6613
|
+
await updateApiPackageJson(projectDir, options);
|
|
6614
|
+
await setupWorkspaceDependencies(projectDir, options);
|
|
6615
|
+
}
|
|
6289
6616
|
}
|
|
6290
6617
|
async function updateRootPackageJson(projectDir, options) {
|
|
6291
6618
|
const rootPackageJsonPath = path.join(projectDir, "package.json");
|
|
@@ -6295,6 +6622,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6295
6622
|
if (!packageJson.scripts) packageJson.scripts = {};
|
|
6296
6623
|
const scripts = packageJson.scripts;
|
|
6297
6624
|
const backendPackageName = options.backend === "convex" ? `@${options.projectName}/backend` : "server";
|
|
6625
|
+
const dbPackageName = `@${options.projectName}/db`;
|
|
6298
6626
|
let serverDevScript = "";
|
|
6299
6627
|
if (options.addons.includes("turborepo")) serverDevScript = `turbo -F ${backendPackageName} dev`;
|
|
6300
6628
|
else if (options.packageManager === "bun") serverDevScript = `bun run --filter ${backendPackageName} dev`;
|
|
@@ -6311,24 +6639,24 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6311
6639
|
scripts["check-types"] = "turbo check-types";
|
|
6312
6640
|
scripts["dev:native"] = "turbo -F native dev";
|
|
6313
6641
|
scripts["dev:web"] = "turbo -F web dev";
|
|
6314
|
-
scripts["dev:server"] = serverDevScript;
|
|
6642
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6315
6643
|
if (options.backend === "convex") scripts["dev:setup"] = `turbo -F ${backendPackageName} dev:setup`;
|
|
6316
6644
|
if (needsDbScripts) {
|
|
6317
|
-
scripts["db:push"] = `turbo -F ${
|
|
6318
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `turbo -F ${
|
|
6645
|
+
scripts["db:push"] = `turbo -F ${dbPackageName} db:push`;
|
|
6646
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `turbo -F ${dbPackageName} db:studio`;
|
|
6319
6647
|
if (options.orm === "prisma") {
|
|
6320
|
-
scripts["db:generate"] = `turbo -F ${
|
|
6321
|
-
scripts["db:migrate"] = `turbo -F ${
|
|
6648
|
+
scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
|
|
6649
|
+
scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
|
|
6322
6650
|
} else if (options.orm === "drizzle") {
|
|
6323
|
-
scripts["db:generate"] = `turbo -F ${
|
|
6324
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${
|
|
6651
|
+
scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
|
|
6652
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
|
|
6325
6653
|
}
|
|
6326
6654
|
}
|
|
6327
6655
|
if (options.dbSetup === "docker") {
|
|
6328
|
-
scripts["db:start"] = `turbo -F ${
|
|
6329
|
-
scripts["db:watch"] = `turbo -F ${
|
|
6330
|
-
scripts["db:stop"] = `turbo -F ${
|
|
6331
|
-
scripts["db:down"] = `turbo -F ${
|
|
6656
|
+
scripts["db:start"] = `turbo -F ${dbPackageName} db:start`;
|
|
6657
|
+
scripts["db:watch"] = `turbo -F ${dbPackageName} db:watch`;
|
|
6658
|
+
scripts["db:stop"] = `turbo -F ${dbPackageName} db:stop`;
|
|
6659
|
+
scripts["db:down"] = `turbo -F ${dbPackageName} db:down`;
|
|
6332
6660
|
}
|
|
6333
6661
|
} else if (options.packageManager === "pnpm") {
|
|
6334
6662
|
scripts.dev = devScript;
|
|
@@ -6336,24 +6664,24 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6336
6664
|
scripts["check-types"] = "pnpm -r check-types";
|
|
6337
6665
|
scripts["dev:native"] = "pnpm --filter native dev";
|
|
6338
6666
|
scripts["dev:web"] = "pnpm --filter web dev";
|
|
6339
|
-
scripts["dev:server"] = serverDevScript;
|
|
6667
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6340
6668
|
if (options.backend === "convex") scripts["dev:setup"] = `pnpm --filter ${backendPackageName} dev:setup`;
|
|
6341
6669
|
if (needsDbScripts) {
|
|
6342
|
-
scripts["db:push"] = `pnpm --filter ${
|
|
6343
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${
|
|
6670
|
+
scripts["db:push"] = `pnpm --filter ${dbPackageName} db:push`;
|
|
6671
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${dbPackageName} db:studio`;
|
|
6344
6672
|
if (options.orm === "prisma") {
|
|
6345
|
-
scripts["db:generate"] = `pnpm --filter ${
|
|
6346
|
-
scripts["db:migrate"] = `pnpm --filter ${
|
|
6673
|
+
scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
|
|
6674
|
+
scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
|
|
6347
6675
|
} else if (options.orm === "drizzle") {
|
|
6348
|
-
scripts["db:generate"] = `pnpm --filter ${
|
|
6349
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${
|
|
6676
|
+
scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
|
|
6677
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
|
|
6350
6678
|
}
|
|
6351
6679
|
}
|
|
6352
6680
|
if (options.dbSetup === "docker") {
|
|
6353
|
-
scripts["db:start"] = `pnpm --filter ${
|
|
6354
|
-
scripts["db:watch"] = `pnpm --filter ${
|
|
6355
|
-
scripts["db:stop"] = `pnpm --filter ${
|
|
6356
|
-
scripts["db:down"] = `pnpm --filter ${
|
|
6681
|
+
scripts["db:start"] = `pnpm --filter ${dbPackageName} db:start`;
|
|
6682
|
+
scripts["db:watch"] = `pnpm --filter ${dbPackageName} db:watch`;
|
|
6683
|
+
scripts["db:stop"] = `pnpm --filter ${dbPackageName} db:stop`;
|
|
6684
|
+
scripts["db:down"] = `pnpm --filter ${dbPackageName} db:down`;
|
|
6357
6685
|
}
|
|
6358
6686
|
} else if (options.packageManager === "npm") {
|
|
6359
6687
|
scripts.dev = devScript;
|
|
@@ -6361,24 +6689,24 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6361
6689
|
scripts["check-types"] = "npm run check-types --workspaces";
|
|
6362
6690
|
scripts["dev:native"] = "npm run dev --workspace native";
|
|
6363
6691
|
scripts["dev:web"] = "npm run dev --workspace web";
|
|
6364
|
-
scripts["dev:server"] = serverDevScript;
|
|
6692
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6365
6693
|
if (options.backend === "convex") scripts["dev:setup"] = `npm run dev:setup --workspace ${backendPackageName}`;
|
|
6366
6694
|
if (needsDbScripts) {
|
|
6367
|
-
scripts["db:push"] = `npm run db:push --workspace ${
|
|
6368
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `npm run db:studio --workspace ${
|
|
6695
|
+
scripts["db:push"] = `npm run db:push --workspace ${dbPackageName}`;
|
|
6696
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `npm run db:studio --workspace ${dbPackageName}`;
|
|
6369
6697
|
if (options.orm === "prisma") {
|
|
6370
|
-
scripts["db:generate"] = `npm run db:generate --workspace ${
|
|
6371
|
-
scripts["db:migrate"] = `npm run db:migrate --workspace ${
|
|
6698
|
+
scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
|
|
6699
|
+
scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
|
|
6372
6700
|
} else if (options.orm === "drizzle") {
|
|
6373
|
-
scripts["db:generate"] = `npm run db:generate --workspace ${
|
|
6374
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `npm run db:migrate --workspace ${
|
|
6701
|
+
scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
|
|
6702
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
|
|
6375
6703
|
}
|
|
6376
6704
|
}
|
|
6377
6705
|
if (options.dbSetup === "docker") {
|
|
6378
|
-
scripts["db:start"] = `npm run db:start --workspace ${
|
|
6379
|
-
scripts["db:watch"] = `npm run db:watch --workspace ${
|
|
6380
|
-
scripts["db:stop"] = `npm run db:stop --workspace ${
|
|
6381
|
-
scripts["db:down"] = `npm run db:down --workspace ${
|
|
6706
|
+
scripts["db:start"] = `npm run db:start --workspace ${dbPackageName}`;
|
|
6707
|
+
scripts["db:watch"] = `npm run db:watch --workspace ${dbPackageName}`;
|
|
6708
|
+
scripts["db:stop"] = `npm run db:stop --workspace ${dbPackageName}`;
|
|
6709
|
+
scripts["db:down"] = `npm run db:down --workspace ${dbPackageName}`;
|
|
6382
6710
|
}
|
|
6383
6711
|
} else if (options.packageManager === "bun") {
|
|
6384
6712
|
scripts.dev = devScript;
|
|
@@ -6386,24 +6714,24 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6386
6714
|
scripts["check-types"] = "bun run --filter '*' check-types";
|
|
6387
6715
|
scripts["dev:native"] = "bun run --filter native dev";
|
|
6388
6716
|
scripts["dev:web"] = "bun run --filter web dev";
|
|
6389
|
-
scripts["dev:server"] = serverDevScript;
|
|
6717
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6390
6718
|
if (options.backend === "convex") scripts["dev:setup"] = `bun run --filter ${backendPackageName} dev:setup`;
|
|
6391
6719
|
if (needsDbScripts) {
|
|
6392
|
-
scripts["db:push"] = `bun run --filter ${
|
|
6393
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${
|
|
6720
|
+
scripts["db:push"] = `bun run --filter ${dbPackageName} db:push`;
|
|
6721
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${dbPackageName} db:studio`;
|
|
6394
6722
|
if (options.orm === "prisma") {
|
|
6395
|
-
scripts["db:generate"] = `bun run --filter ${
|
|
6396
|
-
scripts["db:migrate"] = `bun run --filter ${
|
|
6723
|
+
scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
|
|
6724
|
+
scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
|
|
6397
6725
|
} else if (options.orm === "drizzle") {
|
|
6398
|
-
scripts["db:generate"] = `bun run --filter ${
|
|
6399
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `bun run --filter ${
|
|
6726
|
+
scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
|
|
6727
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
|
|
6400
6728
|
}
|
|
6401
6729
|
}
|
|
6402
6730
|
if (options.dbSetup === "docker") {
|
|
6403
|
-
scripts["db:start"] = `bun run --filter ${
|
|
6404
|
-
scripts["db:watch"] = `bun run --filter ${
|
|
6405
|
-
scripts["db:stop"] = `bun run --filter ${
|
|
6406
|
-
scripts["db:down"] = `bun run --filter ${
|
|
6731
|
+
scripts["db:start"] = `bun run --filter ${dbPackageName} db:start`;
|
|
6732
|
+
scripts["db:watch"] = `bun run --filter ${dbPackageName} db:watch`;
|
|
6733
|
+
scripts["db:stop"] = `bun run --filter ${dbPackageName} db:stop`;
|
|
6734
|
+
scripts["db:down"] = `bun run --filter ${dbPackageName} db:down`;
|
|
6407
6735
|
}
|
|
6408
6736
|
}
|
|
6409
6737
|
try {
|
|
@@ -6428,7 +6756,16 @@ async function updateServerPackageJson(projectDir, options) {
|
|
|
6428
6756
|
if (!await fs.pathExists(serverPackageJsonPath)) return;
|
|
6429
6757
|
const serverPackageJson = await fs.readJson(serverPackageJsonPath);
|
|
6430
6758
|
if (!serverPackageJson.scripts) serverPackageJson.scripts = {};
|
|
6431
|
-
|
|
6759
|
+
await fs.writeJson(serverPackageJsonPath, serverPackageJson, { spaces: 2 });
|
|
6760
|
+
await updateDbPackageJson(projectDir, options);
|
|
6761
|
+
}
|
|
6762
|
+
async function updateDbPackageJson(projectDir, options) {
|
|
6763
|
+
const dbPackageJsonPath = path.join(projectDir, "packages/db/package.json");
|
|
6764
|
+
if (!await fs.pathExists(dbPackageJsonPath)) return;
|
|
6765
|
+
const dbPackageJson = await fs.readJson(dbPackageJsonPath);
|
|
6766
|
+
dbPackageJson.name = `@${options.projectName}/db`;
|
|
6767
|
+
if (!dbPackageJson.scripts) dbPackageJson.scripts = {};
|
|
6768
|
+
const scripts = dbPackageJson.scripts;
|
|
6432
6769
|
if (options.database !== "none") {
|
|
6433
6770
|
if (options.database === "sqlite" && options.orm === "drizzle" && options.dbSetup !== "d1") scripts["db:local"] = "turso dev --db-file local.db";
|
|
6434
6771
|
if (options.orm === "prisma") {
|
|
@@ -6449,7 +6786,21 @@ async function updateServerPackageJson(projectDir, options) {
|
|
|
6449
6786
|
scripts["db:stop"] = "docker compose stop";
|
|
6450
6787
|
scripts["db:down"] = "docker compose down";
|
|
6451
6788
|
}
|
|
6452
|
-
await fs.writeJson(
|
|
6789
|
+
await fs.writeJson(dbPackageJsonPath, dbPackageJson, { spaces: 2 });
|
|
6790
|
+
}
|
|
6791
|
+
async function updateAuthPackageJson(projectDir, options) {
|
|
6792
|
+
const authPackageJsonPath = path.join(projectDir, "packages/auth/package.json");
|
|
6793
|
+
if (!await fs.pathExists(authPackageJsonPath)) return;
|
|
6794
|
+
const authPackageJson = await fs.readJson(authPackageJsonPath);
|
|
6795
|
+
authPackageJson.name = `@${options.projectName}/auth`;
|
|
6796
|
+
await fs.writeJson(authPackageJsonPath, authPackageJson, { spaces: 2 });
|
|
6797
|
+
}
|
|
6798
|
+
async function updateApiPackageJson(projectDir, options) {
|
|
6799
|
+
const apiPackageJsonPath = path.join(projectDir, "packages/api/package.json");
|
|
6800
|
+
if (!await fs.pathExists(apiPackageJsonPath)) return;
|
|
6801
|
+
const apiPackageJson = await fs.readJson(apiPackageJsonPath);
|
|
6802
|
+
apiPackageJson.name = `@${options.projectName}/api`;
|
|
6803
|
+
await fs.writeJson(apiPackageJsonPath, apiPackageJson, { spaces: 2 });
|
|
6453
6804
|
}
|
|
6454
6805
|
async function updateConvexPackageJson(projectDir, options) {
|
|
6455
6806
|
const convexPackageJsonPath = path.join(projectDir, "packages/backend/package.json");
|
|
@@ -6465,15 +6816,14 @@ async function updateConvexPackageJson(projectDir, options) {
|
|
|
6465
6816
|
async function createProject(options, cliInput) {
|
|
6466
6817
|
const projectDir = options.projectDir;
|
|
6467
6818
|
const isConvex = options.backend === "convex";
|
|
6819
|
+
const isSelfBackend = options.backend === "self";
|
|
6820
|
+
const needsServerSetup = !isConvex && !isSelfBackend;
|
|
6468
6821
|
try {
|
|
6469
6822
|
await fs.ensureDir(projectDir);
|
|
6470
6823
|
await copyBaseTemplate(projectDir, options);
|
|
6471
6824
|
await setupFrontendTemplates(projectDir, options);
|
|
6472
6825
|
await setupBackendFramework(projectDir, options);
|
|
6473
|
-
if (
|
|
6474
|
-
await setupDbOrmTemplates(projectDir, options);
|
|
6475
|
-
await setupDockerComposeTemplates(projectDir, options);
|
|
6476
|
-
}
|
|
6826
|
+
if (needsServerSetup) await setupDockerComposeTemplates(projectDir, options);
|
|
6477
6827
|
await setupAuthTemplate(projectDir, options);
|
|
6478
6828
|
if (options.payments && options.payments !== "none") await setupPaymentsTemplate(projectDir, options);
|
|
6479
6829
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamplesTemplate(projectDir, options);
|
|
@@ -6481,9 +6831,11 @@ async function createProject(options, cliInput) {
|
|
|
6481
6831
|
await setupDeploymentTemplates(projectDir, options);
|
|
6482
6832
|
await setupApi(options);
|
|
6483
6833
|
if (!isConvex) {
|
|
6484
|
-
|
|
6834
|
+
if (needsServerSetup) {
|
|
6835
|
+
await setupBackendDependencies(options);
|
|
6836
|
+
await setupRuntime(options);
|
|
6837
|
+
}
|
|
6485
6838
|
await setupDatabase(options, cliInput);
|
|
6486
|
-
await setupRuntime(options);
|
|
6487
6839
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamples(options);
|
|
6488
6840
|
}
|
|
6489
6841
|
if (options.addons.length > 0 && options.addons[0] !== "none") await setupAddons(options);
|
|
@@ -6492,6 +6844,7 @@ async function createProject(options, cliInput) {
|
|
|
6492
6844
|
await handleExtras(projectDir, options);
|
|
6493
6845
|
await setupEnvironmentVariables(options);
|
|
6494
6846
|
await updatePackageConfigurations(projectDir, options);
|
|
6847
|
+
await setupCatalogs(projectDir, options);
|
|
6495
6848
|
await setupWebDeploy(options);
|
|
6496
6849
|
await setupServerDeploy(options);
|
|
6497
6850
|
await createReadme(projectDir, options);
|