create-better-fullstack 1.5.2 → 1.5.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { s as dependencyVersionMap, t as readBtsConfig } from "./bts-config-BCe8SqYV.mjs";
2
+ import { s as dependencyVersionMap, t as readBtsConfig } from "./bts-config-BYD8mHt-.mjs";
3
3
  import { autocompleteMultiselect, cancel, group, isCancel, log, multiselect, select, spinner } from "@clack/prompts";
4
4
  import pc from "picocolors";
5
5
  import fs from "fs-extra";
@@ -255,6 +255,35 @@ function shouldSkipExternalCommands() {
255
255
  return normalized === "1" || normalized === "true" || normalized === "yes";
256
256
  }
257
257
 
258
+ //#endregion
259
+ //#region src/helpers/addons/retry-install.ts
260
+ const DEFAULT_MAX_ATTEMPTS = 3;
261
+ const DEFAULT_INITIAL_DELAY_MS = 750;
262
+ const RETRY_BACKOFF_MULTIPLIER = 2;
263
+ function defaultSleep(ms) {
264
+ return new Promise((resolve) => setTimeout(resolve, ms));
265
+ }
266
+ function formatDelay(ms) {
267
+ return ms >= 1e3 ? `${(ms / 1e3).toFixed(ms % 1e3 === 0 ? 0 : 1)}s` : `${ms}ms`;
268
+ }
269
+ async function runInstallWithRetries({ description, run, maxAttempts = DEFAULT_MAX_ATTEMPTS, initialDelayMs = DEFAULT_INITIAL_DELAY_MS, sleep = defaultSleep }) {
270
+ let delayMs = initialDelayMs;
271
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
272
+ await run();
273
+ return true;
274
+ } catch (error) {
275
+ const message = error instanceof Error ? error.message : String(error);
276
+ if (attempt === maxAttempts) {
277
+ log.warn(pc.yellow(`Warning: Could not ${description} after ${maxAttempts} attempts: ${message}`));
278
+ return false;
279
+ }
280
+ log.warn(pc.yellow(`Warning: Failed to ${description} (attempt ${attempt}/${maxAttempts}): ${message}. Retrying in ${formatDelay(delayMs)}...`));
281
+ await sleep(delayMs);
282
+ delayMs *= RETRY_BACKOFF_MULTIPLIER;
283
+ }
284
+ return false;
285
+ }
286
+
258
287
  //#endregion
259
288
  //#region src/helpers/addons/mcp-setup.ts
260
289
  const MCP_AGENTS = [
@@ -489,14 +518,15 @@ async function setupMcp(config) {
489
518
  ...globalFlags,
490
519
  "-y"
491
520
  ];
492
- try {
493
- await $({
494
- cwd: projectDir,
495
- env: { CI: "true" }
496
- })`${args}`;
497
- } catch (error) {
498
- log.warn(pc.yellow(`Warning: Could not install MCP server '${server.name}': ${error instanceof Error ? error.message : String(error)}`));
499
- }
521
+ await runInstallWithRetries({
522
+ description: `install MCP server '${server.name}'`,
523
+ run: async () => {
524
+ await $({
525
+ cwd: projectDir,
526
+ env: { CI: "true" }
527
+ })`${args}`;
528
+ }
529
+ });
500
530
  }
501
531
  installSpinner.stop("MCP servers installed");
502
532
  }
@@ -912,14 +942,15 @@ async function setupSkills(config) {
912
942
  ...agentFlags,
913
943
  "-y"
914
944
  ];
915
- try {
916
- await $({
917
- cwd: projectDir,
918
- env: { CI: "true" }
919
- })`${args}`;
920
- } catch (error) {
921
- log.warn(pc.yellow(`Warning: Could not install skills from ${source}: ${error instanceof Error ? error.message : String(error)}`));
922
- }
945
+ await runInstallWithRetries({
946
+ description: `install skills from ${source}`,
947
+ run: async () => {
948
+ await $({
949
+ cwd: projectDir,
950
+ env: { CI: "true" }
951
+ })`${args}`;
952
+ }
953
+ });
923
954
  }
924
955
  installSpinner.stop("Skills installed");
925
956
  }
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import "./bts-config-BYD8mHt-.mjs";
3
+ import { i as setupLefthook, n as setupBiome, r as setupHusky, t as setupAddons } from "./addons-setup-Bll5VFJd.mjs";
4
+
5
+ export { setupAddons };
@@ -72,6 +72,7 @@ const DEFAULT_CONFIG_BASE = {
72
72
  rustApi: "none",
73
73
  rustCli: "none",
74
74
  rustLibraries: [],
75
+ rustLogging: "tracing",
75
76
  pythonWebFramework: "fastapi",
76
77
  pythonOrm: "sqlalchemy",
77
78
  pythonValidation: "pydantic",
@@ -181,6 +182,7 @@ async function writeBtsConfig(projectConfig) {
181
182
  rustApi: projectConfig.rustApi,
182
183
  rustCli: projectConfig.rustCli,
183
184
  rustLibraries: projectConfig.rustLibraries,
185
+ rustLogging: projectConfig.rustLogging,
184
186
  pythonWebFramework: projectConfig.pythonWebFramework,
185
187
  pythonOrm: projectConfig.pythonOrm,
186
188
  pythonValidation: projectConfig.pythonValidation,
@@ -241,6 +243,7 @@ async function writeBtsConfig(projectConfig) {
241
243
  rustApi: btsConfig.rustApi,
242
244
  rustCli: btsConfig.rustCli,
243
245
  rustLibraries: btsConfig.rustLibraries,
246
+ rustLogging: btsConfig.rustLogging,
244
247
  pythonWebFramework: btsConfig.pythonWebFramework,
245
248
  pythonOrm: btsConfig.pythonOrm,
246
249
  pythonValidation: btsConfig.pythonValidation,
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  //#region src/cli.ts
3
- if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-C_X1WfCg.mjs").then((m) => m.startMcpServer());
3
+ if (process.argv[2] === "mcp" && process.argv.length === 3) import("./mcp-CRjipp-w.mjs").then((m) => m.startMcpServer());
4
4
  else import("./index.mjs").then((m) => m.createBtsCli().run());
5
5
 
6
6
  //#endregion
package/dist/index.d.mts CHANGED
@@ -30,6 +30,7 @@ declare const router: {
30
30
  yes: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
31
31
  yolo: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
32
32
  verbose: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
33
+ dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
33
34
  ecosystem: z.ZodOptional<z.ZodEnum<{
34
35
  typescript: "typescript";
35
36
  rust: "rust";
@@ -208,6 +209,7 @@ declare const router: {
208
209
  meilisearch: "meilisearch";
209
210
  typesense: "typesense";
210
211
  elasticsearch: "elasticsearch";
212
+ algolia: "algolia";
211
213
  }>>;
212
214
  fileStorage: z.ZodOptional<z.ZodEnum<{
213
215
  none: "none";
@@ -472,10 +474,16 @@ declare const router: {
472
474
  "tokio-test": "tokio-test";
473
475
  mockall: "mockall";
474
476
  }>>>;
477
+ rustLogging: z.ZodOptional<z.ZodEnum<{
478
+ none: "none";
479
+ tracing: "tracing";
480
+ "env-logger": "env-logger";
481
+ }>>;
475
482
  pythonWebFramework: z.ZodOptional<z.ZodEnum<{
476
483
  none: "none";
477
484
  fastapi: "fastapi";
478
485
  django: "django";
486
+ flask: "flask";
479
487
  }>>;
480
488
  pythonOrm: z.ZodOptional<z.ZodEnum<{
481
489
  none: "none";
@@ -507,6 +515,7 @@ declare const router: {
507
515
  none: "none";
508
516
  gin: "gin";
509
517
  echo: "echo";
518
+ fiber: "fiber";
510
519
  }>>;
511
520
  goOrm: z.ZodOptional<z.ZodEnum<{
512
521
  none: "none";
@@ -575,7 +584,90 @@ declare const router: {
575
584
  analytics: "none" | "plausible" | "umami";
576
585
  cms: "none" | "payload" | "sanity" | "strapi" | "tinacms";
577
586
  caching: "none" | "upstash-redis";
578
- search: "none" | "meilisearch" | "typesense" | "elasticsearch";
587
+ search: "none" | "meilisearch" | "typesense" | "elasticsearch" | "algolia";
588
+ fileStorage: "none" | "s3" | "r2";
589
+ rustWebFramework: "none" | "axum" | "actix-web";
590
+ rustFrontend: "none" | "leptos" | "dioxus";
591
+ rustOrm: "none" | "sea-orm" | "sqlx";
592
+ rustApi: "none" | "tonic" | "async-graphql";
593
+ rustCli: "none" | "clap" | "ratatui";
594
+ rustLibraries: ("none" | "serde" | "validator" | "jsonwebtoken" | "argon2" | "tokio-test" | "mockall")[];
595
+ rustLogging: "none" | "tracing" | "env-logger";
596
+ pythonWebFramework: "none" | "fastapi" | "django" | "flask";
597
+ pythonOrm: "none" | "sqlalchemy" | "sqlmodel";
598
+ pythonValidation: "none" | "pydantic";
599
+ pythonAi: ("none" | "langgraph" | "langchain" | "llamaindex" | "openai-sdk" | "anthropic-sdk" | "crewai")[];
600
+ pythonTaskQueue: "none" | "celery";
601
+ pythonQuality: "none" | "ruff";
602
+ goWebFramework: "none" | "gin" | "echo" | "fiber";
603
+ goOrm: "none" | "gorm" | "sqlc";
604
+ goApi: "none" | "grpc-go";
605
+ goCli: "none" | "cobra" | "bubbletea";
606
+ goLogging: "none" | "zap";
607
+ aiDocs: ("none" | "claude-md" | "agents-md" | "cursorrules")[];
608
+ astroIntegration?: "none" | "svelte" | "solid" | "react" | "vue" | undefined;
609
+ shadcnBase?: "radix" | "base" | undefined;
610
+ shadcnStyle?: "vega" | "nova" | "maia" | "lyra" | "mira" | undefined;
611
+ shadcnIconLibrary?: "lucide" | "tabler" | "hugeicons" | "phosphor" | "remixicon" | undefined;
612
+ shadcnColorTheme?: "neutral" | "stone" | "zinc" | "gray" | "amber" | "blue" | "cyan" | "emerald" | "fuchsia" | "green" | "indigo" | "lime" | "orange" | "pink" | "purple" | "red" | "rose" | "sky" | "teal" | "violet" | "yellow" | undefined;
613
+ shadcnBaseColor?: "neutral" | "stone" | "zinc" | "gray" | undefined;
614
+ shadcnFont?: "inter" | "geist" | "noto-sans" | "nunito-sans" | "figtree" | "roboto" | "raleway" | "dm-sans" | "public-sans" | "outfit" | "jetbrains-mono" | "geist-mono" | undefined;
615
+ shadcnRadius?: "default" | "none" | "small" | "medium" | "large" | undefined;
616
+ };
617
+ reproducibleCommand: string;
618
+ timeScaffolded: string;
619
+ elapsedTimeMs: number;
620
+ projectDirectory: string;
621
+ relativePath: string;
622
+ dryRun: boolean;
623
+ fileCount: number;
624
+ directoryCount: number;
625
+ files: string[];
626
+ error?: undefined;
627
+ } | {
628
+ success: boolean;
629
+ projectConfig: {
630
+ projectName: string;
631
+ projectDir: string;
632
+ relativePath: string;
633
+ ecosystem: "typescript" | "rust" | "python" | "go";
634
+ database: "none" | "sqlite" | "postgres" | "mysql" | "mongodb" | "edgedb" | "redis";
635
+ orm: "none" | "drizzle" | "prisma" | "mongoose" | "typeorm" | "kysely" | "mikroorm" | "sequelize";
636
+ backend: "none" | "hono" | "express" | "fastify" | "elysia" | "fets" | "nestjs" | "adonisjs" | "nitro" | "encore" | "convex" | "self";
637
+ runtime: "none" | "bun" | "node" | "workers";
638
+ frontend: ("none" | "tanstack-router" | "react-router" | "react-vite" | "tanstack-start" | "next" | "nuxt" | "native-bare" | "native-uniwind" | "native-unistyles" | "svelte" | "solid" | "solid-start" | "astro" | "qwik" | "angular" | "redwood" | "fresh")[];
639
+ addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "lefthook" | "husky" | "ruler" | "mcp" | "skills" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt" | "msw" | "storybook" | "tanstack-query" | "tanstack-table" | "tanstack-virtual" | "tanstack-db" | "tanstack-pacer")[];
640
+ examples: ("ai" | "none" | "chat-sdk" | "tanstack-showcase")[];
641
+ auth: "none" | "better-auth" | "go-better-auth" | "clerk" | "nextauth" | "stack-auth" | "supabase-auth" | "auth0";
642
+ payments: "none" | "polar" | "stripe" | "lemon-squeezy" | "paddle" | "dodo";
643
+ git: boolean;
644
+ packageManager: "bun" | "npm" | "pnpm" | "yarn";
645
+ versionChannel: "stable" | "latest" | "beta";
646
+ install: boolean;
647
+ dbSetup: "none" | "turso" | "neon" | "prisma-postgres" | "planetscale" | "mongodb-atlas" | "supabase" | "upstash" | "d1" | "docker";
648
+ api: "none" | "trpc" | "orpc" | "ts-rest" | "garph";
649
+ webDeploy: "none" | "docker" | "cloudflare" | "fly" | "railway" | "sst";
650
+ serverDeploy: "none" | "docker" | "cloudflare" | "fly" | "railway" | "sst";
651
+ ai: "none" | "langgraph" | "langchain" | "llamaindex" | "vercel-ai" | "mastra" | "voltagent" | "openai-agents" | "google-adk" | "modelfusion" | "tanstack-ai";
652
+ effect: "effect" | "none" | "effect-full";
653
+ stateManagement: "none" | "zustand" | "jotai" | "nanostores" | "redux-toolkit" | "mobx" | "xstate" | "valtio" | "tanstack-store" | "legend-state";
654
+ forms: "none" | "tanstack-form" | "react-hook-form" | "formik" | "final-form" | "conform" | "modular-forms";
655
+ testing: "none" | "vitest" | "playwright" | "vitest-playwright" | "jest" | "cypress";
656
+ email: "none" | "react-email" | "resend" | "nodemailer" | "postmark" | "sendgrid" | "aws-ses" | "mailgun" | "plunk";
657
+ cssFramework: "none" | "tailwind" | "scss" | "less" | "postcss-only";
658
+ uiLibrary: "none" | "shadcn-ui" | "daisyui" | "radix-ui" | "headless-ui" | "park-ui" | "chakra-ui" | "nextui" | "mantine" | "base-ui" | "ark-ui" | "react-aria";
659
+ validation: "none" | "zod" | "valibot" | "arktype" | "typebox" | "typia" | "runtypes" | "effect-schema";
660
+ realtime: "none" | "socket-io" | "partykit" | "ably" | "pusher" | "liveblocks" | "yjs";
661
+ jobQueue: "none" | "bullmq" | "trigger-dev" | "inngest" | "temporal";
662
+ animation: "none" | "framer-motion" | "gsap" | "react-spring" | "auto-animate" | "lottie";
663
+ fileUpload: "none" | "uploadthing" | "filepond" | "uppy";
664
+ logging: "none" | "pino" | "winston";
665
+ observability: "none" | "opentelemetry" | "sentry" | "grafana";
666
+ featureFlags: "none" | "growthbook" | "posthog";
667
+ analytics: "none" | "plausible" | "umami";
668
+ cms: "none" | "payload" | "sanity" | "strapi" | "tinacms";
669
+ caching: "none" | "upstash-redis";
670
+ search: "none" | "meilisearch" | "typesense" | "elasticsearch" | "algolia";
579
671
  fileStorage: "none" | "s3" | "r2";
580
672
  rustWebFramework: "none" | "axum" | "actix-web";
581
673
  rustFrontend: "none" | "leptos" | "dioxus";
@@ -583,13 +675,14 @@ declare const router: {
583
675
  rustApi: "none" | "tonic" | "async-graphql";
584
676
  rustCli: "none" | "clap" | "ratatui";
585
677
  rustLibraries: ("none" | "serde" | "validator" | "jsonwebtoken" | "argon2" | "tokio-test" | "mockall")[];
586
- pythonWebFramework: "none" | "fastapi" | "django";
678
+ rustLogging: "none" | "tracing" | "env-logger";
679
+ pythonWebFramework: "none" | "fastapi" | "django" | "flask";
587
680
  pythonOrm: "none" | "sqlalchemy" | "sqlmodel";
588
681
  pythonValidation: "none" | "pydantic";
589
682
  pythonAi: ("none" | "langgraph" | "langchain" | "llamaindex" | "openai-sdk" | "anthropic-sdk" | "crewai")[];
590
683
  pythonTaskQueue: "none" | "celery";
591
684
  pythonQuality: "none" | "ruff";
592
- goWebFramework: "none" | "gin" | "echo";
685
+ goWebFramework: "none" | "gin" | "echo" | "fiber";
593
686
  goOrm: "none" | "gorm" | "sqlc";
594
687
  goApi: "none" | "grpc-go";
595
688
  goCli: "none" | "cobra" | "bubbletea";
@@ -609,6 +702,10 @@ declare const router: {
609
702
  elapsedTimeMs: number;
610
703
  projectDirectory: string;
611
704
  relativePath: string;
705
+ dryRun?: undefined;
706
+ fileCount?: undefined;
707
+ directoryCount?: undefined;
708
+ files?: undefined;
612
709
  error?: undefined;
613
710
  } | {
614
711
  success: boolean;
@@ -619,6 +716,10 @@ declare const router: {
619
716
  elapsedTimeMs: number;
620
717
  projectDirectory: string;
621
718
  relativePath: string;
719
+ dryRun?: undefined;
720
+ fileCount?: undefined;
721
+ directoryCount?: undefined;
722
+ files?: undefined;
622
723
  } | undefined, {
623
724
  success: boolean;
624
725
  projectConfig: {
@@ -662,7 +763,90 @@ declare const router: {
662
763
  analytics: "none" | "plausible" | "umami";
663
764
  cms: "none" | "payload" | "sanity" | "strapi" | "tinacms";
664
765
  caching: "none" | "upstash-redis";
665
- search: "none" | "meilisearch" | "typesense" | "elasticsearch";
766
+ search: "none" | "meilisearch" | "typesense" | "elasticsearch" | "algolia";
767
+ fileStorage: "none" | "s3" | "r2";
768
+ rustWebFramework: "none" | "axum" | "actix-web";
769
+ rustFrontend: "none" | "leptos" | "dioxus";
770
+ rustOrm: "none" | "sea-orm" | "sqlx";
771
+ rustApi: "none" | "tonic" | "async-graphql";
772
+ rustCli: "none" | "clap" | "ratatui";
773
+ rustLibraries: ("none" | "serde" | "validator" | "jsonwebtoken" | "argon2" | "tokio-test" | "mockall")[];
774
+ rustLogging: "none" | "tracing" | "env-logger";
775
+ pythonWebFramework: "none" | "fastapi" | "django" | "flask";
776
+ pythonOrm: "none" | "sqlalchemy" | "sqlmodel";
777
+ pythonValidation: "none" | "pydantic";
778
+ pythonAi: ("none" | "langgraph" | "langchain" | "llamaindex" | "openai-sdk" | "anthropic-sdk" | "crewai")[];
779
+ pythonTaskQueue: "none" | "celery";
780
+ pythonQuality: "none" | "ruff";
781
+ goWebFramework: "none" | "gin" | "echo" | "fiber";
782
+ goOrm: "none" | "gorm" | "sqlc";
783
+ goApi: "none" | "grpc-go";
784
+ goCli: "none" | "cobra" | "bubbletea";
785
+ goLogging: "none" | "zap";
786
+ aiDocs: ("none" | "claude-md" | "agents-md" | "cursorrules")[];
787
+ astroIntegration?: "none" | "svelte" | "solid" | "react" | "vue" | undefined;
788
+ shadcnBase?: "radix" | "base" | undefined;
789
+ shadcnStyle?: "vega" | "nova" | "maia" | "lyra" | "mira" | undefined;
790
+ shadcnIconLibrary?: "lucide" | "tabler" | "hugeicons" | "phosphor" | "remixicon" | undefined;
791
+ shadcnColorTheme?: "neutral" | "stone" | "zinc" | "gray" | "amber" | "blue" | "cyan" | "emerald" | "fuchsia" | "green" | "indigo" | "lime" | "orange" | "pink" | "purple" | "red" | "rose" | "sky" | "teal" | "violet" | "yellow" | undefined;
792
+ shadcnBaseColor?: "neutral" | "stone" | "zinc" | "gray" | undefined;
793
+ shadcnFont?: "inter" | "geist" | "noto-sans" | "nunito-sans" | "figtree" | "roboto" | "raleway" | "dm-sans" | "public-sans" | "outfit" | "jetbrains-mono" | "geist-mono" | undefined;
794
+ shadcnRadius?: "default" | "none" | "small" | "medium" | "large" | undefined;
795
+ };
796
+ reproducibleCommand: string;
797
+ timeScaffolded: string;
798
+ elapsedTimeMs: number;
799
+ projectDirectory: string;
800
+ relativePath: string;
801
+ dryRun: boolean;
802
+ fileCount: number;
803
+ directoryCount: number;
804
+ files: string[];
805
+ error?: undefined;
806
+ } | {
807
+ success: boolean;
808
+ projectConfig: {
809
+ projectName: string;
810
+ projectDir: string;
811
+ relativePath: string;
812
+ ecosystem: "typescript" | "rust" | "python" | "go";
813
+ database: "none" | "sqlite" | "postgres" | "mysql" | "mongodb" | "edgedb" | "redis";
814
+ orm: "none" | "drizzle" | "prisma" | "mongoose" | "typeorm" | "kysely" | "mikroorm" | "sequelize";
815
+ backend: "none" | "hono" | "express" | "fastify" | "elysia" | "fets" | "nestjs" | "adonisjs" | "nitro" | "encore" | "convex" | "self";
816
+ runtime: "none" | "bun" | "node" | "workers";
817
+ frontend: ("none" | "tanstack-router" | "react-router" | "react-vite" | "tanstack-start" | "next" | "nuxt" | "native-bare" | "native-uniwind" | "native-unistyles" | "svelte" | "solid" | "solid-start" | "astro" | "qwik" | "angular" | "redwood" | "fresh")[];
818
+ addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "lefthook" | "husky" | "ruler" | "mcp" | "skills" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt" | "msw" | "storybook" | "tanstack-query" | "tanstack-table" | "tanstack-virtual" | "tanstack-db" | "tanstack-pacer")[];
819
+ examples: ("ai" | "none" | "chat-sdk" | "tanstack-showcase")[];
820
+ auth: "none" | "better-auth" | "go-better-auth" | "clerk" | "nextauth" | "stack-auth" | "supabase-auth" | "auth0";
821
+ payments: "none" | "polar" | "stripe" | "lemon-squeezy" | "paddle" | "dodo";
822
+ git: boolean;
823
+ packageManager: "bun" | "npm" | "pnpm" | "yarn";
824
+ versionChannel: "stable" | "latest" | "beta";
825
+ install: boolean;
826
+ dbSetup: "none" | "turso" | "neon" | "prisma-postgres" | "planetscale" | "mongodb-atlas" | "supabase" | "upstash" | "d1" | "docker";
827
+ api: "none" | "trpc" | "orpc" | "ts-rest" | "garph";
828
+ webDeploy: "none" | "docker" | "cloudflare" | "fly" | "railway" | "sst";
829
+ serverDeploy: "none" | "docker" | "cloudflare" | "fly" | "railway" | "sst";
830
+ ai: "none" | "langgraph" | "langchain" | "llamaindex" | "vercel-ai" | "mastra" | "voltagent" | "openai-agents" | "google-adk" | "modelfusion" | "tanstack-ai";
831
+ effect: "effect" | "none" | "effect-full";
832
+ stateManagement: "none" | "zustand" | "jotai" | "nanostores" | "redux-toolkit" | "mobx" | "xstate" | "valtio" | "tanstack-store" | "legend-state";
833
+ forms: "none" | "tanstack-form" | "react-hook-form" | "formik" | "final-form" | "conform" | "modular-forms";
834
+ testing: "none" | "vitest" | "playwright" | "vitest-playwright" | "jest" | "cypress";
835
+ email: "none" | "react-email" | "resend" | "nodemailer" | "postmark" | "sendgrid" | "aws-ses" | "mailgun" | "plunk";
836
+ cssFramework: "none" | "tailwind" | "scss" | "less" | "postcss-only";
837
+ uiLibrary: "none" | "shadcn-ui" | "daisyui" | "radix-ui" | "headless-ui" | "park-ui" | "chakra-ui" | "nextui" | "mantine" | "base-ui" | "ark-ui" | "react-aria";
838
+ validation: "none" | "zod" | "valibot" | "arktype" | "typebox" | "typia" | "runtypes" | "effect-schema";
839
+ realtime: "none" | "socket-io" | "partykit" | "ably" | "pusher" | "liveblocks" | "yjs";
840
+ jobQueue: "none" | "bullmq" | "trigger-dev" | "inngest" | "temporal";
841
+ animation: "none" | "framer-motion" | "gsap" | "react-spring" | "auto-animate" | "lottie";
842
+ fileUpload: "none" | "uploadthing" | "filepond" | "uppy";
843
+ logging: "none" | "pino" | "winston";
844
+ observability: "none" | "opentelemetry" | "sentry" | "grafana";
845
+ featureFlags: "none" | "growthbook" | "posthog";
846
+ analytics: "none" | "plausible" | "umami";
847
+ cms: "none" | "payload" | "sanity" | "strapi" | "tinacms";
848
+ caching: "none" | "upstash-redis";
849
+ search: "none" | "meilisearch" | "typesense" | "elasticsearch" | "algolia";
666
850
  fileStorage: "none" | "s3" | "r2";
667
851
  rustWebFramework: "none" | "axum" | "actix-web";
668
852
  rustFrontend: "none" | "leptos" | "dioxus";
@@ -670,13 +854,14 @@ declare const router: {
670
854
  rustApi: "none" | "tonic" | "async-graphql";
671
855
  rustCli: "none" | "clap" | "ratatui";
672
856
  rustLibraries: ("none" | "serde" | "validator" | "jsonwebtoken" | "argon2" | "tokio-test" | "mockall")[];
673
- pythonWebFramework: "none" | "fastapi" | "django";
857
+ rustLogging: "none" | "tracing" | "env-logger";
858
+ pythonWebFramework: "none" | "fastapi" | "django" | "flask";
674
859
  pythonOrm: "none" | "sqlalchemy" | "sqlmodel";
675
860
  pythonValidation: "none" | "pydantic";
676
861
  pythonAi: ("none" | "langgraph" | "langchain" | "llamaindex" | "openai-sdk" | "anthropic-sdk" | "crewai")[];
677
862
  pythonTaskQueue: "none" | "celery";
678
863
  pythonQuality: "none" | "ruff";
679
- goWebFramework: "none" | "gin" | "echo";
864
+ goWebFramework: "none" | "gin" | "echo" | "fiber";
680
865
  goOrm: "none" | "gorm" | "sqlc";
681
866
  goApi: "none" | "grpc-go";
682
867
  goCli: "none" | "cobra" | "bubbletea";
@@ -696,6 +881,10 @@ declare const router: {
696
881
  elapsedTimeMs: number;
697
882
  projectDirectory: string;
698
883
  relativePath: string;
884
+ dryRun?: undefined;
885
+ fileCount?: undefined;
886
+ directoryCount?: undefined;
887
+ files?: undefined;
699
888
  error?: undefined;
700
889
  } | {
701
890
  success: boolean;
@@ -706,6 +895,10 @@ declare const router: {
706
895
  elapsedTimeMs: number;
707
896
  projectDirectory: string;
708
897
  relativePath: string;
898
+ dryRun?: undefined;
899
+ fileCount?: undefined;
900
+ directoryCount?: undefined;
901
+ files?: undefined;
709
902
  } | undefined>, _orpc_server0.MergedErrorMap<Record<never, never>, Record<never, never>>, Record<never, never>>;
710
903
  sponsors: _orpc_server0.Procedure<_orpc_server0.MergedInitialContext<Record<never, never>, Record<never, never>, Record<never, never>>, Record<never, never>, _orpc_server0.Schema<unknown, unknown>, _orpc_server0.Schema<void, void>, _orpc_server0.MergedErrorMap<Record<never, never>, Record<never, never>>, Record<never, never>>;
711
904
  docs: _orpc_server0.Procedure<_orpc_server0.MergedInitialContext<Record<never, never>, Record<never, never>, Record<never, never>>, Record<never, never>, _orpc_server0.Schema<unknown, unknown>, _orpc_server0.Schema<void, void>, _orpc_server0.MergedErrorMap<Record<never, never>, Record<never, never>>, Record<never, never>>;
@@ -876,10 +1069,11 @@ type RustApi = import__better_fullstack_types.RustApi;
876
1069
  type RustCli = import__better_fullstack_types.RustCli;
877
1070
  type RustFrontend = import__better_fullstack_types.RustFrontend;
878
1071
  type RustLibraries = import__better_fullstack_types.RustLibraries;
1072
+ type RustLogging = import__better_fullstack_types.RustLogging;
879
1073
  type RustOrm = import__better_fullstack_types.RustOrm;
880
1074
  type RustWebFramework = import__better_fullstack_types.RustWebFramework;
881
1075
  type ServerDeploy = import__better_fullstack_types.ServerDeploy;
882
1076
  type Template = import__better_fullstack_types.Template;
883
1077
  type UILibrary = import__better_fullstack_types.UILibrary;
884
1078
  type WebDeploy = import__better_fullstack_types.WebDeploy;
885
- export { type API, type AddInput, type AddResult, type Addons, type AiDocs, type Analytics, type Animation, type Auth, type Backend, type BetterTStackConfig, type CMS, type CSSFramework, type Caching, type CreateInput, type Database, type DatabaseSetup, type DirectoryConflict, EMBEDDED_TEMPLATES, type Ecosystem, type Effect, type Examples, type Frontend, type GeneratorOptions, type GeneratorResult, type GoApi, type GoCli, type GoLogging, type GoOrm, type GoWebFramework, type InitResult, type Logging, type ORM, type PackageManager, type Payments, type PythonAi, type PythonOrm, type PythonQuality, type PythonTaskQueue, type PythonValidation, type PythonWebFramework, type Realtime, type Runtime, type RustApi, type RustCli, type RustFrontend, type RustLibraries, type RustOrm, type RustWebFramework, type ServerDeploy, TEMPLATE_COUNT, type Template, type UILibrary, type VirtualDirectory, type VirtualFile, VirtualFileSystem, type VirtualFileTree, type VirtualNode, type WebDeploy, add, builder, create, createBtsCli, createVirtual, docs, generateVirtualProject, history, router, sponsors };
1079
+ export { type API, type AddInput, type AddResult, type Addons, type AiDocs, type Analytics, type Animation, type Auth, type Backend, type BetterTStackConfig, type CMS, type CSSFramework, type Caching, type CreateInput, type Database, type DatabaseSetup, type DirectoryConflict, EMBEDDED_TEMPLATES, type Ecosystem, type Effect, type Examples, type Frontend, type GeneratorOptions, type GeneratorResult, type GoApi, type GoCli, type GoLogging, type GoOrm, type GoWebFramework, type InitResult, type Logging, type ORM, type PackageManager, type Payments, type PythonAi, type PythonOrm, type PythonQuality, type PythonTaskQueue, type PythonValidation, type PythonWebFramework, type Realtime, type Runtime, type RustApi, type RustCli, type RustFrontend, type RustLibraries, type RustLogging, type RustOrm, type RustWebFramework, type ServerDeploy, TEMPLATE_COUNT, type Template, type UILibrary, type VirtualDirectory, type VirtualFile, VirtualFileSystem, type VirtualFileTree, type VirtualNode, type WebDeploy, add, builder, create, createBtsCli, createVirtual, docs, generateVirtualProject, history, router, sponsors };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as __reExport } from "./chunk-CCII7kTE.mjs";
3
- import { a as DEFAULT_CONFIG, c as getDefaultConfig, i as getLatestCLIVersion, l as getUserPkgManager, n as updateBtsConfig, o as DEFAULT_UI_LIBRARY_BY_FRONTEND, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-BCe8SqYV.mjs";
4
- import { _ as setLastPromptShownUI, a as getPackageExecutionArgs, c as UserCancelledError, d as handleError, f as didLastPromptShowUI, g as setIsFirstPrompt$1, h as runWithContextAsync, l as exitCancelled, m as isSilent, o as addPackageDependency, p as isFirstPrompt, s as CLIError, t as setupAddons, u as exitWithError } from "./addons-setup-1jZXP0D3.mjs";
3
+ import { a as DEFAULT_CONFIG, c as getDefaultConfig, i as getLatestCLIVersion, l as getUserPkgManager, n as updateBtsConfig, o as DEFAULT_UI_LIBRARY_BY_FRONTEND, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-BYD8mHt-.mjs";
4
+ import { _ as setLastPromptShownUI, a as getPackageExecutionArgs, c as UserCancelledError, d as handleError, f as didLastPromptShowUI, g as setIsFirstPrompt$1, h as runWithContextAsync, l as exitCancelled, m as isSilent, o as addPackageDependency, p as isFirstPrompt, s as CLIError, t as setupAddons, u as exitWithError } from "./addons-setup-Bll5VFJd.mjs";
5
5
  import { cancel, confirm, intro, isCancel, log, outro, select, spinner, text } from "@clack/prompts";
6
6
  import { createRouterClient, os } from "@orpc/server";
7
7
  import pc from "picocolors";
@@ -2613,6 +2613,11 @@ async function getGoWebFrameworkChoice(goWebFramework) {
2613
2613
  label: "Echo",
2614
2614
  hint: "High performance, minimalist Go web framework"
2615
2615
  },
2616
+ {
2617
+ value: "fiber",
2618
+ label: "Fiber",
2619
+ hint: "Express-inspired web framework built on Fasthttp"
2620
+ },
2616
2621
  {
2617
2622
  value: "none",
2618
2623
  label: "None",
@@ -3088,6 +3093,11 @@ async function getPythonWebFrameworkChoice(pythonWebFramework) {
3088
3093
  label: "Django",
3089
3094
  hint: "High-level Python web framework with batteries included"
3090
3095
  },
3096
+ {
3097
+ value: "flask",
3098
+ label: "Flask",
3099
+ hint: "Lightweight WSGI web framework with minimal boilerplate"
3100
+ },
3091
3101
  {
3092
3102
  value: "none",
3093
3103
  label: "None",
@@ -3480,6 +3490,32 @@ async function getRustLibrariesChoice(rustLibraries) {
3480
3490
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3481
3491
  return response;
3482
3492
  }
3493
+ async function getRustLoggingChoice(rustLogging) {
3494
+ if (rustLogging !== void 0) return rustLogging;
3495
+ const response = await navigableSelect({
3496
+ message: "Select Rust logging library",
3497
+ options: [
3498
+ {
3499
+ value: "tracing",
3500
+ label: "Tracing",
3501
+ hint: "Structured, composable instrumentation framework from Tokio"
3502
+ },
3503
+ {
3504
+ value: "env-logger",
3505
+ label: "env_logger",
3506
+ hint: "Simple logger configured via environment variables"
3507
+ },
3508
+ {
3509
+ value: "none",
3510
+ label: "None",
3511
+ hint: "No logging library"
3512
+ }
3513
+ ],
3514
+ initialValue: "tracing"
3515
+ });
3516
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3517
+ return response;
3518
+ }
3483
3519
 
3484
3520
  //#endregion
3485
3521
  //#region src/prompts/search.ts
@@ -3504,6 +3540,11 @@ async function getSearchChoice(search, backend) {
3504
3540
  label: "Elasticsearch",
3505
3541
  hint: "Distributed search and analytics engine with local and cloud deployments"
3506
3542
  },
3543
+ {
3544
+ value: "algolia",
3545
+ label: "Algolia",
3546
+ hint: "Hosted search API with instant results, typo tolerance, and analytics"
3547
+ },
3507
3548
  {
3508
3549
  value: "none",
3509
3550
  label: "None",
@@ -4389,6 +4430,10 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
4389
4430
  if (results.ecosystem !== "rust") return Promise.resolve([]);
4390
4431
  return getRustLibrariesChoice(flags.rustLibraries);
4391
4432
  },
4433
+ rustLogging: ({ results }) => {
4434
+ if (results.ecosystem !== "rust") return Promise.resolve("none");
4435
+ return getRustLoggingChoice(flags.rustLogging);
4436
+ },
4392
4437
  pythonWebFramework: ({ results }) => {
4393
4438
  if (results.ecosystem !== "python") return Promise.resolve("none");
4394
4439
  return getPythonWebFrameworkChoice(flags.pythonWebFramework);
@@ -4491,6 +4536,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
4491
4536
  rustApi: result.rustApi,
4492
4537
  rustCli: result.rustCli,
4493
4538
  rustLibraries: result.rustLibraries,
4539
+ rustLogging: result.rustLogging,
4494
4540
  pythonWebFramework: result.pythonWebFramework,
4495
4541
  pythonOrm: result.pythonOrm,
4496
4542
  pythonValidation: result.pythonValidation,
@@ -4777,6 +4823,7 @@ function getRustFlags(config) {
4777
4823
  flags.push(`--rust-api ${config.rustApi}`);
4778
4824
  flags.push(`--rust-cli ${config.rustCli}`);
4779
4825
  flags.push(formatArrayFlag("rust-libraries", config.rustLibraries));
4826
+ flags.push(`--rust-logging ${config.rustLogging}`);
4780
4827
  appendSharedNonTypeScriptFlags(flags, config);
4781
4828
  appendCommonFlags(flags, config);
4782
4829
  return flags;
@@ -6925,7 +6972,9 @@ async function displayPostInstallInstructions(config) {
6925
6972
  const pwaInstructions = addons?.includes("pwa") && (frontend?.includes("react-router") || frontend?.includes("react-vite")) ? getPwaInstructions() : "";
6926
6973
  const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
6927
6974
  const clerkInstructions = config.auth === "clerk" ? getClerkInstructions(config.backend, config.frontend ?? []) : "";
6928
- const polarInstructions = config.payments === "polar" && config.auth === "better-auth" ? getPolarInstructions(backend, packageManager) : "";
6975
+ const authSetupInstructions = getAuthSetupInstructions(config.auth, backend, config.frontend ?? []);
6976
+ const polarInstructions = config.payments === "polar" ? getPolarInstructions(backend, packageManager) : "";
6977
+ const paymentSetupInstructions = getPaymentSetupInstructions(config.payments, backend);
6929
6978
  const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend);
6930
6979
  const hasWeb = frontend?.some((f) => WEB_FRAMEWORKS.includes(f));
6931
6980
  const hasNative = frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles");
@@ -6974,8 +7023,10 @@ async function displayPostInstallInstructions(config) {
6974
7023
  if (alchemyDeployInstructions) output += `\n${alchemyDeployInstructions.trim()}\n`;
6975
7024
  if (starlightInstructions) output += `\n${starlightInstructions.trim()}\n`;
6976
7025
  if (clerkInstructions) output += `\n${clerkInstructions.trim()}\n`;
7026
+ if (authSetupInstructions) output += `\n${authSetupInstructions.trim()}\n`;
6977
7027
  if (betterAuthConvexInstructions) output += `\n${betterAuthConvexInstructions.trim()}\n`;
6978
7028
  if (polarInstructions) output += `\n${polarInstructions.trim()}\n`;
7029
+ if (paymentSetupInstructions) output += `\n${paymentSetupInstructions.trim()}\n`;
6979
7030
  if (noOrmWarning) output += `\n${noOrmWarning.trim()}\n`;
6980
7031
  if (bunWebNativeWarning) output += `\n${bunWebNativeWarning.trim()}\n`;
6981
7032
  output += `\n${pc.bold("Enjoying Better Fullstack?")} Help us grow — star the repo!\n`;
@@ -7023,9 +7074,15 @@ async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup,
7023
7074
  if (database === "mysql" && orm === "drizzle") instructions.push(`${pc.yellow("NOTE:")} Enable foreign key constraints in PlanetScale database settings`);
7024
7075
  if (database === "mysql" && orm === "prisma") instructions.push(`${pc.yellow("NOTE:")} How to handle Prisma migrations with PlanetScale:\n https://github.com/prisma/prisma/issues/7292`);
7025
7076
  }
7026
- if (dbSetup === "turso" && orm === "prisma") instructions.push(`${pc.yellow("NOTE:")} Follow Turso's Prisma guide for migrations via the Turso CLI:\n https://docs.turso.tech/sdk/ts/orm/prisma`);
7077
+ if (dbSetup === "turso" && orm === "prisma") instructions.push(`${pc.yellow("NOTE:")} Turso + Prisma migrations require the Turso CLI.\n 1. Install and authenticate the Turso CLI:\n ${pc.underline("https://docs.turso.tech/cli/installation")}\n 2. Confirm ${pc.white("DATABASE_URL")} and ${pc.white("TURSO_AUTH_TOKEN")} are set in your env file\n 3. Generate Prisma Client: ${`${runCmd} db:generate`}\n 4. Follow the official migration workflow:\n ${pc.underline("https://docs.turso.tech/sdk/ts/orm/prisma")}`);
7078
+ if (dbSetup === "turso" && orm === "drizzle") instructions.push(`${pc.yellow("NOTE:")} Turso + Drizzle requires the Turso CLI for database management.\n 1. Install and authenticate the Turso CLI:\n ${pc.underline("https://docs.turso.tech/cli/installation")}\n 2. Confirm ${pc.white("DATABASE_URL")} and ${pc.white("TURSO_AUTH_TOKEN")} are set in your env file\n 3. Push schema: ${`${runCmd} db:push`}\n 4. Docs: ${pc.underline("https://orm.drizzle.team/docs/get-started/turso-new")}`);
7079
+ if (dbSetup === "neon") instructions.push(`${pc.yellow("NOTE:")} Set your Neon ${pc.white("DATABASE_URL")} in your env file.\n Dashboard: ${pc.underline("https://console.neon.tech")}`);
7080
+ if (dbSetup === "supabase") instructions.push(`${pc.yellow("NOTE:")} Set your Supabase ${pc.white("DATABASE_URL")} in your env file.\n Dashboard: ${pc.underline("https://supabase.com/dashboard")}`);
7081
+ if (dbSetup === "prisma-postgres") instructions.push(`${pc.yellow("NOTE:")} Get your Prisma Postgres connection string from the console.\n Console: ${pc.underline("https://console.prisma.io")}`);
7082
+ if (dbSetup === "mongodb-atlas") instructions.push(`${pc.yellow("NOTE:")} Set your Atlas ${pc.white("DATABASE_URL")} in your env file.\n Dashboard: ${pc.underline("https://cloud.mongodb.com")}`);
7083
+ if (dbSetup === "upstash") instructions.push(`${pc.yellow("NOTE:")} Set your Upstash Redis credentials in your env file.\n Console: ${pc.underline("https://console.upstash.com")}`);
7027
7084
  if (orm === "prisma") {
7028
- if (database === "mongodb" && dbSetup === "docker") instructions.push(`${pc.yellow("WARNING:")} Prisma + MongoDB + Docker: this combination has known issues.\n Consider using MongoDB Atlas (${pc.underline("https://www.mongodb.com/atlas")}) for reliable Prisma + MongoDB support.`);
7085
+ if (database === "mongodb" && dbSetup === "docker") instructions.push(`${pc.yellow("WARNING:")} Prisma + MongoDB + Docker can be unreliable in local development.\n Start MongoDB first and wait until the container is ready before Prisma commands\n • If ${`${runCmd} db:push`} keeps failing locally, switch to MongoDB Atlas for a supported Prisma workflow:\n ${pc.underline("https://www.mongodb.com/atlas")}`);
7029
7086
  if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
7030
7087
  if (!(dbSetup === "d1" && serverDeploy === "cloudflare")) {
7031
7088
  instructions.push(`${pc.cyan("•")} Generate Prisma Client: ${`${runCmd} db:generate`}`);
@@ -7038,6 +7095,8 @@ async function getDatabaseInstructions(database, orm, runCmd, _runtime, dbSetup,
7038
7095
  if (!(dbSetup === "d1" && serverDeploy === "cloudflare")) instructions.push(`${pc.cyan("•")} Database UI: ${`${runCmd} db:studio`}`);
7039
7096
  } else if (orm === "mongoose") {
7040
7097
  if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
7098
+ } else if (orm === "typeorm" || orm === "mikroorm" || orm === "sequelize" || orm === "kysely") {
7099
+ if (dbSetup === "docker") instructions.push(`${pc.cyan("•")} Start docker container: ${`${runCmd} db:start`}`);
7041
7100
  } else if (orm === "none") instructions.push(`${pc.yellow("NOTE:")} Manual database schema setup\n required.`);
7042
7101
  return instructions.length ? `${pc.bold("Database commands:")}\n${instructions.join("\n")}` : "";
7043
7102
  }
@@ -7064,6 +7123,24 @@ function getClerkInstructions(backend, frontend) {
7064
7123
  }
7065
7124
  return "";
7066
7125
  }
7126
+ function getAuthSetupInstructions(auth, backend, frontend) {
7127
+ if (auth === "clerk" || auth === "better-auth" || auth === "go-better-auth" || auth === "none") return "";
7128
+ const envPath = backend === "self" ? "apps/web/.env" : "apps/server/.env";
7129
+ if (auth === "nextauth") return `${pc.bold("NextAuth.js Setup:")}\n${pc.cyan("•")} Generate a secret: ${pc.white("npx auth secret")}\n${pc.cyan("•")} Set ${pc.white("AUTH_SECRET")} in ${pc.white(envPath)}\n${pc.cyan("•")} Configure your OAuth providers (e.g. ${pc.white("AUTH_GITHUB_ID")}, ${pc.white("AUTH_GITHUB_SECRET")})\n${pc.cyan("•")} Docs: ${pc.underline("https://authjs.dev/getting-started")}`;
7130
+ if (auth === "stack-auth") return `${pc.bold("Stack Auth Setup:")}\n${pc.cyan("•")} Create a project at ${pc.underline("https://app.stack-auth.com")}\n${pc.cyan("•")} Set ${pc.white("NEXT_PUBLIC_STACK_PROJECT_ID")}, ${pc.white("NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY")},\n and ${pc.white("STACK_SECRET_SERVER_KEY")} in ${pc.white(envPath)}`;
7131
+ if (auth === "supabase-auth") return `${pc.bold("Supabase Auth Setup:")}\n${pc.cyan("•")} Create a project at ${pc.underline("https://supabase.com/dashboard")}\n${pc.cyan("•")} Set ${pc.white("NEXT_PUBLIC_SUPABASE_URL")}, ${pc.white("NEXT_PUBLIC_SUPABASE_ANON_KEY")},\n and ${pc.white("SUPABASE_SERVICE_ROLE_KEY")} in ${pc.white(envPath)}`;
7132
+ if (auth === "auth0") return `${pc.bold("Auth0 Setup:")}\n${pc.cyan("•")} Create an application at ${pc.underline("https://manage.auth0.com")}\n${pc.cyan("•")} Set ${pc.white("AUTH0_SECRET")}, ${pc.white("AUTH0_CLIENT_ID")}, ${pc.white("AUTH0_CLIENT_SECRET")},\n and ${pc.white("AUTH0_ISSUER_BASE_URL")} in ${pc.white(envPath)}\n${pc.cyan("•")} Docs: ${pc.underline("https://auth0.com/docs/quickstart")}`;
7133
+ return "";
7134
+ }
7135
+ function getPaymentSetupInstructions(payments, backend) {
7136
+ if (payments === "polar" || payments === "none") return "";
7137
+ const envPath = backend === "self" ? "apps/web/.env" : "apps/server/.env";
7138
+ if (payments === "stripe") return `${pc.bold("Stripe Setup:")}\n${pc.cyan("•")} Get API keys from ${pc.underline("https://dashboard.stripe.com/apikeys")}\n${pc.cyan("•")} Set ${pc.white("STRIPE_SECRET_KEY")} and ${pc.white("STRIPE_WEBHOOK_SECRET")} in ${pc.white(envPath)}\n${pc.cyan("•")} For local webhooks: ${pc.white("stripe listen --forward-to localhost:3000/api/webhooks/stripe")}`;
7139
+ if (payments === "lemon-squeezy") return `${pc.bold("Lemon Squeezy Setup:")}\n${pc.cyan("•")} Get API key from ${pc.underline("https://app.lemonsqueezy.com/settings/api")}\n${pc.cyan("•")} Set ${pc.white("LEMONSQUEEZY_API_KEY")} and ${pc.white("LEMONSQUEEZY_STORE_ID")} in ${pc.white(envPath)}`;
7140
+ if (payments === "paddle") return `${pc.bold("Paddle Setup:")}\n${pc.cyan("•")} Get API keys from ${pc.underline("https://vendors.paddle.com")}\n${pc.cyan("•")} Set ${pc.white("PADDLE_API_KEY")} and ${pc.white("PADDLE_WEBHOOK_SECRET")} in ${pc.white(envPath)}`;
7141
+ if (payments === "dodo") return `${pc.bold("Dodo Payments Setup:")}\n${pc.cyan("•")} Get API key from ${pc.underline("https://app.dodopayments.com")}\n${pc.cyan("•")} Set ${pc.white("DODO_PAYMENTS_API_KEY")} and ${pc.white("DODO_PAYMENTS_WEBHOOK_SECRET")} in ${pc.white(envPath)}`;
7142
+ return "";
7143
+ }
7067
7144
  function getBetterAuthConvexInstructions(hasWeb, webPort, packageManager) {
7068
7145
  const cmd = packageManager === "npm" ? "npx" : packageManager === "yarn" ? "yarn dlx" : packageManager;
7069
7146
  return `${pc.bold("Better Auth + Convex Setup:")}\n${pc.cyan("•")} Set environment variables from ${pc.white("packages/backend")}:\n${pc.white(" cd packages/backend")}\n${pc.white(` ${cmd} convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)`)}\n` + (hasWeb ? `${pc.white(` ${cmd} convex env set SITE_URL http://localhost:${webPort}`)}\n` : "");
@@ -7115,6 +7192,11 @@ function displayRustInstructions(config) {
7115
7192
  clap: "Clap",
7116
7193
  ratatui: "Ratatui"
7117
7194
  }[rustCli] || rustCli}\n`;
7195
+ const { rustLogging } = config;
7196
+ if (rustLogging && rustLogging !== "none") output += `${pc.cyan("•")} Logging: ${{
7197
+ tracing: "Tracing",
7198
+ "env-logger": "env_logger"
7199
+ }[rustLogging] || rustLogging}\n`;
7118
7200
  output += `\n${pc.bold("Common Cargo commands:")}\n`;
7119
7201
  output += `${pc.cyan("•")} Build: cargo build\n`;
7120
7202
  output += `${pc.cyan("•")} Run: cargo run\n`;
@@ -7137,7 +7219,8 @@ function displayGoInstructions(config) {
7137
7219
  output += `\n${pc.bold("Your Go project includes:")}\n`;
7138
7220
  if (goWebFramework && goWebFramework !== "none") output += `${pc.cyan("•")} Web Framework: ${{
7139
7221
  gin: "Gin",
7140
- echo: "Echo"
7222
+ echo: "Echo",
7223
+ fiber: "Fiber"
7141
7224
  }[goWebFramework] || goWebFramework}\n`;
7142
7225
  if (goOrm && goOrm !== "none") output += `${pc.cyan("•")} Database: ${{
7143
7226
  gorm: "GORM",
@@ -7169,6 +7252,7 @@ function displayPythonInstructions(config) {
7169
7252
  const cdCmd = `cd ${relativePath}`;
7170
7253
  let runCommand = "uv run uvicorn app.main:app --reload";
7171
7254
  if (pythonWebFramework === "django") runCommand = "uv run python manage.py runserver";
7255
+ else if (pythonWebFramework === "flask") runCommand = "uv run flask --app app.main run --reload";
7172
7256
  let output = `${pc.bold("Next steps")}\n${pc.cyan("1.")} ${cdCmd}\n`;
7173
7257
  let stepCounter = 2;
7174
7258
  if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} uv sync\n`;
@@ -7176,7 +7260,8 @@ function displayPythonInstructions(config) {
7176
7260
  output += `\n${pc.bold("Your Python project includes:")}\n`;
7177
7261
  if (pythonWebFramework && pythonWebFramework !== "none") output += `${pc.cyan("•")} Web Framework: ${{
7178
7262
  fastapi: "FastAPI",
7179
- django: "Django"
7263
+ django: "Django",
7264
+ flask: "Flask"
7180
7265
  }[pythonWebFramework] || pythonWebFramework}\n`;
7181
7266
  if (pythonOrm && pythonOrm !== "none") output += `${pc.cyan("•")} ORM: ${{
7182
7267
  sqlalchemy: "SQLAlchemy",
@@ -7298,93 +7383,104 @@ async function createProjectHandler(input, options = {}) {
7298
7383
  currentPathInput = defaultName;
7299
7384
  } else currentPathInput = await getProjectName(input.projectName);
7300
7385
  const versionChannel = shouldPromptForVersionChannel(input) ? await getVersionChannelChoice() : input.versionChannel ?? "stable";
7301
- let finalPathInput;
7302
- let shouldClearDirectory;
7303
- try {
7304
- if (input.directoryConflict) {
7305
- const result = await handleDirectoryConflictProgrammatically(currentPathInput, input.directoryConflict);
7306
- finalPathInput = result.finalPathInput;
7307
- shouldClearDirectory = result.shouldClearDirectory;
7308
- } else {
7309
- const result = await handleDirectoryConflict(currentPathInput);
7310
- finalPathInput = result.finalPathInput;
7311
- shouldClearDirectory = result.shouldClearDirectory;
7312
- }
7313
- } catch (error) {
7314
- if (error instanceof UserCancelledError || error instanceof CLIError) throw error;
7315
- return {
7316
- success: false,
7317
- projectConfig: {
7318
- projectName: "",
7319
- projectDir: "",
7386
+ let finalResolvedPath;
7387
+ let finalBaseName;
7388
+ if (input.dryRun) {
7389
+ finalBaseName = path.basename(currentPathInput);
7390
+ finalResolvedPath = path.resolve(process.cwd(), currentPathInput);
7391
+ } else {
7392
+ let finalPathInput;
7393
+ let shouldClearDirectory;
7394
+ try {
7395
+ if (input.directoryConflict) {
7396
+ const result = await handleDirectoryConflictProgrammatically(currentPathInput, input.directoryConflict);
7397
+ finalPathInput = result.finalPathInput;
7398
+ shouldClearDirectory = result.shouldClearDirectory;
7399
+ } else {
7400
+ const result = await handleDirectoryConflict(currentPathInput);
7401
+ finalPathInput = result.finalPathInput;
7402
+ shouldClearDirectory = result.shouldClearDirectory;
7403
+ }
7404
+ } catch (error) {
7405
+ if (error instanceof UserCancelledError || error instanceof CLIError) throw error;
7406
+ return {
7407
+ success: false,
7408
+ projectConfig: {
7409
+ projectName: "",
7410
+ projectDir: "",
7411
+ relativePath: "",
7412
+ ecosystem: "typescript",
7413
+ database: "none",
7414
+ orm: "none",
7415
+ backend: "none",
7416
+ runtime: "none",
7417
+ frontend: [],
7418
+ addons: [],
7419
+ examples: [],
7420
+ auth: "none",
7421
+ payments: "none",
7422
+ email: "none",
7423
+ fileUpload: "none",
7424
+ effect: "none",
7425
+ git: false,
7426
+ packageManager: "npm",
7427
+ versionChannel: "stable",
7428
+ install: false,
7429
+ dbSetup: "none",
7430
+ api: "none",
7431
+ webDeploy: "none",
7432
+ serverDeploy: "none",
7433
+ cssFramework: "none",
7434
+ uiLibrary: "none",
7435
+ ai: "none",
7436
+ stateManagement: "none",
7437
+ validation: "zod",
7438
+ forms: "react-hook-form",
7439
+ testing: "vitest",
7440
+ realtime: "none",
7441
+ jobQueue: "none",
7442
+ animation: "none",
7443
+ logging: "none",
7444
+ observability: "none",
7445
+ rustWebFramework: "none",
7446
+ rustFrontend: "none",
7447
+ rustOrm: "none",
7448
+ rustApi: "none",
7449
+ rustCli: "none",
7450
+ rustLibraries: [],
7451
+ rustLogging: "none",
7452
+ cms: "none",
7453
+ caching: "none",
7454
+ search: "none",
7455
+ featureFlags: "none",
7456
+ analytics: "none",
7457
+ fileStorage: "none",
7458
+ pythonWebFramework: "none",
7459
+ pythonOrm: "none",
7460
+ pythonValidation: "none",
7461
+ pythonAi: [],
7462
+ pythonTaskQueue: "none",
7463
+ pythonQuality: "none",
7464
+ goWebFramework: "none",
7465
+ goOrm: "none",
7466
+ goApi: "none",
7467
+ goCli: "none",
7468
+ goLogging: "none",
7469
+ aiDocs: []
7470
+ },
7471
+ reproducibleCommand: "",
7472
+ timeScaffolded,
7473
+ elapsedTimeMs: Date.now() - startTime,
7474
+ projectDirectory: "",
7320
7475
  relativePath: "",
7321
- ecosystem: "typescript",
7322
- database: "none",
7323
- orm: "none",
7324
- backend: "none",
7325
- runtime: "none",
7326
- frontend: [],
7327
- addons: [],
7328
- examples: [],
7329
- auth: "none",
7330
- payments: "none",
7331
- email: "none",
7332
- fileUpload: "none",
7333
- effect: "none",
7334
- git: false,
7335
- packageManager: "npm",
7336
- versionChannel: "stable",
7337
- install: false,
7338
- dbSetup: "none",
7339
- api: "none",
7340
- webDeploy: "none",
7341
- serverDeploy: "none",
7342
- cssFramework: "none",
7343
- uiLibrary: "none",
7344
- ai: "none",
7345
- stateManagement: "none",
7346
- validation: "zod",
7347
- forms: "react-hook-form",
7348
- testing: "vitest",
7349
- realtime: "none",
7350
- jobQueue: "none",
7351
- animation: "none",
7352
- logging: "none",
7353
- observability: "none",
7354
- rustWebFramework: "none",
7355
- rustFrontend: "none",
7356
- rustOrm: "none",
7357
- rustApi: "none",
7358
- rustCli: "none",
7359
- rustLibraries: [],
7360
- cms: "none",
7361
- caching: "none",
7362
- search: "none",
7363
- featureFlags: "none",
7364
- analytics: "none",
7365
- fileStorage: "none",
7366
- pythonWebFramework: "none",
7367
- pythonOrm: "none",
7368
- pythonValidation: "none",
7369
- pythonAi: [],
7370
- pythonTaskQueue: "none",
7371
- pythonQuality: "none",
7372
- goWebFramework: "none",
7373
- goOrm: "none",
7374
- goApi: "none",
7375
- goCli: "none",
7376
- goLogging: "none",
7377
- aiDocs: []
7378
- },
7379
- reproducibleCommand: "",
7380
- timeScaffolded,
7381
- elapsedTimeMs: Date.now() - startTime,
7382
- projectDirectory: "",
7383
- relativePath: "",
7384
- error: error instanceof Error ? error.message : String(error)
7385
- };
7476
+ error: error instanceof Error ? error.message : String(error)
7477
+ };
7478
+ }
7479
+ const setupResult = await setupProjectDirectory(finalPathInput, shouldClearDirectory);
7480
+ finalResolvedPath = setupResult.finalResolvedPath;
7481
+ finalBaseName = setupResult.finalBaseName;
7482
+ currentPathInput = finalPathInput;
7386
7483
  }
7387
- const { finalResolvedPath, finalBaseName } = await setupProjectDirectory(finalPathInput, shouldClearDirectory);
7388
7484
  const originalInput = {
7389
7485
  ...input,
7390
7486
  projectDirectory: input.projectName
@@ -7418,7 +7514,7 @@ async function createProjectHandler(input, options = {}) {
7418
7514
  ...flagConfig,
7419
7515
  projectName: finalBaseName,
7420
7516
  projectDir: finalResolvedPath,
7421
- relativePath: finalPathInput,
7517
+ relativePath: currentPathInput,
7422
7518
  versionChannel
7423
7519
  };
7424
7520
  validateConfigCompatibility(config, providedFlags, cliInput);
@@ -7437,12 +7533,54 @@ async function createProjectHandler(input, options = {}) {
7437
7533
  log.message("");
7438
7534
  }
7439
7535
  config = {
7440
- ...await gatherConfig(flagConfig, finalBaseName, finalResolvedPath, finalPathInput),
7536
+ ...await gatherConfig(flagConfig, finalBaseName, finalResolvedPath, currentPathInput),
7441
7537
  versionChannel
7442
7538
  };
7443
7539
  }
7444
7540
  const preflight = validatePreflightConfig(config);
7445
7541
  if (preflight.hasWarnings && !isSilent()) displayPreflightWarnings(preflight);
7542
+ if (input.dryRun) {
7543
+ const result = await generateVirtualProject$1({
7544
+ config,
7545
+ templates: EMBEDDED_TEMPLATES$1
7546
+ });
7547
+ if (!result.success || !result.tree) throw new Error(result.error || "Failed to generate project templates");
7548
+ const files = [];
7549
+ function walk(nodes, prefix) {
7550
+ for (const node of nodes) {
7551
+ const current = prefix ? `${prefix}/${node.name}` : node.name;
7552
+ if (node.type === "directory" && node.children) walk(node.children, current);
7553
+ else files.push(current);
7554
+ }
7555
+ }
7556
+ walk(result.tree.root.children, "");
7557
+ if (!isSilent()) {
7558
+ log.info(pc.bold(pc.cyan(`Dry run complete — ${result.tree.fileCount} files in ${result.tree.directoryCount} directories`)));
7559
+ log.message("");
7560
+ log.message(pc.bold("Files that would be created:"));
7561
+ for (const file of files) log.message(pc.dim(` ${file}`));
7562
+ }
7563
+ const reproducibleCommand$1 = generateReproducibleCommand(config);
7564
+ if (!isSilent()) {
7565
+ log.message("");
7566
+ log.success(pc.blue(`You can reproduce this setup with the following command:\n${reproducibleCommand$1}`));
7567
+ }
7568
+ const elapsedTimeMs$1 = Date.now() - startTime;
7569
+ if (!isSilent()) outro(pc.magenta("No files were written (dry run)."));
7570
+ return {
7571
+ success: true,
7572
+ projectConfig: config,
7573
+ reproducibleCommand: reproducibleCommand$1,
7574
+ timeScaffolded,
7575
+ elapsedTimeMs: elapsedTimeMs$1,
7576
+ projectDirectory: config.projectDir,
7577
+ relativePath: config.relativePath,
7578
+ dryRun: true,
7579
+ fileCount: result.tree.fileCount,
7580
+ directoryCount: result.tree.directoryCount,
7581
+ files
7582
+ };
7583
+ }
7446
7584
  await createProject(config, { manualDb: cliInput.manualDb ?? input.manualDb });
7447
7585
  const reproducibleCommand = generateReproducibleCommand(config);
7448
7586
  if (!isSilent()) log.success(pc.blue(`You can reproduce this setup with the following command:\n${reproducibleCommand}`));
@@ -7594,7 +7732,7 @@ function displaySponsorsBox(sponsors$1) {
7594
7732
  //#region src/index.ts
7595
7733
  const router = os.router({
7596
7734
  create: os.meta({
7597
- description: "Create a new Better Fullstack project",
7735
+ description: "Scaffold a new Better Fullstack project from 270+ compatible stack options",
7598
7736
  default: true,
7599
7737
  negateBooleans: true
7600
7738
  }).input(z.tuple([types_exports.ProjectNameSchema.optional(), z.object({
@@ -7602,6 +7740,7 @@ const router = os.router({
7602
7740
  yes: z.boolean().optional().default(false).describe("Use default configuration"),
7603
7741
  yolo: z.boolean().optional().default(false).describe("(WARNING - NOT RECOMMENDED) Bypass validations and compatibility checks"),
7604
7742
  verbose: z.boolean().optional().default(false).describe("Show detailed result information"),
7743
+ dryRun: z.boolean().optional().default(false).describe("Preview generated file tree without writing to disk"),
7605
7744
  ecosystem: types_exports.EcosystemSchema.optional().describe("Language ecosystem (typescript, rust, python, or go)"),
7606
7745
  database: types_exports.DatabaseSchema.optional(),
7607
7746
  orm: types_exports.ORMSchema.optional(),
@@ -7659,13 +7798,14 @@ const router = os.router({
7659
7798
  rustApi: types_exports.RustApiSchema.optional().describe("Rust API layer (tonic, async-graphql)"),
7660
7799
  rustCli: types_exports.RustCliSchema.optional().describe("Rust CLI tools (clap, ratatui)"),
7661
7800
  rustLibraries: z.array(types_exports.RustLibrariesSchema).optional().describe("Rust core libraries"),
7801
+ rustLogging: types_exports.RustLoggingSchema.optional().describe("Rust logging (tracing, env-logger)"),
7662
7802
  pythonWebFramework: types_exports.PythonWebFrameworkSchema.optional().describe("Python web framework (fastapi, django)"),
7663
7803
  pythonOrm: types_exports.PythonOrmSchema.optional().describe("Python ORM/database (sqlalchemy, sqlmodel)"),
7664
7804
  pythonValidation: types_exports.PythonValidationSchema.optional().describe("Python validation (pydantic)"),
7665
7805
  pythonAi: z.array(types_exports.PythonAiSchema).optional().describe("Python AI/ML frameworks"),
7666
7806
  pythonTaskQueue: types_exports.PythonTaskQueueSchema.optional().describe("Python task queue (celery)"),
7667
7807
  pythonQuality: types_exports.PythonQualitySchema.optional().describe("Python code quality (ruff)"),
7668
- goWebFramework: types_exports.GoWebFrameworkSchema.optional().describe("Go web framework (gin, echo)"),
7808
+ goWebFramework: types_exports.GoWebFrameworkSchema.optional().describe("Go web framework (gin, echo, fiber)"),
7669
7809
  goOrm: types_exports.GoOrmSchema.optional().describe("Go ORM/database (gorm, sqlc)"),
7670
7810
  goApi: types_exports.GoApiSchema.optional().describe("Go API layer (grpc-go)"),
7671
7811
  goCli: types_exports.GoCliSchema.optional().describe("Go CLI tools (cobra, bubbletea)"),
@@ -7706,7 +7846,7 @@ const router = os.router({
7706
7846
  log.message(`Please visit ${BUILDER_URL}`);
7707
7847
  }
7708
7848
  }),
7709
- add: os.meta({ description: "Add addons or deployment targets to an existing Better Fullstack project" }).input(z.object({
7849
+ add: os.meta({ description: "Add addons or deployment targets to an existing Better Fullstack project using its bts.jsonc config" }).input(z.object({
7710
7850
  addons: z.array(types_exports.AddonsSchema).optional().describe("Addons to add"),
7711
7851
  webDeploy: types_exports.WebDeploySchema.optional().describe("Web deployment option to set"),
7712
7852
  serverDeploy: types_exports.ServerDeploySchema.optional().describe("Server deployment option to set"),
@@ -7741,7 +7881,7 @@ const router = os.router({
7741
7881
  ecosystem: input.ecosystem
7742
7882
  });
7743
7883
  }),
7744
- mcp: os.meta({ description: "Start MCP server for AI agent integration (stdio transport)" }).handler(async () => {
7884
+ mcp: os.meta({ description: "Start the Better Fullstack MCP server so AI agents can inspect the schema, plan stacks, and scaffold projects over stdio" }).handler(async () => {
7745
7885
  log.message("MCP server is started via the 'mcp' subcommand intercepted in cli.ts.");
7746
7886
  log.message("Run: create-better-fullstack mcp");
7747
7887
  })
@@ -7899,6 +8039,7 @@ async function createVirtual(options) {
7899
8039
  rustApi: options.rustApi || "none",
7900
8040
  rustCli: options.rustCli || "none",
7901
8041
  rustLibraries: options.rustLibraries || [],
8042
+ rustLogging: options.rustLogging || (options.ecosystem === "rust" ? "tracing" : "none"),
7902
8043
  pythonWebFramework: options.pythonWebFramework || "none",
7903
8044
  pythonOrm: options.pythonOrm || "none",
7904
8045
  pythonValidation: options.pythonValidation || "none",
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import "./bts-config-BCe8SqYV.mjs";
2
+ import "./bts-config-BYD8mHt-.mjs";
3
3
  import { t as startMcpServer } from "./mcp-entry.mjs";
4
4
 
5
5
  export { startMcpServer };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { i as getLatestCLIVersion, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-BCe8SqYV.mjs";
2
+ import { i as getLatestCLIVersion, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-BYD8mHt-.mjs";
3
3
  import z from "zod";
4
- import { AISchema, APISchema, AddonsSchema, AnalyticsSchema, AnimationSchema, AstroIntegrationSchema, AuthSchema, BackendSchema, CMSSchema, CSSFrameworkSchema, CachingSchema, DatabaseSchema, DatabaseSetupSchema, EcosystemSchema, EffectSchema, EmailSchema, ExamplesSchema, FeatureFlagsSchema, FileStorageSchema, FileUploadSchema, FormsSchema, FrontendSchema, GoApiSchema, GoCliSchema, GoLoggingSchema, GoOrmSchema, GoWebFrameworkSchema, JobQueueSchema, LoggingSchema, ORMSchema, ObservabilitySchema, PackageManagerSchema, PaymentsSchema, PythonAiSchema, PythonOrmSchema, PythonQualitySchema, PythonTaskQueueSchema, PythonValidationSchema, PythonWebFrameworkSchema, RealtimeSchema, RuntimeSchema, RustApiSchema, RustCliSchema, RustFrontendSchema, RustLibrariesSchema, RustOrmSchema, RustWebFrameworkSchema, SearchSchema, ServerDeploySchema, StateManagementSchema, TestingSchema, UILibrarySchema, ValidationSchema, WebDeploySchema, analyzeStackCompatibility } from "@better-fullstack/types";
4
+ import { AISchema, APISchema, AddonsSchema, AnalyticsSchema, AnimationSchema, AstroIntegrationSchema, AuthSchema, BackendSchema, CMSSchema, CSSFrameworkSchema, CachingSchema, DatabaseSchema, DatabaseSetupSchema, EcosystemSchema, EffectSchema, EmailSchema, ExamplesSchema, FeatureFlagsSchema, FileStorageSchema, FileUploadSchema, FormsSchema, FrontendSchema, GoApiSchema, GoCliSchema, GoLoggingSchema, GoOrmSchema, GoWebFrameworkSchema, JobQueueSchema, LoggingSchema, ORMSchema, ObservabilitySchema, PackageManagerSchema, PaymentsSchema, PythonAiSchema, PythonOrmSchema, PythonQualitySchema, PythonTaskQueueSchema, PythonValidationSchema, PythonWebFrameworkSchema, RealtimeSchema, RuntimeSchema, RustApiSchema, RustCliSchema, RustFrontendSchema, RustLibrariesSchema, RustLoggingSchema, RustOrmSchema, RustWebFrameworkSchema, SearchSchema, ServerDeploySchema, StateManagementSchema, TestingSchema, UILibrarySchema, ValidationSchema, WebDeploySchema, analyzeStackCompatibility } from "@better-fullstack/types";
5
5
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
 
@@ -114,6 +114,7 @@ const SCHEMA_MAP = {
114
114
  rustApi: RustApiSchema,
115
115
  rustCli: RustCliSchema,
116
116
  rustLibraries: RustLibrariesSchema,
117
+ rustLogging: RustLoggingSchema,
117
118
  pythonWebFramework: PythonWebFrameworkSchema,
118
119
  pythonOrm: PythonOrmSchema,
119
120
  pythonValidation: PythonValidationSchema,
@@ -165,7 +166,8 @@ const ECOSYSTEM_CATEGORIES = {
165
166
  "rustOrm",
166
167
  "rustApi",
167
168
  "rustCli",
168
- "rustLibraries"
169
+ "rustLibraries",
170
+ "rustLogging"
169
171
  ],
170
172
  python: [
171
173
  "pythonWebFramework",
@@ -302,6 +304,7 @@ function buildProjectConfig(input, overrides) {
302
304
  rustApi: input.rustApi ?? "none",
303
305
  rustCli: input.rustCli ?? "none",
304
306
  rustLibraries: input.rustLibraries ?? [],
307
+ rustLogging: input.rustLogging ?? "none",
305
308
  pythonWebFramework: input.pythonWebFramework ?? "none",
306
309
  pythonOrm: input.pythonOrm ?? "none",
307
310
  pythonValidation: input.pythonValidation ?? "none",
@@ -390,6 +393,7 @@ function buildCompatibilityInput(input) {
390
393
  rustApi: input.rustApi ?? "none",
391
394
  rustCli: input.rustCli ?? "none",
392
395
  rustLibraries: (input.rustLibraries ?? []).join(",") || "none",
396
+ rustLogging: input.rustLogging ?? "none",
393
397
  pythonWebFramework: input.pythonWebFramework ?? "none",
394
398
  pythonOrm: input.pythonOrm ?? "none",
395
399
  pythonValidation: input.pythonValidation ?? "none",
@@ -592,6 +596,7 @@ async function startMcpServer() {
592
596
  rustApi: RustApiSchema.optional().describe("Rust API layer"),
593
597
  rustCli: RustCliSchema.optional().describe("Rust CLI framework"),
594
598
  rustLibraries: z.array(RustLibrariesSchema).optional().describe("Rust libraries"),
599
+ rustLogging: RustLoggingSchema.optional().describe("Rust logging library"),
595
600
  pythonWebFramework: PythonWebFrameworkSchema.optional().describe("Python web framework"),
596
601
  pythonOrm: PythonOrmSchema.optional().describe("Python ORM"),
597
602
  pythonValidation: PythonValidationSchema.optional().describe("Python validation"),
@@ -671,7 +676,7 @@ async function startMcpServer() {
671
676
  await writeBtsConfig(config);
672
677
  let addonWarnings = [];
673
678
  if (config.addons.length > 0 && config.addons[0] !== "none") {
674
- const { setupAddons } = await import("./addons-setup-AbN693PV.mjs");
679
+ const { setupAddons } = await import("./addons-setup-CWGwxN68.mjs");
675
680
  addonWarnings = await setupAddons(config);
676
681
  }
677
682
  const installCmd = getInstallCommand(input.ecosystem ?? "typescript", projectName, input.packageManager);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-fullstack",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "description": "Scaffold production-ready fullstack apps in seconds. Pick your stack from 270+ options — the CLI wires everything together.",
5
5
  "keywords": [
6
6
  "angular",
@@ -101,7 +101,7 @@
101
101
  "check-types": "tsc --noEmit",
102
102
  "test": "bun test ./test/*.test.ts",
103
103
  "test:watch": "bun test --watch",
104
- "test:coverage": "bun test --coverage",
104
+ "test:coverage": "bun test --coverage ./test/*.test.ts",
105
105
  "test:ci": "CI=1 bun test --bail=5",
106
106
  "test:e2e": "E2E=1 bun test test/e2e/e2e.e2e.ts --timeout 600000",
107
107
  "test:integration": "bun test test/e2e/cli-interaction.test.ts test/e2e/cli-binary.test.ts",
@@ -112,10 +112,10 @@
112
112
  "prepublishOnly": "npm run build"
113
113
  },
114
114
  "dependencies": {
115
- "@better-fullstack/template-generator": "^1.5.2",
116
- "@better-fullstack/types": "^1.5.2",
115
+ "@better-fullstack/template-generator": "^1.5.3",
116
+ "@better-fullstack/types": "^1.5.3",
117
117
  "@clack/core": "^0.5.0",
118
- "@clack/prompts": "^1.1.0",
118
+ "@clack/prompts": "^1.2.0",
119
119
  "@orpc/server": "^1.13.13",
120
120
  "consola": "^3.4.2",
121
121
  "env-paths": "^4.0.0",
@@ -127,7 +127,7 @@
127
127
  "oxfmt": "^0.19.0",
128
128
  "picocolors": "^1.1.1",
129
129
  "tinyglobby": "^0.2.15",
130
- "@modelcontextprotocol/sdk": "^1.12.1",
130
+ "@modelcontextprotocol/sdk": "^1.29.0",
131
131
  "trpc-cli": "^0.12.1",
132
132
  "ts-morph": "^27.0.2",
133
133
  "yaml": "^2.8.3",
@@ -136,7 +136,7 @@
136
136
  "devDependencies": {
137
137
  "@types/bun": "^1.3.11",
138
138
  "@types/fs-extra": "^11.0.4",
139
- "@types/node": "^25.5.0",
139
+ "@types/node": "^25.5.2",
140
140
  "publint": "^0.3.18",
141
141
  "tsdown": "^0.18.2",
142
142
  "typescript": "^5.9.3"
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./bts-config-BCe8SqYV.mjs";
3
- import { i as setupLefthook, n as setupBiome, r as setupHusky, t as setupAddons } from "./addons-setup-1jZXP0D3.mjs";
4
-
5
- export { setupAddons };