create-better-t-stack 2.49.1 → 2.50.0-canary.dd7000f2
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-dv6H37db.js} +518 -286
- package/package.json +2 -1
- 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 +1 -1
- 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/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 +2 -2
- 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} +7 -7
- 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/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 +7 -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 +7 -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 +7 -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 +5 -1
- package/templates/db/prisma/mongodb/src/index.ts.hbs +5 -0
- package/templates/db/prisma/mysql/prisma.config.ts.hbs +5 -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 +7 -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 +5 -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/todo/server/drizzle/base/src/routers/todo.ts.hbs +6 -6
- package/templates/examples/todo/server/mongoose/base/src/routers/todo.ts.hbs +4 -4
- package/templates/examples/todo/server/prisma/base/src/routers/todo.ts.hbs +4 -4
- package/templates/frontend/react/tanstack-router/src/routes/__root.tsx.hbs +1 -1
- 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/vite.config.ts.hbs +1 -1
- 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/auth/better-auth/server/next/src/app/api/auth/[...all]/route.ts +0 -4
- 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.1.0",
|
|
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 backend capabilities"
|
|
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
|
|
@@ -2758,35 +2789,52 @@ async function setupFrontendTemplates(projectDir, context) {
|
|
|
2758
2789
|
}
|
|
2759
2790
|
}
|
|
2760
2791
|
}
|
|
2761
|
-
async function
|
|
2762
|
-
if (context.
|
|
2792
|
+
async function setupApiPackage(projectDir, context) {
|
|
2793
|
+
if (context.api === "none") return;
|
|
2794
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
2795
|
+
await fs.ensureDir(apiPackageDir);
|
|
2796
|
+
const apiServerDir = path.join(PKG_ROOT, `templates/api/${context.api}/server`);
|
|
2797
|
+
if (await fs.pathExists(apiServerDir)) await processAndCopyFiles("**/*", apiServerDir, apiPackageDir, context);
|
|
2798
|
+
}
|
|
2799
|
+
async function setupDbPackage(projectDir, context) {
|
|
2800
|
+
if (context.database === "none" || context.orm === "none") return;
|
|
2801
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
2802
|
+
await fs.ensureDir(dbPackageDir);
|
|
2803
|
+
const dbBaseDir = path.join(PKG_ROOT, "templates/db/base");
|
|
2804
|
+
if (await fs.pathExists(dbBaseDir)) await processAndCopyFiles("**/*", dbBaseDir, dbPackageDir, context);
|
|
2805
|
+
const dbOrmSrcDir = path.join(PKG_ROOT, `templates/db/${context.orm}/${context.database}`);
|
|
2806
|
+
if (await fs.pathExists(dbOrmSrcDir)) await processAndCopyFiles("**/*", dbOrmSrcDir, dbPackageDir, context);
|
|
2807
|
+
}
|
|
2808
|
+
async function setupConvexBackend(projectDir, context) {
|
|
2809
|
+
const serverAppDir = path.join(projectDir, "apps/server");
|
|
2810
|
+
if (await fs.pathExists(serverAppDir)) await fs.remove(serverAppDir);
|
|
2811
|
+
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
|
2812
|
+
const convexSrcDir = path.join(PKG_ROOT, "templates/backend/convex/packages/backend");
|
|
2813
|
+
await fs.ensureDir(convexBackendDestDir);
|
|
2814
|
+
if (await fs.pathExists(convexSrcDir)) await processAndCopyFiles("**/*", convexSrcDir, convexBackendDestDir, context);
|
|
2815
|
+
}
|
|
2816
|
+
async function setupServerApp(projectDir, context) {
|
|
2763
2817
|
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
2818
|
await fs.ensureDir(serverAppDir);
|
|
2773
|
-
const serverBaseDir = path.join(PKG_ROOT, "templates/backend/server/
|
|
2819
|
+
const serverBaseDir = path.join(PKG_ROOT, "templates/backend/server/base");
|
|
2774
2820
|
if (await fs.pathExists(serverBaseDir)) await processAndCopyFiles("**/*", serverBaseDir, serverAppDir, context);
|
|
2775
2821
|
const frameworkSrcDir = path.join(PKG_ROOT, `templates/backend/server/${context.backend}`);
|
|
2776
2822
|
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
2823
|
}
|
|
2784
|
-
async function
|
|
2785
|
-
if (context.backend === "
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2824
|
+
async function setupBackendFramework(projectDir, context) {
|
|
2825
|
+
if (context.backend === "none") return;
|
|
2826
|
+
if (context.backend === "convex") {
|
|
2827
|
+
await setupConvexBackend(projectDir, context);
|
|
2828
|
+
return;
|
|
2829
|
+
}
|
|
2830
|
+
if (context.backend === "self") {
|
|
2831
|
+
await setupApiPackage(projectDir, context);
|
|
2832
|
+
await setupDbPackage(projectDir, context);
|
|
2833
|
+
return;
|
|
2834
|
+
}
|
|
2835
|
+
await setupServerApp(projectDir, context);
|
|
2836
|
+
await setupApiPackage(projectDir, context);
|
|
2837
|
+
await setupDbPackage(projectDir, context);
|
|
2790
2838
|
}
|
|
2791
2839
|
async function setupAuthTemplate(projectDir, context) {
|
|
2792
2840
|
if (!context.auth || context.auth === "none") return;
|
|
@@ -2866,21 +2914,21 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2866
2914
|
}
|
|
2867
2915
|
return;
|
|
2868
2916
|
}
|
|
2869
|
-
if (serverAppDirExists && context.backend !== "convex") {
|
|
2917
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex") {
|
|
2918
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
2919
|
+
await fs.ensureDir(authPackageDir);
|
|
2870
2920
|
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
|
-
}
|
|
2921
|
+
if (await fs.pathExists(authServerBaseSrc)) await processAndCopyFiles("**/*", authServerBaseSrc, authPackageDir, context);
|
|
2876
2922
|
if (context.orm !== "none" && context.database !== "none") {
|
|
2923
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
2924
|
+
await fs.ensureDir(dbPackageDir);
|
|
2877
2925
|
const orm = context.orm;
|
|
2878
2926
|
const db = context.database;
|
|
2879
2927
|
let authDbSrc = "";
|
|
2880
2928
|
if (orm === "drizzle") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/drizzle/${db}`);
|
|
2881
2929
|
else if (orm === "prisma") authDbSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/db/prisma/${db}`);
|
|
2882
2930
|
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,
|
|
2931
|
+
if (authDbSrc && await fs.pathExists(authDbSrc)) await processAndCopyFiles("**/*", authDbSrc, dbPackageDir, context);
|
|
2884
2932
|
}
|
|
2885
2933
|
}
|
|
2886
2934
|
if ((hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) && webAppDirExists) {
|
|
@@ -2926,9 +2974,11 @@ async function setupPaymentsTemplate(projectDir, context) {
|
|
|
2926
2974
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
2927
2975
|
const serverAppDirExists = await fs.pathExists(serverAppDir);
|
|
2928
2976
|
const webAppDirExists = await fs.pathExists(webAppDir);
|
|
2929
|
-
if (serverAppDirExists && context.backend !== "convex") {
|
|
2977
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex") {
|
|
2978
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
2979
|
+
await fs.ensureDir(authPackageDir);
|
|
2930
2980
|
const paymentsServerSrc = path.join(PKG_ROOT, `templates/payments/${context.payments}/server/base`);
|
|
2931
|
-
if (await fs.pathExists(paymentsServerSrc)) await processAndCopyFiles("**/*", paymentsServerSrc,
|
|
2981
|
+
if (await fs.pathExists(paymentsServerSrc)) await processAndCopyFiles("**/*", paymentsServerSrc, authPackageDir, context);
|
|
2932
2982
|
}
|
|
2933
2983
|
const hasReactWeb = context.frontend.some((f) => [
|
|
2934
2984
|
"tanstack-router",
|
|
@@ -3004,17 +3054,19 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3004
3054
|
for (const example of context.examples) {
|
|
3005
3055
|
if (example === "none") continue;
|
|
3006
3056
|
const exampleBaseDir = path.join(PKG_ROOT, `templates/examples/${example}`);
|
|
3007
|
-
if (serverAppDirExists && context.backend !== "convex" && context.backend !== "none") {
|
|
3057
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex" && context.backend !== "none") {
|
|
3008
3058
|
const exampleServerSrc = path.join(exampleBaseDir, "server");
|
|
3009
|
-
if (
|
|
3010
|
-
const
|
|
3011
|
-
|
|
3059
|
+
if (context.api !== "none") {
|
|
3060
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
3061
|
+
await fs.ensureDir(apiPackageDir);
|
|
3062
|
+
const exampleOrmBaseSrc = path.join(exampleServerSrc, context.orm, "base");
|
|
3063
|
+
if (await fs.pathExists(exampleOrmBaseSrc)) await processAndCopyFiles("**/*", exampleOrmBaseSrc, apiPackageDir, context, false);
|
|
3012
3064
|
}
|
|
3013
3065
|
if (context.orm !== "none" && context.database !== "none") {
|
|
3014
|
-
const
|
|
3015
|
-
|
|
3066
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
3067
|
+
await fs.ensureDir(dbPackageDir);
|
|
3016
3068
|
const exampleDbSchemaSrc = path.join(exampleServerSrc, context.orm, context.database);
|
|
3017
|
-
if (await fs.pathExists(exampleDbSchemaSrc)) await processAndCopyFiles("**/*", exampleDbSchemaSrc,
|
|
3069
|
+
if (await fs.pathExists(exampleDbSchemaSrc)) await processAndCopyFiles("**/*", exampleDbSchemaSrc, dbPackageDir, context, false);
|
|
3018
3070
|
}
|
|
3019
3071
|
}
|
|
3020
3072
|
if (webAppDirExists) {
|
|
@@ -3081,9 +3133,9 @@ async function handleExtras(projectDir, context) {
|
|
|
3081
3133
|
}
|
|
3082
3134
|
async function setupDockerComposeTemplates(projectDir, context) {
|
|
3083
3135
|
if (context.dbSetup !== "docker" || context.database === "none") return;
|
|
3084
|
-
const
|
|
3136
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
3085
3137
|
const dockerSrcDir = path.join(PKG_ROOT, `templates/db-setup/docker-compose/${context.database}`);
|
|
3086
|
-
if (await fs.pathExists(dockerSrcDir)) await processAndCopyFiles("**/*", dockerSrcDir,
|
|
3138
|
+
if (await fs.pathExists(dockerSrcDir)) await processAndCopyFiles("**/*", dockerSrcDir, dbPackageDir, context);
|
|
3087
3139
|
}
|
|
3088
3140
|
async function setupDeploymentTemplates(projectDir, context) {
|
|
3089
3141
|
if (context.webDeploy === "alchemy" || context.serverDeploy === "alchemy") if (context.webDeploy === "alchemy" && context.serverDeploy === "alchemy") {
|
|
@@ -3504,8 +3556,8 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3504
3556
|
await addPackageDependency({
|
|
3505
3557
|
devDependencies: [
|
|
3506
3558
|
"alchemy",
|
|
3507
|
-
"
|
|
3508
|
-
"
|
|
3559
|
+
"dotenv",
|
|
3560
|
+
"@cloudflare/vite-plugin"
|
|
3509
3561
|
],
|
|
3510
3562
|
projectDir: webAppDir
|
|
3511
3563
|
});
|
|
@@ -3533,17 +3585,6 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3533
3585
|
defaultImport: "alchemy"
|
|
3534
3586
|
});
|
|
3535
3587
|
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
3588
|
const exportAssignment = sourceFile.getExportAssignment((d) => !d.isExportEquals());
|
|
3548
3589
|
if (!exportAssignment) return;
|
|
3549
3590
|
const defineConfigCall = exportAssignment.getExpression();
|
|
@@ -3551,47 +3592,11 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3551
3592
|
let configObject = defineConfigCall.getArguments()[0];
|
|
3552
3593
|
if (!configObject) configObject = defineConfigCall.addArgument("{}");
|
|
3553
3594
|
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
3595
|
const pluginsProperty = configObject.getProperty("plugins");
|
|
3564
3596
|
if (pluginsProperty && Node.isPropertyAssignment(pluginsProperty)) {
|
|
3565
3597
|
const initializer = pluginsProperty.getInitializer();
|
|
3566
3598
|
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}()`);
|
|
3599
|
+
if (!initializer.getElements().some((el) => el.getText().includes("alchemy("))) initializer.addElement("alchemy()");
|
|
3595
3600
|
}
|
|
3596
3601
|
} else configObject.addPropertyAssignment({
|
|
3597
3602
|
name: "plugins",
|
|
@@ -3602,16 +3607,6 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3602
3607
|
} catch (error) {
|
|
3603
3608
|
console.warn("Failed to update vite.config.ts:", error);
|
|
3604
3609
|
}
|
|
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
3610
|
}
|
|
3616
3611
|
|
|
3617
3612
|
//#endregion
|
|
@@ -3778,7 +3773,7 @@ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
|
3778
3773
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3779
3774
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3780
3775
|
await addPackageDependency({
|
|
3781
|
-
devDependencies: ["wrangler"],
|
|
3776
|
+
devDependencies: ["wrangler", "@cloudflare/vite-plugin"],
|
|
3782
3777
|
projectDir: webAppDir
|
|
3783
3778
|
});
|
|
3784
3779
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
@@ -3795,6 +3790,12 @@ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
|
3795
3790
|
if (!await fs.pathExists(viteConfigPath)) return;
|
|
3796
3791
|
const sourceFile = tsProject.addSourceFileAtPathIfExists(viteConfigPath);
|
|
3797
3792
|
if (!sourceFile) return;
|
|
3793
|
+
const cfImport = sourceFile.getImportDeclaration("@cloudflare/vite-plugin");
|
|
3794
|
+
if (!cfImport) sourceFile.addImportDeclaration({
|
|
3795
|
+
moduleSpecifier: "@cloudflare/vite-plugin",
|
|
3796
|
+
namedImports: [{ name: "cloudflare" }]
|
|
3797
|
+
});
|
|
3798
|
+
else if (!cfImport.getNamedImports().some((ni) => ni.getName() === "cloudflare")) cfImport.addNamedImport({ name: "cloudflare" });
|
|
3798
3799
|
const reactImport = sourceFile.getImportDeclaration("@vitejs/plugin-react");
|
|
3799
3800
|
let reactPluginIdentifier = "viteReact";
|
|
3800
3801
|
if (!reactImport) sourceFile.addImportDeclaration({
|
|
@@ -3814,10 +3815,7 @@ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
|
3814
3815
|
const configObj = defineCall.getArguments()[0];
|
|
3815
3816
|
if (!configObj) return;
|
|
3816
3817
|
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);
|
|
3818
|
+
if (!pluginsArray.getElements().some((el) => el.getText().includes("cloudflare("))) pluginsArray.insertElement(0, "cloudflare({ viteEnvironment: { name: 'ssr' } })");
|
|
3821
3819
|
if (!pluginsArray.getElements().some((el) => Node.isCallExpression(el) && el.getExpression().getText() === reactPluginIdentifier)) {
|
|
3822
3820
|
const nextIndex = pluginsArray.getElements().findIndex((el) => el.getText().includes("tanstackStart(")) + 1;
|
|
3823
3821
|
if (nextIndex > 0) pluginsArray.insertElement(nextIndex, `${reactPluginIdentifier}()`);
|
|
@@ -3955,6 +3953,110 @@ async function addDeploymentToProject(input) {
|
|
|
3955
3953
|
}
|
|
3956
3954
|
}
|
|
3957
3955
|
|
|
3956
|
+
//#endregion
|
|
3957
|
+
//#region src/utils/setup-catalogs.ts
|
|
3958
|
+
async function setupCatalogs(projectDir, options) {
|
|
3959
|
+
if (options.packageManager === "npm") return;
|
|
3960
|
+
const packagePaths = [
|
|
3961
|
+
"apps/server",
|
|
3962
|
+
"apps/web",
|
|
3963
|
+
"packages/api",
|
|
3964
|
+
"packages/db",
|
|
3965
|
+
"packages/auth",
|
|
3966
|
+
"packages/backend"
|
|
3967
|
+
];
|
|
3968
|
+
const packagesInfo = [];
|
|
3969
|
+
for (const pkgPath of packagePaths) {
|
|
3970
|
+
const fullPath = path.join(projectDir, pkgPath);
|
|
3971
|
+
const pkgJsonPath = path.join(fullPath, "package.json");
|
|
3972
|
+
if (await fs.pathExists(pkgJsonPath)) {
|
|
3973
|
+
const pkgJson = await fs.readJson(pkgJsonPath);
|
|
3974
|
+
packagesInfo.push({
|
|
3975
|
+
path: fullPath,
|
|
3976
|
+
dependencies: pkgJson.dependencies || {},
|
|
3977
|
+
devDependencies: pkgJson.devDependencies || {}
|
|
3978
|
+
});
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
const catalog = findDuplicateDependencies(packagesInfo, options.projectName);
|
|
3982
|
+
if (Object.keys(catalog).length === 0) return;
|
|
3983
|
+
if (options.packageManager === "bun") await setupBunCatalogs(projectDir, catalog);
|
|
3984
|
+
else if (options.packageManager === "pnpm") await setupPnpmCatalogs(projectDir, catalog);
|
|
3985
|
+
await updatePackageJsonsWithCatalogs(packagesInfo, catalog);
|
|
3986
|
+
}
|
|
3987
|
+
function findDuplicateDependencies(packagesInfo, projectName) {
|
|
3988
|
+
const depCount = /* @__PURE__ */ new Map();
|
|
3989
|
+
const projectScope = `@${projectName}/`;
|
|
3990
|
+
for (const pkg of packagesInfo) {
|
|
3991
|
+
const allDeps = {
|
|
3992
|
+
...pkg.dependencies,
|
|
3993
|
+
...pkg.devDependencies
|
|
3994
|
+
};
|
|
3995
|
+
for (const [depName, version] of Object.entries(allDeps)) {
|
|
3996
|
+
if (depName.startsWith(projectScope)) continue;
|
|
3997
|
+
if (version.startsWith("workspace:")) continue;
|
|
3998
|
+
const existing = depCount.get(depName);
|
|
3999
|
+
if (existing) existing.packages.push(pkg.path);
|
|
4000
|
+
else depCount.set(depName, {
|
|
4001
|
+
version,
|
|
4002
|
+
packages: [pkg.path]
|
|
4003
|
+
});
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
4006
|
+
const catalog = {};
|
|
4007
|
+
for (const [depName, info] of depCount.entries()) if (info.packages.length > 1) catalog[depName] = info.version;
|
|
4008
|
+
return catalog;
|
|
4009
|
+
}
|
|
4010
|
+
async function setupBunCatalogs(projectDir, catalog) {
|
|
4011
|
+
const rootPkgJsonPath = path.join(projectDir, "package.json");
|
|
4012
|
+
const rootPkgJson = await fs.readJson(rootPkgJsonPath);
|
|
4013
|
+
if (!rootPkgJson.workspaces) rootPkgJson.workspaces = {};
|
|
4014
|
+
if (Array.isArray(rootPkgJson.workspaces)) rootPkgJson.workspaces = {
|
|
4015
|
+
packages: rootPkgJson.workspaces,
|
|
4016
|
+
catalog
|
|
4017
|
+
};
|
|
4018
|
+
else if (typeof rootPkgJson.workspaces === "object") {
|
|
4019
|
+
if (!rootPkgJson.workspaces.catalog) rootPkgJson.workspaces.catalog = {};
|
|
4020
|
+
rootPkgJson.workspaces.catalog = {
|
|
4021
|
+
...rootPkgJson.workspaces.catalog,
|
|
4022
|
+
...catalog
|
|
4023
|
+
};
|
|
4024
|
+
}
|
|
4025
|
+
await fs.writeJson(rootPkgJsonPath, rootPkgJson, { spaces: 2 });
|
|
4026
|
+
}
|
|
4027
|
+
async function setupPnpmCatalogs(projectDir, catalog) {
|
|
4028
|
+
const workspaceYamlPath = path.join(projectDir, "pnpm-workspace.yaml");
|
|
4029
|
+
if (!await fs.pathExists(workspaceYamlPath)) return;
|
|
4030
|
+
const workspaceContent = await fs.readFile(workspaceYamlPath, "utf-8");
|
|
4031
|
+
const workspaceYaml = yaml.parse(workspaceContent);
|
|
4032
|
+
if (!workspaceYaml.catalog) workspaceYaml.catalog = {};
|
|
4033
|
+
workspaceYaml.catalog = {
|
|
4034
|
+
...workspaceYaml.catalog,
|
|
4035
|
+
...catalog
|
|
4036
|
+
};
|
|
4037
|
+
await fs.writeFile(workspaceYamlPath, yaml.stringify(workspaceYaml));
|
|
4038
|
+
}
|
|
4039
|
+
async function updatePackageJsonsWithCatalogs(packagesInfo, catalog) {
|
|
4040
|
+
for (const pkg of packagesInfo) {
|
|
4041
|
+
const pkgJsonPath = path.join(pkg.path, "package.json");
|
|
4042
|
+
const pkgJson = await fs.readJson(pkgJsonPath);
|
|
4043
|
+
let updated = false;
|
|
4044
|
+
if (pkgJson.dependencies) {
|
|
4045
|
+
for (const depName of Object.keys(pkgJson.dependencies)) if (catalog[depName]) {
|
|
4046
|
+
pkgJson.dependencies[depName] = "catalog:";
|
|
4047
|
+
updated = true;
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
if (pkgJson.devDependencies) {
|
|
4051
|
+
for (const depName of Object.keys(pkgJson.devDependencies)) if (catalog[depName]) {
|
|
4052
|
+
pkgJson.devDependencies[depName] = "catalog:";
|
|
4053
|
+
updated = true;
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
if (updated) await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
|
|
3958
4060
|
//#endregion
|
|
3959
4061
|
//#region src/helpers/addons/examples-setup.ts
|
|
3960
4062
|
async function setupExamples(config) {
|
|
@@ -3963,10 +4065,10 @@ async function setupExamples(config) {
|
|
|
3963
4065
|
if (examples.includes("ai")) {
|
|
3964
4066
|
const webClientDir = path.join(projectDir, "apps/web");
|
|
3965
4067
|
const nativeClientDir = path.join(projectDir, "apps/native");
|
|
3966
|
-
const
|
|
4068
|
+
const apiDir = path.join(projectDir, "packages/api");
|
|
3967
4069
|
const webClientDirExists = await fs.pathExists(webClientDir);
|
|
3968
4070
|
const nativeClientDirExists = await fs.pathExists(nativeClientDir);
|
|
3969
|
-
const
|
|
4071
|
+
const apiDirExists = await fs.pathExists(apiDir);
|
|
3970
4072
|
const hasNuxt = frontend.includes("nuxt");
|
|
3971
4073
|
const hasSvelte = frontend.includes("svelte");
|
|
3972
4074
|
const hasReactWeb = frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("next") || frontend.includes("tanstack-start");
|
|
@@ -3987,9 +4089,9 @@ async function setupExamples(config) {
|
|
|
3987
4089
|
dependencies: ["ai", "@ai-sdk/react"],
|
|
3988
4090
|
projectDir: nativeClientDir
|
|
3989
4091
|
});
|
|
3990
|
-
if (
|
|
4092
|
+
if (apiDirExists && backend !== "none") await addPackageDependency({
|
|
3991
4093
|
dependencies: ["ai", "@ai-sdk/google"],
|
|
3992
|
-
projectDir:
|
|
4094
|
+
projectDir: apiDir
|
|
3993
4095
|
});
|
|
3994
4096
|
}
|
|
3995
4097
|
}
|
|
@@ -4105,32 +4207,57 @@ function getConvexDependencies(frontend) {
|
|
|
4105
4207
|
return deps;
|
|
4106
4208
|
}
|
|
4107
4209
|
async function setupApi(config) {
|
|
4108
|
-
const { api, projectName, frontend, backend, packageManager, projectDir } = config;
|
|
4210
|
+
const { api, projectName, frontend, backend, packageManager, projectDir, auth } = config;
|
|
4109
4211
|
const isConvex = backend === "convex";
|
|
4110
4212
|
const webDir = path.join(projectDir, "apps/web");
|
|
4111
4213
|
const nativeDir = path.join(projectDir, "apps/native");
|
|
4112
4214
|
const serverDir = path.join(projectDir, "apps/server");
|
|
4113
4215
|
const webDirExists = await fs.pathExists(webDir);
|
|
4114
4216
|
const nativeDirExists = await fs.pathExists(nativeDir);
|
|
4115
|
-
|
|
4217
|
+
await fs.pathExists(serverDir);
|
|
4116
4218
|
const frontendType = getFrontendType(frontend);
|
|
4117
4219
|
if (!isConvex && api !== "none") {
|
|
4118
4220
|
const apiDeps = getApiDependencies(api, frontendType);
|
|
4119
|
-
|
|
4221
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
4222
|
+
if (apiDeps.server) {
|
|
4120
4223
|
await addPackageDependency({
|
|
4121
4224
|
dependencies: apiDeps.server.dependencies,
|
|
4122
|
-
projectDir:
|
|
4225
|
+
projectDir: apiPackageDir
|
|
4226
|
+
});
|
|
4227
|
+
const frameworkDeps = [];
|
|
4228
|
+
if (backend === "hono") frameworkDeps.push("hono");
|
|
4229
|
+
else if (backend === "elysia") frameworkDeps.push("elysia");
|
|
4230
|
+
else if (backend === "express") frameworkDeps.push("express", "@types/express");
|
|
4231
|
+
else if (backend === "fastify") frameworkDeps.push("fastify");
|
|
4232
|
+
else if (backend === "self") {
|
|
4233
|
+
if (frontend.includes("next")) frameworkDeps.push("next");
|
|
4234
|
+
}
|
|
4235
|
+
if (frameworkDeps.length > 0) await addPackageDependency({
|
|
4236
|
+
dependencies: frameworkDeps,
|
|
4237
|
+
projectDir: apiPackageDir
|
|
4123
4238
|
});
|
|
4124
4239
|
if (api === "trpc") {
|
|
4125
4240
|
if (backend === "hono") await addPackageDependency({
|
|
4126
4241
|
dependencies: ["@hono/trpc-server"],
|
|
4127
|
-
projectDir:
|
|
4242
|
+
projectDir: apiPackageDir
|
|
4128
4243
|
});
|
|
4129
4244
|
else if (backend === "elysia") await addPackageDependency({
|
|
4130
4245
|
dependencies: ["@elysiajs/trpc"],
|
|
4131
|
-
projectDir:
|
|
4246
|
+
projectDir: apiPackageDir
|
|
4247
|
+
});
|
|
4248
|
+
else if (backend === "express") await addPackageDependency({
|
|
4249
|
+
dependencies: ["@trpc/server"],
|
|
4250
|
+
projectDir: apiPackageDir
|
|
4251
|
+
});
|
|
4252
|
+
else if (backend === "fastify") await addPackageDependency({
|
|
4253
|
+
dependencies: ["@trpc/server"],
|
|
4254
|
+
projectDir: apiPackageDir
|
|
4132
4255
|
});
|
|
4133
4256
|
}
|
|
4257
|
+
if (auth === "better-auth") await addPackageDependency({
|
|
4258
|
+
dependencies: ["better-auth"],
|
|
4259
|
+
projectDir: apiPackageDir
|
|
4260
|
+
});
|
|
4134
4261
|
}
|
|
4135
4262
|
if (webDirExists && apiDeps.web) await addPackageDependency({
|
|
4136
4263
|
dependencies: apiDeps.web.dependencies,
|
|
@@ -4174,7 +4301,7 @@ async function setupApi(config) {
|
|
|
4174
4301
|
//#endregion
|
|
4175
4302
|
//#region src/helpers/core/backend-setup.ts
|
|
4176
4303
|
async function setupBackendDependencies(config) {
|
|
4177
|
-
const { backend, runtime, api, projectDir } = config;
|
|
4304
|
+
const { backend, runtime, api, auth, examples, projectDir } = config;
|
|
4178
4305
|
if (backend === "convex") return;
|
|
4179
4306
|
const framework = backend;
|
|
4180
4307
|
const serverDir = path.join(projectDir, "apps/server");
|
|
@@ -4202,6 +4329,13 @@ async function setupBackendDependencies(config) {
|
|
|
4202
4329
|
dependencies.push("fastify", "@fastify/cors");
|
|
4203
4330
|
if (runtime === "node") devDependencies.push("tsx", "@types/node");
|
|
4204
4331
|
}
|
|
4332
|
+
if (api === "trpc") {
|
|
4333
|
+
if (framework === "express") dependencies.push("@trpc/server");
|
|
4334
|
+
else if (framework === "fastify") dependencies.push("@trpc/server");
|
|
4335
|
+
else if (runtime === "workers") dependencies.push("@trpc/server");
|
|
4336
|
+
} else if (api === "orpc") dependencies.push("@orpc/server", "@orpc/openapi", "@orpc/zod");
|
|
4337
|
+
if (auth === "better-auth") dependencies.push("better-auth");
|
|
4338
|
+
if (examples.includes("ai")) dependencies.push("ai", "@ai-sdk/google");
|
|
4205
4339
|
if (runtime === "bun") devDependencies.push("@types/bun");
|
|
4206
4340
|
if (dependencies.length > 0 || devDependencies.length > 0) await addPackageDependency({
|
|
4207
4341
|
dependencies,
|
|
@@ -4220,7 +4354,7 @@ async function setupAuth(config) {
|
|
|
4220
4354
|
const nativeDir = path.join(projectDir, "apps/native");
|
|
4221
4355
|
const clientDirExists = await fs.pathExists(clientDir);
|
|
4222
4356
|
const nativeDirExists = await fs.pathExists(nativeDir);
|
|
4223
|
-
|
|
4357
|
+
await fs.pathExists(serverDir);
|
|
4224
4358
|
try {
|
|
4225
4359
|
if (backend === "convex") {
|
|
4226
4360
|
if (auth === "clerk" && clientDirExists) {
|
|
@@ -4276,9 +4410,11 @@ async function setupAuth(config) {
|
|
|
4276
4410
|
});
|
|
4277
4411
|
return;
|
|
4278
4412
|
}
|
|
4279
|
-
|
|
4413
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
4414
|
+
const authPackageDirExists = await fs.pathExists(authPackageDir);
|
|
4415
|
+
if (authPackageDirExists && auth === "better-auth") await addPackageDependency({
|
|
4280
4416
|
dependencies: ["better-auth"],
|
|
4281
|
-
projectDir:
|
|
4417
|
+
projectDir: authPackageDir
|
|
4282
4418
|
});
|
|
4283
4419
|
if (frontend.some((f) => [
|
|
4284
4420
|
"react-router",
|
|
@@ -4300,9 +4436,9 @@ async function setupAuth(config) {
|
|
|
4300
4436
|
dependencies: ["better-auth", "@better-auth/expo"],
|
|
4301
4437
|
projectDir: nativeDir
|
|
4302
4438
|
});
|
|
4303
|
-
if (
|
|
4439
|
+
if (authPackageDirExists) await addPackageDependency({
|
|
4304
4440
|
dependencies: ["@better-auth/expo"],
|
|
4305
|
-
projectDir:
|
|
4441
|
+
projectDir: authPackageDir
|
|
4306
4442
|
});
|
|
4307
4443
|
}
|
|
4308
4444
|
}
|
|
@@ -4485,8 +4621,6 @@ async function setupEnvironmentVariables(config) {
|
|
|
4485
4621
|
return;
|
|
4486
4622
|
}
|
|
4487
4623
|
const serverDir = path.join(projectDir, "apps/server");
|
|
4488
|
-
if (!await fs.pathExists(serverDir)) return;
|
|
4489
|
-
const envPath = path.join(serverDir, ".env");
|
|
4490
4624
|
let corsOrigin = "http://localhost:3001";
|
|
4491
4625
|
if (hasReactRouter || hasSvelte) corsOrigin = "http://localhost:5173";
|
|
4492
4626
|
let databaseUrl = null;
|
|
@@ -4502,47 +4636,50 @@ async function setupEnvironmentVariables(config) {
|
|
|
4502
4636
|
break;
|
|
4503
4637
|
case "sqlite":
|
|
4504
4638
|
if (config.runtime === "workers") databaseUrl = "http://127.0.0.1:8080";
|
|
4505
|
-
else databaseUrl = "
|
|
4639
|
+
else databaseUrl = `file:${path.join(config.projectDir, "apps/server", "local.db")}`;
|
|
4506
4640
|
break;
|
|
4507
4641
|
}
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4642
|
+
if (await fs.pathExists(serverDir)) {
|
|
4643
|
+
const serverEnvPath = path.join(serverDir, ".env");
|
|
4644
|
+
const serverVars = [
|
|
4645
|
+
{
|
|
4646
|
+
key: "BETTER_AUTH_SECRET",
|
|
4647
|
+
value: generateAuthSecret(),
|
|
4648
|
+
condition: !!auth
|
|
4649
|
+
},
|
|
4650
|
+
{
|
|
4651
|
+
key: "BETTER_AUTH_URL",
|
|
4652
|
+
value: "http://localhost:3000",
|
|
4653
|
+
condition: !!auth
|
|
4654
|
+
},
|
|
4655
|
+
{
|
|
4656
|
+
key: "POLAR_ACCESS_TOKEN",
|
|
4657
|
+
value: "",
|
|
4658
|
+
condition: config.payments === "polar"
|
|
4659
|
+
},
|
|
4660
|
+
{
|
|
4661
|
+
key: "POLAR_SUCCESS_URL",
|
|
4662
|
+
value: `${corsOrigin}/success?checkout_id={CHECKOUT_ID}`,
|
|
4663
|
+
condition: config.payments === "polar"
|
|
4664
|
+
},
|
|
4665
|
+
{
|
|
4666
|
+
key: "CORS_ORIGIN",
|
|
4667
|
+
value: corsOrigin,
|
|
4668
|
+
condition: true
|
|
4669
|
+
},
|
|
4670
|
+
{
|
|
4671
|
+
key: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
4672
|
+
value: "",
|
|
4673
|
+
condition: examples?.includes("ai") || false
|
|
4674
|
+
},
|
|
4675
|
+
{
|
|
4676
|
+
key: "DATABASE_URL",
|
|
4677
|
+
value: databaseUrl,
|
|
4678
|
+
condition: database !== "none" && dbSetup === "none"
|
|
4679
|
+
}
|
|
4680
|
+
];
|
|
4681
|
+
await addEnvVariablesToFile(serverEnvPath, serverVars);
|
|
4682
|
+
}
|
|
4546
4683
|
const isUnifiedAlchemy = webDeploy === "alchemy" && serverDeploy === "alchemy";
|
|
4547
4684
|
const isIndividualAlchemy = webDeploy === "alchemy" || serverDeploy === "alchemy";
|
|
4548
4685
|
if (isUnifiedAlchemy) {
|
|
@@ -4561,14 +4698,11 @@ async function setupEnvironmentVariables(config) {
|
|
|
4561
4698
|
condition: true
|
|
4562
4699
|
}]);
|
|
4563
4700
|
}
|
|
4564
|
-
if (serverDeploy === "alchemy") {
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
condition: true
|
|
4570
|
-
}]);
|
|
4571
|
-
}
|
|
4701
|
+
if (serverDeploy === "alchemy") await addEnvVariablesToFile(path.join(serverDir, ".env"), [{
|
|
4702
|
+
key: "ALCHEMY_PASSWORD",
|
|
4703
|
+
value: "please-change-this",
|
|
4704
|
+
condition: true
|
|
4705
|
+
}]);
|
|
4572
4706
|
}
|
|
4573
4707
|
}
|
|
4574
4708
|
|
|
@@ -4603,7 +4737,7 @@ async function setupCloudflareD1(config) {
|
|
|
4603
4737
|
const envPath = path.join(projectDir, "apps/server", ".env");
|
|
4604
4738
|
const variables = [{
|
|
4605
4739
|
key: "DATABASE_URL",
|
|
4606
|
-
value: "
|
|
4740
|
+
value: `file:${path.join(projectDir, "apps/server", "local.db")}`,
|
|
4607
4741
|
condition: true
|
|
4608
4742
|
}];
|
|
4609
4743
|
try {
|
|
@@ -5133,9 +5267,9 @@ async function writeEnvFile$1(projectDir, config) {
|
|
|
5133
5267
|
}
|
|
5134
5268
|
async function addDotenvImportToPrismaConfig(projectDir) {
|
|
5135
5269
|
try {
|
|
5136
|
-
const prismaConfigPath = path.join(projectDir, "
|
|
5270
|
+
const prismaConfigPath = path.join(projectDir, "packages/db/prisma.config.ts");
|
|
5137
5271
|
let content = await fs.readFile(prismaConfigPath, "utf8");
|
|
5138
|
-
content = `import "dotenv
|
|
5272
|
+
content = `import dotenv from "dotenv";\ndotenv.config({ path: "../../apps/server/.env" });\n${content}`;
|
|
5139
5273
|
await fs.writeFile(prismaConfigPath, content);
|
|
5140
5274
|
} catch (_error) {
|
|
5141
5275
|
consola$1.error("Failed to update prisma.config.ts");
|
|
@@ -5151,11 +5285,12 @@ function displayManualSetupInstructions$1() {
|
|
|
5151
5285
|
|
|
5152
5286
|
DATABASE_URL="your_database_url"`);
|
|
5153
5287
|
}
|
|
5154
|
-
async function addPrismaAccelerateExtension(
|
|
5288
|
+
async function addPrismaAccelerateExtension(projectDir) {
|
|
5155
5289
|
try {
|
|
5290
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
5156
5291
|
await addPackageDependency({
|
|
5157
5292
|
dependencies: ["@prisma/extension-accelerate"],
|
|
5158
|
-
projectDir:
|
|
5293
|
+
projectDir: dbPackageDir
|
|
5159
5294
|
});
|
|
5160
5295
|
return true;
|
|
5161
5296
|
} catch (_error) {
|
|
@@ -5216,7 +5351,7 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5216
5351
|
await writeEnvFile$1(projectDir, prismaConfig);
|
|
5217
5352
|
if (orm === "prisma") {
|
|
5218
5353
|
await addDotenvImportToPrismaConfig(projectDir);
|
|
5219
|
-
await addPrismaAccelerateExtension(
|
|
5354
|
+
await addPrismaAccelerateExtension(projectDir);
|
|
5220
5355
|
}
|
|
5221
5356
|
const connectionType = orm === "drizzle" ? "direct connection" : "Prisma Accelerate";
|
|
5222
5357
|
log.success(pc.green(`Prisma Postgres database configured successfully with ${connectionType}!`));
|
|
@@ -5316,18 +5451,18 @@ function displayManualSupabaseInstructions(output) {
|
|
|
5316
5451
|
log.info(`"Manual Supabase Setup Instructions:"
|
|
5317
5452
|
1. Ensure Docker is installed and running.
|
|
5318
5453
|
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 \`
|
|
5454
|
+
3. Run \`supabase init\` in your project's \`packages/db\` directory.
|
|
5455
|
+
4. Run \`supabase start\` in your project's \`packages/db\` directory.
|
|
5321
5456
|
5. Copy the 'DB URL' from the output.${output ? `
|
|
5322
5457
|
${pc.bold("Relevant output from `supabase start`:")}
|
|
5323
5458
|
${pc.dim(output)}` : ""}
|
|
5324
|
-
6. Add the DB URL to the .env file in \`
|
|
5459
|
+
6. Add the DB URL to the .env file in \`packages/db/.env\` as \`DATABASE_URL\`:
|
|
5325
5460
|
${pc.gray("DATABASE_URL=\"your_supabase_db_url\"")}`);
|
|
5326
5461
|
}
|
|
5327
5462
|
async function setupSupabase(config, cliInput) {
|
|
5328
5463
|
const { projectDir, packageManager } = config;
|
|
5329
5464
|
const manualDb = cliInput?.manualDb ?? false;
|
|
5330
|
-
const serverDir = path.join(projectDir, "
|
|
5465
|
+
const serverDir = path.join(projectDir, "packages", "db");
|
|
5331
5466
|
try {
|
|
5332
5467
|
await fs.ensureDir(serverDir);
|
|
5333
5468
|
if (manualDb) {
|
|
@@ -5610,15 +5745,15 @@ async function setupDatabase(config, cliInput) {
|
|
|
5610
5745
|
const { database, orm, dbSetup, backend, projectDir } = config;
|
|
5611
5746
|
if (backend === "convex" || database === "none") {
|
|
5612
5747
|
if (backend !== "convex") {
|
|
5613
|
-
const serverDir
|
|
5614
|
-
const serverDbDir = path.join(serverDir
|
|
5748
|
+
const serverDir = path.join(projectDir, "apps/server");
|
|
5749
|
+
const serverDbDir = path.join(serverDir, "src/db");
|
|
5615
5750
|
if (await fs.pathExists(serverDbDir)) await fs.remove(serverDbDir);
|
|
5616
5751
|
}
|
|
5617
5752
|
return;
|
|
5618
5753
|
}
|
|
5619
5754
|
const s = spinner();
|
|
5620
|
-
const
|
|
5621
|
-
if (!await fs.pathExists(
|
|
5755
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
5756
|
+
if (!await fs.pathExists(dbPackageDir)) return;
|
|
5622
5757
|
try {
|
|
5623
5758
|
if (orm === "prisma") if (database === "mysql" && dbSetup === "planetscale") await addPackageDependency({
|
|
5624
5759
|
dependencies: [
|
|
@@ -5627,23 +5762,27 @@ async function setupDatabase(config, cliInput) {
|
|
|
5627
5762
|
"@planetscale/database"
|
|
5628
5763
|
],
|
|
5629
5764
|
devDependencies: ["prisma"],
|
|
5630
|
-
projectDir:
|
|
5765
|
+
projectDir: dbPackageDir
|
|
5631
5766
|
});
|
|
5632
5767
|
else if (database === "sqlite" && dbSetup === "turso") await addPackageDependency({
|
|
5633
5768
|
dependencies: ["@prisma/client", "@prisma/adapter-libsql"],
|
|
5634
5769
|
devDependencies: ["prisma"],
|
|
5635
|
-
projectDir:
|
|
5770
|
+
projectDir: dbPackageDir
|
|
5636
5771
|
});
|
|
5637
5772
|
else await addPackageDependency({
|
|
5638
5773
|
dependencies: ["@prisma/client"],
|
|
5639
5774
|
devDependencies: ["prisma"],
|
|
5640
|
-
projectDir:
|
|
5775
|
+
projectDir: dbPackageDir
|
|
5641
5776
|
});
|
|
5642
5777
|
else if (orm === "drizzle") {
|
|
5643
5778
|
if (database === "sqlite") await addPackageDependency({
|
|
5644
|
-
dependencies: [
|
|
5779
|
+
dependencies: [
|
|
5780
|
+
"drizzle-orm",
|
|
5781
|
+
"@libsql/client",
|
|
5782
|
+
"libsql"
|
|
5783
|
+
],
|
|
5645
5784
|
devDependencies: ["drizzle-kit"],
|
|
5646
|
-
projectDir:
|
|
5785
|
+
projectDir: dbPackageDir
|
|
5647
5786
|
});
|
|
5648
5787
|
else if (database === "postgres") if (dbSetup === "neon") await addPackageDependency({
|
|
5649
5788
|
dependencies: [
|
|
@@ -5652,32 +5791,32 @@ async function setupDatabase(config, cliInput) {
|
|
|
5652
5791
|
"ws"
|
|
5653
5792
|
],
|
|
5654
5793
|
devDependencies: ["drizzle-kit", "@types/ws"],
|
|
5655
|
-
projectDir:
|
|
5794
|
+
projectDir: dbPackageDir
|
|
5656
5795
|
});
|
|
5657
5796
|
else if (dbSetup === "planetscale") await addPackageDependency({
|
|
5658
5797
|
dependencies: ["drizzle-orm", "pg"],
|
|
5659
5798
|
devDependencies: ["drizzle-kit", "@types/pg"],
|
|
5660
|
-
projectDir:
|
|
5799
|
+
projectDir: dbPackageDir
|
|
5661
5800
|
});
|
|
5662
5801
|
else await addPackageDependency({
|
|
5663
5802
|
dependencies: ["drizzle-orm", "pg"],
|
|
5664
5803
|
devDependencies: ["drizzle-kit", "@types/pg"],
|
|
5665
|
-
projectDir:
|
|
5804
|
+
projectDir: dbPackageDir
|
|
5666
5805
|
});
|
|
5667
5806
|
else if (database === "mysql") if (dbSetup === "planetscale") await addPackageDependency({
|
|
5668
5807
|
dependencies: ["drizzle-orm", "@planetscale/database"],
|
|
5669
5808
|
devDependencies: ["drizzle-kit"],
|
|
5670
|
-
projectDir:
|
|
5809
|
+
projectDir: dbPackageDir
|
|
5671
5810
|
});
|
|
5672
5811
|
else await addPackageDependency({
|
|
5673
5812
|
dependencies: ["drizzle-orm", "mysql2"],
|
|
5674
5813
|
devDependencies: ["drizzle-kit"],
|
|
5675
|
-
projectDir:
|
|
5814
|
+
projectDir: dbPackageDir
|
|
5676
5815
|
});
|
|
5677
5816
|
} else if (orm === "mongoose") await addPackageDependency({
|
|
5678
5817
|
dependencies: ["mongoose"],
|
|
5679
5818
|
devDependencies: [],
|
|
5680
|
-
projectDir:
|
|
5819
|
+
projectDir: dbPackageDir
|
|
5681
5820
|
});
|
|
5682
5821
|
if (dbSetup === "docker") await setupDockerCompose(config);
|
|
5683
5822
|
else if (database === "sqlite" && dbSetup === "turso") await setupTurso(config, cliInput);
|
|
@@ -5700,7 +5839,7 @@ async function setupDatabase(config, cliInput) {
|
|
|
5700
5839
|
//#region src/helpers/core/runtime-setup.ts
|
|
5701
5840
|
async function setupRuntime(config) {
|
|
5702
5841
|
const { runtime, backend, projectDir } = config;
|
|
5703
|
-
if (backend === "convex" || backend === "
|
|
5842
|
+
if (backend === "convex" || backend === "self" || runtime === "none") return;
|
|
5704
5843
|
const serverDir = path.join(projectDir, "apps/server");
|
|
5705
5844
|
if (!await fs.pathExists(serverDir)) return;
|
|
5706
5845
|
if (runtime === "bun") await setupBunRuntime(serverDir, backend);
|
|
@@ -6220,7 +6359,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6220
6359
|
else if (!hasNative && !addons?.includes("starlight")) output += `${pc.yellow("NOTE:")} You are creating a backend-only app\n (no frontend selected)\n`;
|
|
6221
6360
|
if (!isConvex) {
|
|
6222
6361
|
output += `${pc.cyan("•")} Backend API: http://localhost:3000\n`;
|
|
6223
|
-
if (api === "orpc") if (backend === "
|
|
6362
|
+
if (api === "orpc") if (backend === "self") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/rpc/api\n`;
|
|
6224
6363
|
else output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/api\n`;
|
|
6225
6364
|
}
|
|
6226
6365
|
if (addons?.includes("starlight")) output += `${pc.cyan("•")} Docs: http://localhost:4321\n`;
|
|
@@ -6334,12 +6473,78 @@ function getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy) {
|
|
|
6334
6473
|
return instructions.length ? `\n${instructions.join("\n")}` : "";
|
|
6335
6474
|
}
|
|
6336
6475
|
|
|
6476
|
+
//#endregion
|
|
6477
|
+
//#region src/helpers/core/workspace-setup.ts
|
|
6478
|
+
async function setupWorkspaceDependencies(projectDir, options) {
|
|
6479
|
+
const projectName = options.projectName;
|
|
6480
|
+
const workspaceVersion = options.packageManager === "npm" ? "*" : "workspace:*";
|
|
6481
|
+
const commonDeps = ["dotenv", "zod"];
|
|
6482
|
+
const commonDevDeps = ["tsdown"];
|
|
6483
|
+
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
6484
|
+
if (await fs.pathExists(dbPackageDir)) await addPackageDependency({
|
|
6485
|
+
dependencies: commonDeps,
|
|
6486
|
+
devDependencies: commonDevDeps,
|
|
6487
|
+
projectDir: dbPackageDir
|
|
6488
|
+
});
|
|
6489
|
+
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
6490
|
+
if (await fs.pathExists(authPackageDir)) await addPackageDependency({
|
|
6491
|
+
dependencies: commonDeps,
|
|
6492
|
+
devDependencies: commonDevDeps,
|
|
6493
|
+
customDependencies: { [`@${projectName}/db`]: workspaceVersion },
|
|
6494
|
+
projectDir: authPackageDir
|
|
6495
|
+
});
|
|
6496
|
+
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
6497
|
+
if (await fs.pathExists(apiPackageDir)) await addPackageDependency({
|
|
6498
|
+
dependencies: commonDeps,
|
|
6499
|
+
devDependencies: commonDevDeps,
|
|
6500
|
+
customDependencies: {
|
|
6501
|
+
[`@${projectName}/auth`]: workspaceVersion,
|
|
6502
|
+
[`@${projectName}/db`]: workspaceVersion
|
|
6503
|
+
},
|
|
6504
|
+
projectDir: apiPackageDir
|
|
6505
|
+
});
|
|
6506
|
+
const serverPackageDir = path.join(projectDir, "apps/server");
|
|
6507
|
+
if (await fs.pathExists(serverPackageDir)) await addPackageDependency({
|
|
6508
|
+
dependencies: commonDeps,
|
|
6509
|
+
devDependencies: commonDevDeps,
|
|
6510
|
+
customDependencies: {
|
|
6511
|
+
[`@${projectName}/api`]: workspaceVersion,
|
|
6512
|
+
[`@${projectName}/auth`]: workspaceVersion,
|
|
6513
|
+
[`@${projectName}/db`]: workspaceVersion
|
|
6514
|
+
},
|
|
6515
|
+
projectDir: serverPackageDir
|
|
6516
|
+
});
|
|
6517
|
+
const needsApiDependency = options.api && options.api !== "none";
|
|
6518
|
+
const webPackageDir = path.join(projectDir, "apps/web");
|
|
6519
|
+
if (await fs.pathExists(webPackageDir)) {
|
|
6520
|
+
const webDeps = {};
|
|
6521
|
+
if (options.backend === "self") {
|
|
6522
|
+
webDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6523
|
+
webDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
6524
|
+
webDeps[`@${projectName}/db`] = workspaceVersion;
|
|
6525
|
+
} else if (needsApiDependency) webDeps[`@${projectName}/api`] = workspaceVersion;
|
|
6526
|
+
if (Object.keys(webDeps).length > 0) await addPackageDependency({
|
|
6527
|
+
customDependencies: webDeps,
|
|
6528
|
+
projectDir: webPackageDir
|
|
6529
|
+
});
|
|
6530
|
+
}
|
|
6531
|
+
}
|
|
6532
|
+
|
|
6337
6533
|
//#endregion
|
|
6338
6534
|
//#region src/helpers/core/project-config.ts
|
|
6339
6535
|
async function updatePackageConfigurations(projectDir, options) {
|
|
6340
6536
|
await updateRootPackageJson(projectDir, options);
|
|
6341
|
-
if (options.backend
|
|
6342
|
-
else
|
|
6537
|
+
if (options.backend === "convex") await updateConvexPackageJson(projectDir, options);
|
|
6538
|
+
else if (options.backend === "self") {
|
|
6539
|
+
await updateAuthPackageJson(projectDir, options);
|
|
6540
|
+
await updateApiPackageJson(projectDir, options);
|
|
6541
|
+
await setupWorkspaceDependencies(projectDir, options);
|
|
6542
|
+
} else if (options.backend !== "none") {
|
|
6543
|
+
await updateServerPackageJson(projectDir, options);
|
|
6544
|
+
await updateAuthPackageJson(projectDir, options);
|
|
6545
|
+
await updateApiPackageJson(projectDir, options);
|
|
6546
|
+
await setupWorkspaceDependencies(projectDir, options);
|
|
6547
|
+
}
|
|
6343
6548
|
}
|
|
6344
6549
|
async function updateRootPackageJson(projectDir, options) {
|
|
6345
6550
|
const rootPackageJsonPath = path.join(projectDir, "package.json");
|
|
@@ -6349,6 +6554,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6349
6554
|
if (!packageJson.scripts) packageJson.scripts = {};
|
|
6350
6555
|
const scripts = packageJson.scripts;
|
|
6351
6556
|
const backendPackageName = options.backend === "convex" ? `@${options.projectName}/backend` : "server";
|
|
6557
|
+
const dbPackageName = `@${options.projectName}/db`;
|
|
6352
6558
|
let serverDevScript = "";
|
|
6353
6559
|
if (options.addons.includes("turborepo")) serverDevScript = `turbo -F ${backendPackageName} dev`;
|
|
6354
6560
|
else if (options.packageManager === "bun") serverDevScript = `bun run --filter ${backendPackageName} dev`;
|
|
@@ -6365,17 +6571,17 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6365
6571
|
scripts["check-types"] = "turbo check-types";
|
|
6366
6572
|
scripts["dev:native"] = "turbo -F native dev";
|
|
6367
6573
|
scripts["dev:web"] = "turbo -F web dev";
|
|
6368
|
-
scripts["dev:server"] = serverDevScript;
|
|
6574
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6369
6575
|
if (options.backend === "convex") scripts["dev:setup"] = `turbo -F ${backendPackageName} dev:setup`;
|
|
6370
6576
|
if (needsDbScripts) {
|
|
6371
|
-
scripts["db:push"] = `turbo -F ${
|
|
6372
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `turbo -F ${
|
|
6577
|
+
scripts["db:push"] = `turbo -F ${dbPackageName} db:push`;
|
|
6578
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `turbo -F ${dbPackageName} db:studio`;
|
|
6373
6579
|
if (options.orm === "prisma") {
|
|
6374
|
-
scripts["db:generate"] = `turbo -F ${
|
|
6375
|
-
scripts["db:migrate"] = `turbo -F ${
|
|
6580
|
+
scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
|
|
6581
|
+
scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
|
|
6376
6582
|
} else if (options.orm === "drizzle") {
|
|
6377
|
-
scripts["db:generate"] = `turbo -F ${
|
|
6378
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${
|
|
6583
|
+
scripts["db:generate"] = `turbo -F ${dbPackageName} db:generate`;
|
|
6584
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `turbo -F ${dbPackageName} db:migrate`;
|
|
6379
6585
|
}
|
|
6380
6586
|
}
|
|
6381
6587
|
if (options.dbSetup === "docker") {
|
|
@@ -6390,17 +6596,17 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6390
6596
|
scripts["check-types"] = "pnpm -r check-types";
|
|
6391
6597
|
scripts["dev:native"] = "pnpm --filter native dev";
|
|
6392
6598
|
scripts["dev:web"] = "pnpm --filter web dev";
|
|
6393
|
-
scripts["dev:server"] = serverDevScript;
|
|
6599
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6394
6600
|
if (options.backend === "convex") scripts["dev:setup"] = `pnpm --filter ${backendPackageName} dev:setup`;
|
|
6395
6601
|
if (needsDbScripts) {
|
|
6396
|
-
scripts["db:push"] = `pnpm --filter ${
|
|
6397
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${
|
|
6602
|
+
scripts["db:push"] = `pnpm --filter ${dbPackageName} db:push`;
|
|
6603
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `pnpm --filter ${dbPackageName} db:studio`;
|
|
6398
6604
|
if (options.orm === "prisma") {
|
|
6399
|
-
scripts["db:generate"] = `pnpm --filter ${
|
|
6400
|
-
scripts["db:migrate"] = `pnpm --filter ${
|
|
6605
|
+
scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
|
|
6606
|
+
scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
|
|
6401
6607
|
} else if (options.orm === "drizzle") {
|
|
6402
|
-
scripts["db:generate"] = `pnpm --filter ${
|
|
6403
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${
|
|
6608
|
+
scripts["db:generate"] = `pnpm --filter ${dbPackageName} db:generate`;
|
|
6609
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `pnpm --filter ${dbPackageName} db:migrate`;
|
|
6404
6610
|
}
|
|
6405
6611
|
}
|
|
6406
6612
|
if (options.dbSetup === "docker") {
|
|
@@ -6415,17 +6621,17 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6415
6621
|
scripts["check-types"] = "npm run check-types --workspaces";
|
|
6416
6622
|
scripts["dev:native"] = "npm run dev --workspace native";
|
|
6417
6623
|
scripts["dev:web"] = "npm run dev --workspace web";
|
|
6418
|
-
scripts["dev:server"] = serverDevScript;
|
|
6624
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6419
6625
|
if (options.backend === "convex") scripts["dev:setup"] = `npm run dev:setup --workspace ${backendPackageName}`;
|
|
6420
6626
|
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 ${
|
|
6627
|
+
scripts["db:push"] = `npm run db:push --workspace ${dbPackageName}`;
|
|
6628
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `npm run db:studio --workspace ${dbPackageName}`;
|
|
6423
6629
|
if (options.orm === "prisma") {
|
|
6424
|
-
scripts["db:generate"] = `npm run db:generate --workspace ${
|
|
6425
|
-
scripts["db:migrate"] = `npm run db:migrate --workspace ${
|
|
6630
|
+
scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
|
|
6631
|
+
scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
|
|
6426
6632
|
} 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 ${
|
|
6633
|
+
scripts["db:generate"] = `npm run db:generate --workspace ${dbPackageName}`;
|
|
6634
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `npm run db:migrate --workspace ${dbPackageName}`;
|
|
6429
6635
|
}
|
|
6430
6636
|
}
|
|
6431
6637
|
if (options.dbSetup === "docker") {
|
|
@@ -6440,17 +6646,17 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6440
6646
|
scripts["check-types"] = "bun run --filter '*' check-types";
|
|
6441
6647
|
scripts["dev:native"] = "bun run --filter native dev";
|
|
6442
6648
|
scripts["dev:web"] = "bun run --filter web dev";
|
|
6443
|
-
scripts["dev:server"] = serverDevScript;
|
|
6649
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6444
6650
|
if (options.backend === "convex") scripts["dev:setup"] = `bun run --filter ${backendPackageName} dev:setup`;
|
|
6445
6651
|
if (needsDbScripts) {
|
|
6446
|
-
scripts["db:push"] = `bun run --filter ${
|
|
6447
|
-
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${
|
|
6652
|
+
scripts["db:push"] = `bun run --filter ${dbPackageName} db:push`;
|
|
6653
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:studio"] = `bun run --filter ${dbPackageName} db:studio`;
|
|
6448
6654
|
if (options.orm === "prisma") {
|
|
6449
|
-
scripts["db:generate"] = `bun run --filter ${
|
|
6450
|
-
scripts["db:migrate"] = `bun run --filter ${
|
|
6655
|
+
scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
|
|
6656
|
+
scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
|
|
6451
6657
|
} 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 ${
|
|
6658
|
+
scripts["db:generate"] = `bun run --filter ${dbPackageName} db:generate`;
|
|
6659
|
+
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = `bun run --filter ${dbPackageName} db:migrate`;
|
|
6454
6660
|
}
|
|
6455
6661
|
}
|
|
6456
6662
|
if (options.dbSetup === "docker") {
|
|
@@ -6483,6 +6689,22 @@ async function updateServerPackageJson(projectDir, options) {
|
|
|
6483
6689
|
const serverPackageJson = await fs.readJson(serverPackageJsonPath);
|
|
6484
6690
|
if (!serverPackageJson.scripts) serverPackageJson.scripts = {};
|
|
6485
6691
|
const scripts = serverPackageJson.scripts;
|
|
6692
|
+
if (options.dbSetup === "docker") {
|
|
6693
|
+
scripts["db:start"] = "docker compose up -d";
|
|
6694
|
+
scripts["db:watch"] = "docker compose up";
|
|
6695
|
+
scripts["db:stop"] = "docker compose stop";
|
|
6696
|
+
scripts["db:down"] = "docker compose down";
|
|
6697
|
+
}
|
|
6698
|
+
await fs.writeJson(serverPackageJsonPath, serverPackageJson, { spaces: 2 });
|
|
6699
|
+
await updateDbPackageJson(projectDir, options);
|
|
6700
|
+
}
|
|
6701
|
+
async function updateDbPackageJson(projectDir, options) {
|
|
6702
|
+
const dbPackageJsonPath = path.join(projectDir, "packages/db/package.json");
|
|
6703
|
+
if (!await fs.pathExists(dbPackageJsonPath)) return;
|
|
6704
|
+
const dbPackageJson = await fs.readJson(dbPackageJsonPath);
|
|
6705
|
+
dbPackageJson.name = `@${options.projectName}/db`;
|
|
6706
|
+
if (!dbPackageJson.scripts) dbPackageJson.scripts = {};
|
|
6707
|
+
const scripts = dbPackageJson.scripts;
|
|
6486
6708
|
if (options.database !== "none") {
|
|
6487
6709
|
if (options.database === "sqlite" && options.orm === "drizzle" && options.dbSetup !== "d1") scripts["db:local"] = "turso dev --db-file local.db";
|
|
6488
6710
|
if (options.orm === "prisma") {
|
|
@@ -6497,13 +6719,21 @@ async function updateServerPackageJson(projectDir, options) {
|
|
|
6497
6719
|
if (!(options.dbSetup === "d1" && options.serverDeploy === "alchemy")) scripts["db:migrate"] = "drizzle-kit migrate";
|
|
6498
6720
|
}
|
|
6499
6721
|
}
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6722
|
+
await fs.writeJson(dbPackageJsonPath, dbPackageJson, { spaces: 2 });
|
|
6723
|
+
}
|
|
6724
|
+
async function updateAuthPackageJson(projectDir, options) {
|
|
6725
|
+
const authPackageJsonPath = path.join(projectDir, "packages/auth/package.json");
|
|
6726
|
+
if (!await fs.pathExists(authPackageJsonPath)) return;
|
|
6727
|
+
const authPackageJson = await fs.readJson(authPackageJsonPath);
|
|
6728
|
+
authPackageJson.name = `@${options.projectName}/auth`;
|
|
6729
|
+
await fs.writeJson(authPackageJsonPath, authPackageJson, { spaces: 2 });
|
|
6730
|
+
}
|
|
6731
|
+
async function updateApiPackageJson(projectDir, options) {
|
|
6732
|
+
const apiPackageJsonPath = path.join(projectDir, "packages/api/package.json");
|
|
6733
|
+
if (!await fs.pathExists(apiPackageJsonPath)) return;
|
|
6734
|
+
const apiPackageJson = await fs.readJson(apiPackageJsonPath);
|
|
6735
|
+
apiPackageJson.name = `@${options.projectName}/api`;
|
|
6736
|
+
await fs.writeJson(apiPackageJsonPath, apiPackageJson, { spaces: 2 });
|
|
6507
6737
|
}
|
|
6508
6738
|
async function updateConvexPackageJson(projectDir, options) {
|
|
6509
6739
|
const convexPackageJsonPath = path.join(projectDir, "packages/backend/package.json");
|
|
@@ -6519,15 +6749,14 @@ async function updateConvexPackageJson(projectDir, options) {
|
|
|
6519
6749
|
async function createProject(options, cliInput) {
|
|
6520
6750
|
const projectDir = options.projectDir;
|
|
6521
6751
|
const isConvex = options.backend === "convex";
|
|
6752
|
+
const isSelfBackend = options.backend === "self";
|
|
6753
|
+
const needsServerSetup = !isConvex && !isSelfBackend;
|
|
6522
6754
|
try {
|
|
6523
6755
|
await fs.ensureDir(projectDir);
|
|
6524
6756
|
await copyBaseTemplate(projectDir, options);
|
|
6525
6757
|
await setupFrontendTemplates(projectDir, options);
|
|
6526
6758
|
await setupBackendFramework(projectDir, options);
|
|
6527
|
-
if (
|
|
6528
|
-
await setupDbOrmTemplates(projectDir, options);
|
|
6529
|
-
await setupDockerComposeTemplates(projectDir, options);
|
|
6530
|
-
}
|
|
6759
|
+
if (needsServerSetup) await setupDockerComposeTemplates(projectDir, options);
|
|
6531
6760
|
await setupAuthTemplate(projectDir, options);
|
|
6532
6761
|
if (options.payments && options.payments !== "none") await setupPaymentsTemplate(projectDir, options);
|
|
6533
6762
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamplesTemplate(projectDir, options);
|
|
@@ -6535,9 +6764,11 @@ async function createProject(options, cliInput) {
|
|
|
6535
6764
|
await setupDeploymentTemplates(projectDir, options);
|
|
6536
6765
|
await setupApi(options);
|
|
6537
6766
|
if (!isConvex) {
|
|
6538
|
-
|
|
6767
|
+
if (needsServerSetup) {
|
|
6768
|
+
await setupBackendDependencies(options);
|
|
6769
|
+
await setupRuntime(options);
|
|
6770
|
+
}
|
|
6539
6771
|
await setupDatabase(options, cliInput);
|
|
6540
|
-
await setupRuntime(options);
|
|
6541
6772
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamples(options);
|
|
6542
6773
|
}
|
|
6543
6774
|
if (options.addons.length > 0 && options.addons[0] !== "none") await setupAddons(options);
|
|
@@ -6546,6 +6777,7 @@ async function createProject(options, cliInput) {
|
|
|
6546
6777
|
await handleExtras(projectDir, options);
|
|
6547
6778
|
await setupEnvironmentVariables(options);
|
|
6548
6779
|
await updatePackageConfigurations(projectDir, options);
|
|
6780
|
+
await setupCatalogs(projectDir, options);
|
|
6549
6781
|
await setupWebDeploy(options);
|
|
6550
6782
|
await setupServerDeploy(options);
|
|
6551
6783
|
await createReadme(projectDir, options);
|