@better-t-stack/template-generator 3.23.1 → 3.25.3

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.mjs CHANGED
@@ -4,6 +4,7 @@ import { memfs } from "memfs";
4
4
  import { dirname, extname, join, normalize } from "pathe";
5
5
  import Handlebars from "handlebars";
6
6
  import yaml from "yaml";
7
+ import { desktopWebFrontends } from "@better-t-stack/types";
7
8
  import { IndentationText, Node, Project, QuoteKind, SyntaxKind } from "ts-morph";
8
9
 
9
10
  //#region src/types.ts
@@ -267,6 +268,7 @@ const PACKAGE_PATHS = [
267
268
  "apps/server",
268
269
  "apps/web",
269
270
  "apps/native",
271
+ "apps/desktop",
270
272
  "apps/fumadocs",
271
273
  "apps/docs",
272
274
  "packages/api",
@@ -408,6 +410,10 @@ function getDbScriptSupport(config) {
408
410
  //#endregion
409
411
  //#region src/post-process/package-configs.ts
410
412
  /**
413
+ * Package.json configuration post-processor
414
+ * Updates package names, scripts, and workspaces after template generation
415
+ */
416
+ /**
411
417
  * Update all package.json files with proper names, scripts, and workspaces
412
418
  */
413
419
  function processPackageConfigs(vfs, config) {
@@ -416,6 +422,7 @@ function processPackageConfigs(vfs, config) {
416
422
  updateEnvPackageJson(vfs, config);
417
423
  updateUiPackageJson(vfs, config);
418
424
  updateInfraPackageJson(vfs, config);
425
+ updateDesktopPackageJson(vfs, config);
419
426
  renameDevScriptsForAlchemy(vfs, config);
420
427
  if (config.backend === "convex") updateConvexPackageJson(vfs, config);
421
428
  else if (config.backend !== "none") {
@@ -435,16 +442,7 @@ function updateRootPackageJson(vfs, config) {
435
442
  pkgJson.workspaces = workspaces;
436
443
  const scripts = pkgJson.scripts;
437
444
  const { projectName, packageManager, backend, database, orm, dbSetup, addons, frontend } = config;
438
- const hasWebApp = frontend.some((item) => [
439
- "tanstack-router",
440
- "react-router",
441
- "tanstack-start",
442
- "next",
443
- "nuxt",
444
- "svelte",
445
- "solid",
446
- "astro"
447
- ].includes(item));
445
+ const hasWebApp = frontend.some((item) => desktopWebFrontends.includes(item));
448
446
  const hasNativeApp = frontend.some((item) => [
449
447
  "native-bare",
450
448
  "native-uniwind",
@@ -466,6 +464,11 @@ function updateRootPackageJson(vfs, config) {
466
464
  scripts["check-types"] = pmConfig.checkTypes;
467
465
  if (hasNativeApp) scripts["dev:native"] = pmConfig.filter("native", "dev");
468
466
  if (hasWebApp) scripts["dev:web"] = pmConfig.filter("web", "dev");
467
+ if (addons.includes("electrobun")) {
468
+ scripts["dev:desktop"] = pmConfig.filter("desktop", "dev:hmr");
469
+ scripts["build:desktop"] = pmConfig.filter("desktop", "build:stable");
470
+ scripts["build:desktop:canary"] = pmConfig.filter("desktop", "build:canary");
471
+ }
469
472
  if (addons.includes("opentui")) scripts["dev:tui"] = pmConfig.filter("tui", "dev");
470
473
  if (backend !== "self" && backend !== "none") scripts["dev:server"] = pmConfig.filter(backendPackageName, "dev");
471
474
  if (backend === "convex") scripts["dev:setup"] = pmConfig.filter(backendPackageName, "dev:setup");
@@ -537,6 +540,53 @@ function getPackageManagerConfig(packageManager, options) {
537
540
  };
538
541
  }
539
542
  }
543
+ function updateDesktopPackageJson(vfs, config) {
544
+ const pkgJson = vfs.readJson("apps/desktop/package.json");
545
+ if (!pkgJson) return;
546
+ const { packageManager, addons, frontend } = config;
547
+ const hasTurborepo = addons.includes("turborepo");
548
+ const hasNx = addons.includes("nx");
549
+ const desktopBuildScript = frontend.includes("nuxt") ? "generate" : "build";
550
+ const webBuildCommand = getDesktopWebCommand(packageManager, {
551
+ hasTurborepo,
552
+ hasNx
553
+ }, desktopBuildScript);
554
+ const webDevCommand = getDesktopWebCommand(packageManager, {
555
+ hasTurborepo,
556
+ hasNx
557
+ }, "dev");
558
+ const localRunCommand = getLocalRunCommand(packageManager);
559
+ pkgJson.scripts = {
560
+ ...pkgJson.scripts,
561
+ start: `${webBuildCommand} && electrobun dev`,
562
+ dev: "electrobun dev --watch",
563
+ "dev:hmr": `concurrently "${localRunCommand} hmr" "${localRunCommand} start"`,
564
+ hmr: webDevCommand,
565
+ build: `${webBuildCommand} && electrobun build`,
566
+ "build:stable": `${webBuildCommand} && electrobun build --env=stable`,
567
+ "build:canary": `${webBuildCommand} && electrobun build --env=canary`,
568
+ "check-types": "tsc --noEmit"
569
+ };
570
+ vfs.writeJson("apps/desktop/package.json", pkgJson);
571
+ }
572
+ function getDesktopWebCommand(packageManager, options, script) {
573
+ if (options.hasTurborepo) return `turbo -F web ${script}`;
574
+ if (options.hasNx) return `nx run-many -t ${script} --projects=web`;
575
+ switch (packageManager) {
576
+ case "npm": return `npm run ${script} --workspace web`;
577
+ case "pnpm": return `pnpm -w --filter web ${script}`;
578
+ case "bun":
579
+ default: return `bun run --filter web ${script}`;
580
+ }
581
+ }
582
+ function getLocalRunCommand(packageManager) {
583
+ switch (packageManager) {
584
+ case "npm": return "npm run";
585
+ case "pnpm": return "pnpm run";
586
+ case "bun":
587
+ default: return "bun run";
588
+ }
589
+ }
540
590
  function updateDbPackageJson(vfs, config) {
541
591
  const pkgJson = vfs.readJson("packages/db/package.json");
542
592
  if (!pkgJson) return;
@@ -551,6 +601,7 @@ function updateDbPackageJson(vfs, config) {
551
601
  scripts["db:push"] = "prisma db push";
552
602
  scripts["db:generate"] = "prisma generate";
553
603
  scripts["db:migrate"] = "prisma migrate dev";
604
+ scripts.postinstall ??= "prisma generate";
554
605
  if (!isD1Alchemy) scripts["db:studio"] = "prisma studio";
555
606
  } else if (orm === "drizzle") {
556
607
  scripts["db:push"] = "drizzle-kit push";
@@ -591,15 +642,7 @@ function updateEnvPackageJson(vfs, config) {
591
642
  const pkgJson = vfs.readJson("packages/env/package.json");
592
643
  if (!pkgJson) return;
593
644
  pkgJson.name = `@${config.projectName}/env`;
594
- const hasWebFrontend = config.frontend.some((f) => [
595
- "tanstack-router",
596
- "react-router",
597
- "tanstack-start",
598
- "next",
599
- "nuxt",
600
- "svelte",
601
- "solid"
602
- ].includes(f));
645
+ const hasWebFrontend = config.frontend.some((f) => desktopWebFrontends.includes(f));
603
646
  const hasNative = config.frontend.some((f) => [
604
647
  "native-bare",
605
648
  "native-uniwind",
@@ -755,8 +798,9 @@ const dependencyVersionMap = {
755
798
  "nitro-cloudflare-dev": "^0.2.2",
756
799
  "@sveltejs/adapter-cloudflare": "^7.2.4",
757
800
  "@cloudflare/workers-types": "^4.20251213.0",
758
- "@astrojs/cloudflare": "^12.6.12",
759
- alchemy: "^0.82.1",
801
+ "@astrojs/cloudflare": "^13.0.1",
802
+ "@astrojs/node": "^10.0.0-beta.9",
803
+ alchemy: "^0.87.0",
760
804
  dotenv: "^17.2.2",
761
805
  tsdown: "^0.16.5",
762
806
  zod: "^4.1.13",
@@ -2203,6 +2247,20 @@ function setupAIDependencies(vfs, config) {
2203
2247
  });
2204
2248
  }
2205
2249
 
2250
+ //#endregion
2251
+ //#region src/processors/frontend-deps.ts
2252
+ function processFrontendDeps(vfs, config) {
2253
+ const { frontend, webDeploy } = config;
2254
+ if (!frontend.includes("astro") || webDeploy === "cloudflare") return;
2255
+ const webPackagePath = "apps/web/package.json";
2256
+ if (!vfs.exists(webPackagePath)) return;
2257
+ addPackageDependency({
2258
+ vfs,
2259
+ packagePath: webPackagePath,
2260
+ dependencies: ["@astrojs/node"]
2261
+ });
2262
+ }
2263
+
2206
2264
  //#endregion
2207
2265
  //#region src/processors/infra-deps.ts
2208
2266
  function processInfraDeps(vfs, config) {
@@ -2374,6 +2432,18 @@ function processPwaPlugins(vfs, config) {
2374
2432
 
2375
2433
  //#endregion
2376
2434
  //#region src/processors/readme-generator.ts
2435
+ function getDesktopStaticBuildNote(frontend) {
2436
+ const staticBuildFrontends = new Map([
2437
+ ["tanstack-start", "TanStack Start"],
2438
+ ["next", "Next.js"],
2439
+ ["nuxt", "Nuxt"],
2440
+ ["svelte", "SvelteKit"],
2441
+ ["astro", "Astro"]
2442
+ ]);
2443
+ const staticBuildFrontend = frontend.find((value) => staticBuildFrontends.has(value));
2444
+ if (!staticBuildFrontend) return "";
2445
+ return `Desktop builds package static web assets. ${staticBuildFrontends.get(staticBuildFrontend)} needs a static/export build configuration before desktop packaging will work.`;
2446
+ }
2377
2447
  function processReadme(vfs, config) {
2378
2448
  const content = generateReadmeContent(config);
2379
2449
  vfs.writeFile("README.md", content);
@@ -2638,6 +2708,7 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
2638
2708
  const addonFeatures = {
2639
2709
  pwa: "- **PWA** - Progressive Web App support",
2640
2710
  tauri: "- **Tauri** - Build native desktop applications",
2711
+ electrobun: "- **Electrobun** - Lightweight desktop shell for web frontends",
2641
2712
  biome: "- **Biome** - Linting and formatting",
2642
2713
  oxlint: "- **Oxlint** - Oxlint + Oxfmt (linting & formatting)",
2643
2714
  husky: "- **Husky** - Git hooks for code quality",
@@ -2725,8 +2796,19 @@ function generateScriptsList(packageManagerRunCmd, config, hasNative) {
2725
2796
  if (addons.includes("biome")) scripts += `\n- \`${packageManagerRunCmd} check\`: Run Biome formatting and linting`;
2726
2797
  if (addons.includes("oxlint")) scripts += `\n- \`${packageManagerRunCmd} check\`: Run Oxlint and Oxfmt`;
2727
2798
  if (addons.includes("pwa")) scripts += `\n- \`cd apps/web && ${packageManagerRunCmd} generate-pwa-assets\`: Generate PWA assets`;
2728
- if (addons.includes("tauri")) scripts += `\n- \`cd apps/web && ${packageManagerRunCmd} desktop:dev\`: Start Tauri desktop app in development
2799
+ if (addons.includes("tauri")) {
2800
+ scripts += `\n- \`cd apps/web && ${packageManagerRunCmd} desktop:dev\`: Start Tauri desktop app in development
2729
2801
  - \`cd apps/web && ${packageManagerRunCmd} desktop:build\`: Build Tauri desktop app`;
2802
+ const staticBuildNote = getDesktopStaticBuildNote(frontend);
2803
+ if (staticBuildNote) scripts += `\n- Note: ${staticBuildNote}`;
2804
+ }
2805
+ if (addons.includes("electrobun")) {
2806
+ scripts += `\n- \`${packageManagerRunCmd} dev:desktop\`: Start the Electrobun desktop app with HMR
2807
+ - \`${packageManagerRunCmd} build:desktop\`: Build the stable Electrobun desktop app
2808
+ - \`${packageManagerRunCmd} build:desktop:canary\`: Build the canary Electrobun desktop app`;
2809
+ const staticBuildNote = getDesktopStaticBuildNote(frontend);
2810
+ if (staticBuildNote) scripts += `\n- Note: ${staticBuildNote}`;
2811
+ }
2730
2812
  if (addons.includes("starlight")) scripts += `\n- \`cd apps/docs && ${packageManagerRunCmd} dev\`: Start documentation site
2731
2813
  - \`cd apps/docs && ${packageManagerRunCmd} build\`: Build documentation site`;
2732
2814
  return scripts;
@@ -3035,6 +3117,7 @@ function getRuntimeDevDeps(runtime, backend) {
3035
3117
  //#region src/processors/index.ts
3036
3118
  function processDependencies(vfs, config) {
3037
3119
  processWorkspaceDeps(vfs, config);
3120
+ processFrontendDeps(vfs, config);
3038
3121
  processEnvDeps(vfs, config);
3039
3122
  processInfraDeps(vfs, config);
3040
3123
  processDatabaseDeps(vfs, config);
@@ -3440,7 +3523,7 @@ async function processExtrasTemplates(vfs, templates, config) {
3440
3523
  }
3441
3524
  if (config.packageManager === "bun") processTemplatesFromPrefix(vfs, templates, "extras/bunfig.toml", "", config);
3442
3525
  if (config.packageManager === "pnpm" && (hasNative || hasNuxt)) processTemplatesFromPrefix(vfs, templates, "extras/_npmrc", "", config);
3443
- if (config.serverDeploy === "cloudflare") processSingleTemplate(vfs, templates, "extras/env.d.ts", "packages/env/env.d.ts", config);
3526
+ if (config.serverDeploy === "cloudflare" || config.backend === "self" && config.webDeploy === "cloudflare") processSingleTemplate(vfs, templates, "extras/env.d.ts", "packages/env/env.d.ts", config);
3444
3527
  }
3445
3528
 
3446
3529
  //#endregion
@@ -3673,6 +3756,114 @@ const EMBEDDED_TEMPLATES = new Map([
3673
3756
  ]
3674
3757
  {{/if}}
3675
3758
  }
3759
+ `],
3760
+ ["addons/electrobun/apps/desktop/.gitignore", `artifacts
3761
+ `],
3762
+ ["addons/electrobun/apps/desktop/electrobun.config.ts.hbs", `import type { ElectrobunConfig } from "electrobun";
3763
+
3764
+ const webBuildDir =
3765
+ "{{#if (includes frontend "react-router")}}../web/build/client{{else if (includes frontend "tanstack-start")}}../web/dist/client{{else if (includes frontend "next")}}../web/out{{else if (includes frontend "nuxt")}}../web/.output/public{{else if (includes frontend "svelte")}}../web/build{{else}}../web/dist{{/if}}";
3766
+
3767
+ export default {
3768
+ app: {
3769
+ name: "{{projectName}}",
3770
+ identifier: "dev.bettertstack.{{projectName}}.desktop",
3771
+ version: "0.0.1",
3772
+ },
3773
+ runtime: {
3774
+ exitOnLastWindowClosed: true,
3775
+ },
3776
+ build: {
3777
+ bun: {
3778
+ entrypoint: "src/bun/index.ts",
3779
+ },
3780
+ copy: {
3781
+ [webBuildDir]: "views/mainview",
3782
+ },
3783
+ watchIgnore: [\`\${webBuildDir}/**\`],
3784
+ mac: {
3785
+ bundleCEF: true,
3786
+ defaultRenderer: "cef",
3787
+ },
3788
+ linux: {
3789
+ bundleCEF: true,
3790
+ defaultRenderer: "cef",
3791
+ },
3792
+ win: {
3793
+ bundleCEF: true,
3794
+ defaultRenderer: "cef",
3795
+ },
3796
+ },
3797
+ } satisfies ElectrobunConfig;
3798
+ `],
3799
+ ["addons/electrobun/apps/desktop/package.json.hbs", `{
3800
+ "name": "desktop",
3801
+ "private": true,
3802
+ "type": "module",
3803
+ "scripts": {},
3804
+ "dependencies": {
3805
+ "electrobun": "^1.15.1"
3806
+ },
3807
+ "devDependencies": {
3808
+ "@types/bun": "^1.3.4",
3809
+ "concurrently": "^9.1.0",
3810
+ "typescript": "^5"
3811
+ }
3812
+ }
3813
+ `],
3814
+ ["addons/electrobun/apps/desktop/src/bun/index.ts.hbs", `import { BrowserWindow, Updater } from "electrobun/bun";
3815
+
3816
+ const DEV_SERVER_PORT = {{#if (or (includes frontend "react-router") (includes frontend "svelte"))}}5173{{else if (includes frontend "astro")}}4321{{else}}3001{{/if}};
3817
+ const DEV_SERVER_URL = \`http://localhost:\${DEV_SERVER_PORT}\`;
3818
+
3819
+ // Check if the web dev server is running for HMR
3820
+ async function getMainViewUrl(): Promise<string> {
3821
+ const channel = await Updater.localInfo.channel();
3822
+ if (channel === "dev") {
3823
+ try {
3824
+ await fetch(DEV_SERVER_URL, { method: "HEAD" });
3825
+ console.log(\`HMR enabled: Using web dev server at \${DEV_SERVER_URL}\`);
3826
+ return DEV_SERVER_URL;
3827
+ } catch {
3828
+ console.log(
3829
+ 'Web dev server not running. Run "{{packageManager}} run dev:hmr" for HMR support.',
3830
+ );
3831
+ }
3832
+ }
3833
+
3834
+ return "views://mainview/index.html";
3835
+ }
3836
+
3837
+ const url = await getMainViewUrl();
3838
+
3839
+ new BrowserWindow({
3840
+ title: "{{projectName}}",
3841
+ url,
3842
+ frame: {
3843
+ width: 1280,
3844
+ height: 820,
3845
+ x: 120,
3846
+ y: 120,
3847
+ },
3848
+ });
3849
+
3850
+ console.log("Electrobun desktop shell started.");
3851
+ `],
3852
+ ["addons/electrobun/apps/desktop/tsconfig.json.hbs", `{
3853
+ "extends": "../../packages/config/tsconfig.base.json",
3854
+ "compilerOptions": {
3855
+ "lib": ["ESNext", "DOM"],
3856
+ "target": "ESNext",
3857
+ "module": "ESNext",
3858
+ "moduleResolution": "bundler",
3859
+ "noEmit": true,
3860
+ "baseUrl": ".",
3861
+ "paths": {
3862
+ "@/*": ["./src/*"]
3863
+ }
3864
+ },
3865
+ "include": ["src/**/*.ts", "electrobun.config.ts"]
3866
+ }
3676
3867
  `],
3677
3868
  ["addons/husky/.husky/pre-commit", `lint-staged
3678
3869
  `],
@@ -3773,142 +3964,6 @@ export default defineConfig({
3773
3964
  preset,
3774
3965
  images: ["public/logo.png"],
3775
3966
  });
3776
- `],
3777
- ["addons/ruler/.ruler/bts.md.hbs", `# Better-T-Stack Project Rules
3778
-
3779
- This is a {{projectName}} project created with Better-T-Stack CLI.
3780
-
3781
- ## Project Structure
3782
-
3783
- This is a monorepo with the following structure:
3784
-
3785
- {{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "tanstack-start")
3786
- (includes frontend "next") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
3787
- - **\`apps/web/\`** - {{#if (eq backend "self")}}Fullstack application{{else}}Frontend application{{/if}}{{#if (includes frontend "tanstack-router")}} (React with TanStack Router){{else if (includes frontend "react-router")}} (React with React Router){{else if (includes frontend "tanstack-start")}} (TanStack Start){{else if (includes frontend "next")}} (Next.js){{else if (includes frontend "nuxt")}} (Nuxt.js){{else if (includes frontend "svelte")}} (SvelteKit){{else if (includes frontend "solid")}} (SolidStart){{/if}}
3788
- {{/if}}
3789
-
3790
- {{#if (ne backend "convex")}}
3791
- {{#if (and (ne backend "none") (ne backend "self"))}}
3792
- - **\`apps/server/\`** - Backend server{{#if (eq backend "hono")}} (Hono){{else if (eq backend "express")}} (Express){{else if (eq backend "fastify")}} (Fastify){{else if (eq backend "elysia")}} (Elysia){{/if}}
3793
- {{/if}}
3794
- {{else}}
3795
- - **\`packages/backend/\`** - Convex backend functions
3796
- {{/if}}
3797
-
3798
- {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
3799
- - **\`apps/native/\`** - React Native mobile app{{#if (includes frontend "native-uniwind")}} (with NativeWind){{else if (includes frontend "native-unistyles")}} (with Unistyles){{else if (includes frontend "native-bare")}} (bare styling){{/if}}
3800
- {{/if}}
3801
-
3802
- {{#if (ne backend "convex")}}
3803
- {{#if (ne api "none")}}
3804
- - **\`packages/api/\`** - Shared API logic and types
3805
- {{/if}}
3806
- {{#if (and (ne auth "none") (ne backend "convex"))}}
3807
- - **\`packages/auth/\`** - Authentication logic and utilities
3808
- {{/if}}
3809
- {{#if (and (ne database "none") (ne orm "none"))}}
3810
- - **\`packages/db/\`** - Database schema and utilities
3811
- {{/if}}
3812
- - **\`packages/env/\`** - Shared environment variables and validation
3813
- - **\`packages/config/\`** - Shared TypeScript configuration
3814
- {{#if (or (eq webDeploy "cloudflare") (eq serverDeploy "cloudflare"))}}
3815
- - **\`packages/infra/\`** - Infrastructure as code (Alchemy for Cloudflare)
3816
- {{/if}}
3817
- {{/if}}
3818
-
3819
- ## Available Scripts
3820
-
3821
- - \`{{packageManager}} run dev\` - Start all apps in development mode
3822
- {{#if (and (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "tanstack-start")
3823
- (includes frontend "next") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid")) (ne backend "self"))}}
3824
- - \`{{packageManager}} run dev:web\` - Start only the web app
3825
- {{/if}}
3826
- {{#if (and (ne backend "none") (ne backend "convex") (ne backend "self"))}}
3827
- - \`{{packageManager}} run dev:server\` - Start only the server
3828
- {{/if}}
3829
- {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
3830
- - \`{{packageManager}} run dev:native\` - Start only the native app
3831
- {{/if}}
3832
- - \`{{packageManager}} run build\` - Build all apps
3833
- - \`{{packageManager}} run lint\` - Lint all packages
3834
- - \`{{packageManager}} run typecheck\` - Type check all packages
3835
-
3836
- {{#if (and (ne database "none") (ne orm "none") (ne backend "convex"))}}
3837
- ## Database Commands
3838
-
3839
- All database operations should be run from the {{#if (eq backend "self")}}web{{else}}server{{/if}} workspace:
3840
-
3841
- - \`{{packageManager}} run db:push\` - Push schema changes to database
3842
- - \`{{packageManager}} run db:studio\` - Open database studio
3843
- - \`{{packageManager}} run db:generate\` - Generate {{#if (eq orm "drizzle")}}Drizzle{{else if (eq orm "prisma")}}Prisma{{else}}{{orm}}{{/if}} files
3844
- - \`{{packageManager}} run db:migrate\` - Run database migrations
3845
-
3846
- {{#if (eq orm "drizzle")}}
3847
- Database schema files are located in {{#if (eq backend "self")}}\`apps/web/src/db/schema/\`{{else}}\`packages/db/src/schema/\`{{/if}}
3848
- {{else if (eq orm "prisma")}}
3849
- Database schema is located in {{#if (eq backend "self")}}\`apps/web/prisma/schema.prisma\`{{else}}\`packages/db/prisma/schema.prisma\`{{/if}}
3850
- {{else if (eq orm "mongoose")}}
3851
- Database models are located in {{#if (eq backend "self")}}\`apps/web/src/db/models/\`{{else}}\`packages/db/src/models/\`{{/if}}
3852
- {{/if}}
3853
- {{/if}}
3854
-
3855
- {{#if (ne api "none")}}
3856
- ## API Structure
3857
-
3858
- {{#if (eq api "trpc")}}
3859
- - tRPC routers are in \`packages/api/src/routers/\`
3860
- - Client-side tRPC utils are in \`apps/web/src/utils/trpc.ts\`
3861
- {{else if (eq api "orpc")}}
3862
- - oRPC contracts and routers are in \`packages/api/src/\`
3863
- - Client-side oRPC client is in \`apps/web/src/utils/orpc.ts\`
3864
- {{/if}}
3865
- {{/if}}
3866
-
3867
- {{#if (eq auth "better-auth")}}
3868
- ## Authentication
3869
-
3870
- Authentication is powered by Better Auth:
3871
- - Auth configuration is in \`packages/auth/src/\`
3872
- {{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "tanstack-start")
3873
- (includes frontend "next") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
3874
- - Web app auth client is in \`apps/web/src/lib/auth-client.ts\`
3875
- {{/if}}
3876
- {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
3877
- - Native app auth client is in \`apps/native/src/lib/auth-client.ts\`
3878
- {{/if}}
3879
- {{/if}}
3880
-
3881
- ## Project Configuration
3882
-
3883
- This project includes a \`bts.jsonc\` configuration file that stores your Better-T-Stack settings:
3884
-
3885
- - Contains your selected stack configuration (database, ORM, backend, frontend, etc.)
3886
- - Used by the CLI to understand your project structure
3887
- - Safe to delete if not needed
3888
-
3889
- ## Key Points
3890
-
3891
- - This is a {{#if (includes addons "turborepo")}}Turborepo {{/if}}monorepo using {{packageManager}} workspaces
3892
- - Each app has its own \`package.json\` and dependencies
3893
- - Run commands from the root to execute across all workspaces
3894
- - Run workspace-specific commands with \`{{packageManager}} run command-name\`
3895
- {{#if (includes addons "turborepo")}}
3896
- - Turborepo handles build caching and parallel execution
3897
- {{/if}}
3898
- {{#if (or (includes addons "husky") (includes addons "lefthook"))}}
3899
- - Git hooks are configured with {{#if (includes addons "husky")}}Husky{{else}}Lefthook{{/if}} for pre-commit checks
3900
- {{/if}}
3901
- `],
3902
- ["addons/ruler/.ruler/ruler.toml.hbs", `# Ruler Configuration File
3903
- # See https://okigu.com/ruler for documentation.
3904
-
3905
- # Default agents to run when --agents is not specified
3906
- default_agents = []
3907
-
3908
- # --- Global .gitignore Configuration ---
3909
- [gitignore]
3910
- # Enable/disable automatic .gitignore updates (default: true)
3911
- enabled = true
3912
3967
  `],
3913
3968
  ["api/orpc/fullstack/astro/src/pages/rpc/[...rest].ts.hbs", `import type { APIRoute } from "astro";
3914
3969
  import { RPCHandler } from "@orpc/server/fetch";
@@ -4172,24 +4227,23 @@ export const queryClient = new QueryClient({
4172
4227
 
4173
4228
  export const link = new RPCLink({
4174
4229
  {{#if (eq backend "self")}}
4175
- {{#unless (includes frontend "astro")}}
4230
+ {{#if (or (includes frontend "next") (includes frontend "tanstack-start"))}}
4176
4231
  url: \`\${env.EXPO_PUBLIC_SERVER_URL}/api/rpc\`,
4177
4232
  {{else}}
4178
4233
  url: \`\${env.EXPO_PUBLIC_SERVER_URL}/rpc\`,
4179
- {{/unless}}
4234
+ {{/if}}
4180
4235
  {{else}}
4181
4236
  url: \`\${env.EXPO_PUBLIC_SERVER_URL}/rpc\`,
4182
4237
  {{/if}}
4183
4238
  {{#if (eq auth "better-auth")}}
4184
4239
  fetch:
4185
- Platform.OS !== "web"
4186
- ? undefined
4187
- : function (url, options) {
4188
- return fetch(url, {
4189
- ...options,
4190
- credentials: "include",
4191
- });
4192
- },
4240
+ function (url, options) {
4241
+ return fetch(url, {
4242
+ ...options,
4243
+ // Better Auth Expo forwards the session cookie manually on native.
4244
+ credentials: Platform.OS === "web" ? "include" : "omit",
4245
+ });
4246
+ },
4193
4247
  headers() {
4194
4248
  if (Platform.OS === "web") {
4195
4249
  return {};
@@ -4877,14 +4931,13 @@ const trpcClient = createTRPCClient<AppRouter>({
4877
4931
  {{/if}}
4878
4932
  {{#if (eq auth "better-auth")}}
4879
4933
  fetch:
4880
- Platform.OS !== "web"
4881
- ? undefined
4882
- : function (url, options) {
4883
- return fetch(url, {
4884
- ...options,
4885
- credentials: "include",
4886
- });
4887
- },
4934
+ function (url, options) {
4935
+ return fetch(url, {
4936
+ ...options,
4937
+ // Better Auth Expo forwards the session cookie manually on native.
4938
+ credentials: Platform.OS === "web" ? "include" : "omit",
4939
+ });
4940
+ },
4888
4941
  headers() {
4889
4942
  if (Platform.OS === "web") {
4890
4943
  return {};
@@ -9911,6 +9964,8 @@ export const auth = betterAuth({
9911
9964
  emailAndPassword: {
9912
9965
  enabled: true,
9913
9966
  },
9967
+ secret: env.BETTER_AUTH_SECRET,
9968
+ baseURL: env.BETTER_AUTH_URL,
9914
9969
  {{#if (ne backend "self")}}
9915
9970
  advanced: {
9916
9971
  defaultCookieAttributes: {
@@ -9982,6 +10037,8 @@ export const auth = betterAuth({
9982
10037
  emailAndPassword: {
9983
10038
  enabled: true,
9984
10039
  },
10040
+ secret: env.BETTER_AUTH_SECRET,
10041
+ baseURL: env.BETTER_AUTH_URL,
9985
10042
  {{#if (ne backend "self")}}
9986
10043
  advanced: {
9987
10044
  defaultCookieAttributes: {
@@ -10129,6 +10186,8 @@ export const auth = betterAuth({
10129
10186
  emailAndPassword: {
10130
10187
  enabled: true,
10131
10188
  },
10189
+ secret: env.BETTER_AUTH_SECRET,
10190
+ baseURL: env.BETTER_AUTH_URL,
10132
10191
  {{#if (ne backend "self")}}
10133
10192
  advanced: {
10134
10193
  defaultCookieAttributes: {
@@ -10191,6 +10250,8 @@ export const auth = betterAuth({
10191
10250
  emailAndPassword: {
10192
10251
  enabled: true,
10193
10252
  },
10253
+ secret: env.BETTER_AUTH_SECRET,
10254
+ baseURL: env.BETTER_AUTH_URL,
10194
10255
  {{#if (ne backend "self")}}
10195
10256
  advanced: {
10196
10257
  defaultCookieAttributes: {
@@ -22663,7 +22724,11 @@ linker = "hoisted" # having issues with Nuxt when linker is isolated
22663
22724
  {{else}}
22664
22725
  linker = "isolated"
22665
22726
  {{/if}}`],
22666
- ["extras/env.d.ts.hbs", `import { type server } from "@{{projectName}}/infra/alchemy.run";
22727
+ ["extras/env.d.ts.hbs", `{{#if (eq serverDeploy "cloudflare")}}
22728
+ import { type server } from "@{{projectName}}/infra/alchemy.run";
22729
+ {{else}}
22730
+ import { type web as server } from "@{{projectName}}/infra/alchemy.run";
22731
+ {{/if}}
22667
22732
 
22668
22733
  // This file infers types for the cloudflare:workers environment from your Alchemy Worker.
22669
22734
  // @see https://alchemy.run/concepts/bindings/#type-safe-bindings
@@ -22746,8 +22811,7 @@ export default defineConfig({
22746
22811
  "astro": "astro"
22747
22812
  },
22748
22813
  "dependencies": {
22749
- "@astrojs/node": "^9.5.2",
22750
- "astro": "^5.16.11"
22814
+ "astro": "^6.0.1"
22751
22815
  },
22752
22816
  "devDependencies": {
22753
22817
  "@tailwindcss/vite": "^4.1.18",
@@ -28913,7 +28977,7 @@ export const env = createEnv({
28913
28977
  runtimeEnv: process.env,
28914
28978
  emptyStringAsUndefined: true,
28915
28979
  });`],
28916
- ["packages/env/src/server.ts.hbs", `{{#if (eq serverDeploy "cloudflare")}}
28980
+ ["packages/env/src/server.ts.hbs", `{{#if (or (eq serverDeploy "cloudflare") (and (eq backend "self") (eq webDeploy "cloudflare")))}}
28917
28981
  /// <reference path="../env.d.ts" />
28918
28982
  // For Cloudflare Workers, env is accessed via cloudflare:workers module
28919
28983
  // Types are defined in env.d.ts based on your alchemy.run.ts bindings
@@ -28951,7 +29015,8 @@ export const env = createEnv({
28951
29015
  runtimeEnv: process.env,
28952
29016
  emptyStringAsUndefined: true,
28953
29017
  });
28954
- {{/if}}`],
29018
+ {{/if}}
29019
+ `],
28955
29020
  ["packages/env/src/web.ts.hbs", `{{#if (includes frontend "next")}}
28956
29021
  import { createEnv } from "@t3-oss/env-nextjs";
28957
29022
  {{else if (includes frontend "nuxt")}}
@@ -29317,6 +29382,11 @@ export const web = await Vite("web", {
29317
29382
  {{else if (includes frontend "astro")}}
29318
29383
  export const web = await Astro("web", {
29319
29384
  cwd: "../../apps/web",
29385
+ entrypoint: "dist/server/entry.mjs",
29386
+ assets: "dist/client",
29387
+ {{#if (eq backend "self")}}
29388
+ compatibility: "node",
29389
+ {{/if}}
29320
29390
  bindings: {
29321
29391
  {{#if (ne backend "self")}}
29322
29392
  PUBLIC_SERVER_URL: alchemy.env.PUBLIC_SERVER_URL!,
@@ -30348,7 +30418,7 @@ function SuccessPage() {
30348
30418
  </div>
30349
30419
  `]
30350
30420
  ]);
30351
- const TEMPLATE_COUNT = 441;
30421
+ const TEMPLATE_COUNT = 444;
30352
30422
 
30353
30423
  //#endregion
30354
30424
  export { EMBEDDED_TEMPLATES, GeneratorError, Handlebars, TEMPLATE_COUNT, VirtualFileSystem, dependencyVersionMap, generate, generateReproducibleCommand, isBinaryFile, processAddonTemplates, processAddonsDeps, processFileContent, processTemplateString, transformFilename, writeBtsConfigToVfs };