@better-t-stack/template-generator 3.35.3 → 3.36.1
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/index.d.mts +7 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +540 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -189,6 +189,33 @@ Handlebars.registerHelper("and", (...args) => args.slice(0, -1).every(Boolean));
|
|
|
189
189
|
Handlebars.registerHelper("or", (...args) => args.slice(0, -1).some(Boolean));
|
|
190
190
|
Handlebars.registerHelper("not", (a) => !a);
|
|
191
191
|
Handlebars.registerHelper("includes", (arr, val) => Array.isArray(arr) && arr.includes(val));
|
|
192
|
+
const getServerUrlSource = `function getServerUrl(url: string) {
|
|
193
|
+
const normalized = url.endsWith("/") ? url.slice(0, -1) : url;
|
|
194
|
+
|
|
195
|
+
if (!normalized.startsWith("/")) {
|
|
196
|
+
return normalized;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (typeof window !== "undefined") {
|
|
200
|
+
return \`\${window.location.origin}\${normalized}\`;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const processEnv = (globalThis as {
|
|
204
|
+
process?: { env?: Record<string, string | undefined> };
|
|
205
|
+
}).process?.env;
|
|
206
|
+
const vercelUrl =
|
|
207
|
+
processEnv?.VERCEL_ENV === "production"
|
|
208
|
+
? (processEnv?.VERCEL_PROJECT_PRODUCTION_URL ?? processEnv?.VERCEL_URL)
|
|
209
|
+
: (processEnv?.VERCEL_URL ?? processEnv?.VERCEL_PROJECT_PRODUCTION_URL);
|
|
210
|
+
if (vercelUrl) {
|
|
211
|
+
const origin = vercelUrl.startsWith("http") ? vercelUrl : \`https://\${vercelUrl}\`;
|
|
212
|
+
return \`\${origin}\${normalized}\`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return \`http://localhost:3000\${normalized}\`;
|
|
216
|
+
}`;
|
|
217
|
+
Handlebars.registerPartial("getServerUrl", getServerUrlSource);
|
|
218
|
+
Handlebars.registerPartial("getServerUrlSpaces", getServerUrlSource.replaceAll(" ", " "));
|
|
192
219
|
function processTemplateString(content, context) {
|
|
193
220
|
return Handlebars.compile(content)(context);
|
|
194
221
|
}
|
|
@@ -201,6 +228,7 @@ function transformFilename(filename) {
|
|
|
201
228
|
if (basename === "_gitignore") result = result.replace(/_gitignore$/, ".gitignore");
|
|
202
229
|
else if (basename === "_npmrc") result = result.replace(/_npmrc$/, ".npmrc");
|
|
203
230
|
else if (basename === "_dockerignore") result = result.replace(/_dockerignore$/, ".dockerignore");
|
|
231
|
+
else if (basename === "_vercelignore") result = result.replace(/_vercelignore$/, ".vercelignore");
|
|
204
232
|
return result;
|
|
205
233
|
}
|
|
206
234
|
function processFileContent(filePath, content, context) {
|
|
@@ -492,10 +520,13 @@ const dependencyVersionMap = {
|
|
|
492
520
|
"nitro-cloudflare-dev": "^0.2.2",
|
|
493
521
|
"@sveltejs/adapter-cloudflare": "^7.2.9",
|
|
494
522
|
"@sveltejs/adapter-node": "^5.5.7",
|
|
523
|
+
"@sveltejs/adapter-vercel": "^6.3.4",
|
|
495
524
|
"@cloudflare/workers-types": "^4.20260702.1",
|
|
496
525
|
"@astrojs/cloudflare": "^14.1.0",
|
|
497
526
|
"@astrojs/node": "^11.0.1",
|
|
527
|
+
"@astrojs/vercel": "^11.0.1",
|
|
498
528
|
alchemy: "^0.93.12",
|
|
529
|
+
vercel: "^54.18.6",
|
|
499
530
|
dotenv: "^17.4.2",
|
|
500
531
|
tsdown: "^0.22.3",
|
|
501
532
|
zod: "^4.4.3",
|
|
@@ -522,8 +553,9 @@ function addPackageDependency(options) {
|
|
|
522
553
|
const version = dependencyVersionMap[dep];
|
|
523
554
|
if (!version) throw new Error(`Missing version for dependency: ${dep}. Add it to dependencyVersionMap in add-deps.ts`);
|
|
524
555
|
pkgJson.dependencies[dep] = version;
|
|
556
|
+
delete pkgJson.devDependencies[dep];
|
|
525
557
|
}
|
|
526
|
-
for (const dep of devDependencies) if (!pkgJson.devDependencies[dep]) {
|
|
558
|
+
for (const dep of devDependencies) if (!pkgJson.devDependencies[dep] && !pkgJson.dependencies[dep]) {
|
|
527
559
|
const version = dependencyVersionMap[dep];
|
|
528
560
|
if (!version) throw new Error(`Missing version for devDependency: ${dep}. Add it to dependencyVersionMap in add-deps.ts`);
|
|
529
561
|
pkgJson.devDependencies[dep] = version;
|
|
@@ -659,10 +691,25 @@ function updateRootPackageJson(vfs, config) {
|
|
|
659
691
|
scripts["db:down"] = pmConfig.filter(dbPackageName, "db:down");
|
|
660
692
|
}
|
|
661
693
|
const infraPackageName = `@${projectName}/infra`;
|
|
662
|
-
|
|
663
|
-
|
|
694
|
+
const hasCloudflareDeploy = config.webDeploy === "cloudflare" || config.serverDeploy === "cloudflare";
|
|
695
|
+
const hasVercelDeploy = config.webDeploy === "vercel" || config.serverDeploy === "vercel";
|
|
696
|
+
const isMixedCloud = hasCloudflareDeploy && hasVercelDeploy;
|
|
697
|
+
if (hasCloudflareDeploy) {
|
|
698
|
+
const cfDeployScript = isMixedCloud ? config.webDeploy === "cloudflare" ? "deploy:web" : "deploy:server" : "deploy";
|
|
699
|
+
scripts[cfDeployScript] = pmConfig.filter(infraPackageName, "deploy");
|
|
664
700
|
scripts.destroy = pmConfig.filter(infraPackageName, "destroy");
|
|
665
701
|
}
|
|
702
|
+
if (hasVercelDeploy) {
|
|
703
|
+
const vercelTarget = config.webDeploy === "vercel" ? "web" : "server";
|
|
704
|
+
const vercelDeploy = isMixedCloud ? `deploy:${vercelTarget}` : "deploy";
|
|
705
|
+
scripts["deploy:setup"] = "vercel link";
|
|
706
|
+
scripts["dev:vercel"] = "vercel dev -L";
|
|
707
|
+
scripts["env:preview"] = "tsx scripts/sync-vercel-env.ts preview";
|
|
708
|
+
scripts["env:production"] = "tsx scripts/sync-vercel-env.ts production";
|
|
709
|
+
scripts[vercelDeploy] = "vercel deploy";
|
|
710
|
+
scripts[`${vercelDeploy}:prod`] = "vercel deploy --prod";
|
|
711
|
+
scripts["deploy:check"] = "vercel deploy --dry";
|
|
712
|
+
}
|
|
666
713
|
if (config.webDeploy === "docker" || config.serverDeploy === "docker") {
|
|
667
714
|
scripts["docker:build"] = "docker compose build";
|
|
668
715
|
scripts["docker:up"] = "docker compose up -d --build";
|
|
@@ -941,6 +988,86 @@ function updateVitePlusPackageScripts(vfs, config) {
|
|
|
941
988
|
vfs.writeJson(webPkgPath, webPkg);
|
|
942
989
|
}
|
|
943
990
|
//#endregion
|
|
991
|
+
//#region src/post-process/vercel-config.ts
|
|
992
|
+
function getWebFramework(frontend, isDesktop) {
|
|
993
|
+
if (frontend.includes("next")) return "nextjs";
|
|
994
|
+
if (frontend.includes("nuxt")) return "nuxtjs";
|
|
995
|
+
if (frontend.includes("svelte")) return "sveltekit";
|
|
996
|
+
if (frontend.includes("astro")) return "astro";
|
|
997
|
+
if (frontend.includes("tanstack-start")) return "tanstack-start";
|
|
998
|
+
if (frontend.includes("react-router") && !isDesktop) return "react-router";
|
|
999
|
+
return "vite";
|
|
1000
|
+
}
|
|
1001
|
+
function getPublicServerUrlVar(frontend) {
|
|
1002
|
+
if (frontend.includes("next")) return "NEXT_PUBLIC_SERVER_URL";
|
|
1003
|
+
if (frontend.includes("nuxt")) return "NUXT_PUBLIC_SERVER_URL";
|
|
1004
|
+
if (frontend.includes("svelte") || frontend.includes("astro")) return "PUBLIC_SERVER_URL";
|
|
1005
|
+
return "VITE_SERVER_URL";
|
|
1006
|
+
}
|
|
1007
|
+
function processVercelConfig(vfs, config) {
|
|
1008
|
+
const { webDeploy, serverDeploy, backend, runtime, frontend, addons, packageManager } = config;
|
|
1009
|
+
if (webDeploy !== "vercel" && serverDeploy !== "vercel") return;
|
|
1010
|
+
const hasWeb = webDeploy === "vercel";
|
|
1011
|
+
const hasServer = serverDeploy === "vercel" && backend !== "self";
|
|
1012
|
+
const isDesktop = addons.includes("tauri") || addons.includes("electrobun");
|
|
1013
|
+
const isStaticSpa = frontend.includes("tanstack-router") || frontend.includes("solid") || frontend.includes("react-router") && isDesktop;
|
|
1014
|
+
const installCommand = `cd ../.. && ${packageManager} install`;
|
|
1015
|
+
const services = {};
|
|
1016
|
+
if (hasWeb) {
|
|
1017
|
+
const web = {
|
|
1018
|
+
root: "apps/web",
|
|
1019
|
+
framework: getWebFramework(frontend, isDesktop),
|
|
1020
|
+
installCommand
|
|
1021
|
+
};
|
|
1022
|
+
if (hasServer) web.buildCommand = `${getPublicServerUrlVar(frontend)}=/api ${packageManager} run build`;
|
|
1023
|
+
if (frontend.includes("react-router") && isDesktop) web.outputDirectory = "build/client";
|
|
1024
|
+
if (isStaticSpa) web.rewrites = [{
|
|
1025
|
+
source: "/(.*)",
|
|
1026
|
+
destination: "/index.html"
|
|
1027
|
+
}];
|
|
1028
|
+
services.web = web;
|
|
1029
|
+
}
|
|
1030
|
+
if (hasServer) {
|
|
1031
|
+
const server = {
|
|
1032
|
+
root: "apps/server",
|
|
1033
|
+
framework: backend,
|
|
1034
|
+
entrypoint: "src/index.ts",
|
|
1035
|
+
installCommand
|
|
1036
|
+
};
|
|
1037
|
+
if (hasWeb) server.routes = [{
|
|
1038
|
+
src: "/api/((?!auth(?:/|$)).*)",
|
|
1039
|
+
transforms: [{
|
|
1040
|
+
type: "request.path",
|
|
1041
|
+
op: "set",
|
|
1042
|
+
args: "/$1"
|
|
1043
|
+
}]
|
|
1044
|
+
}];
|
|
1045
|
+
services.server = server;
|
|
1046
|
+
}
|
|
1047
|
+
const rewrites = [];
|
|
1048
|
+
if (hasWeb && hasServer) rewrites.push({
|
|
1049
|
+
source: "/api/(.*)",
|
|
1050
|
+
destination: { service: "server" }
|
|
1051
|
+
}, {
|
|
1052
|
+
source: "/(.*)",
|
|
1053
|
+
destination: { service: "web" }
|
|
1054
|
+
});
|
|
1055
|
+
else if (hasWeb) rewrites.push({
|
|
1056
|
+
source: "/(.*)",
|
|
1057
|
+
destination: { service: "web" }
|
|
1058
|
+
});
|
|
1059
|
+
else if (hasServer) rewrites.push({
|
|
1060
|
+
source: "/(.*)",
|
|
1061
|
+
destination: { service: "server" }
|
|
1062
|
+
});
|
|
1063
|
+
vfs.writeJson("vercel.json", {
|
|
1064
|
+
$schema: "https://openapi.vercel.sh/vercel.json",
|
|
1065
|
+
...hasServer && runtime === "bun" ? { bunVersion: "1.x" } : {},
|
|
1066
|
+
services,
|
|
1067
|
+
rewrites
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
//#endregion
|
|
944
1071
|
//#region src/processors/addons-deps.ts
|
|
945
1072
|
function processAddonsDeps(vfs, config) {
|
|
946
1073
|
if (!config.addons || config.addons.length === 0) return;
|
|
@@ -2062,12 +2189,47 @@ function processDrizzleDeps(vfs, config, dbPkgPath, webPkgPath, webExists) {
|
|
|
2062
2189
|
//#endregion
|
|
2063
2190
|
//#region src/processors/deploy-deps.ts
|
|
2064
2191
|
function processDeployDeps(vfs, config) {
|
|
2065
|
-
const { webDeploy, serverDeploy, frontend, backend } = config;
|
|
2192
|
+
const { webDeploy, serverDeploy, frontend, backend, addons } = config;
|
|
2066
2193
|
const isCloudflareWeb = webDeploy === "cloudflare";
|
|
2067
2194
|
const isCloudflareServer = serverDeploy === "cloudflare";
|
|
2068
2195
|
const isDockerWeb = webDeploy === "docker";
|
|
2196
|
+
const isVercelWeb = webDeploy === "vercel";
|
|
2197
|
+
const isVercelServer = serverDeploy === "vercel";
|
|
2069
2198
|
const isBackendSelf = backend === "self";
|
|
2070
|
-
if (!isCloudflareWeb && !isCloudflareServer && !isDockerWeb) return;
|
|
2199
|
+
if (!isCloudflareWeb && !isCloudflareServer && !isDockerWeb && !isVercelWeb && !isVercelServer) return;
|
|
2200
|
+
if (isVercelWeb || isVercelServer) addPackageDependency({
|
|
2201
|
+
vfs,
|
|
2202
|
+
packagePath: "package.json",
|
|
2203
|
+
devDependencies: [
|
|
2204
|
+
"@types/node",
|
|
2205
|
+
"tsx",
|
|
2206
|
+
"vercel"
|
|
2207
|
+
]
|
|
2208
|
+
});
|
|
2209
|
+
if (isVercelWeb && frontend.includes("tanstack-start")) {
|
|
2210
|
+
const webPkgPath = "apps/web/package.json";
|
|
2211
|
+
if (vfs.exists(webPkgPath)) addPackageDependency({
|
|
2212
|
+
vfs,
|
|
2213
|
+
packagePath: webPkgPath,
|
|
2214
|
+
dependencies: ["nitro"]
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
if (isVercelWeb && frontend.includes("astro") && !addons.includes("electrobun") && !addons.includes("tauri")) {
|
|
2218
|
+
const webPkgPath = "apps/web/package.json";
|
|
2219
|
+
if (vfs.exists(webPkgPath)) addPackageDependency({
|
|
2220
|
+
vfs,
|
|
2221
|
+
packagePath: webPkgPath,
|
|
2222
|
+
dependencies: ["@astrojs/vercel"]
|
|
2223
|
+
});
|
|
2224
|
+
}
|
|
2225
|
+
if (isVercelWeb && frontend.includes("svelte") && !addons.includes("electrobun") && !addons.includes("tauri")) {
|
|
2226
|
+
const webPkgPath = "apps/web/package.json";
|
|
2227
|
+
if (vfs.exists(webPkgPath)) addPackageDependency({
|
|
2228
|
+
vfs,
|
|
2229
|
+
packagePath: webPkgPath,
|
|
2230
|
+
devDependencies: ["@sveltejs/adapter-vercel"]
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2071
2233
|
if (isDockerWeb) {
|
|
2072
2234
|
const webPkgPath = "apps/web/package.json";
|
|
2073
2235
|
if (vfs.exists(webPkgPath)) {
|
|
@@ -2686,7 +2848,7 @@ function setupAIDependencies(vfs, config) {
|
|
|
2686
2848
|
//#region src/processors/frontend-deps.ts
|
|
2687
2849
|
function processFrontendDeps(vfs, config) {
|
|
2688
2850
|
const { addons, frontend, webDeploy } = config;
|
|
2689
|
-
if (!frontend.includes("astro") || addons.includes("electrobun") || addons.includes("tauri") || webDeploy === "cloudflare") return;
|
|
2851
|
+
if (!frontend.includes("astro") || addons.includes("electrobun") || addons.includes("tauri") || webDeploy === "cloudflare" || webDeploy === "vercel") return;
|
|
2690
2852
|
const webPackagePath = "apps/web/package.json";
|
|
2691
2853
|
if (!vfs.exists(webPackagePath)) return;
|
|
2692
2854
|
addPackageDependency({
|
|
@@ -2786,6 +2948,7 @@ function getStackGeneratedIgnorePatterns(config) {
|
|
|
2786
2948
|
patterns.add("**/.wrangler/**");
|
|
2787
2949
|
if (config.frontend.includes("next")) patterns.add("apps/web/.open-next/**");
|
|
2788
2950
|
}
|
|
2951
|
+
if (config.webDeploy === "vercel" || config.serverDeploy === "vercel") patterns.add(".vercel/**");
|
|
2789
2952
|
return [...patterns];
|
|
2790
2953
|
}
|
|
2791
2954
|
//#endregion
|
|
@@ -3456,20 +3619,39 @@ function generateScriptsList(packageManagerRunCmd, config, hasNative) {
|
|
|
3456
3619
|
- \`${packageManagerRunCmd} docker:up\`: Build and start the Docker Compose stack
|
|
3457
3620
|
- \`${packageManagerRunCmd} docker:logs\`: Tail logs from the Docker Compose stack
|
|
3458
3621
|
- \`${packageManagerRunCmd} docker:down\`: Stop the Docker Compose stack`;
|
|
3622
|
+
if (webDeploy === "vercel" || serverDeploy === "vercel") {
|
|
3623
|
+
const v = getVercelScriptNames(webDeploy, serverDeploy);
|
|
3624
|
+
scripts += `\n- \`${packageManagerRunCmd} ${v.setup}\`: Link this repo to a Vercel project (first-time setup)
|
|
3625
|
+
- \`${packageManagerRunCmd} dev:vercel\`: Run the Vercel Services dev environment locally
|
|
3626
|
+
- \`${packageManagerRunCmd} ${v.envPreview}\`: Sync local env files to the Vercel preview environment
|
|
3627
|
+
- \`${packageManagerRunCmd} ${v.envProduction}\`: Sync local env files to the Vercel production environment
|
|
3628
|
+
- \`${packageManagerRunCmd} ${v.deploy}\`: Create a Vercel preview deployment
|
|
3629
|
+
- \`${packageManagerRunCmd} ${v.deployProd}\`: Deploy to Vercel production
|
|
3630
|
+
- \`${packageManagerRunCmd} ${v.deployCheck}\`: Dry-run a deploy to preview framework detection and included files without uploading`;
|
|
3631
|
+
}
|
|
3459
3632
|
return scripts;
|
|
3460
3633
|
}
|
|
3461
3634
|
function generateDeploymentCommands(packageManagerRunCmd, webDeploy, serverDeploy, backend) {
|
|
3462
3635
|
const hasCloudflare = webDeploy === "cloudflare" || serverDeploy === "cloudflare";
|
|
3463
3636
|
const hasDocker = webDeploy === "docker" || serverDeploy === "docker";
|
|
3464
|
-
|
|
3637
|
+
const hasVercel = webDeploy === "vercel" || serverDeploy === "vercel";
|
|
3638
|
+
if (!hasCloudflare && !hasDocker && !hasVercel) return "";
|
|
3465
3639
|
const lines = ["## Deployment"];
|
|
3466
3640
|
if (hasCloudflare) {
|
|
3467
3641
|
const targetLabel = webDeploy === "cloudflare" && (serverDeploy === "cloudflare" || backend === "self") ? "web + server" : webDeploy === "cloudflare" ? "web" : "server";
|
|
3468
|
-
|
|
3642
|
+
const cfDeployScript = hasVercel ? webDeploy === "cloudflare" ? "deploy:web" : "deploy:server" : "deploy";
|
|
3643
|
+
lines.push("", "### Cloudflare via Alchemy", "", `- Target: ${targetLabel}`, `- Dev: ${packageManagerRunCmd} dev`, `- Deploy: ${packageManagerRunCmd} ${cfDeployScript}`, `- Destroy: ${packageManagerRunCmd} destroy`, "", "For more details, see the guide on [Deploying to Cloudflare with Alchemy](https://www.better-t-stack.dev/docs/guides/cloudflare-alchemy).");
|
|
3469
3644
|
}
|
|
3470
3645
|
if (hasDocker) {
|
|
3471
3646
|
const targetLabel = webDeploy === "docker" && (serverDeploy === "docker" || backend === "self") ? "web + server" : webDeploy === "docker" ? "web" : "server";
|
|
3472
|
-
lines.push("", "### Docker Compose", "", `- Target: ${targetLabel}`, "- Config: `docker-compose.yml` (app Dockerfiles live in `apps/*/Dockerfile`)", `- Build images: ${packageManagerRunCmd} docker:build`, `- Start: ${packageManagerRunCmd} docker:up`, `- Logs: ${packageManagerRunCmd} docker:logs`, `- Stop: ${packageManagerRunCmd} docker:down`, "", "Environment variables are read from each app's `.env` file (baked into web builds for public variables) and overridden in `docker-compose.yml` for container networking.");
|
|
3647
|
+
lines.push("", "### Docker Compose", "", `- Target: ${targetLabel}`, "- Config: `docker-compose.yml` (app Dockerfiles live in `apps/*/Dockerfile`)", `- Build images: ${packageManagerRunCmd} docker:build`, `- Start: ${packageManagerRunCmd} docker:up`, `- Logs: ${packageManagerRunCmd} docker:logs`, `- Stop: ${packageManagerRunCmd} docker:down`, "", "Environment variables are read from each app's `.env` file (baked into web builds for public variables) and overridden in `docker-compose.yml` for container networking.", "", "For more details, see the guide on [Deploying with Docker Compose](https://www.better-t-stack.dev/docs/guides/docker).");
|
|
3648
|
+
}
|
|
3649
|
+
if (hasVercel) {
|
|
3650
|
+
const vercelNames = getVercelScriptNames(webDeploy, serverDeploy);
|
|
3651
|
+
const targetLabel = webDeploy === "vercel" && (serverDeploy === "vercel" || backend === "self") ? "web + server" : webDeploy === "vercel" ? "web" : "server";
|
|
3652
|
+
lines.push("", "### Vercel Services", "", `- Target: ${targetLabel}`, "- Config: `vercel.json`", `- Link the project first: ${packageManagerRunCmd} ${vercelNames.setup}`, `- Local Vercel dev: ${packageManagerRunCmd} dev:vercel`, `- Sync preview env: ${packageManagerRunCmd} ${vercelNames.envPreview}`, `- Sync production env: ${packageManagerRunCmd} ${vercelNames.envProduction}`, `- Dry-run check (no upload): ${packageManagerRunCmd} ${vercelNames.deployCheck}`, `- Preview deploy: ${packageManagerRunCmd} ${vercelNames.deploy}`, `- Production deploy: ${packageManagerRunCmd} ${vercelNames.deployProd}`);
|
|
3653
|
+
if (webDeploy === "vercel" && serverDeploy === "vercel" && backend !== "self") lines.push("- Web requests under `/api/*` route to the server service and are rewritten before reaching the backend.");
|
|
3654
|
+
lines.push("Vercel Services share project environment variables, but deploys do not upload local `.env` files automatically. Link the project with `vercel link`, then run the env sync command before your first deploy (otherwise the deployment starts with no env vars), or pass one-off envs with `vercel deploy -e KEY=value`.", `Pass Vercel CLI flags to the env sync command directly, for example: \`${packageManagerRunCmd} ${vercelNames.envProduction} --scope your-team\`.`, "", "For more details, see the guide on [Deploying to Vercel](https://www.better-t-stack.dev/docs/guides/vercel).");
|
|
3473
3655
|
}
|
|
3474
3656
|
return `${lines.join("\n")}\n`;
|
|
3475
3657
|
}
|
|
@@ -3486,6 +3668,17 @@ function generateGitHooksSection(packageManagerRunCmd, addons) {
|
|
|
3486
3668
|
if (hasLinting) lines.push(`- Run checks: \`${packageManagerRunCmd} check\``);
|
|
3487
3669
|
return `${lines.join("\n")}\n\n`;
|
|
3488
3670
|
}
|
|
3671
|
+
function getVercelScriptNames(webDeploy, serverDeploy) {
|
|
3672
|
+
const deploy = webDeploy === "cloudflare" || serverDeploy === "cloudflare" ? `deploy:${webDeploy === "vercel" ? "web" : "server"}` : "deploy";
|
|
3673
|
+
return {
|
|
3674
|
+
setup: "deploy:setup",
|
|
3675
|
+
envPreview: "env:preview",
|
|
3676
|
+
envProduction: "env:production",
|
|
3677
|
+
deploy,
|
|
3678
|
+
deployProd: `${deploy}:prod`,
|
|
3679
|
+
deployCheck: "deploy:check"
|
|
3680
|
+
};
|
|
3681
|
+
}
|
|
3489
3682
|
//#endregion
|
|
3490
3683
|
//#region src/processors/runtime-deps.ts
|
|
3491
3684
|
function processRuntimeDeps(vfs, config) {
|
|
@@ -4233,7 +4426,6 @@ async function processExtrasTemplates(vfs, templates, config) {
|
|
|
4233
4426
|
].includes(f));
|
|
4234
4427
|
const hasNuxt = config.frontend.includes("nuxt");
|
|
4235
4428
|
if (config.packageManager === "pnpm") processSingleTemplate(vfs, templates, "extras/pnpm-workspace.yaml", "pnpm-workspace.yaml", config);
|
|
4236
|
-
if (config.packageManager === "bun") processSingleTemplate(vfs, templates, "extras/bunfig.toml", "bunfig.toml", config);
|
|
4237
4429
|
if (config.packageManager === "pnpm" && (hasNative || hasNuxt)) processSingleTemplate(vfs, templates, "extras/_npmrc", ".npmrc", config);
|
|
4238
4430
|
if (config.serverDeploy === "cloudflare" || config.backend === "self" && config.webDeploy === "cloudflare") processSingleTemplate(vfs, templates, "extras/env.d.ts", "packages/env/env.d.ts", config);
|
|
4239
4431
|
}
|
|
@@ -4243,7 +4435,8 @@ async function processDeployTemplates(vfs, templates, config) {
|
|
|
4243
4435
|
const isBackendSelf = config.backend === "self";
|
|
4244
4436
|
if (config.webDeploy === "cloudflare" || config.serverDeploy === "cloudflare") processTemplatesFromPrefix(vfs, templates, "packages/infra", "packages/infra", config);
|
|
4245
4437
|
if (config.webDeploy === "docker" || config.serverDeploy === "docker") processTemplatesFromPrefix(vfs, templates, "deploy/docker/compose", "", config);
|
|
4246
|
-
if (config.webDeploy
|
|
4438
|
+
if (config.webDeploy === "vercel" || config.serverDeploy === "vercel") processTemplatesFromPrefix(vfs, templates, "deploy/vercel", "", config);
|
|
4439
|
+
if (config.webDeploy !== "none" && config.webDeploy !== "cloudflare" && config.webDeploy !== "vercel") {
|
|
4247
4440
|
const templateMap = {
|
|
4248
4441
|
"tanstack-router": "react/tanstack-router",
|
|
4249
4442
|
"tanstack-start": "react/tanstack-start",
|
|
@@ -4256,7 +4449,7 @@ async function processDeployTemplates(vfs, templates, config) {
|
|
|
4256
4449
|
};
|
|
4257
4450
|
for (const f of config.frontend) if (templateMap[f]) processTemplatesFromPrefix(vfs, templates, `deploy/${config.webDeploy}/web/${templateMap[f]}`, "apps/web", config);
|
|
4258
4451
|
}
|
|
4259
|
-
if (config.serverDeploy !== "none" && config.serverDeploy !== "cloudflare" && !isBackendSelf) processTemplatesFromPrefix(vfs, templates, `deploy/${config.serverDeploy}/server`, "apps/server", config);
|
|
4452
|
+
if (config.serverDeploy !== "none" && config.serverDeploy !== "cloudflare" && config.serverDeploy !== "vercel" && !isBackendSelf) processTemplatesFromPrefix(vfs, templates, `deploy/${config.serverDeploy}/server`, "apps/server", config);
|
|
4260
4453
|
}
|
|
4261
4454
|
//#endregion
|
|
4262
4455
|
//#region src/utils/reproducible-command.ts
|
|
@@ -4344,6 +4537,7 @@ async function generate(options) {
|
|
|
4344
4537
|
processAlchemyPlugins(vfs, config);
|
|
4345
4538
|
processPwaPlugins(vfs, config);
|
|
4346
4539
|
processCatalogs(vfs, config);
|
|
4540
|
+
processVercelConfig(vfs, config);
|
|
4347
4541
|
processReadme(vfs, config);
|
|
4348
4542
|
if (options.version) {
|
|
4349
4543
|
const reproducibleCommand = generateReproducibleCommand(config);
|
|
@@ -5625,13 +5819,16 @@ import { RPCLink } from "@orpc/client/fetch";
|
|
|
5625
5819
|
|
|
5626
5820
|
{{#if (eq backend "self")}}
|
|
5627
5821
|
export const link = new RPCLink({
|
|
5628
|
-
|
|
5822
|
+
// Lazy: this module is imported during SSR where window does not exist
|
|
5823
|
+
url: () => \`\${window.location.origin}/rpc\`,
|
|
5629
5824
|
});
|
|
5630
5825
|
{{else}}
|
|
5631
5826
|
import { PUBLIC_SERVER_URL } from "astro:env/client";
|
|
5632
5827
|
|
|
5828
|
+
{{> getServerUrlSpaces}}
|
|
5829
|
+
|
|
5633
5830
|
export const link = new RPCLink({
|
|
5634
|
-
url: \`\${PUBLIC_SERVER_URL}/rpc\`,
|
|
5831
|
+
url: \`\${getServerUrl(PUBLIC_SERVER_URL)}/rpc\`,
|
|
5635
5832
|
{{#if (eq auth "better-auth")}}
|
|
5636
5833
|
fetch(url, options) {
|
|
5637
5834
|
return fetch(url, {
|
|
@@ -5651,11 +5848,25 @@ import { createORPCClient } from '@orpc/client'
|
|
|
5651
5848
|
import { RPCLink } from '@orpc/client/fetch'
|
|
5652
5849
|
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
|
|
5653
5850
|
|
|
5851
|
+
function getServerUrl(url: string) {
|
|
5852
|
+
const normalized = url.endsWith("/") ? url.slice(0, -1) : url;
|
|
5853
|
+
|
|
5854
|
+
if (!normalized.startsWith("/")) {
|
|
5855
|
+
return normalized;
|
|
5856
|
+
}
|
|
5857
|
+
|
|
5858
|
+
if (import.meta.server) {
|
|
5859
|
+
return \`\${useRequestURL().origin}\${normalized}\`;
|
|
5860
|
+
}
|
|
5861
|
+
|
|
5862
|
+
return \`\${window.location.origin}\${normalized}\`;
|
|
5863
|
+
}
|
|
5864
|
+
|
|
5654
5865
|
export default defineNuxtPlugin(() => {
|
|
5655
5866
|
const config = useRuntimeConfig();
|
|
5656
5867
|
const serverUrl =
|
|
5657
5868
|
(import.meta.server && config.serverUrl) || config.public.serverUrl;
|
|
5658
|
-
const rpcUrl = \`\${serverUrl}/rpc\`;
|
|
5869
|
+
const rpcUrl = \`\${getServerUrl(serverUrl)}/rpc\`;
|
|
5659
5870
|
|
|
5660
5871
|
const rpcLink = new RPCLink({
|
|
5661
5872
|
url: rpcUrl,
|
|
@@ -5783,6 +5994,10 @@ export function createQueryClient() {
|
|
|
5783
5994
|
export const queryClient = createQueryClient();
|
|
5784
5995
|
{{/unless}}
|
|
5785
5996
|
|
|
5997
|
+
{{#unless (eq backend "self")}}
|
|
5998
|
+
{{> getServerUrl}}
|
|
5999
|
+
|
|
6000
|
+
{{/unless}}
|
|
5786
6001
|
{{#if (and (includes frontend "tanstack-start") (eq backend "self"))}}
|
|
5787
6002
|
const getORPCClient = createIsomorphicFn()
|
|
5788
6003
|
.server(() =>
|
|
@@ -5811,7 +6026,7 @@ const getORPCClient = createIsomorphicFn()
|
|
|
5811
6026
|
export const client: RouterClient<typeof appRouter> = getORPCClient();
|
|
5812
6027
|
{{else if (includes frontend "tanstack-start")}}
|
|
5813
6028
|
const link = new RPCLink({
|
|
5814
|
-
url: \`\${env.VITE_SERVER_URL}/rpc\`,
|
|
6029
|
+
url: \`\${getServerUrl(env.VITE_SERVER_URL)}/rpc\`,
|
|
5815
6030
|
{{#if (eq auth "clerk")}}
|
|
5816
6031
|
headers: async () => {
|
|
5817
6032
|
const token = await getClerkAuthToken();
|
|
@@ -5838,9 +6053,9 @@ export const link = new RPCLink({
|
|
|
5838
6053
|
{{#if (and (eq backend "self") (includes frontend "next"))}}
|
|
5839
6054
|
url: \`\${typeof window !== "undefined" ? window.location.origin : "http://localhost:3001"}/api/rpc\`,
|
|
5840
6055
|
{{else if (includes frontend "next")}}
|
|
5841
|
-
url: \`\${env.NEXT_PUBLIC_SERVER_URL}/rpc\`,
|
|
6056
|
+
url: \`\${getServerUrl(env.NEXT_PUBLIC_SERVER_URL)}/rpc\`,
|
|
5842
6057
|
{{else}}
|
|
5843
|
-
url: \`\${env.VITE_SERVER_URL}/rpc\`,
|
|
6058
|
+
url: \`\${getServerUrl(env.VITE_SERVER_URL)}/rpc\`,
|
|
5844
6059
|
{{/if}}
|
|
5845
6060
|
{{#if (eq auth "clerk")}}
|
|
5846
6061
|
headers: async () => {
|
|
@@ -5901,8 +6116,10 @@ export const queryClient = new QueryClient({
|
|
|
5901
6116
|
}),
|
|
5902
6117
|
});
|
|
5903
6118
|
|
|
6119
|
+
{{> getServerUrl}}
|
|
6120
|
+
|
|
5904
6121
|
export const link = new RPCLink({
|
|
5905
|
-
url: \`\${env.VITE_SERVER_URL}/rpc\`,
|
|
6122
|
+
url: \`\${getServerUrl(env.VITE_SERVER_URL)}/rpc\`,
|
|
5906
6123
|
{{#if (eq auth "better-auth")}}
|
|
5907
6124
|
fetch(url, options) {
|
|
5908
6125
|
return fetch(url, {
|
|
@@ -5934,6 +6151,10 @@ export const queryClient = new QueryClient({
|
|
|
5934
6151
|
}),
|
|
5935
6152
|
});
|
|
5936
6153
|
|
|
6154
|
+
{{#unless (eq backend "self")}}
|
|
6155
|
+
{{> getServerUrl}}
|
|
6156
|
+
|
|
6157
|
+
{{/unless}}
|
|
5937
6158
|
export const link = new RPCLink({
|
|
5938
6159
|
{{#if (eq backend "self")}}
|
|
5939
6160
|
url: () => {
|
|
@@ -5944,7 +6165,7 @@ export const link = new RPCLink({
|
|
|
5944
6165
|
return \`\${window.location.origin}/rpc\`;
|
|
5945
6166
|
},
|
|
5946
6167
|
{{else}}
|
|
5947
|
-
url: \`\${PUBLIC_SERVER_URL}/rpc\`,
|
|
6168
|
+
url: \`\${getServerUrl(PUBLIC_SERVER_URL)}/rpc\`,
|
|
5948
6169
|
{{/if}}
|
|
5949
6170
|
{{#if (eq auth "better-auth")}}
|
|
5950
6171
|
fetch(url, options) {
|
|
@@ -6470,6 +6691,8 @@ import type { AppRouter } from "@{{projectName}}/api/routers/index";
|
|
|
6470
6691
|
import { toast } from 'sonner';
|
|
6471
6692
|
{{#unless (eq backend "self")}}
|
|
6472
6693
|
import { env } from "@{{projectName}}/env/web";
|
|
6694
|
+
|
|
6695
|
+
{{> getServerUrl}}
|
|
6473
6696
|
{{/unless}}
|
|
6474
6697
|
{{#if (eq auth "clerk")}}
|
|
6475
6698
|
import { getClerkAuthToken } from "@/utils/clerk-auth";
|
|
@@ -6496,7 +6719,7 @@ const trpcClient = createTRPCClient<AppRouter>({
|
|
|
6496
6719
|
{{#if (eq backend "self")}}
|
|
6497
6720
|
url: "/api/trpc",
|
|
6498
6721
|
{{else}}
|
|
6499
|
-
url: \`\${env.NEXT_PUBLIC_SERVER_URL}/trpc\`,
|
|
6722
|
+
url: \`\${getServerUrl(env.NEXT_PUBLIC_SERVER_URL)}/trpc\`,
|
|
6500
6723
|
{{/if}}
|
|
6501
6724
|
{{#if (eq auth "clerk")}}
|
|
6502
6725
|
headers: async () => {
|
|
@@ -6547,6 +6770,8 @@ import { env } from "@{{projectName}}/env/web";
|
|
|
6547
6770
|
import { getClerkAuthToken } from "@/utils/clerk-auth";
|
|
6548
6771
|
{{/if}}
|
|
6549
6772
|
|
|
6773
|
+
{{> getServerUrl}}
|
|
6774
|
+
|
|
6550
6775
|
export const queryClient = new QueryClient({
|
|
6551
6776
|
queryCache: new QueryCache({
|
|
6552
6777
|
onError: (error, query) => {
|
|
@@ -6565,7 +6790,7 @@ export const queryClient = new QueryClient({
|
|
|
6565
6790
|
export const trpcClient = createTRPCClient<AppRouter>({
|
|
6566
6791
|
links: [
|
|
6567
6792
|
httpBatchLink({
|
|
6568
|
-
url: \`\${env.VITE_SERVER_URL}/trpc\`,
|
|
6793
|
+
url: \`\${getServerUrl(env.VITE_SERVER_URL)}/trpc\`,
|
|
6569
6794
|
{{#if (eq auth "clerk")}}
|
|
6570
6795
|
headers: async () => {
|
|
6571
6796
|
const token = await getClerkAuthToken();
|
|
@@ -13361,9 +13586,15 @@ import { polarClient } from "@polar-sh/better-auth/client";
|
|
|
13361
13586
|
import { PUBLIC_SERVER_URL } from "astro:env/client";
|
|
13362
13587
|
{{/if}}
|
|
13363
13588
|
|
|
13589
|
+
{{#if (ne backend "self")}}
|
|
13590
|
+
{{> getServerUrlSpaces}}
|
|
13591
|
+
|
|
13592
|
+
{{/if}}
|
|
13364
13593
|
export const authClient = createAuthClient({
|
|
13365
13594
|
{{#if (ne backend "self")}}
|
|
13366
|
-
|
|
13595
|
+
// better-auth derives its route-matching base from this URL's path, so the
|
|
13596
|
+
// public auth path must equal the server-side mount (/api/auth everywhere)
|
|
13597
|
+
baseURL: new URL("/api/auth", getServerUrl(PUBLIC_SERVER_URL)).toString(),
|
|
13367
13598
|
{{/if}}
|
|
13368
13599
|
{{#if (eq payments "polar")}}
|
|
13369
13600
|
plugins: [polarClient()],
|
|
@@ -13897,11 +14128,17 @@ import { polarClient } from "@polar-sh/better-auth/client";
|
|
|
13897
14128
|
export default defineNuxtPlugin(() => {
|
|
13898
14129
|
{{#if (ne backend "self")}}
|
|
13899
14130
|
const config = useRuntimeConfig();
|
|
14131
|
+
const rawServerUrl = (import.meta.server && config.serverUrl) || config.public.serverUrl;
|
|
14132
|
+
// Same-origin paths like /api need an absolute base, and better-auth derives
|
|
14133
|
+
// its route matching from this URL's path, so it must be exactly /api/auth
|
|
14134
|
+
const serverOrigin = rawServerUrl.startsWith("/")
|
|
14135
|
+
? (import.meta.server ? useRequestURL() : window.location).origin + rawServerUrl
|
|
14136
|
+
: rawServerUrl;
|
|
13900
14137
|
{{/if}}
|
|
13901
14138
|
|
|
13902
14139
|
const authClient = createAuthClient({
|
|
13903
14140
|
{{#if (ne backend "self")}}
|
|
13904
|
-
baseURL: (
|
|
14141
|
+
baseURL: new URL("/api/auth", serverOrigin).toString(),
|
|
13905
14142
|
{{/if}}
|
|
13906
14143
|
{{#if (eq payments "polar")}}
|
|
13907
14144
|
plugins: [polarClient()],
|
|
@@ -13921,11 +14158,15 @@ import { polarClient } from "@polar-sh/better-auth/client";
|
|
|
13921
14158
|
{{/if}}
|
|
13922
14159
|
{{#unless (eq backend "self")}}
|
|
13923
14160
|
import { env } from "@{{projectName}}/env/web";
|
|
14161
|
+
|
|
14162
|
+
{{> getServerUrl}}
|
|
13924
14163
|
{{/unless}}
|
|
13925
14164
|
|
|
13926
14165
|
export const authClient = createAuthClient({
|
|
13927
14166
|
{{#unless (eq backend "self")}}
|
|
13928
|
-
|
|
14167
|
+
// better-auth derives its route-matching base from this URL's path, so the
|
|
14168
|
+
// public auth path must equal the server-side mount (/api/auth everywhere)
|
|
14169
|
+
baseURL: new URL("/api/auth", getServerUrl(env.{{#if (includes frontend "next")}}NEXT_PUBLIC_SERVER_URL{{else}}VITE_SERVER_URL{{/if}})).toString(),
|
|
13929
14170
|
{{/unless}}
|
|
13930
14171
|
{{#if (eq payments "polar")}}
|
|
13931
14172
|
plugins: [polarClient()]
|
|
@@ -16219,8 +16460,12 @@ import { polarClient } from "@polar-sh/better-auth/client";
|
|
|
16219
16460
|
{{/if}}
|
|
16220
16461
|
import { env } from "@{{projectName}}/env/web";
|
|
16221
16462
|
|
|
16463
|
+
{{> getServerUrl}}
|
|
16464
|
+
|
|
16222
16465
|
export const authClient = createAuthClient({
|
|
16223
|
-
|
|
16466
|
+
// better-auth derives its route-matching base from this URL's path, so the
|
|
16467
|
+
// public auth path must equal the server-side mount (/api/auth everywhere)
|
|
16468
|
+
baseURL: new URL("/api/auth", getServerUrl(env.VITE_SERVER_URL)).toString(),
|
|
16224
16469
|
{{#if (eq payments "polar")}}
|
|
16225
16470
|
plugins: [polarClient()]
|
|
16226
16471
|
{{/if}}
|
|
@@ -16636,9 +16881,15 @@ import { createAuthClient } from "better-auth/svelte";
|
|
|
16636
16881
|
import { polarClient } from "@polar-sh/better-auth/client";
|
|
16637
16882
|
{{/if}}
|
|
16638
16883
|
|
|
16884
|
+
{{#unless (eq backend "self")}}
|
|
16885
|
+
{{> getServerUrl}}
|
|
16886
|
+
|
|
16887
|
+
{{/unless}}
|
|
16639
16888
|
export const authClient = createAuthClient({
|
|
16640
16889
|
{{#unless (eq backend "self")}}
|
|
16641
|
-
|
|
16890
|
+
// better-auth derives its route-matching base from this URL's path, so the
|
|
16891
|
+
// public auth path must equal the server-side mount (/api/auth everywhere)
|
|
16892
|
+
baseURL: new URL("/api/auth", getServerUrl(PUBLIC_SERVER_URL)).toString(),
|
|
16642
16893
|
{{/unless}}
|
|
16643
16894
|
{{#if (eq payments "polar")}}
|
|
16644
16895
|
plugins: [polarClient()]
|
|
@@ -18664,11 +18915,7 @@ const apiHandler = new OpenAPIHandler(appRouter, {
|
|
|
18664
18915
|
});
|
|
18665
18916
|
{{/if}}
|
|
18666
18917
|
|
|
18667
|
-
{{#if (eq runtime "node")}}
|
|
18668
|
-
new Elysia({ adapter: node() })
|
|
18669
|
-
{{else}}
|
|
18670
|
-
new Elysia()
|
|
18671
|
-
{{/if}}
|
|
18918
|
+
const app = {{#if (eq runtime "node")}}new Elysia({ adapter: node() }){{else}}new Elysia(){{/if}}
|
|
18672
18919
|
.use(
|
|
18673
18920
|
cors({
|
|
18674
18921
|
origin: env.CORS_ORIGIN,
|
|
@@ -18774,9 +19021,22 @@ new Elysia()
|
|
|
18774
19021
|
})
|
|
18775
19022
|
{{/if}}
|
|
18776
19023
|
.get("/", () => "OK")
|
|
19024
|
+
{{#if (eq serverDeploy "vercel")}};
|
|
19025
|
+
|
|
19026
|
+
export default app;
|
|
19027
|
+
|
|
19028
|
+
// Elysia's default export is not auto-served by Bun or Node, so start a local
|
|
19029
|
+
// server outside Vercel while still exporting the app for Vercel functions.
|
|
19030
|
+
if (!process.env.VERCEL) {
|
|
19031
|
+
app.listen(3000, () => {
|
|
19032
|
+
console.log("Server is running on http://localhost:3000");
|
|
19033
|
+
});
|
|
19034
|
+
}
|
|
19035
|
+
{{else}}
|
|
18777
19036
|
.listen(3000, () => {
|
|
18778
19037
|
console.log("Server is running on http://localhost:3000");
|
|
18779
19038
|
});
|
|
19039
|
+
{{/if}}
|
|
18780
19040
|
`],
|
|
18781
19041
|
["backend/server/express/src/index.ts.hbs", `import { env } from "@{{projectName}}/env/server";
|
|
18782
19042
|
{{#if (eq api "trpc")}}
|
|
@@ -19347,15 +19607,23 @@ app.get("/", (c) => {
|
|
|
19347
19607
|
{{#if (eq runtime "node")}}
|
|
19348
19608
|
import { serve } from "@hono/node-server";
|
|
19349
19609
|
|
|
19350
|
-
|
|
19351
|
-
|
|
19352
|
-
|
|
19353
|
-
|
|
19354
|
-
|
|
19355
|
-
(
|
|
19356
|
-
|
|
19357
|
-
|
|
19358
|
-
|
|
19610
|
+
{{#if (eq serverDeploy "vercel")}}
|
|
19611
|
+
export default app;
|
|
19612
|
+
|
|
19613
|
+
if (!process.env.VERCEL) {
|
|
19614
|
+
{{/if}}
|
|
19615
|
+
serve(
|
|
19616
|
+
{
|
|
19617
|
+
fetch: app.fetch,
|
|
19618
|
+
port: 3000,
|
|
19619
|
+
},
|
|
19620
|
+
(info) => {
|
|
19621
|
+
console.log(\`Server is running on http://localhost:\${info.port}\`);
|
|
19622
|
+
}
|
|
19623
|
+
);
|
|
19624
|
+
{{#if (eq serverDeploy "vercel")}}
|
|
19625
|
+
}
|
|
19626
|
+
{{/if}}
|
|
19359
19627
|
{{else}}
|
|
19360
19628
|
{{#if (eq runtime "bun")}}
|
|
19361
19629
|
export default app;
|
|
@@ -19409,6 +19677,7 @@ lerna-debug.log*
|
|
|
19409
19677
|
|
|
19410
19678
|
# Better-T-Stack
|
|
19411
19679
|
.alchemy
|
|
19680
|
+
.vercel
|
|
19412
19681
|
|
|
19413
19682
|
# Testing
|
|
19414
19683
|
coverage
|
|
@@ -20278,7 +20547,7 @@ services:
|
|
|
20278
20547
|
{{/if}}
|
|
20279
20548
|
init: true
|
|
20280
20549
|
ports:
|
|
20281
|
-
{{#if (or (includes frontend "tanstack-router") (includes frontend "
|
|
20550
|
+
{{#if (or (includes frontend "tanstack-router") (includes frontend "solid"))}}
|
|
20282
20551
|
- "3001:80"
|
|
20283
20552
|
{{else}}
|
|
20284
20553
|
- "3001:3001"
|
|
@@ -20325,7 +20594,7 @@ services:
|
|
|
20325
20594
|
{{/if}}
|
|
20326
20595
|
{{/if}}
|
|
20327
20596
|
healthcheck:
|
|
20328
|
-
{{#if (or (includes frontend "tanstack-router") (includes frontend "
|
|
20597
|
+
{{#if (or (includes frontend "tanstack-router") (includes frontend "solid"))}}
|
|
20329
20598
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:80/"]
|
|
20330
20599
|
{{else}}
|
|
20331
20600
|
test:
|
|
@@ -20686,30 +20955,14 @@ ENV VITE_CLERK_PUBLISHABLE_KEY=\${VITE_CLERK_PUBLISHABLE_KEY}
|
|
|
20686
20955
|
ENV NODE_ENV=production
|
|
20687
20956
|
RUN cd apps/web && {{packageManager}} run build
|
|
20688
20957
|
|
|
20689
|
-
FROM
|
|
20690
|
-
|
|
20691
|
-
COPY
|
|
20692
|
-
|
|
20693
|
-
|
|
20694
|
-
|
|
20695
|
-
|
|
20696
|
-
|
|
20697
|
-
server_name _;
|
|
20698
|
-
root /usr/share/nginx/html;
|
|
20699
|
-
index index.html;
|
|
20700
|
-
|
|
20701
|
-
gzip on;
|
|
20702
|
-
gzip_types text/plain text/css application/json application/javascript image/svg+xml;
|
|
20703
|
-
|
|
20704
|
-
location /assets/ {
|
|
20705
|
-
add_header Cache-Control "public, max-age=31536000, immutable";
|
|
20706
|
-
}
|
|
20707
|
-
|
|
20708
|
-
# SPA fallback
|
|
20709
|
-
location / {
|
|
20710
|
-
try_files $uri $uri/ /index.html;
|
|
20711
|
-
}
|
|
20712
|
-
}
|
|
20958
|
+
FROM node:24-slim AS runner
|
|
20959
|
+
WORKDIR /app
|
|
20960
|
+
COPY --from=builder /app .
|
|
20961
|
+
ENV NODE_ENV=production
|
|
20962
|
+
ENV PORT=3001
|
|
20963
|
+
ENV HOST=0.0.0.0
|
|
20964
|
+
EXPOSE 3001
|
|
20965
|
+
CMD ["sh", "-c", "cd apps/web && npm run start"]
|
|
20713
20966
|
`],
|
|
20714
20967
|
["deploy/docker/web/react/tanstack-router/Dockerfile.hbs", `FROM node:24{{#unless (includes addons "vite-plus")}}-slim{{/unless}} AS builder
|
|
20715
20968
|
{{#if (eq packageManager "bun")}}
|
|
@@ -20949,6 +21202,148 @@ EXPOSE 3001
|
|
|
20949
21202
|
|
|
20950
21203
|
WORKDIR /app/apps/web
|
|
20951
21204
|
CMD ["node", "build/index.js"]
|
|
21205
|
+
`],
|
|
21206
|
+
["deploy/vercel/_vercelignore", `# Local env files must never ship in deployments: Vercel project env vars are
|
|
21207
|
+
# the source of truth (bun env:vercel:*), and frameworks like Next.js would
|
|
21208
|
+
# otherwise load these localhost values at runtime.
|
|
21209
|
+
.env
|
|
21210
|
+
.env.*
|
|
21211
|
+
**/.env
|
|
21212
|
+
**/.env.*
|
|
21213
|
+
!**/.env.example
|
|
21214
|
+
local.db
|
|
21215
|
+
local.db-*
|
|
21216
|
+
.alchemy/
|
|
21217
|
+
`],
|
|
21218
|
+
["deploy/vercel/scripts/sync-vercel-env.ts.hbs", `import { spawnSync } from "node:child_process";
|
|
21219
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
21220
|
+
import dotenv from "dotenv";
|
|
21221
|
+
|
|
21222
|
+
const DEFAULT_ENVIRONMENT = "preview";
|
|
21223
|
+
const VALID_ENVIRONMENTS = new Set(["development", "preview", "production"]);
|
|
21224
|
+
const VERCEL_COMMAND = [{{#if (eq packageManager "npm")}}"npx", "vercel"{{else if (eq packageManager "pnpm")}}"pnpm", "exec", "vercel"{{else}}"bunx", "vercel"{{/if}}] as const;
|
|
21225
|
+
const DEFAULT_FILES = [
|
|
21226
|
+
{{#if (eq webDeploy "vercel")}}
|
|
21227
|
+
"apps/web/.env",
|
|
21228
|
+
{{/if}}
|
|
21229
|
+
{{#if (and (eq serverDeploy "vercel") (ne backend "self") (ne backend "none") (ne backend "convex"))}}
|
|
21230
|
+
"apps/server/.env",
|
|
21231
|
+
{{/if}}
|
|
21232
|
+
];
|
|
21233
|
+
const SKIP_KEYS = new Set([
|
|
21234
|
+
{{#if (or (and (eq webDeploy "vercel") (eq serverDeploy "vercel") (ne backend "self") (ne backend "none") (ne backend "convex")) (and (eq webDeploy "vercel") (eq backend "self")))}}
|
|
21235
|
+
"BETTER_AUTH_URL",
|
|
21236
|
+
"CORS_ORIGIN",
|
|
21237
|
+
"NODE_ENV",
|
|
21238
|
+
{{else if (and (eq serverDeploy "vercel") (ne backend "self") (ne backend "none") (ne backend "convex"))}}
|
|
21239
|
+
// BETTER_AUTH_URL derives from the deployment's own origin at runtime;
|
|
21240
|
+
// CORS_ORIGIN stays synced because the web app (if any) lives on another host
|
|
21241
|
+
"BETTER_AUTH_URL",
|
|
21242
|
+
"NODE_ENV",
|
|
21243
|
+
{{/if}}
|
|
21244
|
+
]);
|
|
21245
|
+
const OVERRIDE_KEYS = new Map([
|
|
21246
|
+
{{#if (and (eq webDeploy "vercel") (eq serverDeploy "vercel") (ne backend "self") (ne backend "none") (ne backend "convex"))}}
|
|
21247
|
+
["NEXT_PUBLIC_SERVER_URL", "/api"],
|
|
21248
|
+
["NUXT_PUBLIC_SERVER_URL", "/api"],
|
|
21249
|
+
["PUBLIC_SERVER_URL", "/api"],
|
|
21250
|
+
["VITE_SERVER_URL", "/api"],
|
|
21251
|
+
{{/if}}
|
|
21252
|
+
]);
|
|
21253
|
+
|
|
21254
|
+
const args = process.argv.slice(2);
|
|
21255
|
+
const separatorIndex = args.indexOf("--");
|
|
21256
|
+
const scriptArgs = separatorIndex === -1 ? args : args.slice(0, separatorIndex);
|
|
21257
|
+
const forwardedArgs = separatorIndex === -1 ? [] : args.slice(separatorIndex + 1);
|
|
21258
|
+
|
|
21259
|
+
const environment =
|
|
21260
|
+
scriptArgs[0] && VALID_ENVIRONMENTS.has(scriptArgs[0]) ? scriptArgs[0] : DEFAULT_ENVIRONMENT;
|
|
21261
|
+
const remainingArgs = scriptArgs.slice(VALID_ENVIRONMENTS.has(scriptArgs[0] ?? "") ? 1 : 0);
|
|
21262
|
+
// Split remaining args into env-file paths and passthrough Vercel CLI flags.
|
|
21263
|
+
// A bare token counts as a file only when it exists on disk, so flags and their
|
|
21264
|
+
// values (e.g. \`--scope my-team\`) forward correctly regardless of argument order.
|
|
21265
|
+
const files: string[] = [];
|
|
21266
|
+
const passthroughArgs: string[] = [];
|
|
21267
|
+
for (const arg of remainingArgs) {
|
|
21268
|
+
if (!arg.startsWith("-") && existsSync(arg)) {
|
|
21269
|
+
files.push(arg);
|
|
21270
|
+
} else {
|
|
21271
|
+
passthroughArgs.push(arg);
|
|
21272
|
+
}
|
|
21273
|
+
}
|
|
21274
|
+
const vercelArgs = [...passthroughArgs, ...forwardedArgs];
|
|
21275
|
+
const envFiles = files.length > 0 ? files : DEFAULT_FILES;
|
|
21276
|
+
|
|
21277
|
+
if (envFiles.length === 0) {
|
|
21278
|
+
console.log("No env files configured for this Vercel stack.");
|
|
21279
|
+
process.exit(0);
|
|
21280
|
+
}
|
|
21281
|
+
|
|
21282
|
+
const env = new Map<string, string>();
|
|
21283
|
+
|
|
21284
|
+
for (const file of envFiles) {
|
|
21285
|
+
if (!existsSync(file)) {
|
|
21286
|
+
console.warn(\`Skipping missing env file: \${file}\`);
|
|
21287
|
+
continue;
|
|
21288
|
+
}
|
|
21289
|
+
|
|
21290
|
+
for (const [key, value] of Object.entries(dotenv.parse(readFileSync(file, "utf8")))) {
|
|
21291
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
21292
|
+
env.set(key, OVERRIDE_KEYS.get(key) ?? value);
|
|
21293
|
+
}
|
|
21294
|
+
}
|
|
21295
|
+
|
|
21296
|
+
if (env.size === 0) {
|
|
21297
|
+
console.log("No Vercel env vars found to sync.");
|
|
21298
|
+
process.exit(0);
|
|
21299
|
+
}
|
|
21300
|
+
|
|
21301
|
+
const LOCAL_VALUE_PATTERN = /localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|^file:/i;
|
|
21302
|
+
const localKeys = [...env.entries()]
|
|
21303
|
+
.filter(([, value]) => LOCAL_VALUE_PATTERN.test(value))
|
|
21304
|
+
.map(([key]) => key);
|
|
21305
|
+
if (localKeys.length > 0) {
|
|
21306
|
+
console.warn(
|
|
21307
|
+
\`Warning: \${localKeys.join(", ")} look\${localKeys.length === 1 ? "s" : ""} like local-only value(s). Update them in your .env file(s) and re-run this sync if your deployed app should not point at local endpoints.\`,
|
|
21308
|
+
);
|
|
21309
|
+
}
|
|
21310
|
+
|
|
21311
|
+
console.log(\`Syncing \${env.size} env var(s) to Vercel \${environment}.\`);
|
|
21312
|
+
for (const [key, value] of env.entries()) {
|
|
21313
|
+
const result = spawnSync(
|
|
21314
|
+
VERCEL_COMMAND[0],
|
|
21315
|
+
[
|
|
21316
|
+
...VERCEL_COMMAND.slice(1),
|
|
21317
|
+
"env",
|
|
21318
|
+
"add",
|
|
21319
|
+
key,
|
|
21320
|
+
environment,
|
|
21321
|
+
"--force",
|
|
21322
|
+
"--yes",
|
|
21323
|
+
"--non-interactive",
|
|
21324
|
+
...vercelArgs,
|
|
21325
|
+
],
|
|
21326
|
+
{
|
|
21327
|
+
input: \`\${value}\\n\`,
|
|
21328
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
21329
|
+
encoding: "utf8",
|
|
21330
|
+
// Windows resolves bunx/npx/pnpm via .cmd shims, which need a shell
|
|
21331
|
+
shell: process.platform === "win32",
|
|
21332
|
+
},
|
|
21333
|
+
);
|
|
21334
|
+
|
|
21335
|
+
if (result.error) {
|
|
21336
|
+
console.error(\`Failed to sync \${key}: \${result.error.message}\`);
|
|
21337
|
+
process.exit(1);
|
|
21338
|
+
}
|
|
21339
|
+
|
|
21340
|
+
if (result.status !== 0) {
|
|
21341
|
+
console.error(\`Failed to sync \${key}\`);
|
|
21342
|
+
process.exit(result.status ?? 1);
|
|
21343
|
+
}
|
|
21344
|
+
}
|
|
21345
|
+
|
|
21346
|
+
console.log("Vercel env sync complete. Redeploy for changes to take effect.");
|
|
20952
21347
|
`],
|
|
20953
21348
|
["examples/ai/convex/packages/backend/convex/agent.ts.hbs", `import { Agent } from "@convex-dev/agent";
|
|
20954
21349
|
import { google } from "@ai-sdk/google";
|
|
@@ -29644,16 +30039,6 @@ function TodosRoute() {
|
|
|
29644
30039
|
shamefully-hoist=true
|
|
29645
30040
|
strict-peer-dependencies=false
|
|
29646
30041
|
{{/if}}`],
|
|
29647
|
-
["extras/bunfig.toml.hbs", `[install]
|
|
29648
|
-
{{#if (includes frontend "nuxt")}}
|
|
29649
|
-
linker = "hoisted" # Nuxt needs hoisting for its dependency resolver
|
|
29650
|
-
{{else}}
|
|
29651
|
-
linker = "isolated"
|
|
29652
|
-
{{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
|
|
29653
|
-
peer = false # Expo native projects declare SDK peers explicitly; this keeps Bun isolated installs deduped for native modules
|
|
29654
|
-
{{/if}}
|
|
29655
|
-
{{/if}}
|
|
29656
|
-
`],
|
|
29657
30042
|
["extras/env.d.ts.hbs", `{{#if (eq serverDeploy "cloudflare")}}
|
|
29658
30043
|
import { type server } from "@{{projectName}}/infra/alchemy.run";
|
|
29659
30044
|
{{else}}
|
|
@@ -29678,19 +30063,19 @@ declare module "cloudflare:workers" {
|
|
|
29678
30063
|
["extras/pnpm-workspace.yaml.hbs", `packages:
|
|
29679
30064
|
- "apps/*"
|
|
29680
30065
|
- "packages/*"
|
|
29681
|
-
{{#if (or (eq runtime "node") (eq webDeploy "cloudflare") (eq serverDeploy "cloudflare") (eq webDeploy "docker") (eq serverDeploy "docker") (eq orm "prisma") (includes addons "lefthook") (includes addons "nx") (includes addons "pwa") (includes addons "turborepo") (includes addons "vite-plus") (includes frontend "react-router") (includes frontend "next") (includes frontend "nuxt"))}}
|
|
30066
|
+
{{#if (or (eq runtime "node") (eq webDeploy "cloudflare") (eq serverDeploy "cloudflare") (eq webDeploy "docker") (eq serverDeploy "docker") (eq webDeploy "vercel") (eq serverDeploy "vercel") (eq orm "prisma") (includes addons "lefthook") (includes addons "nx") (includes addons "pwa") (includes addons "turborepo") (includes addons "vite-plus") (includes frontend "react-router") (includes frontend "next") (includes frontend "nuxt"))}}
|
|
29682
30067
|
|
|
29683
30068
|
# pnpm 11 blocks dependency lifecycle scripts unless they are approved here.
|
|
29684
30069
|
# Entries are scoped to packages this generated stack can pull in.
|
|
29685
30070
|
allowBuilds:
|
|
29686
|
-
{{#if (or (eq runtime "node") (eq webDeploy "cloudflare") (eq serverDeploy "cloudflare") (eq webDeploy "docker") (eq serverDeploy "docker") (includes addons "turborepo") (includes addons "vite-plus") (includes frontend "react-router") (includes frontend "nuxt"))}}
|
|
30071
|
+
{{#if (or (eq runtime "node") (eq webDeploy "cloudflare") (eq serverDeploy "cloudflare") (eq webDeploy "docker") (eq serverDeploy "docker") (eq webDeploy "vercel") (eq serverDeploy "vercel") (includes addons "turborepo") (includes addons "vite-plus") (includes frontend "react-router") (includes frontend "nuxt"))}}
|
|
29687
30072
|
esbuild: true
|
|
29688
30073
|
{{/if}}
|
|
29689
30074
|
{{#if (includes frontend "nuxt")}}
|
|
29690
30075
|
"@parcel/watcher": true
|
|
29691
30076
|
vue-demi: true
|
|
29692
30077
|
{{/if}}
|
|
29693
|
-
{{#if (or (eq webDeploy "cloudflare") (eq serverDeploy "cloudflare") (eq webDeploy "docker") (includes addons "pwa") (includes frontend "next"))}}
|
|
30078
|
+
{{#if (or (eq webDeploy "cloudflare") (eq serverDeploy "cloudflare") (eq webDeploy "docker") (eq webDeploy "vercel") (includes addons "pwa") (includes frontend "next"))}}
|
|
29694
30079
|
sharp: true
|
|
29695
30080
|
{{/if}}
|
|
29696
30081
|
{{#if (or (eq webDeploy "cloudflare") (eq serverDeploy "cloudflare"))}}
|
|
@@ -29737,6 +30122,8 @@ pnpm-debug.log*
|
|
|
29737
30122
|
import tailwindcss from "@tailwindcss/vite";
|
|
29738
30123
|
import { defineConfig, envField } from "astro/config";
|
|
29739
30124
|
{{#if (or (includes addons "electrobun") (includes addons "tauri"))}}
|
|
30125
|
+
{{else if (eq webDeploy "vercel")}}
|
|
30126
|
+
import vercel from "@astrojs/vercel";
|
|
29740
30127
|
{{else}}
|
|
29741
30128
|
import node from "@astrojs/node";
|
|
29742
30129
|
{{/if}}
|
|
@@ -29745,6 +30132,9 @@ import node from "@astrojs/node";
|
|
|
29745
30132
|
export default defineConfig({
|
|
29746
30133
|
{{#if (or (includes addons "electrobun") (includes addons "tauri"))}}
|
|
29747
30134
|
output: "static",
|
|
30135
|
+
{{else if (eq webDeploy "vercel")}}
|
|
30136
|
+
output: "server",
|
|
30137
|
+
adapter: vercel(),
|
|
29748
30138
|
{{else}}
|
|
29749
30139
|
output: "server",
|
|
29750
30140
|
adapter: node({ mode: "standalone" }),
|
|
@@ -29905,9 +30295,6 @@ const { title = "{{projectName}}" } = Astro.props;
|
|
|
29905
30295
|
`],
|
|
29906
30296
|
["frontend/astro/src/pages/index.astro.hbs", `---
|
|
29907
30297
|
import Layout from "../layouts/Layout.astro";
|
|
29908
|
-
{{#if (eq api "orpc")}}
|
|
29909
|
-
import { orpc } from "../lib/orpc";
|
|
29910
|
-
{{/if}}
|
|
29911
30298
|
|
|
29912
30299
|
const TITLE_TEXT = \`
|
|
29913
30300
|
██████╗ ███████╗████████╗████████╗███████╗██████╗
|
|
@@ -34429,10 +34816,16 @@ export function ThemeProvider({
|
|
|
34429
34816
|
}
|
|
34430
34817
|
`],
|
|
34431
34818
|
["frontend/react/react-router/public/favicon.ico", `[Binary file]`],
|
|
34432
|
-
["frontend/react/react-router/react-router.config.ts", `import type { Config } from "@react-router/dev/config";
|
|
34819
|
+
["frontend/react/react-router/react-router.config.ts.hbs", `import type { Config } from "@react-router/dev/config";
|
|
34433
34820
|
|
|
34434
34821
|
export default {
|
|
34822
|
+
{{#if (and (eq webDeploy "vercel") (not (or (includes addons "tauri") (includes addons "electrobun"))))}}
|
|
34823
|
+
// Adopt vercelPreset() once @vercel/react-router supports RR8 (vercel/vercel#16730)
|
|
34824
|
+
{{/if}}
|
|
34825
|
+
{{#if (or (includes addons "tauri") (includes addons "electrobun"))}}
|
|
34826
|
+
// Desktop addons package static web assets; SSR output cannot be bundled
|
|
34435
34827
|
ssr: false,
|
|
34828
|
+
{{/if}}
|
|
34436
34829
|
appDirectory: "src",
|
|
34437
34830
|
} satisfies Config;
|
|
34438
34831
|
`],
|
|
@@ -34910,6 +35303,12 @@ export default defineConfig({
|
|
|
34910
35303
|
reactRouter(),
|
|
34911
35304
|
tsconfigPaths(),
|
|
34912
35305
|
],
|
|
35306
|
+
{{#if (and (eq webDeploy "vercel") (not (or (includes addons "tauri") (includes addons "electrobun"))))}}
|
|
35307
|
+
ssr: {
|
|
35308
|
+
// Vercel functions have no node_modules; bundle all deps into the server build
|
|
35309
|
+
noExternal: true,
|
|
35310
|
+
},
|
|
35311
|
+
{{/if}}
|
|
34913
35312
|
});
|
|
34914
35313
|
`],
|
|
34915
35314
|
["frontend/react/tanstack-router/index.html.hbs", `<!DOCTYPE html>
|
|
@@ -35480,6 +35879,10 @@ export function getRouter() {
|
|
|
35480
35879
|
}
|
|
35481
35880
|
{{else}}
|
|
35482
35881
|
{{#if (eq api "trpc")}}
|
|
35882
|
+
{{#unless (eq backend "self")}}
|
|
35883
|
+
{{> getServerUrl}}
|
|
35884
|
+
|
|
35885
|
+
{{/unless}}
|
|
35483
35886
|
function createQueryClient() {
|
|
35484
35887
|
return new QueryClient({
|
|
35485
35888
|
queryCache: new QueryCache({
|
|
@@ -35501,7 +35904,7 @@ function createQueryClient() {
|
|
|
35501
35904
|
const trpcClient = createTRPCClient<AppRouter>({
|
|
35502
35905
|
links: [
|
|
35503
35906
|
httpBatchLink({
|
|
35504
|
-
url: {{#if (eq backend "self")}}"/api/trpc"{{else}}\`\${env.VITE_SERVER_URL}/trpc\`{{/if}},
|
|
35907
|
+
url: {{#if (eq backend "self")}}"/api/trpc"{{else}}\`\${getServerUrl(env.VITE_SERVER_URL)}/trpc\`{{/if}},
|
|
35505
35908
|
{{#if (eq auth "clerk")}}
|
|
35506
35909
|
headers: async () => {
|
|
35507
35910
|
const token = await getClerkAuthToken();
|
|
@@ -35944,7 +36347,7 @@ function HomeComponent() {
|
|
|
35944
36347
|
`],
|
|
35945
36348
|
["frontend/react/tanstack-start/vite.config.ts.hbs", `import { defineConfig } from "{{#if (includes addons "vite-plus")}}vite-plus{{else}}vite{{/if}}";
|
|
35946
36349
|
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
|
|
35947
|
-
{{#if (eq webDeploy "docker")}}
|
|
36350
|
+
{{#if (or (eq webDeploy "docker") (eq webDeploy "vercel"))}}
|
|
35948
36351
|
import { nitro } from "nitro/vite";
|
|
35949
36352
|
{{/if}}
|
|
35950
36353
|
import tailwindcss from "@tailwindcss/vite";
|
|
@@ -35966,12 +36369,17 @@ export default defineConfig({
|
|
|
35966
36369
|
},
|
|
35967
36370
|
},
|
|
35968
36371
|
{{/if}}),
|
|
35969
|
-
{{#if (eq webDeploy "docker")}}
|
|
36372
|
+
{{#if (or (eq webDeploy "docker") (eq webDeploy "vercel"))}}
|
|
35970
36373
|
nitro(),
|
|
35971
36374
|
{{/if}}
|
|
35972
36375
|
viteReact(),
|
|
35973
36376
|
],
|
|
35974
|
-
{{#if (
|
|
36377
|
+
{{#if (eq webDeploy "vercel")}}
|
|
36378
|
+
// Bundle all SSR deps: Vercel functions have no node_modules at runtime
|
|
36379
|
+
ssr: {
|
|
36380
|
+
noExternal: true,
|
|
36381
|
+
},
|
|
36382
|
+
{{else if (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
35975
36383
|
ssr: {
|
|
35976
36384
|
noExternal: ["@convex-dev/better-auth"],
|
|
35977
36385
|
},
|
|
@@ -36767,6 +37175,8 @@ import adapter from '@sveltejs/adapter-static';
|
|
|
36767
37175
|
import alchemy from 'alchemy/cloudflare/sveltekit';
|
|
36768
37176
|
{{else if (eq webDeploy "docker")}}
|
|
36769
37177
|
import adapter from '@sveltejs/adapter-node';
|
|
37178
|
+
{{else if (eq webDeploy "vercel")}}
|
|
37179
|
+
import adapter from '@sveltejs/adapter-vercel';
|
|
36770
37180
|
{{else}}
|
|
36771
37181
|
import adapter from '@sveltejs/adapter-auto';
|
|
36772
37182
|
{{/if}}
|
|
@@ -36792,6 +37202,8 @@ const config = {
|
|
|
36792
37202
|
{{else if (eq webDeploy "docker")}}
|
|
36793
37203
|
// adapter-node builds a standalone Node server (run with \`node build/index.js\`).
|
|
36794
37204
|
adapter: adapter()
|
|
37205
|
+
{{else if (eq webDeploy "vercel")}}
|
|
37206
|
+
adapter: adapter()
|
|
36795
37207
|
{{else}}
|
|
36796
37208
|
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
|
|
36797
37209
|
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
|
@@ -37022,6 +37434,33 @@ import "dotenv/config";
|
|
|
37022
37434
|
import { createEnv } from "@t3-oss/env-core";
|
|
37023
37435
|
import { z } from "zod";
|
|
37024
37436
|
|
|
37437
|
+
{{#if (or (eq webDeploy "vercel") (eq serverDeploy "vercel"))}}
|
|
37438
|
+
function getVercelOrigin() {
|
|
37439
|
+
const vercelUrl =
|
|
37440
|
+
process.env.VERCEL_ENV === "production"
|
|
37441
|
+
? (process.env.VERCEL_PROJECT_PRODUCTION_URL ?? process.env.VERCEL_URL)
|
|
37442
|
+
: (process.env.VERCEL_URL ?? process.env.VERCEL_PROJECT_PRODUCTION_URL);
|
|
37443
|
+
if (!vercelUrl) return undefined;
|
|
37444
|
+
return vercelUrl.startsWith("http") ? vercelUrl : \`https://\${vercelUrl}\`;
|
|
37445
|
+
}
|
|
37446
|
+
|
|
37447
|
+
const vercelOrigin = getVercelOrigin();
|
|
37448
|
+
|
|
37449
|
+
const runtimeEnv = {
|
|
37450
|
+
...process.env,
|
|
37451
|
+
{{#if (eq auth "better-auth")}}
|
|
37452
|
+
{{#if (and (eq webDeploy "vercel") (eq serverDeploy "vercel") (ne backend "self"))}}
|
|
37453
|
+
// Public auth base: /api/auth bypasses the rewrite's path strip, so the
|
|
37454
|
+
// same URL works for incoming matching and generated callbacks
|
|
37455
|
+
BETTER_AUTH_URL: process.env.BETTER_AUTH_URL ?? (vercelOrigin ? \`\${vercelOrigin}/api/auth\` : undefined),
|
|
37456
|
+
{{else}}
|
|
37457
|
+
BETTER_AUTH_URL: process.env.BETTER_AUTH_URL ?? vercelOrigin,
|
|
37458
|
+
{{/if}}
|
|
37459
|
+
{{/if}}
|
|
37460
|
+
CORS_ORIGIN: process.env.CORS_ORIGIN ?? vercelOrigin,
|
|
37461
|
+
};
|
|
37462
|
+
|
|
37463
|
+
{{/if}}
|
|
37025
37464
|
export const env = createEnv({
|
|
37026
37465
|
server: {
|
|
37027
37466
|
{{#if (ne database "none")}}
|
|
@@ -37053,7 +37492,7 @@ export const env = createEnv({
|
|
|
37053
37492
|
CORS_ORIGIN: z.url(),
|
|
37054
37493
|
NODE_ENV: z.enum(["development", "production", "test"]).default("development"),
|
|
37055
37494
|
},
|
|
37056
|
-
runtimeEnv: process.env,
|
|
37495
|
+
runtimeEnv: {{#if (or (eq webDeploy "vercel") (eq serverDeploy "vercel"))}}runtimeEnv{{else}}process.env{{/if}},
|
|
37057
37496
|
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
|
|
37058
37497
|
emptyStringAsUndefined: true,
|
|
37059
37498
|
});
|
|
@@ -37070,6 +37509,13 @@ import { createEnv } from "@t3-oss/env-core";
|
|
|
37070
37509
|
{{/if}}
|
|
37071
37510
|
import { z } from "zod";
|
|
37072
37511
|
|
|
37512
|
+
{{#if (and (eq webDeploy "vercel") (eq serverDeploy "vercel") (ne backend "self") (ne backend "none") (ne backend "convex"))}}
|
|
37513
|
+
const serverUrlSchema = z.union([
|
|
37514
|
+
z.url(),
|
|
37515
|
+
z.string().regex(/^\\/(?!\\/)/, "Use an absolute URL or a same-origin path like /api"),
|
|
37516
|
+
]);
|
|
37517
|
+
|
|
37518
|
+
{{/if}}
|
|
37073
37519
|
{{#if (eq backend "convex")}}
|
|
37074
37520
|
const convexUrlSchema = (exampleHost: string) =>
|
|
37075
37521
|
z.url().refine((url) => new URL(url).hostname !== exampleHost, {
|
|
@@ -37155,7 +37601,7 @@ export const env = createEnv({
|
|
|
37155
37601
|
{{else if (ne backend "none")}}
|
|
37156
37602
|
{{#if (includes frontend "next")}}
|
|
37157
37603
|
client: {
|
|
37158
|
-
NEXT_PUBLIC_SERVER_URL: z.url(),
|
|
37604
|
+
NEXT_PUBLIC_SERVER_URL: {{#if (and (eq webDeploy "vercel") (eq serverDeploy "vercel"))}}serverUrlSchema{{else}}z.url(){{/if}},
|
|
37159
37605
|
{{#if (eq auth "clerk")}}
|
|
37160
37606
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
|
|
37161
37607
|
{{/if}}
|
|
@@ -37168,18 +37614,18 @@ export const env = createEnv({
|
|
|
37168
37614
|
},
|
|
37169
37615
|
{{else if (includes frontend "nuxt")}}
|
|
37170
37616
|
client: {
|
|
37171
|
-
NUXT_PUBLIC_SERVER_URL: z.url(),
|
|
37617
|
+
NUXT_PUBLIC_SERVER_URL: {{#if (and (eq webDeploy "vercel") (eq serverDeploy "vercel"))}}serverUrlSchema{{else}}z.url(){{/if}},
|
|
37172
37618
|
},
|
|
37173
37619
|
{{else if (or (includes frontend "svelte") (includes frontend "astro"))}}
|
|
37174
37620
|
clientPrefix: "PUBLIC_",
|
|
37175
37621
|
client: {
|
|
37176
|
-
PUBLIC_SERVER_URL: z.url(),
|
|
37622
|
+
PUBLIC_SERVER_URL: {{#if (and (eq webDeploy "vercel") (eq serverDeploy "vercel"))}}serverUrlSchema{{else}}z.url(){{/if}},
|
|
37177
37623
|
},
|
|
37178
37624
|
runtimeEnv: (import.meta as any).env,
|
|
37179
37625
|
{{else}}
|
|
37180
37626
|
clientPrefix: "VITE_",
|
|
37181
37627
|
client: {
|
|
37182
|
-
VITE_SERVER_URL: z.url(),
|
|
37628
|
+
VITE_SERVER_URL: {{#if (and (eq webDeploy "vercel") (eq serverDeploy "vercel"))}}serverUrlSchema{{else}}z.url(){{/if}},
|
|
37183
37629
|
{{#if (eq auth "clerk")}}
|
|
37184
37630
|
VITE_CLERK_PUBLISHABLE_KEY: z.string().min(1),
|
|
37185
37631
|
{{/if}}
|
|
@@ -39644,6 +40090,6 @@ function SuccessPage() {
|
|
|
39644
40090
|
]);
|
|
39645
40091
|
const TEMPLATE_COUNT = 506;
|
|
39646
40092
|
//#endregion
|
|
39647
|
-
export { EMBEDDED_TEMPLATES, GeneratorError, Handlebars, TEMPLATE_COUNT, VirtualFileSystem, dependencyVersionMap, generate, generateReproducibleCommand, isBinaryFile, processAddonTemplates, processAddonsDeps, processFileContent, processNxConfig, processPackageConfigs, processTemplateString, processTurboConfig, processVitePlusConfig, transformFilename, writeBtsConfigToVfs };
|
|
40093
|
+
export { EMBEDDED_TEMPLATES, GeneratorError, Handlebars, TEMPLATE_COUNT, VirtualFileSystem, dependencyVersionMap, generate, generateReproducibleCommand, isBinaryFile, processAddonTemplates, processAddonsDeps, processFileContent, processNxConfig, processPackageConfigs, processTemplateString, processTurboConfig, processVercelConfig, processVitePlusConfig, transformFilename, writeBtsConfigToVfs };
|
|
39648
40094
|
|
|
39649
40095
|
//# sourceMappingURL=index.mjs.map
|