create-better-t-stack 2.49.1-canary.80158905 → 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-CyG8-I-3.js → src-dv6H37db.js} +257 -157
- package/package.json +2 -1
- package/templates/api/orpc/server/{rest/src → src}/context.ts.hbs +1 -1
- package/templates/api/trpc/server/{rest/src → src}/context.ts.hbs +1 -1
- package/templates/auth/better-auth/server/base/src/index.ts.hbs +1 -1
- package/templates/auth/clerk/convex/web/react/tanstack-start/src/server.ts.hbs +1 -0
- package/templates/backend/server/elysia/src/index.ts.hbs +1 -1
- package/templates/backend/server/express/src/index.ts.hbs +1 -1
- package/templates/backend/server/fastify/src/index.ts.hbs +1 -1
- package/templates/backend/server/hono/src/index.ts.hbs +2 -2
- package/templates/db/drizzle/mysql/src/index.ts.hbs +1 -1
- package/templates/db/drizzle/postgres/src/index.ts.hbs +1 -1
- package/templates/db/drizzle/sqlite/src/index.ts.hbs +1 -1
- package/templates/deploy/wrangler/web/react/tanstack-start/wrangler.jsonc.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 +4 -4
- 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/examples/ai/server/next/src/app/ai/route.ts.hbs +0 -15
- /package/templates/api/orpc/server/{base/_gitignore → _gitignore} +0 -0
- /package/templates/api/orpc/server/{base/package.json.hbs → package.json.hbs} +0 -0
- /package/templates/api/orpc/server/{rest/src → src}/index.ts.hbs +0 -0
- /package/templates/api/orpc/server/{base/src → src}/routers/index.ts.hbs +0 -0
- /package/templates/api/orpc/server/{base/tsconfig.json.hbs → tsconfig.json.hbs} +0 -0
- /package/templates/api/orpc/server/{base/tsdown.config.ts.hbs → tsdown.config.ts.hbs} +0 -0
- /package/templates/api/trpc/server/{base/_gitignore → _gitignore} +0 -0
- /package/templates/api/trpc/server/{base/package.json.hbs → package.json.hbs} +0 -0
- /package/templates/api/trpc/server/{rest/src → src}/index.ts.hbs +0 -0
- /package/templates/api/trpc/server/{base/src → src}/routers/index.ts.hbs +0 -0
- /package/templates/api/trpc/server/{base/tsconfig.json.hbs → tsconfig.json.hbs} +0 -0
- /package/templates/api/trpc/server/{base/tsdown.config.ts.hbs → tsdown.config.ts.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/drizzle/mysql/src/schema/{auth.ts → auth.ts.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/drizzle/postgres/src/schema/{auth.ts → auth.ts.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/drizzle/sqlite/src/schema/{auth.ts → auth.ts.hbs} +0 -0
- /package/templates/auth/better-auth/server/db/mongoose/mongodb/src/models/{auth.model.ts → 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/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 → models}/todo.model.ts.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,7 +66,7 @@ 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",
|
|
@@ -124,6 +125,7 @@ const dependencyVersionMap = {
|
|
|
124
125
|
"@trpc/tanstack-react-query": "^11.5.0",
|
|
125
126
|
"@trpc/server": "^11.5.0",
|
|
126
127
|
"@trpc/client": "^11.5.0",
|
|
128
|
+
next: "^15.1.0",
|
|
127
129
|
convex: "^1.27.0",
|
|
128
130
|
"@convex-dev/react-query": "^0.0.0-alpha.8",
|
|
129
131
|
"convex-svelte": "^0.0.11",
|
|
@@ -139,13 +141,13 @@ const dependencyVersionMap = {
|
|
|
139
141
|
"@tanstack/solid-query": "^5.87.4",
|
|
140
142
|
"@tanstack/solid-query-devtools": "^5.87.4",
|
|
141
143
|
"@tanstack/solid-router-devtools": "^1.131.44",
|
|
142
|
-
wrangler: "^4.
|
|
143
|
-
"@cloudflare/vite-plugin": "^1.
|
|
144
|
+
wrangler: "^4.40.3",
|
|
145
|
+
"@cloudflare/vite-plugin": "^1.13.8",
|
|
144
146
|
"@opennextjs/cloudflare": "^1.6.5",
|
|
145
147
|
"nitro-cloudflare-dev": "^0.2.2",
|
|
146
148
|
"@sveltejs/adapter-cloudflare": "^7.2.1",
|
|
147
149
|
"@cloudflare/workers-types": "^4.20250822.0",
|
|
148
|
-
alchemy: "^0.
|
|
150
|
+
alchemy: "^0.70.0",
|
|
149
151
|
nitropack: "^2.12.4",
|
|
150
152
|
dotenv: "^17.2.2",
|
|
151
153
|
tsdown: "^0.15.5",
|
|
@@ -198,9 +200,9 @@ const BackendSchema = z.enum([
|
|
|
198
200
|
"hono",
|
|
199
201
|
"express",
|
|
200
202
|
"fastify",
|
|
201
|
-
"next",
|
|
202
203
|
"elysia",
|
|
203
204
|
"convex",
|
|
205
|
+
"self",
|
|
204
206
|
"none"
|
|
205
207
|
]).describe("Backend framework");
|
|
206
208
|
const RuntimeSchema = z.enum([
|
|
@@ -346,6 +348,22 @@ function ensureSingleWebAndNative(frontends) {
|
|
|
346
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");
|
|
347
349
|
if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-nativewind, native-unistyles");
|
|
348
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
|
+
}
|
|
349
367
|
function validateWorkersCompatibility(providedFlags, options, config) {
|
|
350
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.`);
|
|
351
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.`);
|
|
@@ -667,36 +685,39 @@ async function getAuthChoice(auth, hasDatabase, backend, frontend) {
|
|
|
667
685
|
|
|
668
686
|
//#endregion
|
|
669
687
|
//#region src/prompts/backend.ts
|
|
688
|
+
const FULLSTACK_FRONTENDS = [
|
|
689
|
+
"next",
|
|
690
|
+
"nuxt",
|
|
691
|
+
"svelte",
|
|
692
|
+
"tanstack-start"
|
|
693
|
+
];
|
|
670
694
|
async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
671
695
|
if (backendFramework !== void 0) return backendFramework;
|
|
672
696
|
const hasIncompatibleFrontend = frontends?.some((f) => f === "solid");
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
hint: "Ergonomic web framework for building backend servers"
|
|
698
|
-
}
|
|
699
|
-
];
|
|
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
|
+
});
|
|
700
721
|
if (!hasIncompatibleFrontend) backendOptions.push({
|
|
701
722
|
value: "convex",
|
|
702
723
|
label: "Convex",
|
|
@@ -710,7 +731,7 @@ async function getBackendFrameworkChoice(backendFramework, frontends) {
|
|
|
710
731
|
const response = await select({
|
|
711
732
|
message: "Select backend",
|
|
712
733
|
options: backendOptions,
|
|
713
|
-
initialValue: DEFAULT_CONFIG.backend
|
|
734
|
+
initialValue: hasFullstackFrontend ? "self" : DEFAULT_CONFIG.backend
|
|
714
735
|
});
|
|
715
736
|
if (isCancel(response)) return exitCancelled("Operation cancelled");
|
|
716
737
|
return response;
|
|
@@ -1089,9 +1110,8 @@ async function getPaymentsChoice(payments, auth, backend, frontends) {
|
|
|
1089
1110
|
//#endregion
|
|
1090
1111
|
//#region src/prompts/runtime.ts
|
|
1091
1112
|
async function getRuntimeChoice(runtime, backend) {
|
|
1092
|
-
if (backend === "convex" || backend === "none") return "none";
|
|
1113
|
+
if (backend === "convex" || backend === "none" || backend === "self") return "none";
|
|
1093
1114
|
if (runtime !== void 0) return runtime;
|
|
1094
|
-
if (backend === "next") return "node";
|
|
1095
1115
|
const runtimeOptions = [{
|
|
1096
1116
|
value: "bun",
|
|
1097
1117
|
label: "Bun",
|
|
@@ -1768,8 +1788,8 @@ function validateBackendConstraints(config, providedFlags, options) {
|
|
|
1768
1788
|
].includes(f));
|
|
1769
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.`);
|
|
1770
1790
|
}
|
|
1771
|
-
if (providedFlags.has("backend") && backend && backend !== "convex" && backend !== "none") {
|
|
1772
|
-
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.");
|
|
1773
1793
|
}
|
|
1774
1794
|
if (backend === "convex" && providedFlags.has("frontend") && options.frontend) {
|
|
1775
1795
|
const incompatibleFrontends = options.frontend.filter((f) => f === "solid");
|
|
@@ -1799,6 +1819,7 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
1799
1819
|
validateFrontendConstraints(config, providedFlags);
|
|
1800
1820
|
validateApiConstraints(config, options);
|
|
1801
1821
|
validateServerDeployRequiresBackend(config.serverDeploy, config.backend);
|
|
1822
|
+
validateSelfBackendCompatibility(providedFlags, options, config);
|
|
1802
1823
|
validateWorkersCompatibility(providedFlags, options, config);
|
|
1803
1824
|
if (config.runtime === "workers" && config.serverDeploy === "none") exitWithError("Cloudflare Workers runtime requires a server deployment. Please choose 'wrangler' or 'alchemy' for --server-deploy.");
|
|
1804
1825
|
if (config.addons && config.addons.length > 0) {
|
|
@@ -1852,6 +1873,7 @@ const CORE_STACK_FLAGS = new Set([
|
|
|
1852
1873
|
"examples",
|
|
1853
1874
|
"auth",
|
|
1854
1875
|
"dbSetup",
|
|
1876
|
+
"payments",
|
|
1855
1877
|
"api",
|
|
1856
1878
|
"webDeploy",
|
|
1857
1879
|
"serverDeploy"
|
|
@@ -2660,8 +2682,12 @@ async function processTemplate(srcPath, destPath, context) {
|
|
|
2660
2682
|
}
|
|
2661
2683
|
handlebars.registerHelper("eq", (a, b) => a === b);
|
|
2662
2684
|
handlebars.registerHelper("ne", (a, b) => a !== b);
|
|
2663
|
-
handlebars.registerHelper("and", (
|
|
2664
|
-
|
|
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
|
+
});
|
|
2665
2691
|
handlebars.registerHelper("includes", (array, value) => Array.isArray(array) && array.includes(value));
|
|
2666
2692
|
|
|
2667
2693
|
//#endregion
|
|
@@ -2763,40 +2789,52 @@ async function setupFrontendTemplates(projectDir, context) {
|
|
|
2763
2789
|
}
|
|
2764
2790
|
}
|
|
2765
2791
|
}
|
|
2766
|
-
async function
|
|
2767
|
-
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) {
|
|
2768
2817
|
const serverAppDir = path.join(projectDir, "apps/server");
|
|
2769
|
-
if (context.backend === "convex") {
|
|
2770
|
-
if (await fs.pathExists(serverAppDir)) await fs.remove(serverAppDir);
|
|
2771
|
-
const convexBackendDestDir = path.join(projectDir, "packages/backend");
|
|
2772
|
-
const convexSrcDir = path.join(PKG_ROOT, "templates/backend/convex/packages/backend");
|
|
2773
|
-
await fs.ensureDir(convexBackendDestDir);
|
|
2774
|
-
if (await fs.pathExists(convexSrcDir)) await processAndCopyFiles("**/*", convexSrcDir, convexBackendDestDir, context);
|
|
2775
|
-
return;
|
|
2776
|
-
}
|
|
2777
2818
|
await fs.ensureDir(serverAppDir);
|
|
2778
2819
|
const serverBaseDir = path.join(PKG_ROOT, "templates/backend/server/base");
|
|
2779
2820
|
if (await fs.pathExists(serverBaseDir)) await processAndCopyFiles("**/*", serverBaseDir, serverAppDir, context);
|
|
2780
2821
|
const frameworkSrcDir = path.join(PKG_ROOT, `templates/backend/server/${context.backend}`);
|
|
2781
2822
|
if (await fs.pathExists(frameworkSrcDir)) await processAndCopyFiles("**/*", frameworkSrcDir, serverAppDir, context, true);
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
2794
|
-
await fs.ensureDir(dbPackageDir);
|
|
2795
|
-
const dbBaseDir = path.join(PKG_ROOT, "templates/db/base");
|
|
2796
|
-
if (await fs.pathExists(dbBaseDir)) await processAndCopyFiles("**/*", dbBaseDir, dbPackageDir, context);
|
|
2797
|
-
const dbOrmSrcDir = path.join(PKG_ROOT, `templates/db/${context.orm}/${context.database}`);
|
|
2798
|
-
if (await fs.pathExists(dbOrmSrcDir)) await processAndCopyFiles("**/*", dbOrmSrcDir, dbPackageDir, context);
|
|
2823
|
+
}
|
|
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;
|
|
2799
2834
|
}
|
|
2835
|
+
await setupServerApp(projectDir, context);
|
|
2836
|
+
await setupApiPackage(projectDir, context);
|
|
2837
|
+
await setupDbPackage(projectDir, context);
|
|
2800
2838
|
}
|
|
2801
2839
|
async function setupAuthTemplate(projectDir, context) {
|
|
2802
2840
|
if (!context.auth || context.auth === "none") return;
|
|
@@ -2876,15 +2914,11 @@ async function setupAuthTemplate(projectDir, context) {
|
|
|
2876
2914
|
}
|
|
2877
2915
|
return;
|
|
2878
2916
|
}
|
|
2879
|
-
if (serverAppDirExists && context.backend !== "convex") {
|
|
2917
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex") {
|
|
2880
2918
|
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
2881
2919
|
await fs.ensureDir(authPackageDir);
|
|
2882
2920
|
const authServerBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/base`);
|
|
2883
2921
|
if (await fs.pathExists(authServerBaseSrc)) await processAndCopyFiles("**/*", authServerBaseSrc, authPackageDir, context);
|
|
2884
|
-
if (context.backend === "next") {
|
|
2885
|
-
const authServerNextSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/server/next`);
|
|
2886
|
-
if (await fs.pathExists(authServerNextSrc)) await processAndCopyFiles("**/*", authServerNextSrc, authPackageDir, context);
|
|
2887
|
-
}
|
|
2888
2922
|
if (context.orm !== "none" && context.database !== "none") {
|
|
2889
2923
|
const dbPackageDir = path.join(projectDir, "packages/db");
|
|
2890
2924
|
await fs.ensureDir(dbPackageDir);
|
|
@@ -2940,7 +2974,7 @@ async function setupPaymentsTemplate(projectDir, context) {
|
|
|
2940
2974
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
2941
2975
|
const serverAppDirExists = await fs.pathExists(serverAppDir);
|
|
2942
2976
|
const webAppDirExists = await fs.pathExists(webAppDir);
|
|
2943
|
-
if (serverAppDirExists && context.backend !== "convex") {
|
|
2977
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex") {
|
|
2944
2978
|
const authPackageDir = path.join(projectDir, "packages/auth");
|
|
2945
2979
|
await fs.ensureDir(authPackageDir);
|
|
2946
2980
|
const paymentsServerSrc = path.join(PKG_ROOT, `templates/payments/${context.payments}/server/base`);
|
|
@@ -3020,7 +3054,7 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3020
3054
|
for (const example of context.examples) {
|
|
3021
3055
|
if (example === "none") continue;
|
|
3022
3056
|
const exampleBaseDir = path.join(PKG_ROOT, `templates/examples/${example}`);
|
|
3023
|
-
if (serverAppDirExists && context.backend !== "convex" && context.backend !== "none") {
|
|
3057
|
+
if ((serverAppDirExists || context.backend === "self") && context.backend !== "convex" && context.backend !== "none") {
|
|
3024
3058
|
const exampleServerSrc = path.join(exampleBaseDir, "server");
|
|
3025
3059
|
if (context.api !== "none") {
|
|
3026
3060
|
const apiPackageDir = path.join(projectDir, "packages/api");
|
|
@@ -3034,10 +3068,6 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3034
3068
|
const exampleDbSchemaSrc = path.join(exampleServerSrc, context.orm, context.database);
|
|
3035
3069
|
if (await fs.pathExists(exampleDbSchemaSrc)) await processAndCopyFiles("**/*", exampleDbSchemaSrc, dbPackageDir, context, false);
|
|
3036
3070
|
}
|
|
3037
|
-
if (example === "ai" && context.backend === "next") {
|
|
3038
|
-
const aiNextServerSrc = path.join(exampleServerSrc, "next");
|
|
3039
|
-
if (await fs.pathExists(aiNextServerSrc)) await processAndCopyFiles("**/*", aiNextServerSrc, serverAppDir, context, false);
|
|
3040
|
-
}
|
|
3041
3071
|
}
|
|
3042
3072
|
if (webAppDirExists) {
|
|
3043
3073
|
if (hasReactWeb) {
|
|
@@ -3526,8 +3556,8 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3526
3556
|
await addPackageDependency({
|
|
3527
3557
|
devDependencies: [
|
|
3528
3558
|
"alchemy",
|
|
3529
|
-
"
|
|
3530
|
-
"
|
|
3559
|
+
"dotenv",
|
|
3560
|
+
"@cloudflare/vite-plugin"
|
|
3531
3561
|
],
|
|
3532
3562
|
projectDir: webAppDir
|
|
3533
3563
|
});
|
|
@@ -3555,17 +3585,6 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3555
3585
|
defaultImport: "alchemy"
|
|
3556
3586
|
});
|
|
3557
3587
|
else alchemyImport.setModuleSpecifier("alchemy/cloudflare/tanstack-start");
|
|
3558
|
-
const reactImport = sourceFile.getImportDeclaration("@vitejs/plugin-react");
|
|
3559
|
-
let reactPluginIdentifier = "viteReact";
|
|
3560
|
-
if (!reactImport) sourceFile.addImportDeclaration({
|
|
3561
|
-
moduleSpecifier: "@vitejs/plugin-react",
|
|
3562
|
-
defaultImport: "viteReact"
|
|
3563
|
-
});
|
|
3564
|
-
else {
|
|
3565
|
-
const defaultImport = reactImport.getDefaultImport();
|
|
3566
|
-
if (defaultImport) reactPluginIdentifier = defaultImport.getText();
|
|
3567
|
-
else reactImport.setDefaultImport("viteReact");
|
|
3568
|
-
}
|
|
3569
3588
|
const exportAssignment = sourceFile.getExportAssignment((d) => !d.isExportEquals());
|
|
3570
3589
|
if (!exportAssignment) return;
|
|
3571
3590
|
const defineConfigCall = exportAssignment.getExpression();
|
|
@@ -3573,47 +3592,11 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3573
3592
|
let configObject = defineConfigCall.getArguments()[0];
|
|
3574
3593
|
if (!configObject) configObject = defineConfigCall.addArgument("{}");
|
|
3575
3594
|
if (Node.isObjectLiteralExpression(configObject)) {
|
|
3576
|
-
if (!configObject.getProperty("build")) configObject.addPropertyAssignment({
|
|
3577
|
-
name: "build",
|
|
3578
|
-
initializer: `{
|
|
3579
|
-
target: "esnext",
|
|
3580
|
-
rollupOptions: {
|
|
3581
|
-
external: ["node:async_hooks", "cloudflare:workers"],
|
|
3582
|
-
},
|
|
3583
|
-
}`
|
|
3584
|
-
});
|
|
3585
3595
|
const pluginsProperty = configObject.getProperty("plugins");
|
|
3586
3596
|
if (pluginsProperty && Node.isPropertyAssignment(pluginsProperty)) {
|
|
3587
3597
|
const initializer = pluginsProperty.getInitializer();
|
|
3588
3598
|
if (Node.isArrayLiteralExpression(initializer)) {
|
|
3589
|
-
if (!initializer.getElements().some((el) => el.getText().includes("alchemy"))) initializer.addElement("alchemy()");
|
|
3590
|
-
const tanstackElements = initializer.getElements().filter((el) => el.getText().includes("tanstackStart"));
|
|
3591
|
-
let needsReactPlugin = false;
|
|
3592
|
-
tanstackElements.forEach((element) => {
|
|
3593
|
-
if (Node.isCallExpression(element)) {
|
|
3594
|
-
const args = element.getArguments();
|
|
3595
|
-
if (args.length === 0) {
|
|
3596
|
-
element.addArgument(`{
|
|
3597
|
-
target: "cloudflare-module",
|
|
3598
|
-
customViteReactPlugin: true,
|
|
3599
|
-
}`);
|
|
3600
|
-
needsReactPlugin = true;
|
|
3601
|
-
} else if (args.length === 1 && Node.isObjectLiteralExpression(args[0])) {
|
|
3602
|
-
const configObj = args[0];
|
|
3603
|
-
if (!configObj.getProperty("target")) configObj.addPropertyAssignment({
|
|
3604
|
-
name: "target",
|
|
3605
|
-
initializer: "\"cloudflare-module\""
|
|
3606
|
-
});
|
|
3607
|
-
if (!!!configObj.getProperty("customViteReactPlugin")) configObj.addPropertyAssignment({
|
|
3608
|
-
name: "customViteReactPlugin",
|
|
3609
|
-
initializer: "true"
|
|
3610
|
-
});
|
|
3611
|
-
needsReactPlugin = true;
|
|
3612
|
-
}
|
|
3613
|
-
}
|
|
3614
|
-
});
|
|
3615
|
-
const hasReactPlugin = initializer.getElements().some((el) => Node.isCallExpression(el) && el.getExpression().getText() === reactPluginIdentifier);
|
|
3616
|
-
if (needsReactPlugin && !hasReactPlugin) initializer.addElement(`${reactPluginIdentifier}()`);
|
|
3599
|
+
if (!initializer.getElements().some((el) => el.getText().includes("alchemy("))) initializer.addElement("alchemy()");
|
|
3617
3600
|
}
|
|
3618
3601
|
} else configObject.addPropertyAssignment({
|
|
3619
3602
|
name: "plugins",
|
|
@@ -3624,16 +3607,6 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3624
3607
|
} catch (error) {
|
|
3625
3608
|
console.warn("Failed to update vite.config.ts:", error);
|
|
3626
3609
|
}
|
|
3627
|
-
const nitroConfigPath = path.join(webAppDir, "nitro.config.ts");
|
|
3628
|
-
await fs.writeFile(nitroConfigPath, `import { defineNitroConfig } from "nitropack/config";
|
|
3629
|
-
|
|
3630
|
-
export default defineNitroConfig({
|
|
3631
|
-
preset: "cloudflare-module",
|
|
3632
|
-
cloudflare: {
|
|
3633
|
-
nodeCompat: true,
|
|
3634
|
-
},
|
|
3635
|
-
});
|
|
3636
|
-
`, "utf-8");
|
|
3637
3610
|
}
|
|
3638
3611
|
|
|
3639
3612
|
//#endregion
|
|
@@ -3800,7 +3773,7 @@ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
|
3800
3773
|
const webAppDir = path.join(projectDir, "apps/web");
|
|
3801
3774
|
if (!await fs.pathExists(webAppDir)) return;
|
|
3802
3775
|
await addPackageDependency({
|
|
3803
|
-
devDependencies: ["wrangler"],
|
|
3776
|
+
devDependencies: ["wrangler", "@cloudflare/vite-plugin"],
|
|
3804
3777
|
projectDir: webAppDir
|
|
3805
3778
|
});
|
|
3806
3779
|
const pkgPath = path.join(webAppDir, "package.json");
|
|
@@ -3817,6 +3790,12 @@ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
|
3817
3790
|
if (!await fs.pathExists(viteConfigPath)) return;
|
|
3818
3791
|
const sourceFile = tsProject.addSourceFileAtPathIfExists(viteConfigPath);
|
|
3819
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" });
|
|
3820
3799
|
const reactImport = sourceFile.getImportDeclaration("@vitejs/plugin-react");
|
|
3821
3800
|
let reactPluginIdentifier = "viteReact";
|
|
3822
3801
|
if (!reactImport) sourceFile.addImportDeclaration({
|
|
@@ -3836,10 +3815,7 @@ async function setupTanstackStartWorkersDeploy(projectDir, packageManager) {
|
|
|
3836
3815
|
const configObj = defineCall.getArguments()[0];
|
|
3837
3816
|
if (!configObj) return;
|
|
3838
3817
|
const pluginsArray = ensureArrayProperty(configObj, "plugins");
|
|
3839
|
-
|
|
3840
|
-
const tanstackPluginText = "tanstackStart({ target: \"cloudflare-module\", customViteReactPlugin: true })";
|
|
3841
|
-
if (tanstackPluginIndex === -1) pluginsArray.addElement(tanstackPluginText);
|
|
3842
|
-
else pluginsArray.getElements()[tanstackPluginIndex].replaceWithText(tanstackPluginText);
|
|
3818
|
+
if (!pluginsArray.getElements().some((el) => el.getText().includes("cloudflare("))) pluginsArray.insertElement(0, "cloudflare({ viteEnvironment: { name: 'ssr' } })");
|
|
3843
3819
|
if (!pluginsArray.getElements().some((el) => Node.isCallExpression(el) && el.getExpression().getText() === reactPluginIdentifier)) {
|
|
3844
3820
|
const nextIndex = pluginsArray.getElements().findIndex((el) => el.getText().includes("tanstackStart(")) + 1;
|
|
3845
3821
|
if (nextIndex > 0) pluginsArray.insertElement(nextIndex, `${reactPluginIdentifier}()`);
|
|
@@ -3977,6 +3953,110 @@ async function addDeploymentToProject(input) {
|
|
|
3977
3953
|
}
|
|
3978
3954
|
}
|
|
3979
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
|
+
|
|
3980
4060
|
//#endregion
|
|
3981
4061
|
//#region src/helpers/addons/examples-setup.ts
|
|
3982
4062
|
async function setupExamples(config) {
|
|
@@ -4149,6 +4229,9 @@ async function setupApi(config) {
|
|
|
4149
4229
|
else if (backend === "elysia") frameworkDeps.push("elysia");
|
|
4150
4230
|
else if (backend === "express") frameworkDeps.push("express", "@types/express");
|
|
4151
4231
|
else if (backend === "fastify") frameworkDeps.push("fastify");
|
|
4232
|
+
else if (backend === "self") {
|
|
4233
|
+
if (frontend.includes("next")) frameworkDeps.push("next");
|
|
4234
|
+
}
|
|
4152
4235
|
if (frameworkDeps.length > 0) await addPackageDependency({
|
|
4153
4236
|
dependencies: frameworkDeps,
|
|
4154
4237
|
projectDir: apiPackageDir
|
|
@@ -5756,7 +5839,7 @@ async function setupDatabase(config, cliInput) {
|
|
|
5756
5839
|
//#region src/helpers/core/runtime-setup.ts
|
|
5757
5840
|
async function setupRuntime(config) {
|
|
5758
5841
|
const { runtime, backend, projectDir } = config;
|
|
5759
|
-
if (backend === "convex" || backend === "
|
|
5842
|
+
if (backend === "convex" || backend === "self" || runtime === "none") return;
|
|
5760
5843
|
const serverDir = path.join(projectDir, "apps/server");
|
|
5761
5844
|
if (!await fs.pathExists(serverDir)) return;
|
|
5762
5845
|
if (runtime === "bun") await setupBunRuntime(serverDir, backend);
|
|
@@ -6276,7 +6359,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6276
6359
|
else if (!hasNative && !addons?.includes("starlight")) output += `${pc.yellow("NOTE:")} You are creating a backend-only app\n (no frontend selected)\n`;
|
|
6277
6360
|
if (!isConvex) {
|
|
6278
6361
|
output += `${pc.cyan("•")} Backend API: http://localhost:3000\n`;
|
|
6279
|
-
if (api === "orpc") if (backend === "
|
|
6362
|
+
if (api === "orpc") if (backend === "self") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/rpc/api\n`;
|
|
6280
6363
|
else output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/api\n`;
|
|
6281
6364
|
}
|
|
6282
6365
|
if (addons?.includes("starlight")) output += `${pc.cyan("•")} Docs: http://localhost:4321\n`;
|
|
@@ -6431,10 +6514,17 @@ async function setupWorkspaceDependencies(projectDir, options) {
|
|
|
6431
6514
|
},
|
|
6432
6515
|
projectDir: serverPackageDir
|
|
6433
6516
|
});
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
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,
|
|
6438
6528
|
projectDir: webPackageDir
|
|
6439
6529
|
});
|
|
6440
6530
|
}
|
|
@@ -6444,12 +6534,17 @@ async function setupWorkspaceDependencies(projectDir, options) {
|
|
|
6444
6534
|
//#region src/helpers/core/project-config.ts
|
|
6445
6535
|
async function updatePackageConfigurations(projectDir, options) {
|
|
6446
6536
|
await updateRootPackageJson(projectDir, options);
|
|
6447
|
-
if (options.backend
|
|
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") {
|
|
6448
6543
|
await updateServerPackageJson(projectDir, options);
|
|
6449
6544
|
await updateAuthPackageJson(projectDir, options);
|
|
6450
6545
|
await updateApiPackageJson(projectDir, options);
|
|
6451
6546
|
await setupWorkspaceDependencies(projectDir, options);
|
|
6452
|
-
}
|
|
6547
|
+
}
|
|
6453
6548
|
}
|
|
6454
6549
|
async function updateRootPackageJson(projectDir, options) {
|
|
6455
6550
|
const rootPackageJsonPath = path.join(projectDir, "package.json");
|
|
@@ -6476,7 +6571,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6476
6571
|
scripts["check-types"] = "turbo check-types";
|
|
6477
6572
|
scripts["dev:native"] = "turbo -F native dev";
|
|
6478
6573
|
scripts["dev:web"] = "turbo -F web dev";
|
|
6479
|
-
scripts["dev:server"] = serverDevScript;
|
|
6574
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6480
6575
|
if (options.backend === "convex") scripts["dev:setup"] = `turbo -F ${backendPackageName} dev:setup`;
|
|
6481
6576
|
if (needsDbScripts) {
|
|
6482
6577
|
scripts["db:push"] = `turbo -F ${dbPackageName} db:push`;
|
|
@@ -6501,7 +6596,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6501
6596
|
scripts["check-types"] = "pnpm -r check-types";
|
|
6502
6597
|
scripts["dev:native"] = "pnpm --filter native dev";
|
|
6503
6598
|
scripts["dev:web"] = "pnpm --filter web dev";
|
|
6504
|
-
scripts["dev:server"] = serverDevScript;
|
|
6599
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6505
6600
|
if (options.backend === "convex") scripts["dev:setup"] = `pnpm --filter ${backendPackageName} dev:setup`;
|
|
6506
6601
|
if (needsDbScripts) {
|
|
6507
6602
|
scripts["db:push"] = `pnpm --filter ${dbPackageName} db:push`;
|
|
@@ -6526,7 +6621,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6526
6621
|
scripts["check-types"] = "npm run check-types --workspaces";
|
|
6527
6622
|
scripts["dev:native"] = "npm run dev --workspace native";
|
|
6528
6623
|
scripts["dev:web"] = "npm run dev --workspace web";
|
|
6529
|
-
scripts["dev:server"] = serverDevScript;
|
|
6624
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6530
6625
|
if (options.backend === "convex") scripts["dev:setup"] = `npm run dev:setup --workspace ${backendPackageName}`;
|
|
6531
6626
|
if (needsDbScripts) {
|
|
6532
6627
|
scripts["db:push"] = `npm run db:push --workspace ${dbPackageName}`;
|
|
@@ -6551,7 +6646,7 @@ async function updateRootPackageJson(projectDir, options) {
|
|
|
6551
6646
|
scripts["check-types"] = "bun run --filter '*' check-types";
|
|
6552
6647
|
scripts["dev:native"] = "bun run --filter native dev";
|
|
6553
6648
|
scripts["dev:web"] = "bun run --filter web dev";
|
|
6554
|
-
scripts["dev:server"] = serverDevScript;
|
|
6649
|
+
if (options.backend !== "self" && options.backend !== "none") scripts["dev:server"] = serverDevScript;
|
|
6555
6650
|
if (options.backend === "convex") scripts["dev:setup"] = `bun run --filter ${backendPackageName} dev:setup`;
|
|
6556
6651
|
if (needsDbScripts) {
|
|
6557
6652
|
scripts["db:push"] = `bun run --filter ${dbPackageName} db:push`;
|
|
@@ -6654,12 +6749,14 @@ async function updateConvexPackageJson(projectDir, options) {
|
|
|
6654
6749
|
async function createProject(options, cliInput) {
|
|
6655
6750
|
const projectDir = options.projectDir;
|
|
6656
6751
|
const isConvex = options.backend === "convex";
|
|
6752
|
+
const isSelfBackend = options.backend === "self";
|
|
6753
|
+
const needsServerSetup = !isConvex && !isSelfBackend;
|
|
6657
6754
|
try {
|
|
6658
6755
|
await fs.ensureDir(projectDir);
|
|
6659
6756
|
await copyBaseTemplate(projectDir, options);
|
|
6660
6757
|
await setupFrontendTemplates(projectDir, options);
|
|
6661
6758
|
await setupBackendFramework(projectDir, options);
|
|
6662
|
-
if (
|
|
6759
|
+
if (needsServerSetup) await setupDockerComposeTemplates(projectDir, options);
|
|
6663
6760
|
await setupAuthTemplate(projectDir, options);
|
|
6664
6761
|
if (options.payments && options.payments !== "none") await setupPaymentsTemplate(projectDir, options);
|
|
6665
6762
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamplesTemplate(projectDir, options);
|
|
@@ -6667,9 +6764,11 @@ async function createProject(options, cliInput) {
|
|
|
6667
6764
|
await setupDeploymentTemplates(projectDir, options);
|
|
6668
6765
|
await setupApi(options);
|
|
6669
6766
|
if (!isConvex) {
|
|
6670
|
-
|
|
6767
|
+
if (needsServerSetup) {
|
|
6768
|
+
await setupBackendDependencies(options);
|
|
6769
|
+
await setupRuntime(options);
|
|
6770
|
+
}
|
|
6671
6771
|
await setupDatabase(options, cliInput);
|
|
6672
|
-
await setupRuntime(options);
|
|
6673
6772
|
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamples(options);
|
|
6674
6773
|
}
|
|
6675
6774
|
if (options.addons.length > 0 && options.addons[0] !== "none") await setupAddons(options);
|
|
@@ -6678,6 +6777,7 @@ async function createProject(options, cliInput) {
|
|
|
6678
6777
|
await handleExtras(projectDir, options);
|
|
6679
6778
|
await setupEnvironmentVariables(options);
|
|
6680
6779
|
await updatePackageConfigurations(projectDir, options);
|
|
6780
|
+
await setupCatalogs(projectDir, options);
|
|
6681
6781
|
await setupWebDeploy(options);
|
|
6682
6782
|
await setupServerDeploy(options);
|
|
6683
6783
|
await createReadme(projectDir, options);
|