create-better-t-stack 2.49.1 → 2.50.0-canary.5b25d7db
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 +2 -2
- package/dist/index.js +1 -1
- package/dist/{src-CKCxH6aF.js → src-Vtq3I-LI.js} +684 -372
- 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/auth/clerk/convex/web/react/tanstack-start/src/server.ts.hbs +1 -0
- package/templates/backend/server/{server-base → base}/package.json.hbs +0 -1
- package/templates/backend/server/{server-base → base}/tsconfig.json.hbs +5 -10
- package/templates/backend/server/base/tsdown.config.ts.hbs +14 -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 +23 -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/wrangler/web/react/tanstack-start/wrangler.jsonc.hbs +1 -1
- 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 +7 -7
- 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/package.json.hbs +7 -7
- package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +5 -5
- package/templates/frontend/react/tanstack-start/tsconfig.json.hbs +1 -6
- package/templates/frontend/react/tanstack-start/vite.config.ts.hbs +1 -1
- 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
|
|
@@ -65,12 +66,13 @@ const dependencyVersionMap = {
|
|
|
65
66
|
"@better-auth/expo": "^1.3.13",
|
|
66
67
|
"@clerk/nextjs": "^6.31.5",
|
|
67
68
|
"@clerk/clerk-react": "^5.45.0",
|
|
68
|
-
"@clerk/tanstack-react-start": "^0.
|
|
69
|
+
"@clerk/tanstack-react-start": "^0.25.1",
|
|
69
70
|
"@clerk/clerk-expo": "^2.14.25",
|
|
70
71
|
"drizzle-orm": "^0.44.2",
|
|
71
72
|
"drizzle-kit": "^0.31.2",
|
|
72
73
|
"@planetscale/database": "^1.19.0",
|
|
73
74
|
"@libsql/client": "^0.15.9",
|
|
75
|
+
libsql: "^0.5.22",
|
|
74
76
|
"@neondatabase/serverless": "^1.0.1",
|
|
75
77
|
pg: "^8.14.1",
|
|
76
78
|
"@types/pg": "^8.11.11",
|
|
@@ -123,6 +125,7 @@ const dependencyVersionMap = {
|
|
|
123
125
|
"@trpc/tanstack-react-query": "^11.5.0",
|
|
124
126
|
"@trpc/server": "^11.5.0",
|
|
125
127
|
"@trpc/client": "^11.5.0",
|
|
128
|
+
next: "15.5.4",
|
|
126
129
|
convex: "^1.27.0",
|
|
127
130
|
"@convex-dev/react-query": "^0.0.0-alpha.8",
|
|
128
131
|
"convex-svelte": "^0.0.11",
|
|
@@ -138,15 +141,17 @@ const dependencyVersionMap = {
|
|
|
138
141
|
"@tanstack/solid-query": "^5.87.4",
|
|
139
142
|
"@tanstack/solid-query-devtools": "^5.87.4",
|
|
140
143
|
"@tanstack/solid-router-devtools": "^1.131.44",
|
|
141
|
-
wrangler: "^4.
|
|
142
|
-
"@cloudflare/vite-plugin": "^1.
|
|
144
|
+
wrangler: "^4.40.3",
|
|
145
|
+
"@cloudflare/vite-plugin": "^1.13.8",
|
|
143
146
|
"@opennextjs/cloudflare": "^1.6.5",
|
|
144
147
|
"nitro-cloudflare-dev": "^0.2.2",
|
|
145
148
|
"@sveltejs/adapter-cloudflare": "^7.2.1",
|
|
146
149
|
"@cloudflare/workers-types": "^4.20250822.0",
|
|
147
|
-
alchemy: "^0.
|
|
150
|
+
alchemy: "^0.70.0",
|
|
148
151
|
nitropack: "^2.12.4",
|
|
149
|
-
dotenv: "^17.2.
|
|
152
|
+
dotenv: "^17.2.2",
|
|
153
|
+
tsdown: "^0.15.5",
|
|
154
|
+
zod: "^4.1.11",
|
|
150
155
|
"@polar-sh/better-auth": "^1.1.3",
|
|
151
156
|
"@polar-sh/sdk": "^0.34.16"
|
|
152
157
|
};
|
|
@@ -195,9 +200,9 @@ const BackendSchema = z.enum([
|
|
|
195
200
|
"hono",
|
|
196
201
|
"express",
|
|
197
202
|
"fastify",
|
|
198
|
-
"next",
|
|
199
203
|
"elysia",
|
|
200
204
|
"convex",
|
|
205
|
+
"self",
|
|
201
206
|
"none"
|
|
202
207
|
]).describe("Backend framework");
|
|
203
208
|
const RuntimeSchema = z.enum([
|
|
@@ -343,6 +348,22 @@ function ensureSingleWebAndNative(frontends) {
|
|
|
343
348
|
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
349
|
if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-nativewind, native-unistyles");
|
|
345
350
|
}
|
|
351
|
+
const FULLSTACK_FRONTENDS$1 = [
|
|
352
|
+
"next",
|
|
353
|
+
"nuxt",
|
|
354
|
+
"svelte",
|
|
355
|
+
"tanstack-start"
|
|
356
|
+
];
|
|
357
|
+
function validateSelfBackendCompatibility(providedFlags, options, config) {
|
|
358
|
+
const backend = config.backend || options.backend;
|
|
359
|
+
const frontends = config.frontend || options.frontend || [];
|
|
360
|
+
if (backend === "self") {
|
|
361
|
+
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");
|
|
362
|
+
if (frontends.length > 1) exitWithError("Backend 'self' (fullstack) can only be used with a single frontend framework.");
|
|
363
|
+
}
|
|
364
|
+
const hasFullstackFrontend = frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f));
|
|
365
|
+
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.");
|
|
366
|
+
}
|
|
346
367
|
function validateWorkersCompatibility(providedFlags, options, config) {
|
|
347
368
|
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
369
|
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 +685,39 @@ async function getAuthChoice(auth, hasDatabase, backend, frontend) {
|
|
|
664
685
|
|
|
665
686
|
//#endregion
|
|
666
687
|
//#region src/prompts/backend.ts
|
|
688
|
+
const FULLSTACK_FRONTENDS = [
|
|
689
|
+
"next",
|
|
690
|
+
"nuxt",
|
|
691
|
+
"svelte",
|
|
692
|
+
"tanstack-start"
|
|
693
|
+
];
|
|
667
694
|
async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
668
695
|
if (backendFramework !== void 0) return backendFramework;
|
|
669
696
|
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
|
-
];
|
|
697
|
+
const hasFullstackFrontend = frontends?.some((f) => FULLSTACK_FRONTENDS.includes(f));
|
|
698
|
+
const backendOptions = [];
|
|
699
|
+
if (hasFullstackFrontend) backendOptions.push({
|
|
700
|
+
value: "self",
|
|
701
|
+
label: "Self (Fullstack)",
|
|
702
|
+
hint: "Use frontend's built-in api routes"
|
|
703
|
+
});
|
|
704
|
+
backendOptions.push({
|
|
705
|
+
value: "hono",
|
|
706
|
+
label: "Hono",
|
|
707
|
+
hint: "Lightweight, ultrafast web framework"
|
|
708
|
+
}, {
|
|
709
|
+
value: "express",
|
|
710
|
+
label: "Express",
|
|
711
|
+
hint: "Fast, unopinionated, minimalist web framework for Node.js"
|
|
712
|
+
}, {
|
|
713
|
+
value: "fastify",
|
|
714
|
+
label: "Fastify",
|
|
715
|
+
hint: "Fast, low-overhead web framework for Node.js"
|
|
716
|
+
}, {
|
|
717
|
+
value: "elysia",
|
|
718
|
+
label: "Elysia",
|
|
719
|
+
hint: "Ergonomic web framework for building backend servers"
|
|
720
|
+
});
|
|
697
721
|
if (!hasIncompatibleFrontend) backendOptions.push({
|
|
698
722
|
value: "convex",
|
|
699
723
|
label: "Convex",
|
|
@@ -707,7 +731,7 @@ async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
|
707
731
|
const response = await select({
|
|
708
732
|
message: "Select backend",
|
|
709
733
|
options: backendOptions,
|
|
710
|
-
initialValue: DEFAULT_CONFIG.backend
|
|
734
|
+
initialValue: hasFullstackFrontend ? "self" : DEFAULT_CONFIG.backend
|
|
711
735
|
});
|
|
712
736
|
if (isCancel(response)) return exitCancelled("Operation cancelled");
|
|
713
737
|
return response;
|
|
@@ -1086,9 +1110,8 @@ async function getPaymentsChoice(payments, auth, backend, frontends) {
|
|
|
1086
1110
|
//#endregion
|
|
1087
1111
|
//#region src/prompts/runtime.ts
|
|
1088
1112
|
async function getRuntimeChoice(runtime, backend) {
|
|
1089
|
-
if (backend === "convex" || backend === "none") return "none";
|
|
1113
|
+
if (backend === "convex" || backend === "none" || backend === "self") return "none";
|
|
1090
1114
|
if (runtime !== void 0) return runtime;
|
|
1091
|
-
if (backend === "next") return "node";
|
|
1092
1115
|
const runtimeOptions = [{
|
|
1093
1116
|
value: "bun",
|
|
1094
1117
|
label: "Bun",
|
|
@@ -1375,7 +1398,7 @@ const getLatestCLIVersion = () => {
|
|
|
1375
1398
|
*/
|
|
1376
1399
|
function isTelemetryEnabled() {
|
|
1377
1400
|
const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
|
|
1378
|
-
const BTS_TELEMETRY = "
|
|
1401
|
+
const BTS_TELEMETRY = "0";
|
|
1379
1402
|
if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
|
|
1380
1403
|
if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
|
|
1381
1404
|
return true;
|
|
@@ -1383,8 +1406,8 @@ function isTelemetryEnabled() {
|
|
|
1383
1406
|
|
|
1384
1407
|
//#endregion
|
|
1385
1408
|
//#region src/utils/analytics.ts
|
|
1386
|
-
const POSTHOG_API_KEY = "
|
|
1387
|
-
const POSTHOG_HOST = "
|
|
1409
|
+
const POSTHOG_API_KEY = "random";
|
|
1410
|
+
const POSTHOG_HOST = "random";
|
|
1388
1411
|
function generateSessionId() {
|
|
1389
1412
|
const rand = Math.random().toString(36).slice(2);
|
|
1390
1413
|
return `cli_${Date.now().toString(36)}${rand}`;
|
|
@@ -1765,8 +1788,8 @@ function validateBackendConstraints(config, providedFlags, options) {
|
|
|
1765
1788
|
].includes(f));
|
|
1766
1789
|
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
1790
|
}
|
|
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
|
|
1791
|
+
if (providedFlags.has("backend") && backend && backend !== "convex" && backend !== "none" && backend !== "self") {
|
|
1792
|
+
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
1793
|
}
|
|
1771
1794
|
if (backend === "convex" && providedFlags.has("frontend") && options.frontend) {
|
|
1772
1795
|
const incompatibleFrontends = options.frontend.filter((f) => f === "solid");
|
|
@@ -1796,6 +1819,7 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
1796
1819
|
validateFrontendConstraints(config, providedFlags);
|
|
1797
1820
|
validateApiConstraints(config, options);
|
|
1798
1821
|
validateServerDeployRequiresBackend(config.serverDeploy, config.backend);
|
|
1822
|
+
validateSelfBackendCompatibility(providedFlags, options, config);
|
|
1799
1823
|
validateWorkersCompatibility(providedFlags, options, config);
|
|
1800
1824
|
if (config.runtime === "workers" && config.serverDeploy === "none") exitWithError("Cloudflare Workers runtime requires a server deployment. Please choose 'wrangler' or 'alchemy' for --server-deploy.");
|
|
1801
1825
|
if (config.addons && config.addons.length > 0) {
|
|
@@ -1849,6 +1873,7 @@ const CORE_STACK_FLAGS = new Set([
|
|
|
1849
1873
|
"examples",
|
|
1850
1874
|
"auth",
|
|
1851
1875
|
"dbSetup",
|
|
1876
|
+
"payments",
|
|
1852
1877
|
"api",
|
|
1853
1878
|
"webDeploy",
|
|
1854
1879
|
"serverDeploy"
|
|
@@ -1992,15 +2017,17 @@ const addPackageDependency = async (opts) => {
|
|
|
1992
2017
|
if (!pkgJson.dependencies) pkgJson.dependencies = {};
|
|
1993
2018
|
if (!pkgJson.devDependencies) pkgJson.devDependencies = {};
|
|
1994
2019
|
for (const pkgName of dependencies) {
|
|
1995
|
-
const version =
|
|
2020
|
+
const version = dependencyVersionMap[pkgName];
|
|
1996
2021
|
if (version) pkgJson.dependencies[pkgName] = version;
|
|
1997
2022
|
else console.warn(`Warning: Dependency ${pkgName} not found in version map.`);
|
|
1998
2023
|
}
|
|
1999
2024
|
for (const pkgName of devDependencies) {
|
|
2000
|
-
const version =
|
|
2025
|
+
const version = dependencyVersionMap[pkgName];
|
|
2001
2026
|
if (version) pkgJson.devDependencies[pkgName] = version;
|
|
2002
2027
|
else console.warn(`Warning: Dev dependency ${pkgName} not found in version map.`);
|
|
2003
2028
|
}
|
|
2029
|
+
for (const [pkgName, version] of Object.entries(customDependencies)) pkgJson.dependencies[pkgName] = version;
|
|
2030
|
+
for (const [pkgName, version] of Object.entries(customDevDependencies)) pkgJson.devDependencies[pkgName] = version;
|
|
2004
2031
|
await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
2005
2032
|
};
|
|
2006
2033
|
|
|
@@ -2655,8 +2682,12 @@ async function processTemplate(srcPath, destPath, context) {
|
|
|
2655
2682
|
}
|
|
2656
2683
|
handlebars.registerHelper("eq", (a, b) => a === b);
|
|
2657
2684
|
handlebars.registerHelper("ne", (a, b) => a !== b);
|
|
2658
|
-
handlebars.registerHelper("and", (
|
|
2659
|
-
|
|
2685
|
+
handlebars.registerHelper("and", (...args) => {
|
|
2686
|
+
return args.slice(0, -1).every((value) => value);
|
|
2687
|
+
});
|
|
2688
|
+
handlebars.registerHelper("or", (...args) => {
|
|
2689
|
+
return args.slice(0, -1).some((value) => value);
|
|
2690
|
+
});
|
|
2660
2691
|
handlebars.registerHelper("includes", (array, value) => Array.isArray(array) && array.includes(value));
|
|
2661
2692
|
|
|
2662
2693
|
//#endregion
|
|
@@ -2718,6 +2749,10 @@ async function setupFrontendTemplates(projectDir, context) {
|
|
|
2718
2749
|
const apiWebBaseDir = path.join(PKG_ROOT, `templates/api/${context.api}/web/react/base`);
|
|
2719
2750
|
if (await fs.pathExists(apiWebBaseDir)) await processAndCopyFiles("**/*", apiWebBaseDir, webAppDir, context);
|
|
2720
2751
|
}
|
|
2752
|
+
if (context.backend === "self" && reactFramework === "next" && context.api !== "none") {
|
|
2753
|
+
const apiFullstackDir = path.join(PKG_ROOT, `templates/api/${context.api}/fullstack/next`);
|
|
2754
|
+
if (await fs.pathExists(apiFullstackDir)) await processAndCopyFiles("**/*", apiFullstackDir, webAppDir, context);
|
|
2755
|
+
}
|
|
2721
2756
|
}
|
|
2722
2757
|
} else if (hasNuxtWeb) {
|
|
2723
2758
|
const nuxtBaseDir = path.join(PKG_ROOT, "templates/frontend/nuxt");
|
|
@@ -2758,35 +2793,52 @@ async function setupFrontendTemplates(projectDir, context) {
|
|
|
2758
2793
|
}
|
|
2759
2794
|
}
|
|
2760
2795
|
}
|
|
2761
|
-
async function
|
|
2762
|
-
if (context.
|
|
2796
|
+
async function setupApiPackage(projectDir, context) {
|
|
2797
|
+
if (context.api === "none") return;
|
|
2798
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
2799
|
+
await fs.ensureDir(apiPackageDir);
|
|
2800
|
+
const apiServerDir = path.join(PKG_ROOT, `templates/api/${context.api}/server`);
|
|
2801
|
+
if (await fs.pathExists(apiServerDir)) await processAndCopyFiles("**/*", apiServerDir, apiPackageDir, context);
|
|
2802
|
+
}
|
|
2803
|
+
async function setupDbPackage(projectDir, context) {
|
|
2804
|
+
if (context.database === "none" || context.orm === "none") return;
|
|
2805
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
2806
|
+
await fs.ensureDir(dbPackageDir);
|
|
2807
|
+
const dbBaseDir = path.join(PKG_ROOT, "templates/db/base");
|
|
2808
|
+
if (await fs.pathExists(dbBaseDir)) await processAndCopyFiles("**/*", dbBaseDir, dbPackageDir, context);
|
|
2809
|
+
const dbOrmSrcDir = path.join(PKG_ROOT, `templates/db/${context.orm}/${context.database}`);
|
|
2810
|
+
if (await fs.pathExists(dbOrmSrcDir)) await processAndCopyFiles("**/*", dbOrmSrcDir, dbPackageDir, context);
|
|
2811
|
+
}
|
|
2812
|
+
async function setupConvexBackend(projectDir, context) {
|
|
2813
|
+
const serverAppDir = path.join(projectDir, "apps/server");
|
|
2814
|
+
if (await fs.pathExists(serverAppDir)) await fs.remove(serverAppDir);
|
|
2815
|
+
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
|
2816
|
+
const convexSrcDir = path.join(PKG_ROOT, "templates/backend/convex/packages/backend");
|
|
2817
|
+
await fs.ensureDir(convexBackendDestDir);
|
|
2818
|
+
if (await fs.pathExists(convexSrcDir)) await processAndCopyFiles("**/*", convexSrcDir, convexBackendDestDir, context);
|
|
2819
|
+
}
|
|
2820
|
+
async function setupServerApp(projectDir, context) {
|
|
2763
2821
|
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
2822
|
await fs.ensureDir(serverAppDir);
|
|
2773
|
-
const serverBaseDir = path.join(PKG_ROOT, "templates/backend/server/
|
|
2823
|
+
const serverBaseDir = path.join(PKG_ROOT, "templates/backend/server/base");
|
|
2774
2824
|
if (await fs.pathExists(serverBaseDir)) await processAndCopyFiles("**/*", serverBaseDir, serverAppDir, context);
|
|
2775
2825
|
const frameworkSrcDir = path.join(PKG_ROOT, `templates/backend/server/${context.backend}`);
|
|
2776
2826
|
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
2827
|
}
|
|
2784
|
-
async function
|
|
2785
|
-
if (context.backend === "
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2828
|
+
async function setupBackendFramework(projectDir, context) {
|
|
2829
|
+
if (context.backend === "none") return;
|
|
2830
|
+
if (context.backend === "convex") {
|
|
2831
|
+
await setupConvexBackend(projectDir, context);
|
|
2832
|
+
return;
|
|
2833
|
+
}
|
|
2834
|
+
if (context.backend === "self") {
|
|
2835
|
+
await setupApiPackage(projectDir, context);
|
|
2836
|
+
await setupDbPackage(projectDir, context);
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
await setupServerApp(projectDir, context);
|
|
2840
|
+
await setupApiPackage(projectDir, context);
|
|
2841
|
+
await setupDbPackage(projectDir, context);
|
|
2790
2842
|
}
|
|
2791
2843
|
async function setupAuthTemplate(projectDir, context) {
|
|
2792
2844
|
if (!context.auth || context.auth === "none") return;
|
|
@@ -2866,21 +2918,21 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2866
2918
|
}
|
|
2867
2919
|
return;
|
|
2868
2920
|
}
|
|
2869
|
-
if (serverAppDirExists && context.backend !== "convex") {
|
|
2921
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex") {
|
|
2922
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
2923
|
+
await fs.ensureDir(authPackageDir);
|
|
2870
2924
|
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
|
-
}
|
|
2925
|
+
if (await fs.pathExists(authServerBaseSrc)) await processAndCopyFiles("**/*", authServerBaseSrc, authPackageDir, context);
|
|
2876
2926
|
if (context.orm !== "none" && context.database !== "none") {
|
|
2927
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
2928
|
+
await fs.ensureDir(dbPackageDir);
|
|
2877
2929
|
const orm = context.orm;
|
|
2878
2930
|
const db = context.database;
|
|
2879
2931
|
let authDbSrc = "";
|
|
2880
2932
|
if (orm === "drizzle") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/drizzle/${db}`);
|
|
2881
2933
|
else if (orm === "prisma") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/prisma/${db}`);
|
|
2882
2934
|
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,
|
|
2935
|
+
if (authDbSrc && await fs.pathExists(authDbSrc)) await processAndCopyFiles("**/*", authDbSrc, dbPackageDir, context);
|
|
2884
2936
|
}
|
|
2885
2937
|
}
|
|
2886
2938
|
if ((hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) && webAppDirExists) {
|
|
@@ -2896,6 +2948,10 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2896
2948
|
if (reactFramework) {
|
|
2897
2949
|
const authWebFrameworkSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/react/${reactFramework}`);
|
|
2898
2950
|
if (await fs.pathExists(authWebFrameworkSrc)) await processAndCopyFiles("**/*", authWebFrameworkSrc, webAppDir, context);
|
|
2951
|
+
if (context.backend === "self" && reactFramework === "next") {
|
|
2952
|
+
const authFullstackSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/fullstack/next`);
|
|
2953
|
+
if (await fs.pathExists(authFullstackSrc)) await processAndCopyFiles("**/*", authFullstackSrc, webAppDir, context);
|
|
2954
|
+
}
|
|
2899
2955
|
}
|
|
2900
2956
|
} else if (hasNuxtWeb) {
|
|
2901
2957
|
const authWebNuxtSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/web/nuxt`);
|
|
@@ -2926,9 +2982,11 @@ async function setupPaymentsTemplate(projectDir, context) {
|
|
|
2926
2982
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
2927
2983
|
const serverAppDirExists = await fs.pathExists(serverAppDir);
|
|
2928
2984
|
const webAppDirExists = await fs.pathExists(webAppDir);
|
|
2929
|
-
if (serverAppDirExists && context.backend !== "convex") {
|
|
2985
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex") {
|
|
2986
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
2987
|
+
await fs.ensureDir(authPackageDir);
|
|
2930
2988
|
const paymentsServerSrc = path.join(PKG_ROOT, `templates/payments/${context.payments}/server/base`);
|
|
2931
|
-
if (await fs.pathExists(paymentsServerSrc)) await processAndCopyFiles("**/*", paymentsServerSrc,
|
|
2989
|
+
if (await fs.pathExists(paymentsServerSrc)) await processAndCopyFiles("**/*", paymentsServerSrc, authPackageDir, context);
|
|
2932
2990
|
}
|
|
2933
2991
|
const hasReactWeb = context.frontend.some((f) => [
|
|
2934
2992
|
"tanstack-router",
|
|
@@ -3004,17 +3062,19 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3004
3062
|
for (const example of context.examples) {
|
|
3005
3063
|
if (example === "none") continue;
|
|
3006
3064
|
const exampleBaseDir = path.join(PKG_ROOT, `templates/examples/${example}`);
|
|
3007
|
-
if (serverAppDirExists && context.backend !== "convex" && context.backend !== "none") {
|
|
3065
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex" && context.backend !== "none") {
|
|
3008
3066
|
const exampleServerSrc = path.join(exampleBaseDir, "server");
|
|
3009
|
-
if (
|
|
3010
|
-
const
|
|
3011
|
-
|
|
3067
|
+
if (context.api !== "none") {
|
|
3068
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
3069
|
+
await fs.ensureDir(apiPackageDir);
|
|
3070
|
+
const exampleOrmBaseSrc = path.join(exampleServerSrc, context.orm, "base");
|
|
3071
|
+
if (await fs.pathExists(exampleOrmBaseSrc)) await processAndCopyFiles("**/*", exampleOrmBaseSrc, apiPackageDir, context, false);
|
|
3012
3072
|
}
|
|
3013
3073
|
if (context.orm !== "none" && context.database !== "none") {
|
|
3014
|
-
const
|
|
3015
|
-
|
|
3074
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
3075
|
+
await fs.ensureDir(dbPackageDir);
|
|
3016
3076
|
const exampleDbSchemaSrc = path.join(exampleServerSrc, context.orm, context.database);
|
|
3017
|
-
if (await fs.pathExists(exampleDbSchemaSrc)) await processAndCopyFiles("**/*", exampleDbSchemaSrc,
|
|
3077
|
+
if (await fs.pathExists(exampleDbSchemaSrc)) await processAndCopyFiles("**/*", exampleDbSchemaSrc, dbPackageDir, context, false);
|
|
3018
3078
|
}
|
|
3019
3079
|
}
|
|
3020
3080
|
if (webAppDirExists) {
|
|
@@ -3034,6 +3094,10 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3034
3094
|
if (reactFramework) {
|
|
3035
3095
|
const exampleWebFrameworkSrc = path.join(exampleWebSrc, reactFramework);
|
|
3036
3096
|
if (await fs.pathExists(exampleWebFrameworkSrc)) await processAndCopyFiles("**/*", exampleWebFrameworkSrc, webAppDir, context, false);
|
|
3097
|
+
if (context.backend === "self" && reactFramework === "next") {
|
|
3098
|
+
const exampleFullstackSrc = path.join(exampleBaseDir, "fullstack/next");
|
|
3099
|
+
if (await fs.pathExists(exampleFullstackSrc)) await processAndCopyFiles("**/*", exampleFullstackSrc, webAppDir, context, false);
|
|
3100
|
+
}
|
|
3037
3101
|
}
|
|
3038
3102
|
}
|
|
3039
3103
|
} else if (hasNuxtWeb) {
|
|
@@ -3081,9 +3145,9 @@ async function handleExtras(projectDir, context) {
|
|
|
3081
3145
|
}
|
|
3082
3146
|
async function setupDockerComposeTemplates(projectDir, context) {
|
|
3083
3147
|
if (context.dbSetup !== "docker" || context.database === "none") return;
|
|
3084
|
-
const
|
|
3148
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
3085
3149
|
const dockerSrcDir = path.join(PKG_ROOT, `templates/db-setup/docker-compose/${context.database}`);
|
|
3086
|
-
if (await fs.pathExists(dockerSrcDir)) await processAndCopyFiles("**/*", dockerSrcDir,
|
|
3150
|
+
if (await fs.pathExists(dockerSrcDir)) await processAndCopyFiles("**/*", dockerSrcDir, dbPackageDir, context);
|
|
3087
3151
|
}
|
|
3088
3152
|
async function setupDeploymentTemplates(projectDir, context) {
|
|
3089
3153
|
if (context.webDeploy === "alchemy" || context.serverDeploy === "alchemy") if (context.webDeploy === "alchemy" && context.serverDeploy === "alchemy") {
|
|
@@ -3504,8 +3568,8 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3504
3568
|
await addPackageDependency({
|
|
3505
3569
|
devDependencies: [
|
|
3506
3570
|
"alchemy",
|
|
3507
|
-
"
|
|
3508
|
-
"
|
|
3571
|
+
"dotenv",
|
|
3572
|
+
"@cloudflare/vite-plugin"
|
|
3509
3573
|
],
|
|
3510
3574
|
projectDir: webAppDir
|
|
3511
3575
|
});
|
|
@@ -3533,17 +3597,6 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3533
3597
|
defaultImport: "alchemy"
|
|
3534
3598
|
});
|
|
3535
3599
|
else alchemyImport.setModuleSpecifier("alchemy/cloudflare/tanstack-start");
|
|
3536
|
-
const reactImport = sourceFile.getImportDeclaration("@vitejs/plugin-react");
|
|
3537
|
-
let reactPluginIdentifier = "viteReact";
|
|
3538
|
-
if (!reactImport) sourceFile.addImportDeclaration({
|
|
3539
|
-
moduleSpecifier: "@vitejs/plugin-react",
|
|
3540
|
-
defaultImport: "viteReact"
|
|
3541
|
-
});
|
|
3542
|
-
else {
|
|
3543
|
-
const defaultImport = reactImport.getDefaultImport();
|
|
3544
|
-
if (defaultImport) reactPluginIdentifier = defaultImport.getText();
|
|
3545
|
-
else reactImport.setDefaultImport("viteReact");
|
|
3546
|
-
}
|
|
3547
3600
|
const exportAssignment = sourceFile.getExportAssignment((d) => !d.isExportEquals());
|
|
3548
3601
|
if (!exportAssignment) return;
|
|
3549
3602
|
const defineConfigCall = exportAssignment.getExpression();
|
|
@@ -3551,47 +3604,11 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3551
3604
|
let configObject = defineConfigCall.getArguments()[0];
|
|
3552
3605
|
if (!configObject) configObject = defineConfigCall.addArgument("{}");
|
|
3553
3606
|
if (Node.isObjectLiteralExpression(configObject)) {
|
|
3554
|
-
if (!configObject.getProperty("build")) configObject.addPropertyAssignment({
|
|
3555
|
-
name: "build",
|
|
3556
|
-
initializer: `{
|
|
3557
|
-
target: "esnext",
|
|
3558
|
-
rollupOptions: {
|
|
3559
|
-
external: ["node:async_hooks", "cloudflare:workers"],
|
|
3560
|
-
},
|
|
3561
|
-
}`
|
|
3562
|
-
});
|
|
3563
3607
|
const pluginsProperty = configObject.getProperty("plugins");
|
|
3564
3608
|
if (pluginsProperty && Node.isPropertyAssignment(pluginsProperty)) {
|
|
3565
3609
|
const initializer = pluginsProperty.getInitializer();
|
|
3566
3610
|
if (Node.isArrayLiteralExpression(initializer)) {
|
|
3567
|
-
if (!initializer.getElements().some((el) => el.getText().includes("alchemy"))) initializer.addElement("alchemy()");
|
|
3568
|
-
const tanstackElements = initializer.getElements().filter((el) => el.getText().includes("tanstackStart"));
|
|
3569
|
-
let needsReactPlugin = false;
|
|
3570
|
-
tanstackElements.forEach((element) => {
|
|
3571
|
-
if (Node.isCallExpression(element)) {
|
|
3572
|
-
const args = element.getArguments();
|
|
3573
|
-
if (args.length === 0) {
|
|
3574
|
-
element.addArgument(`{
|
|
3575
|
-
target: "cloudflare-module",
|
|
3576
|
-
customViteReactPlugin: true,
|
|
3577
|
-
}`);
|
|
3578
|
-
needsReactPlugin = true;
|
|
3579
|
-
} else if (args.length === 1 && Node.isObjectLiteralExpression(args[0])) {
|
|
3580
|
-
const configObj = args[0];
|
|
3581
|
-
if (!configObj.getProperty("target")) configObj.addPropertyAssignment({
|
|
3582
|
-
name: "target",
|
|
3583
|
-
initializer: "\"cloudflare-module\""
|
|
3584
|
-
});
|
|
3585
|
-
if (!!!configObj.getProperty("customViteReactPlugin")) configObj.addPropertyAssignment({
|
|
3586
|
-
name: "customViteReactPlugin",
|
|
3587
|
-
initializer: "true"
|
|
3588
|
-
});
|
|
3589
|
-
needsReactPlugin = true;
|
|
3590
|
-
}
|
|
3591
|
-
}
|
|
3592
|
-
});
|
|
3593
|
-
const hasReactPlugin = initializer.getElements().some((el) => Node.isCallExpression(el) && el.getExpression().getText() === reactPluginIdentifier);
|
|
3594
|
-
if (needsReactPlugin && !hasReactPlugin) initializer.addElement(`${reactPluginIdentifier}()`);
|
|
3611
|
+
if (!initializer.getElements().some((el) => el.getText().includes("alchemy("))) initializer.addElement("alchemy()");
|
|
3595
3612
|
}
|
|
3596
3613
|
} else configObject.addPropertyAssignment({
|
|
3597
3614
|
name: "plugins",
|
|
@@ -3602,16 +3619,6 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3602
3619
|
} catch (error) {
|
|
3603
3620
|
console.warn("Failed to update vite.config.ts:", error);
|
|
3604
3621
|
}
|
|
3605
|
-
const nitroConfigPath = path.join(webAppDir, "nitro.config.ts");
|
|
3606
|
-
await fs.writeFile(nitroConfigPath, `import { defineNitroConfig } from "nitropack/config";
|
|
3607
|
-
|
|
3608
|
-
export default defineNitroConfig({
|
|
3609
|
-
preset: "cloudflare-module",
|
|
3610
|
-
cloudflare: {
|
|
3611
|
-
nodeCompat: true,
|
|
3612
|
-
},
|
|
3613
|
-
});
|
|
3614
|
-
`, "utf-8");
|
|
3615
3622
|
}
|
|
3616
3623
|
|
|
3617
3624
|
//#endregion
|
|
@@ -3778,7 +3785,7 @@ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
|
3778
3785
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3779
3786
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3780
3787
|
await addPackageDependency({
|
|
3781
|
-
devDependencies: ["wrangler"],
|
|
3788
|
+
devDependencies: ["wrangler", "@cloudflare/vite-plugin"],
|
|
3782
3789
|
projectDir: webAppDir
|
|
3783
3790
|
});
|
|
3784
3791
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
@@ -3795,6 +3802,12 @@ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
|
3795
3802
|
if (!await fs.pathExists(viteConfigPath)) return;
|
|
3796
3803
|
const sourceFile = tsProject.addSourceFileAtPathIfExists(viteConfigPath);
|
|
3797
3804
|
if (!sourceFile) return;
|
|
3805
|
+
const cfImport = sourceFile.getImportDeclaration("@cloudflare/vite-plugin");
|
|
3806
|
+
if (!cfImport) sourceFile.addImportDeclaration({
|
|
3807
|
+
moduleSpecifier: "@cloudflare/vite-plugin",
|
|
3808
|
+
namedImports: [{ name: "cloudflare" }]
|
|
3809
|
+
});
|
|
3810
|
+
else if (!cfImport.getNamedImports().some((ni) => ni.getName() === "cloudflare")) cfImport.addNamedImport({ name: "cloudflare" });
|
|
3798
3811
|
const reactImport = sourceFile.getImportDeclaration("@vitejs/plugin-react");
|
|
3799
3812
|
let reactPluginIdentifier = "viteReact";
|
|
3800
3813
|
if (!reactImport) sourceFile.addImportDeclaration({
|
|
@@ -3814,10 +3827,7 @@ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
|
3814
3827
|
const configObj = defineCall.getArguments()[0];
|
|
3815
3828
|
if (!configObj) return;
|
|
3816
3829
|
const pluginsArray = ensureArrayProperty(configObj, "plugins");
|
|
3817
|
-
|
|
3818
|
-
const tanstackPluginText = "tanstackStart({ target: \"cloudflare-module\", customViteReactPlugin: true })";
|
|
3819
|
-
if (tanstackPluginIndex === -1) pluginsArray.addElement(tanstackPluginText);
|
|
3820
|
-
else pluginsArray.getElements()[tanstackPluginIndex].replaceWithText(tanstackPluginText);
|
|
3830
|
+
if (!pluginsArray.getElements().some((el) => el.getText().includes("cloudflare("))) pluginsArray.insertElement(0, "cloudflare({ viteEnvironment: { name: 'ssr' } })");
|
|
3821
3831
|
if (!pluginsArray.getElements().some((el) => Node.isCallExpression(el) && el.getExpression().getText() === reactPluginIdentifier)) {
|
|
3822
3832
|
const nextIndex = pluginsArray.getElements().findIndex((el) => el.getText().includes("tanstackStart(")) + 1;
|
|
3823
3833
|
if (nextIndex > 0) pluginsArray.insertElement(nextIndex, `${reactPluginIdentifier}()`);
|
|
@@ -3955,18 +3965,137 @@ async function addDeploymentToProject(input) {
|
|
|
3955
3965
|
}
|
|
3956
3966
|
}
|
|
3957
3967
|
|
|
3968
|
+
//#endregion
|
|
3969
|
+
//#region src/utils/setup-catalogs.ts
|
|
3970
|
+
async function setupCatalogs(projectDir, options) {
|
|
3971
|
+
if (options.packageManager === "npm") return;
|
|
3972
|
+
const packagePaths = [
|
|
3973
|
+
"apps/server",
|
|
3974
|
+
"apps/web",
|
|
3975
|
+
"packages/api",
|
|
3976
|
+
"packages/db",
|
|
3977
|
+
"packages/auth",
|
|
3978
|
+
"packages/backend"
|
|
3979
|
+
];
|
|
3980
|
+
const packagesInfo = [];
|
|
3981
|
+
for (const pkgPath of packagePaths) {
|
|
3982
|
+
const fullPath = path.join(projectDir, pkgPath);
|
|
3983
|
+
const pkgJsonPath = path.join(fullPath, "package.json");
|
|
3984
|
+
if (await fs.pathExists(pkgJsonPath)) {
|
|
3985
|
+
const pkgJson = await fs.readJson(pkgJsonPath);
|
|
3986
|
+
packagesInfo.push({
|
|
3987
|
+
path: fullPath,
|
|
3988
|
+
dependencies: pkgJson.dependencies || {},
|
|
3989
|
+
devDependencies: pkgJson.devDependencies || {}
|
|
3990
|
+
});
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
const catalog = findDuplicateDependencies(packagesInfo, options.projectName);
|
|
3994
|
+
if (Object.keys(catalog).length === 0) return;
|
|
3995
|
+
if (options.packageManager === "bun") await setupBunCatalogs(projectDir, catalog);
|
|
3996
|
+
else if (options.packageManager === "pnpm") await setupPnpmCatalogs(projectDir, catalog);
|
|
3997
|
+
await updatePackageJsonsWithCatalogs(packagesInfo, catalog);
|
|
3998
|
+
}
|
|
3999
|
+
function findDuplicateDependencies(packagesInfo, projectName) {
|
|
4000
|
+
const depCount = /* @__PURE__ */ new Map();
|
|
4001
|
+
const projectScope = `@${projectName}/`;
|
|
4002
|
+
for (const pkg of packagesInfo) {
|
|
4003
|
+
const allDeps = {
|
|
4004
|
+
...pkg.dependencies,
|
|
4005
|
+
...pkg.devDependencies
|
|
4006
|
+
};
|
|
4007
|
+
for (const [depName, version] of Object.entries(allDeps)) {
|
|
4008
|
+
if (depName.startsWith(projectScope)) continue;
|
|
4009
|
+
if (version.startsWith("workspace:")) continue;
|
|
4010
|
+
const existing = depCount.get(depName);
|
|
4011
|
+
if (existing) existing.packages.push(pkg.path);
|
|
4012
|
+
else depCount.set(depName, {
|
|
4013
|
+
version,
|
|
4014
|
+
packages: [pkg.path]
|
|
4015
|
+
});
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
const catalog = {};
|
|
4019
|
+
for (const [depName, info] of depCount.entries()) if (info.packages.length > 1) catalog[depName] = info.version;
|
|
4020
|
+
return catalog;
|
|
4021
|
+
}
|
|
4022
|
+
async function setupBunCatalogs(projectDir, catalog) {
|
|
4023
|
+
const rootPkgJsonPath = path.join(projectDir, "package.json");
|
|
4024
|
+
const rootPkgJson = await fs.readJson(rootPkgJsonPath);
|
|
4025
|
+
if (!rootPkgJson.workspaces) rootPkgJson.workspaces = {};
|
|
4026
|
+
if (Array.isArray(rootPkgJson.workspaces)) rootPkgJson.workspaces = {
|
|
4027
|
+
packages: rootPkgJson.workspaces,
|
|
4028
|
+
catalog
|
|
4029
|
+
};
|
|
4030
|
+
else if (typeof rootPkgJson.workspaces === "object") {
|
|
4031
|
+
if (!rootPkgJson.workspaces.catalog) rootPkgJson.workspaces.catalog = {};
|
|
4032
|
+
rootPkgJson.workspaces.catalog = {
|
|
4033
|
+
...rootPkgJson.workspaces.catalog,
|
|
4034
|
+
...catalog
|
|
4035
|
+
};
|
|
4036
|
+
}
|
|
4037
|
+
await fs.writeJson(rootPkgJsonPath, rootPkgJson, { spaces: 2 });
|
|
4038
|
+
}
|
|
4039
|
+
async function setupPnpmCatalogs(projectDir, catalog) {
|
|
4040
|
+
const workspaceYamlPath = path.join(projectDir, "pnpm-workspace.yaml");
|
|
4041
|
+
if (!await fs.pathExists(workspaceYamlPath)) return;
|
|
4042
|
+
const workspaceContent = await fs.readFile(workspaceYamlPath, "utf-8");
|
|
4043
|
+
const workspaceYaml = yaml.parse(workspaceContent);
|
|
4044
|
+
if (!workspaceYaml.catalog) workspaceYaml.catalog = {};
|
|
4045
|
+
workspaceYaml.catalog = {
|
|
4046
|
+
...workspaceYaml.catalog,
|
|
4047
|
+
...catalog
|
|
4048
|
+
};
|
|
4049
|
+
await fs.writeFile(workspaceYamlPath, yaml.stringify(workspaceYaml));
|
|
4050
|
+
}
|
|
4051
|
+
async function updatePackageJsonsWithCatalogs(packagesInfo, catalog) {
|
|
4052
|
+
for (const pkg of packagesInfo) {
|
|
4053
|
+
const pkgJsonPath = path.join(pkg.path, "package.json");
|
|
4054
|
+
const pkgJson = await fs.readJson(pkgJsonPath);
|
|
4055
|
+
let updated = false;
|
|
4056
|
+
if (pkgJson.dependencies) {
|
|
4057
|
+
for (const depName of Object.keys(pkgJson.dependencies)) if (catalog[depName]) {
|
|
4058
|
+
pkgJson.dependencies[depName] = "catalog:";
|
|
4059
|
+
updated = true;
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
if (pkgJson.devDependencies) {
|
|
4063
|
+
for (const depName of Object.keys(pkgJson.devDependencies)) if (catalog[depName]) {
|
|
4064
|
+
pkgJson.devDependencies[depName] = "catalog:";
|
|
4065
|
+
updated = true;
|
|
4066
|
+
}
|
|
4067
|
+
}
|
|
4068
|
+
if (updated) await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
|
|
3958
4072
|
//#endregion
|
|
3959
4073
|
//#region src/helpers/addons/examples-setup.ts
|
|
3960
4074
|
async function setupExamples(config) {
|
|
3961
|
-
const { examples, frontend, backend, projectDir } = config;
|
|
4075
|
+
const { examples, frontend, backend, projectDir, orm } = config;
|
|
3962
4076
|
if (backend === "convex" || !examples || examples.length === 0 || examples[0] === "none") return;
|
|
4077
|
+
const apiDir = path.join(projectDir, "packages/api");
|
|
4078
|
+
if (await fs.pathExists(apiDir) && backend !== "none") {
|
|
4079
|
+
if (orm === "drizzle") await addPackageDependency({
|
|
4080
|
+
dependencies: ["drizzle-orm"],
|
|
4081
|
+
projectDir: apiDir
|
|
4082
|
+
});
|
|
4083
|
+
else if (orm === "prisma") await addPackageDependency({
|
|
4084
|
+
dependencies: ["@prisma/client"],
|
|
4085
|
+
projectDir: apiDir
|
|
4086
|
+
});
|
|
4087
|
+
else if (orm === "mongoose") await addPackageDependency({
|
|
4088
|
+
dependencies: ["mongoose"],
|
|
4089
|
+
projectDir: apiDir
|
|
4090
|
+
});
|
|
4091
|
+
}
|
|
3963
4092
|
if (examples.includes("ai")) {
|
|
3964
4093
|
const webClientDir = path.join(projectDir, "apps/web");
|
|
3965
4094
|
const nativeClientDir = path.join(projectDir, "apps/native");
|
|
3966
|
-
const
|
|
4095
|
+
const apiDir$1 = path.join(projectDir, "packages/api");
|
|
3967
4096
|
const webClientDirExists = await fs.pathExists(webClientDir);
|
|
3968
4097
|
const nativeClientDirExists = await fs.pathExists(nativeClientDir);
|
|
3969
|
-
const
|
|
4098
|
+
const apiDirExists = await fs.pathExists(apiDir$1);
|
|
3970
4099
|
const hasNuxt = frontend.includes("nuxt");
|
|
3971
4100
|
const hasSvelte = frontend.includes("svelte");
|
|
3972
4101
|
const hasReactWeb = frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("next") || frontend.includes("tanstack-start");
|
|
@@ -3987,9 +4116,13 @@ async function setupExamples(config) {
|
|
|
3987
4116
|
dependencies: ["ai", "@ai-sdk/react"],
|
|
3988
4117
|
projectDir: nativeClientDir
|
|
3989
4118
|
});
|
|
3990
|
-
if (
|
|
4119
|
+
if (apiDirExists && backend !== "none") await addPackageDependency({
|
|
3991
4120
|
dependencies: ["ai", "@ai-sdk/google"],
|
|
3992
|
-
projectDir:
|
|
4121
|
+
projectDir: apiDir$1
|
|
4122
|
+
});
|
|
4123
|
+
if (backend === "self" && webClientDirExists) await addPackageDependency({
|
|
4124
|
+
dependencies: ["ai", "@ai-sdk/google"],
|
|
4125
|
+
projectDir: webClientDir
|
|
3993
4126
|
});
|
|
3994
4127
|
}
|
|
3995
4128
|
}
|
|
@@ -4105,32 +4238,61 @@ function getConvexDependencies(frontend) {
|
|
|
4105
4238
|
return deps;
|
|
4106
4239
|
}
|
|
4107
4240
|
async function setupApi(config) {
|
|
4108
|
-
const { api, projectName, frontend, backend, packageManager, projectDir } = config;
|
|
4241
|
+
const { api, projectName, frontend, backend, packageManager, projectDir, auth } = config;
|
|
4109
4242
|
const isConvex = backend === "convex";
|
|
4110
4243
|
const webDir = path.join(projectDir, "apps/web");
|
|
4111
4244
|
const nativeDir = path.join(projectDir, "apps/native");
|
|
4112
4245
|
const serverDir = path.join(projectDir, "apps/server");
|
|
4113
4246
|
const webDirExists = await fs.pathExists(webDir);
|
|
4114
4247
|
const nativeDirExists = await fs.pathExists(nativeDir);
|
|
4115
|
-
|
|
4248
|
+
await fs.pathExists(serverDir);
|
|
4116
4249
|
const frontendType = getFrontendType(frontend);
|
|
4117
4250
|
if (!isConvex && api !== "none") {
|
|
4118
4251
|
const apiDeps = getApiDependencies(api, frontendType);
|
|
4119
|
-
|
|
4252
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
4253
|
+
if (apiDeps.server) {
|
|
4120
4254
|
await addPackageDependency({
|
|
4121
4255
|
dependencies: apiDeps.server.dependencies,
|
|
4122
|
-
projectDir:
|
|
4256
|
+
projectDir: apiPackageDir
|
|
4257
|
+
});
|
|
4258
|
+
if (backend === "self" && webDirExists) await addPackageDependency({
|
|
4259
|
+
dependencies: apiDeps.server.dependencies,
|
|
4260
|
+
projectDir: webDir
|
|
4261
|
+
});
|
|
4262
|
+
const frameworkDeps = [];
|
|
4263
|
+
if (backend === "hono") frameworkDeps.push("hono");
|
|
4264
|
+
else if (backend === "elysia") frameworkDeps.push("elysia");
|
|
4265
|
+
else if (backend === "express") frameworkDeps.push("express", "@types/express");
|
|
4266
|
+
else if (backend === "fastify") frameworkDeps.push("fastify");
|
|
4267
|
+
else if (backend === "self") {
|
|
4268
|
+
if (frontend.includes("next")) frameworkDeps.push("next");
|
|
4269
|
+
}
|
|
4270
|
+
if (frameworkDeps.length > 0) await addPackageDependency({
|
|
4271
|
+
dependencies: frameworkDeps,
|
|
4272
|
+
projectDir: apiPackageDir
|
|
4123
4273
|
});
|
|
4124
4274
|
if (api === "trpc") {
|
|
4125
4275
|
if (backend === "hono") await addPackageDependency({
|
|
4126
4276
|
dependencies: ["@hono/trpc-server"],
|
|
4127
|
-
projectDir:
|
|
4277
|
+
projectDir: apiPackageDir
|
|
4128
4278
|
});
|
|
4129
4279
|
else if (backend === "elysia") await addPackageDependency({
|
|
4130
4280
|
dependencies: ["@elysiajs/trpc"],
|
|
4131
|
-
projectDir:
|
|
4281
|
+
projectDir: apiPackageDir
|
|
4282
|
+
});
|
|
4283
|
+
else if (backend === "express") await addPackageDependency({
|
|
4284
|
+
dependencies: ["@trpc/server"],
|
|
4285
|
+
projectDir: apiPackageDir
|
|
4286
|
+
});
|
|
4287
|
+
else if (backend === "fastify") await addPackageDependency({
|
|
4288
|
+
dependencies: ["@trpc/server"],
|
|
4289
|
+
projectDir: apiPackageDir
|
|
4132
4290
|
});
|
|
4133
4291
|
}
|
|
4292
|
+
if (auth === "better-auth") await addPackageDependency({
|
|
4293
|
+
dependencies: ["better-auth"],
|
|
4294
|
+
projectDir: apiPackageDir
|
|
4295
|
+
});
|
|
4134
4296
|
}
|
|
4135
4297
|
if (webDirExists && apiDeps.web) await addPackageDependency({
|
|
4136
4298
|
dependencies: apiDeps.web.dependencies,
|
|
@@ -4174,7 +4336,7 @@ async function setupApi(config) {
|
|
|
4174
4336
|
//#endregion
|
|
4175
4337
|
//#region src/helpers/core/backend-setup.ts
|
|
4176
4338
|
async function setupBackendDependencies(config) {
|
|
4177
|
-
const { backend, runtime, api, projectDir } = config;
|
|
4339
|
+
const { backend, runtime, api, auth, examples, projectDir } = config;
|
|
4178
4340
|
if (backend === "convex") return;
|
|
4179
4341
|
const framework = backend;
|
|
4180
4342
|
const serverDir = path.join(projectDir, "apps/server");
|
|
@@ -4202,6 +4364,13 @@ async function setupBackendDependencies(config) {
|
|
|
4202
4364
|
dependencies.push("fastify", "@fastify/cors");
|
|
4203
4365
|
if (runtime === "node") devDependencies.push("tsx", "@types/node");
|
|
4204
4366
|
}
|
|
4367
|
+
if (api === "trpc") {
|
|
4368
|
+
if (framework === "express") dependencies.push("@trpc/server");
|
|
4369
|
+
else if (framework === "fastify") dependencies.push("@trpc/server");
|
|
4370
|
+
else if (runtime === "workers") dependencies.push("@trpc/server");
|
|
4371
|
+
} else if (api === "orpc") dependencies.push("@orpc/server", "@orpc/openapi", "@orpc/zod");
|
|
4372
|
+
if (auth === "better-auth") dependencies.push("better-auth");
|
|
4373
|
+
if (examples.includes("ai")) dependencies.push("ai", "@ai-sdk/google");
|
|
4205
4374
|
if (runtime === "bun") devDependencies.push("@types/bun");
|
|
4206
4375
|
if (dependencies.length > 0 || devDependencies.length > 0) await addPackageDependency({
|
|
4207
4376
|
dependencies,
|
|
@@ -4220,7 +4389,7 @@ async function setupAuth(config) {
|
|
|
4220
4389
|
const nativeDir = path.join(projectDir, "apps/native");
|
|
4221
4390
|
const clientDirExists = await fs.pathExists(clientDir);
|
|
4222
4391
|
const nativeDirExists = await fs.pathExists(nativeDir);
|
|
4223
|
-
|
|
4392
|
+
await fs.pathExists(serverDir);
|
|
4224
4393
|
try {
|
|
4225
4394
|
if (backend === "convex") {
|
|
4226
4395
|
if (auth === "clerk" && clientDirExists) {
|
|
@@ -4276,9 +4445,11 @@ async function setupAuth(config) {
|
|
|
4276
4445
|
});
|
|
4277
4446
|
return;
|
|
4278
4447
|
}
|
|
4279
|
-
|
|
4448
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
4449
|
+
const authPackageDirExists = await fs.pathExists(authPackageDir);
|
|
4450
|
+
if (authPackageDirExists && auth === "better-auth") await addPackageDependency({
|
|
4280
4451
|
dependencies: ["better-auth"],
|
|
4281
|
-
projectDir:
|
|
4452
|
+
projectDir: authPackageDir
|
|
4282
4453
|
});
|
|
4283
4454
|
if (frontend.some((f) => [
|
|
4284
4455
|
"react-router",
|
|
@@ -4300,9 +4471,9 @@ async function setupAuth(config) {
|
|
|
4300
4471
|
dependencies: ["better-auth", "@better-auth/expo"],
|
|
4301
4472
|
projectDir: nativeDir
|
|
4302
4473
|
});
|
|
4303
|
-
if (
|
|
4474
|
+
if (authPackageDirExists) await addPackageDependency({
|
|
4304
4475
|
dependencies: ["@better-auth/expo"],
|
|
4305
|
-
projectDir:
|
|
4476
|
+
projectDir: authPackageDir
|
|
4306
4477
|
});
|
|
4307
4478
|
}
|
|
4308
4479
|
}
|
|
@@ -4321,6 +4492,34 @@ function generateAuthSecret(length = 32) {
|
|
|
4321
4492
|
|
|
4322
4493
|
//#endregion
|
|
4323
4494
|
//#region src/helpers/core/env-setup.ts
|
|
4495
|
+
function getClientServerVar(frontend, backend) {
|
|
4496
|
+
const hasNextJs = frontend.includes("next");
|
|
4497
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
4498
|
+
const hasSvelte = frontend.includes("svelte");
|
|
4499
|
+
if (backend === "self") return {
|
|
4500
|
+
key: "",
|
|
4501
|
+
value: "",
|
|
4502
|
+
write: false
|
|
4503
|
+
};
|
|
4504
|
+
let key = "VITE_SERVER_URL";
|
|
4505
|
+
if (hasNextJs) key = "NEXT_PUBLIC_SERVER_URL";
|
|
4506
|
+
else if (hasNuxt) key = "NUXT_PUBLIC_SERVER_URL";
|
|
4507
|
+
else if (hasSvelte) key = "PUBLIC_SERVER_URL";
|
|
4508
|
+
return {
|
|
4509
|
+
key,
|
|
4510
|
+
value: "http://localhost:3000",
|
|
4511
|
+
write: true
|
|
4512
|
+
};
|
|
4513
|
+
}
|
|
4514
|
+
function getConvexVar(frontend) {
|
|
4515
|
+
const hasNextJs = frontend.includes("next");
|
|
4516
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
4517
|
+
const hasSvelte = frontend.includes("svelte");
|
|
4518
|
+
if (hasNextJs) return "NEXT_PUBLIC_CONVEX_URL";
|
|
4519
|
+
if (hasNuxt) return "NUXT_PUBLIC_CONVEX_URL";
|
|
4520
|
+
if (hasSvelte) return "PUBLIC_CONVEX_URL";
|
|
4521
|
+
return "VITE_CONVEX_URL";
|
|
4522
|
+
}
|
|
4324
4523
|
async function addEnvVariablesToFile(filePath, variables) {
|
|
4325
4524
|
await fs.ensureDir(path.dirname(filePath));
|
|
4326
4525
|
let envContent = "";
|
|
@@ -4379,22 +4578,13 @@ async function setupEnvironmentVariables(config) {
|
|
|
4379
4578
|
if (hasReactRouter || hasTanStackRouter || hasTanStackStart || hasNextJs || hasNuxt || hasSolid || hasSvelte) {
|
|
4380
4579
|
const clientDir = path.join(projectDir, "apps/web");
|
|
4381
4580
|
if (await fs.pathExists(clientDir)) {
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
else if (hasNuxt) envVarName = "NUXT_PUBLIC_SERVER_URL";
|
|
4386
|
-
else if (hasSvelte) envVarName = "PUBLIC_SERVER_URL";
|
|
4387
|
-
if (backend === "convex") {
|
|
4388
|
-
if (hasNextJs) envVarName = "NEXT_PUBLIC_CONVEX_URL";
|
|
4389
|
-
else if (hasNuxt) envVarName = "NUXT_PUBLIC_CONVEX_URL";
|
|
4390
|
-
else if (hasSvelte) envVarName = "PUBLIC_CONVEX_URL";
|
|
4391
|
-
else envVarName = "VITE_CONVEX_URL";
|
|
4392
|
-
serverUrl = "https://<YOUR_CONVEX_URL>";
|
|
4393
|
-
}
|
|
4581
|
+
const baseVar = getClientServerVar(frontend, backend);
|
|
4582
|
+
const envVarName = backend === "convex" ? getConvexVar(frontend) : baseVar.key;
|
|
4583
|
+
const serverUrl = backend === "convex" ? "https://<YOUR_CONVEX_URL>" : baseVar.value;
|
|
4394
4584
|
const clientVars = [{
|
|
4395
4585
|
key: envVarName,
|
|
4396
4586
|
value: serverUrl,
|
|
4397
|
-
condition: true
|
|
4587
|
+
condition: backend === "convex" ? true : baseVar.write
|
|
4398
4588
|
}];
|
|
4399
4589
|
if (backend === "convex" && auth === "clerk") {
|
|
4400
4590
|
if (hasNextJs) clientVars.push({
|
|
@@ -4485,10 +4675,9 @@ async function setupEnvironmentVariables(config) {
|
|
|
4485
4675
|
return;
|
|
4486
4676
|
}
|
|
4487
4677
|
const serverDir = path.join(projectDir, "apps/server");
|
|
4488
|
-
if (!await fs.pathExists(serverDir)) return;
|
|
4489
|
-
const envPath = path.join(serverDir, ".env");
|
|
4490
4678
|
let corsOrigin = "http://localhost:3001";
|
|
4491
|
-
if (
|
|
4679
|
+
if (backend === "self") corsOrigin = "http://localhost:3001";
|
|
4680
|
+
else if (hasReactRouter || hasSvelte) corsOrigin = "http://localhost:5173";
|
|
4492
4681
|
let databaseUrl = null;
|
|
4493
4682
|
if (database !== "none" && dbSetup === "none") switch (database) {
|
|
4494
4683
|
case "postgres":
|
|
@@ -4502,15 +4691,13 @@ async function setupEnvironmentVariables(config) {
|
|
|
4502
4691
|
break;
|
|
4503
4692
|
case "sqlite":
|
|
4504
4693
|
if (config.runtime === "workers") databaseUrl = "http://127.0.0.1:8080";
|
|
4505
|
-
else
|
|
4694
|
+
else {
|
|
4695
|
+
const dbAppDir = backend === "self" ? "apps/web" : "apps/server";
|
|
4696
|
+
databaseUrl = `file:${path.join(config.projectDir, dbAppDir, "local.db")}`;
|
|
4697
|
+
}
|
|
4506
4698
|
break;
|
|
4507
4699
|
}
|
|
4508
4700
|
const serverVars = [
|
|
4509
|
-
{
|
|
4510
|
-
key: "CORS_ORIGIN",
|
|
4511
|
-
value: corsOrigin,
|
|
4512
|
-
condition: true
|
|
4513
|
-
},
|
|
4514
4701
|
{
|
|
4515
4702
|
key: "BETTER_AUTH_SECRET",
|
|
4516
4703
|
value: generateAuthSecret(),
|
|
@@ -4518,19 +4705,9 @@ async function setupEnvironmentVariables(config) {
|
|
|
4518
4705
|
},
|
|
4519
4706
|
{
|
|
4520
4707
|
key: "BETTER_AUTH_URL",
|
|
4521
|
-
value: "http://localhost:3000",
|
|
4708
|
+
value: backend === "self" ? "http://localhost:3001" : "http://localhost:3000",
|
|
4522
4709
|
condition: !!auth
|
|
4523
4710
|
},
|
|
4524
|
-
{
|
|
4525
|
-
key: "DATABASE_URL",
|
|
4526
|
-
value: databaseUrl,
|
|
4527
|
-
condition: database !== "none" && dbSetup === "none"
|
|
4528
|
-
},
|
|
4529
|
-
{
|
|
4530
|
-
key: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
4531
|
-
value: "",
|
|
4532
|
-
condition: examples?.includes("ai") || false
|
|
4533
|
-
},
|
|
4534
4711
|
{
|
|
4535
4712
|
key: "POLAR_ACCESS_TOKEN",
|
|
4536
4713
|
value: "",
|
|
@@ -4540,9 +4717,27 @@ async function setupEnvironmentVariables(config) {
|
|
|
4540
4717
|
key: "POLAR_SUCCESS_URL",
|
|
4541
4718
|
value: `${corsOrigin}/success?checkout_id={CHECKOUT_ID}`,
|
|
4542
4719
|
condition: config.payments === "polar"
|
|
4720
|
+
},
|
|
4721
|
+
{
|
|
4722
|
+
key: "CORS_ORIGIN",
|
|
4723
|
+
value: corsOrigin,
|
|
4724
|
+
condition: true
|
|
4725
|
+
},
|
|
4726
|
+
{
|
|
4727
|
+
key: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
4728
|
+
value: "",
|
|
4729
|
+
condition: examples?.includes("ai") || false
|
|
4730
|
+
},
|
|
4731
|
+
{
|
|
4732
|
+
key: "DATABASE_URL",
|
|
4733
|
+
value: databaseUrl,
|
|
4734
|
+
condition: database !== "none" && dbSetup === "none"
|
|
4543
4735
|
}
|
|
4544
4736
|
];
|
|
4545
|
-
|
|
4737
|
+
if (backend === "self") {
|
|
4738
|
+
const webDir = path.join(projectDir, "apps/web");
|
|
4739
|
+
if (await fs.pathExists(webDir)) await addEnvVariablesToFile(path.join(webDir, ".env"), serverVars);
|
|
4740
|
+
} else if (await fs.pathExists(serverDir)) await addEnvVariablesToFile(path.join(serverDir, ".env"), serverVars);
|
|
4546
4741
|
const isUnifiedAlchemy = webDeploy === "alchemy" && serverDeploy === "alchemy";
|
|
4547
4742
|
const isIndividualAlchemy = webDeploy === "alchemy" || serverDeploy === "alchemy";
|
|
4548
4743
|
if (isUnifiedAlchemy) {
|
|
@@ -4562,12 +4757,15 @@ async function setupEnvironmentVariables(config) {
|
|
|
4562
4757
|
}]);
|
|
4563
4758
|
}
|
|
4564
4759
|
if (serverDeploy === "alchemy") {
|
|
4565
|
-
const
|
|
4566
|
-
if (await fs.pathExists(serverDir$1)) await addEnvVariablesToFile(path.join(serverDir$1, ".env"), [{
|
|
4760
|
+
const serverAlchemyVars = [{
|
|
4567
4761
|
key: "ALCHEMY_PASSWORD",
|
|
4568
4762
|
value: "please-change-this",
|
|
4569
4763
|
condition: true
|
|
4570
|
-
}]
|
|
4764
|
+
}];
|
|
4765
|
+
if (backend === "self") {
|
|
4766
|
+
const webDir = path.join(projectDir, "apps/web");
|
|
4767
|
+
if (await fs.pathExists(webDir)) await addEnvVariablesToFile(path.join(webDir, ".env"), serverAlchemyVars);
|
|
4768
|
+
} else await addEnvVariablesToFile(path.join(serverDir, ".env"), serverAlchemyVars);
|
|
4571
4769
|
}
|
|
4572
4770
|
}
|
|
4573
4771
|
}
|
|
@@ -4575,9 +4773,10 @@ async function setupEnvironmentVariables(config) {
|
|
|
4575
4773
|
//#endregion
|
|
4576
4774
|
//#region src/helpers/database-providers/d1-setup.ts
|
|
4577
4775
|
async function setupCloudflareD1(config) {
|
|
4578
|
-
const { projectDir, serverDeploy, orm } = config;
|
|
4776
|
+
const { projectDir, serverDeploy, orm, backend } = config;
|
|
4579
4777
|
if (serverDeploy === "wrangler") {
|
|
4580
|
-
const
|
|
4778
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
4779
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4581
4780
|
const variables = [
|
|
4582
4781
|
{
|
|
4583
4782
|
key: "CLOUDFLARE_ACCOUNT_ID",
|
|
@@ -4600,16 +4799,17 @@ async function setupCloudflareD1(config) {
|
|
|
4600
4799
|
} catch (_err) {}
|
|
4601
4800
|
}
|
|
4602
4801
|
if ((serverDeploy === "wrangler" || serverDeploy === "alchemy") && orm === "prisma") {
|
|
4603
|
-
const
|
|
4802
|
+
const targetApp2 = backend === "self" ? "apps/web" : "apps/server";
|
|
4803
|
+
const envPath = path.join(projectDir, targetApp2, ".env");
|
|
4604
4804
|
const variables = [{
|
|
4605
4805
|
key: "DATABASE_URL",
|
|
4606
|
-
value: "
|
|
4806
|
+
value: `file:${path.join(projectDir, "apps/server", "local.db")}`,
|
|
4607
4807
|
condition: true
|
|
4608
4808
|
}];
|
|
4609
4809
|
try {
|
|
4610
4810
|
await addEnvVariablesToFile(envPath, variables);
|
|
4611
4811
|
} catch (_err) {}
|
|
4612
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
4812
|
+
const serverDir = path.join(projectDir, backend === "self" ? "apps/web" : "apps/server");
|
|
4613
4813
|
await addPackageDependency({
|
|
4614
4814
|
dependencies: ["@prisma/adapter-d1"],
|
|
4615
4815
|
projectDir: serverDir
|
|
@@ -4702,9 +4902,10 @@ async function initMongoDBAtlas(serverDir) {
|
|
|
4702
4902
|
return null;
|
|
4703
4903
|
}
|
|
4704
4904
|
}
|
|
4705
|
-
async function writeEnvFile$3(projectDir, config) {
|
|
4905
|
+
async function writeEnvFile$3(projectDir, backend, config) {
|
|
4706
4906
|
try {
|
|
4707
|
-
const
|
|
4907
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
4908
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4708
4909
|
const variables = [{
|
|
4709
4910
|
key: "DATABASE_URL",
|
|
4710
4911
|
value: config?.connectionString ?? "mongodb://localhost:27017/mydb",
|
|
@@ -4733,16 +4934,16 @@ ${pc.green("MongoDB Atlas Manual Setup Instructions:")}
|
|
|
4733
4934
|
`);
|
|
4734
4935
|
}
|
|
4735
4936
|
async function setupMongoDBAtlas(config, cliInput) {
|
|
4736
|
-
const { projectDir } = config;
|
|
4937
|
+
const { projectDir, backend } = config;
|
|
4737
4938
|
const manualDb = cliInput?.manualDb ?? false;
|
|
4738
4939
|
const mainSpinner = spinner();
|
|
4739
4940
|
mainSpinner.start("Setting up MongoDB Atlas...");
|
|
4740
|
-
const serverDir = path.join(projectDir, "
|
|
4941
|
+
const serverDir = path.join(projectDir, "packages/db");
|
|
4741
4942
|
try {
|
|
4742
4943
|
await fs.ensureDir(serverDir);
|
|
4743
4944
|
if (manualDb) {
|
|
4744
4945
|
mainSpinner.stop("MongoDB Atlas manual setup selected");
|
|
4745
|
-
await writeEnvFile$3(projectDir);
|
|
4946
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4746
4947
|
displayManualSetupInstructions$3();
|
|
4747
4948
|
return;
|
|
4748
4949
|
}
|
|
@@ -4762,25 +4963,25 @@ async function setupMongoDBAtlas(config, cliInput) {
|
|
|
4762
4963
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
4763
4964
|
if (mode === "manual") {
|
|
4764
4965
|
mainSpinner.stop("MongoDB Atlas manual setup selected");
|
|
4765
|
-
await writeEnvFile$3(projectDir);
|
|
4966
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4766
4967
|
displayManualSetupInstructions$3();
|
|
4767
4968
|
return;
|
|
4768
4969
|
}
|
|
4769
4970
|
mainSpinner.stop("MongoDB Atlas setup ready");
|
|
4770
4971
|
const config$1 = await initMongoDBAtlas(serverDir);
|
|
4771
4972
|
if (config$1) {
|
|
4772
|
-
await writeEnvFile$3(projectDir, config$1);
|
|
4973
|
+
await writeEnvFile$3(projectDir, backend, config$1);
|
|
4773
4974
|
log.success(pc.green("MongoDB Atlas setup complete! Connection saved to .env file."));
|
|
4774
4975
|
} else {
|
|
4775
4976
|
log.warn(pc.yellow("Falling back to local MongoDB configuration"));
|
|
4776
|
-
await writeEnvFile$3(projectDir);
|
|
4977
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4777
4978
|
displayManualSetupInstructions$3();
|
|
4778
4979
|
}
|
|
4779
4980
|
} catch (error) {
|
|
4780
4981
|
mainSpinner.stop(pc.red("MongoDB Atlas setup failed"));
|
|
4781
4982
|
consola.error(pc.red(`Error during MongoDB Atlas setup: ${error instanceof Error ? error.message : String(error)}`));
|
|
4782
4983
|
try {
|
|
4783
|
-
await writeEnvFile$3(projectDir);
|
|
4984
|
+
await writeEnvFile$3(projectDir, backend);
|
|
4784
4985
|
displayManualSetupInstructions$3();
|
|
4785
4986
|
} catch {}
|
|
4786
4987
|
}
|
|
@@ -4837,7 +5038,7 @@ async function executeNeonCommand(packageManager, commandArgsString, spinnerText
|
|
|
4837
5038
|
}
|
|
4838
5039
|
async function createNeonProject(projectName, regionId, packageManager) {
|
|
4839
5040
|
try {
|
|
4840
|
-
const commandArgsString = `neonctl projects create --name ${projectName} --region-id ${regionId} --output json`;
|
|
5041
|
+
const commandArgsString = `neonctl@latest projects create --name ${projectName} --region-id ${regionId} --output json`;
|
|
4841
5042
|
const { stdout } = await executeNeonCommand(packageManager, commandArgsString, `Creating Neon project "${projectName}"...`);
|
|
4842
5043
|
const response = JSON.parse(stdout);
|
|
4843
5044
|
if (response.project && response.connection_uris && response.connection_uris.length > 0) {
|
|
@@ -4857,8 +5058,9 @@ async function createNeonProject(projectName, regionId, packageManager) {
|
|
|
4857
5058
|
consola$1.error(pc.red("Failed to create Neon project"));
|
|
4858
5059
|
}
|
|
4859
5060
|
}
|
|
4860
|
-
async function writeEnvFile$2(projectDir, config) {
|
|
4861
|
-
const
|
|
5061
|
+
async function writeEnvFile$2(projectDir, backend, config) {
|
|
5062
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5063
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4862
5064
|
const variables = [{
|
|
4863
5065
|
key: "DATABASE_URL",
|
|
4864
5066
|
value: config?.connectionString ?? "postgresql://postgres:postgres@localhost:5432/mydb?schema=public",
|
|
@@ -4867,16 +5069,17 @@ async function writeEnvFile$2(projectDir, config) {
|
|
|
4867
5069
|
await addEnvVariablesToFile(envPath, variables);
|
|
4868
5070
|
return true;
|
|
4869
5071
|
}
|
|
4870
|
-
async function setupWithNeonDb(projectDir, packageManager) {
|
|
5072
|
+
async function setupWithNeonDb(projectDir, packageManager, backend) {
|
|
4871
5073
|
try {
|
|
4872
5074
|
const s = spinner();
|
|
4873
5075
|
s.start("Creating Neon database using neondb...");
|
|
4874
|
-
const
|
|
4875
|
-
|
|
4876
|
-
|
|
5076
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5077
|
+
const targetDir = path.join(projectDir, targetApp);
|
|
5078
|
+
await fs.ensureDir(targetDir);
|
|
5079
|
+
const packageCmd = getPackageExecutionCommand(packageManager, "neondb@latest --yes");
|
|
4877
5080
|
await execa(packageCmd, {
|
|
4878
5081
|
shell: true,
|
|
4879
|
-
cwd:
|
|
5082
|
+
cwd: targetDir
|
|
4880
5083
|
});
|
|
4881
5084
|
s.stop(pc.green("Neon database created successfully!"));
|
|
4882
5085
|
return true;
|
|
@@ -4885,23 +5088,23 @@ async function setupWithNeonDb(projectDir, packageManager) {
|
|
|
4885
5088
|
throw error;
|
|
4886
5089
|
}
|
|
4887
5090
|
}
|
|
4888
|
-
function displayManualSetupInstructions$2() {
|
|
5091
|
+
function displayManualSetupInstructions$2(target) {
|
|
4889
5092
|
log.info(`Manual Neon PostgreSQL Setup Instructions:
|
|
4890
5093
|
|
|
4891
5094
|
1. Visit https://neon.tech and create an account
|
|
4892
5095
|
2. Create a new project from the dashboard
|
|
4893
5096
|
3. Get your connection string
|
|
4894
|
-
4. Add the database URL to the .env file in
|
|
5097
|
+
4. Add the database URL to the .env file in ${target}/.env
|
|
4895
5098
|
|
|
4896
5099
|
DATABASE_URL="your_connection_string"`);
|
|
4897
5100
|
}
|
|
4898
5101
|
async function setupNeonPostgres(config, cliInput) {
|
|
4899
|
-
const { packageManager, projectDir } = config;
|
|
5102
|
+
const { packageManager, projectDir, backend } = config;
|
|
4900
5103
|
const manualDb = cliInput?.manualDb ?? false;
|
|
4901
5104
|
try {
|
|
4902
5105
|
if (manualDb) {
|
|
4903
|
-
await writeEnvFile$2(projectDir);
|
|
4904
|
-
displayManualSetupInstructions$2();
|
|
5106
|
+
await writeEnvFile$2(projectDir, backend);
|
|
5107
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
4905
5108
|
return;
|
|
4906
5109
|
}
|
|
4907
5110
|
const mode = await select({
|
|
@@ -4919,8 +5122,8 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
4919
5122
|
});
|
|
4920
5123
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
4921
5124
|
if (mode === "manual") {
|
|
4922
|
-
await writeEnvFile$2(projectDir);
|
|
4923
|
-
displayManualSetupInstructions$2();
|
|
5125
|
+
await writeEnvFile$2(projectDir, backend);
|
|
5126
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
4924
5127
|
return;
|
|
4925
5128
|
}
|
|
4926
5129
|
const setupMethod = await select({
|
|
@@ -4937,7 +5140,7 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
4937
5140
|
initialValue: "neondb"
|
|
4938
5141
|
});
|
|
4939
5142
|
if (isCancel(setupMethod)) return exitCancelled("Operation cancelled");
|
|
4940
|
-
if (setupMethod === "neondb") await setupWithNeonDb(projectDir, packageManager);
|
|
5143
|
+
if (setupMethod === "neondb") await setupWithNeonDb(projectDir, packageManager, backend);
|
|
4941
5144
|
else {
|
|
4942
5145
|
const suggestedProjectName = path.basename(projectDir);
|
|
4943
5146
|
const projectName = await text({
|
|
@@ -4955,22 +5158,22 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
4955
5158
|
if (!neonConfig) throw new Error("Failed to create project - couldn't get connection information");
|
|
4956
5159
|
const finalSpinner = spinner();
|
|
4957
5160
|
finalSpinner.start("Configuring database connection");
|
|
4958
|
-
await
|
|
4959
|
-
await writeEnvFile$2(projectDir, neonConfig);
|
|
5161
|
+
await writeEnvFile$2(projectDir, backend, neonConfig);
|
|
4960
5162
|
finalSpinner.stop("Neon database configured!");
|
|
4961
5163
|
}
|
|
4962
5164
|
} catch (error) {
|
|
4963
5165
|
if (error instanceof Error) consola$1.error(pc.red(error.message));
|
|
4964
|
-
await writeEnvFile$2(projectDir);
|
|
4965
|
-
displayManualSetupInstructions$2();
|
|
5166
|
+
await writeEnvFile$2(projectDir, backend);
|
|
5167
|
+
displayManualSetupInstructions$2(backend === "self" ? "apps/web" : "apps/server");
|
|
4966
5168
|
}
|
|
4967
5169
|
}
|
|
4968
5170
|
|
|
4969
5171
|
//#endregion
|
|
4970
5172
|
//#region src/helpers/database-providers/planetscale-setup.ts
|
|
4971
5173
|
async function setupPlanetScale(config) {
|
|
4972
|
-
const { projectDir, database, orm } = config;
|
|
4973
|
-
const
|
|
5174
|
+
const { projectDir, database, orm, backend } = config;
|
|
5175
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5176
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
4974
5177
|
if (database === "mysql" && orm === "drizzle") {
|
|
4975
5178
|
const variables = [
|
|
4976
5179
|
{
|
|
@@ -4994,7 +5197,7 @@ async function setupPlanetScale(config) {
|
|
|
4994
5197
|
condition: true
|
|
4995
5198
|
}
|
|
4996
5199
|
];
|
|
4997
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5200
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
4998
5201
|
await addEnvVariablesToFile(envPath, variables);
|
|
4999
5202
|
}
|
|
5000
5203
|
if (database === "postgres" && orm === "prisma") {
|
|
@@ -5003,7 +5206,7 @@ async function setupPlanetScale(config) {
|
|
|
5003
5206
|
value: "postgresql://username:password@host/database?sslaccept=strict",
|
|
5004
5207
|
condition: true
|
|
5005
5208
|
}];
|
|
5006
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5209
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
5007
5210
|
await addEnvVariablesToFile(envPath, variables);
|
|
5008
5211
|
}
|
|
5009
5212
|
if (database === "postgres" && orm === "drizzle") {
|
|
@@ -5012,7 +5215,7 @@ async function setupPlanetScale(config) {
|
|
|
5012
5215
|
value: "postgresql://username:password@host/database?sslmode=verify-full",
|
|
5013
5216
|
condition: true
|
|
5014
5217
|
}];
|
|
5015
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5218
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
5016
5219
|
await addEnvVariablesToFile(envPath, variables);
|
|
5017
5220
|
}
|
|
5018
5221
|
if (database === "mysql" && orm === "prisma") {
|
|
@@ -5021,7 +5224,7 @@ async function setupPlanetScale(config) {
|
|
|
5021
5224
|
value: "mysql://username:password@host/database?sslaccept=strict",
|
|
5022
5225
|
condition: true
|
|
5023
5226
|
}];
|
|
5024
|
-
await fs.ensureDir(path.join(projectDir,
|
|
5227
|
+
await fs.ensureDir(path.join(projectDir, targetApp));
|
|
5025
5228
|
await addEnvVariablesToFile(envPath, variables);
|
|
5026
5229
|
}
|
|
5027
5230
|
}
|
|
@@ -5091,7 +5294,7 @@ async function initPrismaDatabase(serverDir, packageManager) {
|
|
|
5091
5294
|
try {
|
|
5092
5295
|
const prismaDir = path.join(serverDir, "prisma");
|
|
5093
5296
|
await fs.ensureDir(prismaDir);
|
|
5094
|
-
log.info("Starting Prisma PostgreSQL setup.
|
|
5297
|
+
log.info("Starting Prisma PostgreSQL setup.");
|
|
5095
5298
|
const prismaInitCommand = getPackageExecutionCommand(packageManager, "prisma init --db");
|
|
5096
5299
|
await execa(prismaInitCommand, {
|
|
5097
5300
|
cwd: serverDir,
|
|
@@ -5113,9 +5316,10 @@ async function initPrismaDatabase(serverDir, packageManager) {
|
|
|
5113
5316
|
return null;
|
|
5114
5317
|
}
|
|
5115
5318
|
}
|
|
5116
|
-
async function writeEnvFile$1(projectDir, config) {
|
|
5319
|
+
async function writeEnvFile$1(projectDir, backend, config) {
|
|
5117
5320
|
try {
|
|
5118
|
-
const
|
|
5321
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5322
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5119
5323
|
const variables = [{
|
|
5120
5324
|
key: "DATABASE_URL",
|
|
5121
5325
|
value: config?.databaseUrl ?? "postgresql://postgres:postgres@localhost:5432/mydb?schema=public",
|
|
@@ -5131,31 +5335,32 @@ async function writeEnvFile$1(projectDir, config) {
|
|
|
5131
5335
|
consola$1.error("Failed to update environment configuration");
|
|
5132
5336
|
}
|
|
5133
5337
|
}
|
|
5134
|
-
async function addDotenvImportToPrismaConfig(projectDir) {
|
|
5338
|
+
async function addDotenvImportToPrismaConfig(projectDir, backend) {
|
|
5135
5339
|
try {
|
|
5136
|
-
const prismaConfigPath = path.join(projectDir, "
|
|
5340
|
+
const prismaConfigPath = path.join(projectDir, "packages/db/prisma.config.ts");
|
|
5137
5341
|
let content = await fs.readFile(prismaConfigPath, "utf8");
|
|
5138
|
-
content = `import "dotenv
|
|
5342
|
+
content = `import dotenv from "dotenv";\ndotenv.config({ path: "${backend === "self" ? "../../apps/web/.env" : "../../apps/server/.env"}" });\n${content}`;
|
|
5139
5343
|
await fs.writeFile(prismaConfigPath, content);
|
|
5140
5344
|
} catch (_error) {
|
|
5141
5345
|
consola$1.error("Failed to update prisma.config.ts");
|
|
5142
5346
|
}
|
|
5143
5347
|
}
|
|
5144
|
-
function displayManualSetupInstructions$1() {
|
|
5348
|
+
function displayManualSetupInstructions$1(target) {
|
|
5145
5349
|
log.info(`Manual Prisma PostgreSQL Setup Instructions:
|
|
5146
5350
|
|
|
5147
5351
|
1. Visit https://console.prisma.io and create an account
|
|
5148
5352
|
2. Create a new PostgreSQL database from the dashboard
|
|
5149
5353
|
3. Get your database URL
|
|
5150
|
-
4. Add the database URL to the .env file in
|
|
5354
|
+
4. Add the database URL to the .env file in ${target}/.env
|
|
5151
5355
|
|
|
5152
5356
|
DATABASE_URL="your_database_url"`);
|
|
5153
5357
|
}
|
|
5154
|
-
async function addPrismaAccelerateExtension(
|
|
5358
|
+
async function addPrismaAccelerateExtension(projectDir) {
|
|
5155
5359
|
try {
|
|
5360
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
5156
5361
|
await addPackageDependency({
|
|
5157
5362
|
dependencies: ["@prisma/extension-accelerate"],
|
|
5158
|
-
projectDir:
|
|
5363
|
+
projectDir: dbPackageDir
|
|
5159
5364
|
});
|
|
5160
5365
|
return true;
|
|
5161
5366
|
} catch (_error) {
|
|
@@ -5164,14 +5369,14 @@ async function addPrismaAccelerateExtension(serverDir) {
|
|
|
5164
5369
|
}
|
|
5165
5370
|
}
|
|
5166
5371
|
async function setupPrismaPostgres(config, cliInput) {
|
|
5167
|
-
const { packageManager, projectDir, orm } = config;
|
|
5372
|
+
const { packageManager, projectDir, orm, backend } = config;
|
|
5168
5373
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5169
|
-
const
|
|
5374
|
+
const dbDir = path.join(projectDir, "packages/db");
|
|
5170
5375
|
try {
|
|
5171
|
-
await fs.ensureDir(
|
|
5376
|
+
await fs.ensureDir(dbDir);
|
|
5172
5377
|
if (manualDb) {
|
|
5173
|
-
await writeEnvFile$1(projectDir);
|
|
5174
|
-
displayManualSetupInstructions$1();
|
|
5378
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5379
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5175
5380
|
return;
|
|
5176
5381
|
}
|
|
5177
5382
|
const mode = await select({
|
|
@@ -5189,8 +5394,8 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5189
5394
|
});
|
|
5190
5395
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5191
5396
|
if (mode === "manual") {
|
|
5192
|
-
await writeEnvFile$1(projectDir);
|
|
5193
|
-
displayManualSetupInstructions$1();
|
|
5397
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5398
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5194
5399
|
return;
|
|
5195
5400
|
}
|
|
5196
5401
|
const setupOptions = [{
|
|
@@ -5210,26 +5415,26 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5210
5415
|
});
|
|
5211
5416
|
if (isCancel(setupMethod)) return exitCancelled("Operation cancelled");
|
|
5212
5417
|
let prismaConfig = null;
|
|
5213
|
-
if (setupMethod === "create-db") prismaConfig = await setupWithCreateDb(
|
|
5214
|
-
else prismaConfig = await initPrismaDatabase(
|
|
5418
|
+
if (setupMethod === "create-db") prismaConfig = await setupWithCreateDb(dbDir, packageManager, orm);
|
|
5419
|
+
else prismaConfig = await initPrismaDatabase(dbDir, packageManager);
|
|
5215
5420
|
if (prismaConfig) {
|
|
5216
|
-
await writeEnvFile$1(projectDir, prismaConfig);
|
|
5421
|
+
await writeEnvFile$1(projectDir, backend, prismaConfig);
|
|
5217
5422
|
if (orm === "prisma") {
|
|
5218
|
-
await addDotenvImportToPrismaConfig(projectDir);
|
|
5219
|
-
await addPrismaAccelerateExtension(
|
|
5423
|
+
await addDotenvImportToPrismaConfig(projectDir, backend);
|
|
5424
|
+
await addPrismaAccelerateExtension(projectDir);
|
|
5220
5425
|
}
|
|
5221
5426
|
const connectionType = orm === "drizzle" ? "direct connection" : "Prisma Accelerate";
|
|
5222
5427
|
log.success(pc.green(`Prisma Postgres database configured successfully with ${connectionType}!`));
|
|
5223
5428
|
if (prismaConfig.claimUrl) log.info(pc.blue(`Claim URL saved to .env: ${prismaConfig.claimUrl}`));
|
|
5224
5429
|
} else {
|
|
5225
|
-
await writeEnvFile$1(projectDir);
|
|
5226
|
-
displayManualSetupInstructions$1();
|
|
5430
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5431
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5227
5432
|
}
|
|
5228
5433
|
} catch (error) {
|
|
5229
5434
|
consola$1.error(pc.red(`Error during Prisma Postgres setup: ${error instanceof Error ? error.message : String(error)}`));
|
|
5230
5435
|
try {
|
|
5231
|
-
await writeEnvFile$1(projectDir);
|
|
5232
|
-
displayManualSetupInstructions$1();
|
|
5436
|
+
await writeEnvFile$1(projectDir, backend);
|
|
5437
|
+
displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
|
|
5233
5438
|
} catch {}
|
|
5234
5439
|
log.info("Setup completed with manual configuration required.");
|
|
5235
5440
|
}
|
|
@@ -5237,9 +5442,10 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5237
5442
|
|
|
5238
5443
|
//#endregion
|
|
5239
5444
|
//#region src/helpers/database-providers/supabase-setup.ts
|
|
5240
|
-
async function writeSupabaseEnvFile(projectDir, databaseUrl) {
|
|
5445
|
+
async function writeSupabaseEnvFile(projectDir, backend, databaseUrl) {
|
|
5241
5446
|
try {
|
|
5242
|
-
const
|
|
5447
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5448
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5243
5449
|
const dbUrlToUse = databaseUrl || "postgresql://postgres:postgres@127.0.0.1:54322/postgres";
|
|
5244
5450
|
await addEnvVariablesToFile(envPath, [{
|
|
5245
5451
|
key: "DATABASE_URL",
|
|
@@ -5316,23 +5522,23 @@ function displayManualSupabaseInstructions(output) {
|
|
|
5316
5522
|
log.info(`"Manual Supabase Setup Instructions:"
|
|
5317
5523
|
1. Ensure Docker is installed and running.
|
|
5318
5524
|
2. Install the Supabase CLI (e.g., \`npm install -g supabase\`).
|
|
5319
|
-
3. Run \`supabase init\` in your project's \`
|
|
5320
|
-
4. Run \`supabase start\` in your project's \`
|
|
5525
|
+
3. Run \`supabase init\` in your project's \`packages/db\` directory.
|
|
5526
|
+
4. Run \`supabase start\` in your project's \`packages/db\` directory.
|
|
5321
5527
|
5. Copy the 'DB URL' from the output.${output ? `
|
|
5322
5528
|
${pc.bold("Relevant output from `supabase start`:")}
|
|
5323
5529
|
${pc.dim(output)}` : ""}
|
|
5324
|
-
6. Add the DB URL to the .env file in \`
|
|
5530
|
+
6. Add the DB URL to the .env file in \`packages/db/.env\` as \`DATABASE_URL\`:
|
|
5325
5531
|
${pc.gray("DATABASE_URL=\"your_supabase_db_url\"")}`);
|
|
5326
5532
|
}
|
|
5327
5533
|
async function setupSupabase(config, cliInput) {
|
|
5328
|
-
const { projectDir, packageManager } = config;
|
|
5534
|
+
const { projectDir, packageManager, backend } = config;
|
|
5329
5535
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5330
|
-
const serverDir = path.join(projectDir, "
|
|
5536
|
+
const serverDir = path.join(projectDir, "packages", "db");
|
|
5331
5537
|
try {
|
|
5332
5538
|
await fs.ensureDir(serverDir);
|
|
5333
5539
|
if (manualDb) {
|
|
5334
5540
|
displayManualSupabaseInstructions();
|
|
5335
|
-
await writeSupabaseEnvFile(projectDir, "");
|
|
5541
|
+
await writeSupabaseEnvFile(projectDir, backend, "");
|
|
5336
5542
|
return;
|
|
5337
5543
|
}
|
|
5338
5544
|
const mode = await select({
|
|
@@ -5351,7 +5557,7 @@ async function setupSupabase(config, cliInput) {
|
|
|
5351
5557
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5352
5558
|
if (mode === "manual") {
|
|
5353
5559
|
displayManualSupabaseInstructions();
|
|
5354
|
-
await writeSupabaseEnvFile(projectDir, "");
|
|
5560
|
+
await writeSupabaseEnvFile(projectDir, backend, "");
|
|
5355
5561
|
return;
|
|
5356
5562
|
}
|
|
5357
5563
|
if (!await initializeSupabase(serverDir, packageManager)) {
|
|
@@ -5364,7 +5570,7 @@ async function setupSupabase(config, cliInput) {
|
|
|
5364
5570
|
return;
|
|
5365
5571
|
}
|
|
5366
5572
|
const dbUrl = extractDbUrl(supabaseOutput);
|
|
5367
|
-
if (dbUrl) if (await writeSupabaseEnvFile(projectDir, dbUrl)) log.success(pc.green("Supabase local development setup ready!"));
|
|
5573
|
+
if (dbUrl) if (await writeSupabaseEnvFile(projectDir, backend, dbUrl)) log.success(pc.green("Supabase local development setup ready!"));
|
|
5368
5574
|
else {
|
|
5369
5575
|
log.error(pc.red("Supabase setup completed, but failed to update .env automatically."));
|
|
5370
5576
|
displayManualSupabaseInstructions(supabaseOutput);
|
|
@@ -5492,8 +5698,9 @@ async function createTursoDatabase(dbName, groupName) {
|
|
|
5492
5698
|
s.stop(pc.red("Failed to retrieve database connection details"));
|
|
5493
5699
|
}
|
|
5494
5700
|
}
|
|
5495
|
-
async function writeEnvFile(projectDir, config) {
|
|
5496
|
-
const
|
|
5701
|
+
async function writeEnvFile(projectDir, backend, config) {
|
|
5702
|
+
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
5703
|
+
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5497
5704
|
const variables = [{
|
|
5498
5705
|
key: "DATABASE_URL",
|
|
5499
5706
|
value: config?.dbUrl ?? "",
|
|
@@ -5517,12 +5724,12 @@ DATABASE_URL=your_database_url
|
|
|
5517
5724
|
DATABASE_AUTH_TOKEN=your_auth_token`);
|
|
5518
5725
|
}
|
|
5519
5726
|
async function setupTurso(config, cliInput) {
|
|
5520
|
-
const { orm, projectDir } = config;
|
|
5727
|
+
const { orm, projectDir, backend } = config;
|
|
5521
5728
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5522
5729
|
const setupSpinner = spinner();
|
|
5523
5730
|
try {
|
|
5524
5731
|
if (manualDb) {
|
|
5525
|
-
await writeEnvFile(projectDir);
|
|
5732
|
+
await writeEnvFile(projectDir, backend);
|
|
5526
5733
|
displayManualSetupInstructions();
|
|
5527
5734
|
return;
|
|
5528
5735
|
}
|
|
@@ -5541,7 +5748,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5541
5748
|
});
|
|
5542
5749
|
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
5543
5750
|
if (mode === "manual") {
|
|
5544
|
-
await writeEnvFile(projectDir);
|
|
5751
|
+
await writeEnvFile(projectDir, backend);
|
|
5545
5752
|
displayManualSetupInstructions();
|
|
5546
5753
|
return;
|
|
5547
5754
|
}
|
|
@@ -5551,7 +5758,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5551
5758
|
if (platform === "win32") {
|
|
5552
5759
|
if (setupSpinner) setupSpinner.stop(pc.yellow("Turso setup not supported on Windows"));
|
|
5553
5760
|
log.warn(pc.yellow("Automatic Turso setup is not supported on Windows."));
|
|
5554
|
-
await writeEnvFile(projectDir);
|
|
5761
|
+
await writeEnvFile(projectDir, backend);
|
|
5555
5762
|
displayManualSetupInstructions();
|
|
5556
5763
|
return;
|
|
5557
5764
|
}
|
|
@@ -5563,7 +5770,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5563
5770
|
});
|
|
5564
5771
|
if (isCancel(shouldInstall)) return exitCancelled("Operation cancelled");
|
|
5565
5772
|
if (!shouldInstall) {
|
|
5566
|
-
await writeEnvFile(projectDir);
|
|
5773
|
+
await writeEnvFile(projectDir, backend);
|
|
5567
5774
|
displayManualSetupInstructions();
|
|
5568
5775
|
return;
|
|
5569
5776
|
}
|
|
@@ -5585,7 +5792,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5585
5792
|
dbName = dbNameResponse;
|
|
5586
5793
|
try {
|
|
5587
5794
|
const config$1 = await createTursoDatabase(dbName, selectedGroup);
|
|
5588
|
-
await writeEnvFile(projectDir, config$1);
|
|
5795
|
+
await writeEnvFile(projectDir, backend, config$1);
|
|
5589
5796
|
success = true;
|
|
5590
5797
|
} catch (error) {
|
|
5591
5798
|
if (error instanceof Error && error.message === "DATABASE_EXISTS") {
|
|
@@ -5598,7 +5805,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5598
5805
|
} catch (error) {
|
|
5599
5806
|
if (setupSpinner) setupSpinner.stop(pc.red("Turso CLI availability check failed"));
|
|
5600
5807
|
consola.error(pc.red(`Error during Turso setup: ${error instanceof Error ? error.message : String(error)}`));
|
|
5601
|
-
await writeEnvFile(projectDir);
|
|
5808
|
+
await writeEnvFile(projectDir, backend);
|
|
5602
5809
|
displayManualSetupInstructions();
|
|
5603
5810
|
log.success("Setup completed with manual configuration required.");
|
|
5604
5811
|
}
|
|
@@ -5610,40 +5817,52 @@ async function setupDatabase(config, cliInput) {
|
|
|
5610
5817
|
const { database, orm, dbSetup, backend, projectDir } = config;
|
|
5611
5818
|
if (backend === "convex" || database === "none") {
|
|
5612
5819
|
if (backend !== "convex") {
|
|
5613
|
-
const serverDir
|
|
5614
|
-
const serverDbDir = path.join(serverDir
|
|
5820
|
+
const serverDir = path.join(projectDir, "apps/server");
|
|
5821
|
+
const serverDbDir = path.join(serverDir, "src/db");
|
|
5615
5822
|
if (await fs.pathExists(serverDbDir)) await fs.remove(serverDbDir);
|
|
5616
5823
|
}
|
|
5617
5824
|
return;
|
|
5618
5825
|
}
|
|
5619
5826
|
const s = spinner();
|
|
5620
|
-
const
|
|
5621
|
-
if (!await fs.pathExists(
|
|
5827
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
5828
|
+
if (!await fs.pathExists(dbPackageDir)) return;
|
|
5622
5829
|
try {
|
|
5623
|
-
if (orm === "prisma")
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5830
|
+
if (orm === "prisma") {
|
|
5831
|
+
if (database === "mysql" && dbSetup === "planetscale") await addPackageDependency({
|
|
5832
|
+
dependencies: [
|
|
5833
|
+
"@prisma/client",
|
|
5834
|
+
"@prisma/adapter-planetscale",
|
|
5835
|
+
"@planetscale/database"
|
|
5836
|
+
],
|
|
5837
|
+
devDependencies: ["prisma"],
|
|
5838
|
+
projectDir: dbPackageDir
|
|
5839
|
+
});
|
|
5840
|
+
else if (database === "sqlite" && dbSetup === "turso") await addPackageDependency({
|
|
5841
|
+
dependencies: ["@prisma/client", "@prisma/adapter-libsql"],
|
|
5842
|
+
devDependencies: ["prisma"],
|
|
5843
|
+
projectDir: dbPackageDir
|
|
5844
|
+
});
|
|
5845
|
+
else await addPackageDependency({
|
|
5846
|
+
dependencies: ["@prisma/client"],
|
|
5847
|
+
devDependencies: ["prisma"],
|
|
5848
|
+
projectDir: dbPackageDir
|
|
5849
|
+
});
|
|
5850
|
+
if (backend === "self") {
|
|
5851
|
+
const webDir = path.join(projectDir, "apps/web");
|
|
5852
|
+
if (await fs.pathExists(webDir)) await addPackageDependency({
|
|
5853
|
+
dependencies: ["@prisma/client"],
|
|
5854
|
+
projectDir: webDir
|
|
5855
|
+
});
|
|
5856
|
+
}
|
|
5857
|
+
} else if (orm === "drizzle") {
|
|
5643
5858
|
if (database === "sqlite") await addPackageDependency({
|
|
5644
|
-
dependencies: [
|
|
5859
|
+
dependencies: [
|
|
5860
|
+
"drizzle-orm",
|
|
5861
|
+
"@libsql/client",
|
|
5862
|
+
"libsql"
|
|
5863
|
+
],
|
|
5645
5864
|
devDependencies: ["drizzle-kit"],
|
|
5646
|
-
projectDir:
|
|
5865
|
+
projectDir: dbPackageDir
|
|
5647
5866
|
});
|
|
5648
5867
|
else if (database === "postgres") if (dbSetup === "neon") await addPackageDependency({
|
|
5649
5868
|
dependencies: [
|
|
@@ -5652,32 +5871,32 @@ async function setupDatabase(config, cliInput) {
|
|
|
5652
5871
|
"ws"
|
|
5653
5872
|
],
|
|
5654
5873
|
devDependencies: ["drizzle-kit", "@types/ws"],
|
|
5655
|
-
projectDir:
|
|
5874
|
+
projectDir: dbPackageDir
|
|
5656
5875
|
});
|
|
5657
5876
|
else if (dbSetup === "planetscale") await addPackageDependency({
|
|
5658
5877
|
dependencies: ["drizzle-orm", "pg"],
|
|
5659
5878
|
devDependencies: ["drizzle-kit", "@types/pg"],
|
|
5660
|
-
projectDir:
|
|
5879
|
+
projectDir: dbPackageDir
|
|
5661
5880
|
});
|
|
5662
5881
|
else await addPackageDependency({
|
|
5663
5882
|
dependencies: ["drizzle-orm", "pg"],
|
|
5664
5883
|
devDependencies: ["drizzle-kit", "@types/pg"],
|
|
5665
|
-
projectDir:
|
|
5884
|
+
projectDir: dbPackageDir
|
|
5666
5885
|
});
|
|
5667
5886
|
else if (database === "mysql") if (dbSetup === "planetscale") await addPackageDependency({
|
|
5668
5887
|
dependencies: ["drizzle-orm", "@planetscale/database"],
|
|
5669
5888
|
devDependencies: ["drizzle-kit"],
|
|
5670
|
-
projectDir:
|
|
5889
|
+
projectDir: dbPackageDir
|
|
5671
5890
|
});
|
|
5672
5891
|
else await addPackageDependency({
|
|
5673
5892
|
dependencies: ["drizzle-orm", "mysql2"],
|
|
5674
5893
|
devDependencies: ["drizzle-kit"],
|
|
5675
|
-
projectDir:
|
|
5894
|
+
projectDir: dbPackageDir
|
|
5676
5895
|
});
|
|
5677
5896
|
} else if (orm === "mongoose") await addPackageDependency({
|
|
5678
5897
|
dependencies: ["mongoose"],
|
|
5679
5898
|
devDependencies: [],
|
|
5680
|
-
projectDir:
|
|
5899
|
+
projectDir: dbPackageDir
|
|
5681
5900
|
});
|
|
5682
5901
|
if (dbSetup === "docker") await setupDockerCompose(config);
|
|
5683
5902
|
else if (database === "sqlite" && dbSetup === "turso") await setupTurso(config, cliInput);
|
|
@@ -5700,7 +5919,7 @@ async function setupDatabase(config, cliInput) {
|
|
|
5700
5919
|
//#region src/helpers/core/runtime-setup.ts
|
|
5701
5920
|
async function setupRuntime(config) {
|
|
5702
5921
|
const { runtime, backend, projectDir } = config;
|
|
5703
|
-
if (backend === "convex" || backend === "
|
|
5922
|
+
if (backend === "convex" || backend === "self" || runtime === "none") return;
|
|
5704
5923
|
const serverDir = path.join(projectDir, "apps/server");
|
|
5705
5924
|
if (!await fs.pathExists(serverDir)) return;
|
|
5706
5925
|
if (runtime === "bun") await setupBunRuntime(serverDir, backend);
|
|
@@ -6089,15 +6308,14 @@ async function initializeGit(projectDir, useGit) {
|
|
|
6089
6308
|
async function setupPayments(config) {
|
|
6090
6309
|
const { payments, projectDir, frontend } = config;
|
|
6091
6310
|
if (!payments || payments === "none") return;
|
|
6092
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
6093
6311
|
const clientDir = path.join(projectDir, "apps/web");
|
|
6094
|
-
const
|
|
6312
|
+
const authDir = path.join(projectDir, "packages/auth");
|
|
6095
6313
|
const clientDirExists = await fs.pathExists(clientDir);
|
|
6096
|
-
|
|
6314
|
+
const authDirExists = await fs.pathExists(authDir);
|
|
6097
6315
|
if (payments === "polar") {
|
|
6098
|
-
await addPackageDependency({
|
|
6316
|
+
if (authDirExists) await addPackageDependency({
|
|
6099
6317
|
dependencies: ["@polar-sh/better-auth", "@polar-sh/sdk"],
|
|
6100
|
-
projectDir:
|
|
6318
|
+
projectDir: authDir
|
|
6101
6319
|
});
|
|
6102
6320
|
if (clientDirExists) {
|
|
6103
6321
|
if (frontend.some((f) => [
|
|
@@ -6220,7 +6438,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6220
6438
|
else if (!hasNative && !addons?.includes("starlight")) output += `${pc.yellow("NOTE:")} You are creating a backend-only app\n (no frontend selected)\n`;
|
|
6221
6439
|
if (!isConvex) {
|
|
6222
6440
|
output += `${pc.cyan("•")} Backend API: http://localhost:3000\n`;
|
|
6223
|
-
if (api === "orpc") if (backend === "
|
|
6441
|
+
if (api === "orpc") if (backend === "self") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/rpc/api\n`;
|
|
6224
6442
|
else output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/api\n`;
|
|
6225
6443
|
}
|
|
6226
6444
|
if (addons?.includes("starlight")) output += `${pc.cyan("•")} Docs: http://localhost:4321\n`;
|
|
@@ -6334,12 +6552,79 @@ function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy) {
|
|
|
6334
6552
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
6335
6553
|
}
|
|
6336
6554
|
|
|
6555
|
+
//#endregion
|
|
6556
|
+
//#region src/helpers/core/workspace-setup.ts
|
|
6557
|
+
async function setupWorkspaceDependencies(projectDir, options) {
|
|
6558
|
+
const projectName = options.projectName;
|
|
6559
|
+
const workspaceVersion = options.packageManager === "npm" ? "*" : "workspace:*";
|
|
6560
|
+
const commonDeps = ["dotenv", "zod"];
|
|
6561
|
+
const commonDevDeps = ["tsdown"];
|
|
6562
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
6563
|
+
if (await fs.pathExists(dbPackageDir)) await addPackageDependency({
|
|
6564
|
+
dependencies: commonDeps,
|
|
6565
|
+
devDependencies: commonDevDeps,
|
|
6566
|
+
projectDir: dbPackageDir
|
|
6567
|
+
});
|
|
6568
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
6569
|
+
if (await fs.pathExists(authPackageDir)) await addPackageDependency({
|
|
6570
|
+
dependencies: commonDeps,
|
|
6571
|
+
devDependencies: commonDevDeps,
|
|
6572
|
+
customDependencies: { [`@${projectName}/db`]: workspaceVersion },
|
|
6573
|
+
projectDir: authPackageDir
|
|
6574
|
+
});
|
|
6575
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
6576
|
+
if (await fs.pathExists(apiPackageDir)) await addPackageDependency({
|
|
6577
|
+
dependencies: commonDeps,
|
|
6578
|
+
devDependencies: commonDevDeps,
|
|
6579
|
+
customDependencies: {
|
|
6580
|
+
[`@${projectName}/auth`]: workspaceVersion,
|
|
6581
|
+
[`@${projectName}/db`]: workspaceVersion
|
|
6582
|
+
},
|
|
6583
|
+
projectDir: apiPackageDir
|
|
6584
|
+
});
|
|
6585
|
+
const serverPackageDir = path.join(projectDir, "apps/server");
|
|
6586
|
+
if (await fs.pathExists(serverPackageDir)) await addPackageDependency({
|
|
6587
|
+
dependencies: commonDeps,
|
|
6588
|
+
devDependencies: commonDevDeps,
|
|
6589
|
+
customDependencies: {
|
|
6590
|
+
[`@${projectName}/api`]: workspaceVersion,
|
|
6591
|
+
[`@${projectName}/auth`]: workspaceVersion,
|
|
6592
|
+
[`@${projectName}/db`]: workspaceVersion
|
|
6593
|
+
},
|
|
6594
|
+
projectDir: serverPackageDir
|
|
6595
|
+
});
|
|
6596
|
+
const needsApiDependency = options.api && options.api !== "none";
|
|
6597
|
+
const webPackageDir = path.join(projectDir, "apps/web");
|
|
6598
|
+
if (await fs.pathExists(webPackageDir)) {
|
|
6599
|
+
const webDeps = {};
|
|
6600
|
+
if (options.backend === "self") {
|
|
6601
|
+
webDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6602
|
+
webDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
6603
|
+
webDeps[`@${projectName}/db`] = workspaceVersion;
|
|
6604
|
+
} else if (needsApiDependency) webDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6605
|
+
if (Object.keys(webDeps).length > 0) await addPackageDependency({
|
|
6606
|
+
customDependencies: webDeps,
|
|
6607
|
+
projectDir: webPackageDir
|
|
6608
|
+
});
|
|
6609
|
+
}
|
|
6610
|
+
}
|
|
6611
|
+
|
|
6337
6612
|
//#endregion
|
|
6338
6613
|
//#region src/helpers/core/project-config.ts
|
|
6339
6614
|
async function updatePackageConfigurations(projectDir, options) {
|
|
6340
6615
|
await updateRootPackageJson(projectDir, options);
|
|
6341
|
-
if (options.backend
|
|
6342
|
-
else
|
|
6616
|
+
if (options.backend === "convex") await updateConvexPackageJson(projectDir, options);
|
|
6617
|
+
else if (options.backend === "self") {
|
|
6618
|
+
await updateDbPackageJson(projectDir, options);
|
|
6619
|
+
await updateAuthPackageJson(projectDir, options);
|
|
6620
|
+
await updateApiPackageJson(projectDir, options);
|
|
6621
|
+
await setupWorkspaceDependencies(projectDir, options);
|
|
6622
|
+
} else if (options.backend !== "none") {
|
|
6623
|
+
await updateServerPackageJson(projectDir, options);
|
|
6624
|
+
await updateAuthPackageJson(projectDir, options);
|
|
6625
|
+
await updateApiPackageJson(projectDir, options);
|
|
6626
|
+
await setupWorkspaceDependencies(projectDir, options);
|
|
6627
|
+
}
|
|
6343
6628
|
}
|
|
6344
6629
|
async function updateRootPackageJson(projectDir, options) {
|
|
6345
6630
|
const rootPackageJsonPath = path.join(projectDir, "package.json");
|
|
@@ -6349,6 +6634,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6349
6634
|
if (!packageJson.scripts) packageJson.scripts = {};
|
|
6350
6635
|
const scripts = packageJson.scripts;
|
|
6351
6636
|
const backendPackageName = options.backend === "convex" ? `@${options.projectName}/backend` : "server";
|
|
6637
|
+
const dbPackageName = `@${options.projectName}/db`;
|
|
6352
6638
|
let serverDevScript = "";
|
|
6353
6639
|
if (options.addons.includes("turborepo")) serverDevScript = `turbo -F ${backendPackageName} dev`;
|
|
6354
6640
|
else if (options.packageManager === "bun") serverDevScript = `bun run --filter ${backendPackageName} dev`;
|
|
@@ -6365,17 +6651,17 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6365
6651
|
scripts["check-types"] = "turbo check-types";
|
|
6366
6652
|
scripts["dev:native"] = "turbo -F native dev";
|
|
6367
6653
|
scripts["dev:web"] = "turbo -F web dev";
|
|
6368
|
-
scripts["dev:server"] = serverDevScript;
|
|
6654
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6369
6655
|
if (options.backend === "convex") scripts["dev:setup"] = `turbo -F ${backendPackageName} dev:setup`;
|
|
6370
6656
|
if (needsDbScripts) {
|
|
6371
|
-
scripts["db:push"] = `turbo -F ${
|
|
6372
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `turbo -F ${
|
|
6657
|
+
scripts["db:push"] = `turbo -F ${dbPackageName} db:push`;
|
|
6658
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `turbo -F ${dbPackageName} db:studio`;
|
|
6373
6659
|
if (options.orm === "prisma") {
|
|
6374
|
-
scripts["db:generate"] = `turbo -F ${
|
|
6375
|
-
scripts["db:migrate"] = `turbo -F ${
|
|
6660
|
+
scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
|
|
6661
|
+
scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
|
|
6376
6662
|
} else if (options.orm === "drizzle") {
|
|
6377
|
-
scripts["db:generate"] = `turbo -F ${
|
|
6378
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${
|
|
6663
|
+
scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
|
|
6664
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
|
|
6379
6665
|
}
|
|
6380
6666
|
}
|
|
6381
6667
|
if (options.dbSetup === "docker") {
|
|
@@ -6390,17 +6676,17 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6390
6676
|
scripts["check-types"] = "pnpm -r check-types";
|
|
6391
6677
|
scripts["dev:native"] = "pnpm --filter native dev";
|
|
6392
6678
|
scripts["dev:web"] = "pnpm --filter web dev";
|
|
6393
|
-
scripts["dev:server"] = serverDevScript;
|
|
6679
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6394
6680
|
if (options.backend === "convex") scripts["dev:setup"] = `pnpm --filter ${backendPackageName} dev:setup`;
|
|
6395
6681
|
if (needsDbScripts) {
|
|
6396
|
-
scripts["db:push"] = `pnpm --filter ${
|
|
6397
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${
|
|
6682
|
+
scripts["db:push"] = `pnpm --filter ${dbPackageName} db:push`;
|
|
6683
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${dbPackageName} db:studio`;
|
|
6398
6684
|
if (options.orm === "prisma") {
|
|
6399
|
-
scripts["db:generate"] = `pnpm --filter ${
|
|
6400
|
-
scripts["db:migrate"] = `pnpm --filter ${
|
|
6685
|
+
scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
|
|
6686
|
+
scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
|
|
6401
6687
|
} else if (options.orm === "drizzle") {
|
|
6402
|
-
scripts["db:generate"] = `pnpm --filter ${
|
|
6403
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${
|
|
6688
|
+
scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
|
|
6689
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
|
|
6404
6690
|
}
|
|
6405
6691
|
}
|
|
6406
6692
|
if (options.dbSetup === "docker") {
|
|
@@ -6415,17 +6701,17 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6415
6701
|
scripts["check-types"] = "npm run check-types --workspaces";
|
|
6416
6702
|
scripts["dev:native"] = "npm run dev --workspace native";
|
|
6417
6703
|
scripts["dev:web"] = "npm run dev --workspace web";
|
|
6418
|
-
scripts["dev:server"] = serverDevScript;
|
|
6704
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6419
6705
|
if (options.backend === "convex") scripts["dev:setup"] = `npm run dev:setup --workspace ${backendPackageName}`;
|
|
6420
6706
|
if (needsDbScripts) {
|
|
6421
|
-
scripts["db:push"] = `npm run db:push --workspace ${
|
|
6422
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `npm run db:studio --workspace ${
|
|
6707
|
+
scripts["db:push"] = `npm run db:push --workspace ${dbPackageName}`;
|
|
6708
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `npm run db:studio --workspace ${dbPackageName}`;
|
|
6423
6709
|
if (options.orm === "prisma") {
|
|
6424
|
-
scripts["db:generate"] = `npm run db:generate --workspace ${
|
|
6425
|
-
scripts["db:migrate"] = `npm run db:migrate --workspace ${
|
|
6710
|
+
scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
|
|
6711
|
+
scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
|
|
6426
6712
|
} else if (options.orm === "drizzle") {
|
|
6427
|
-
scripts["db:generate"] = `npm run db:generate --workspace ${
|
|
6428
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `npm run db:migrate --workspace ${
|
|
6713
|
+
scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
|
|
6714
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
|
|
6429
6715
|
}
|
|
6430
6716
|
}
|
|
6431
6717
|
if (options.dbSetup === "docker") {
|
|
@@ -6440,17 +6726,17 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6440
6726
|
scripts["check-types"] = "bun run --filter '*' check-types";
|
|
6441
6727
|
scripts["dev:native"] = "bun run --filter native dev";
|
|
6442
6728
|
scripts["dev:web"] = "bun run --filter web dev";
|
|
6443
|
-
scripts["dev:server"] = serverDevScript;
|
|
6729
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6444
6730
|
if (options.backend === "convex") scripts["dev:setup"] = `bun run --filter ${backendPackageName} dev:setup`;
|
|
6445
6731
|
if (needsDbScripts) {
|
|
6446
|
-
scripts["db:push"] = `bun run --filter ${
|
|
6447
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${
|
|
6732
|
+
scripts["db:push"] = `bun run --filter ${dbPackageName} db:push`;
|
|
6733
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${dbPackageName} db:studio`;
|
|
6448
6734
|
if (options.orm === "prisma") {
|
|
6449
|
-
scripts["db:generate"] = `bun run --filter ${
|
|
6450
|
-
scripts["db:migrate"] = `bun run --filter ${
|
|
6735
|
+
scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
|
|
6736
|
+
scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
|
|
6451
6737
|
} else if (options.orm === "drizzle") {
|
|
6452
|
-
scripts["db:generate"] = `bun run --filter ${
|
|
6453
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `bun run --filter ${
|
|
6738
|
+
scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
|
|
6739
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
|
|
6454
6740
|
}
|
|
6455
6741
|
}
|
|
6456
6742
|
if (options.dbSetup === "docker") {
|
|
@@ -6483,6 +6769,22 @@ async function updateServerPackageJson(projectDir, options) {
|
|
|
6483
6769
|
const serverPackageJson = await fs.readJson(serverPackageJsonPath);
|
|
6484
6770
|
if (!serverPackageJson.scripts) serverPackageJson.scripts = {};
|
|
6485
6771
|
const scripts = serverPackageJson.scripts;
|
|
6772
|
+
if (options.dbSetup === "docker") {
|
|
6773
|
+
scripts["db:start"] = "docker compose up -d";
|
|
6774
|
+
scripts["db:watch"] = "docker compose up";
|
|
6775
|
+
scripts["db:stop"] = "docker compose stop";
|
|
6776
|
+
scripts["db:down"] = "docker compose down";
|
|
6777
|
+
}
|
|
6778
|
+
await fs.writeJson(serverPackageJsonPath, serverPackageJson, { spaces: 2 });
|
|
6779
|
+
await updateDbPackageJson(projectDir, options);
|
|
6780
|
+
}
|
|
6781
|
+
async function updateDbPackageJson(projectDir, options) {
|
|
6782
|
+
const dbPackageJsonPath = path.join(projectDir, "packages/db/package.json");
|
|
6783
|
+
if (!await fs.pathExists(dbPackageJsonPath)) return;
|
|
6784
|
+
const dbPackageJson = await fs.readJson(dbPackageJsonPath);
|
|
6785
|
+
dbPackageJson.name = `@${options.projectName}/db`;
|
|
6786
|
+
if (!dbPackageJson.scripts) dbPackageJson.scripts = {};
|
|
6787
|
+
const scripts = dbPackageJson.scripts;
|
|
6486
6788
|
if (options.database !== "none") {
|
|
6487
6789
|
if (options.database === "sqlite" && options.orm === "drizzle" && options.dbSetup !== "d1") scripts["db:local"] = "turso dev --db-file local.db";
|
|
6488
6790
|
if (options.orm === "prisma") {
|
|
@@ -6497,13 +6799,21 @@ async function updateServerPackageJson(projectDir, options) {
|
|
|
6497
6799
|
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = "drizzle-kit migrate";
|
|
6498
6800
|
}
|
|
6499
6801
|
}
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6802
|
+
await fs.writeJson(dbPackageJsonPath, dbPackageJson, { spaces: 2 });
|
|
6803
|
+
}
|
|
6804
|
+
async function updateAuthPackageJson(projectDir, options) {
|
|
6805
|
+
const authPackageJsonPath = path.join(projectDir, "packages/auth/package.json");
|
|
6806
|
+
if (!await fs.pathExists(authPackageJsonPath)) return;
|
|
6807
|
+
const authPackageJson = await fs.readJson(authPackageJsonPath);
|
|
6808
|
+
authPackageJson.name = `@${options.projectName}/auth`;
|
|
6809
|
+
await fs.writeJson(authPackageJsonPath, authPackageJson, { spaces: 2 });
|
|
6810
|
+
}
|
|
6811
|
+
async function updateApiPackageJson(projectDir, options) {
|
|
6812
|
+
const apiPackageJsonPath = path.join(projectDir, "packages/api/package.json");
|
|
6813
|
+
if (!await fs.pathExists(apiPackageJsonPath)) return;
|
|
6814
|
+
const apiPackageJson = await fs.readJson(apiPackageJsonPath);
|
|
6815
|
+
apiPackageJson.name = `@${options.projectName}/api`;
|
|
6816
|
+
await fs.writeJson(apiPackageJsonPath, apiPackageJson, { spaces: 2 });
|
|
6507
6817
|
}
|
|
6508
6818
|
async function updateConvexPackageJson(projectDir, options) {
|
|
6509
6819
|
const convexPackageJsonPath = path.join(projectDir, "packages/backend/package.json");
|
|
@@ -6519,15 +6829,14 @@ async function updateConvexPackageJson(projectDir, options) {
|
|
|
6519
6829
|
async function createProject(options, cliInput) {
|
|
6520
6830
|
const projectDir = options.projectDir;
|
|
6521
6831
|
const isConvex = options.backend === "convex";
|
|
6832
|
+
const isSelfBackend = options.backend === "self";
|
|
6833
|
+
const needsServerSetup = !isConvex && !isSelfBackend;
|
|
6522
6834
|
try {
|
|
6523
6835
|
await fs.ensureDir(projectDir);
|
|
6524
6836
|
await copyBaseTemplate(projectDir, options);
|
|
6525
6837
|
await setupFrontendTemplates(projectDir, options);
|
|
6526
6838
|
await setupBackendFramework(projectDir, options);
|
|
6527
|
-
if (
|
|
6528
|
-
await setupDbOrmTemplates(projectDir, options);
|
|
6529
|
-
await setupDockerComposeTemplates(projectDir, options);
|
|
6530
|
-
}
|
|
6839
|
+
if (needsServerSetup) await setupDockerComposeTemplates(projectDir, options);
|
|
6531
6840
|
await setupAuthTemplate(projectDir, options);
|
|
6532
6841
|
if (options.payments && options.payments !== "none") await setupPaymentsTemplate(projectDir, options);
|
|
6533
6842
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamplesTemplate(projectDir, options);
|
|
@@ -6535,9 +6844,11 @@ async function createProject(options, cliInput) {
|
|
|
6535
6844
|
await setupDeploymentTemplates(projectDir, options);
|
|
6536
6845
|
await setupApi(options);
|
|
6537
6846
|
if (!isConvex) {
|
|
6538
|
-
|
|
6847
|
+
if (needsServerSetup) {
|
|
6848
|
+
await setupBackendDependencies(options);
|
|
6849
|
+
await setupRuntime(options);
|
|
6850
|
+
}
|
|
6539
6851
|
await setupDatabase(options, cliInput);
|
|
6540
|
-
await setupRuntime(options);
|
|
6541
6852
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamples(options);
|
|
6542
6853
|
}
|
|
6543
6854
|
if (options.addons.length > 0 && options.addons[0] !== "none") await setupAddons(options);
|
|
@@ -6546,6 +6857,7 @@ async function createProject(options, cliInput) {
|
|
|
6546
6857
|
await handleExtras(projectDir, options);
|
|
6547
6858
|
await setupEnvironmentVariables(options);
|
|
6548
6859
|
await updatePackageConfigurations(projectDir, options);
|
|
6860
|
+
await setupCatalogs(projectDir, options);
|
|
6549
6861
|
await setupWebDeploy(options);
|
|
6550
6862
|
await setupServerDeploy(options);
|
|
6551
6863
|
await createReadme(projectDir, options);
|