@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/core/template-reader.d.mts.map +1 -1
- package/dist/fs-writer.d.mts.map +1 -1
- package/dist/fs-writer.mjs.map +1 -1
- package/dist/index.d.mts +4 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +253 -183
- package/dist/index.mjs.map +1 -1
- package/dist/template-reader-DOXCnctl.mjs.map +1 -1
- package/dist/types-zSU486rU.d.mts.map +1 -1
- package/package.json +2 -2
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": "^
|
|
759
|
-
|
|
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"))
|
|
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
|
-
{{#
|
|
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
|
-
{{/
|
|
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
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
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
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
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", `
|
|
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
|
-
"
|
|
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 =
|
|
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 };
|