create-better-fullstack 1.4.6 → 1.4.8

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/README.md CHANGED
@@ -26,7 +26,7 @@ Options:
26
26
  --yolo Random configuration (experimental)
27
27
  --database <type> Database type (none, sqlite, postgres, mysql, mongodb)
28
28
  --orm <type> ORM type (drizzle, prisma, mongoose, typeorm, kysely, mikroorm, sequelize, none)
29
- --auth <type> Authentication (better-auth, clerk, nextauth, none)
29
+ --auth <type> Authentication (better-auth, go-better-auth, clerk, nextauth, stack-auth, supabase-auth, auth0, none)
30
30
  --payments <type> Payments (polar, stripe, lemon-squeezy, paddle, dodo, none)
31
31
  --frontend <types...> Frontend types
32
32
  --backend <framework> Backend framework
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { s as createBtsCli } from "./src-B5kV0Yns.mjs";
2
+ import { s as createBtsCli } from "./src-Cu97R-IA.mjs";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createBtsCli().run();
package/dist/index.d.mts CHANGED
@@ -57,6 +57,7 @@ declare const router: {
57
57
  auth: z.ZodOptional<z.ZodEnum<{
58
58
  none: "none";
59
59
  "better-auth": "better-auth";
60
+ "go-better-auth": "go-better-auth";
60
61
  clerk: "clerk";
61
62
  nextauth: "nextauth";
62
63
  "stack-auth": "stack-auth";
@@ -179,6 +180,11 @@ declare const router: {
179
180
  sentry: "sentry";
180
181
  grafana: "grafana";
181
182
  }>>;
183
+ featureFlags: z.ZodOptional<z.ZodEnum<{
184
+ none: "none";
185
+ growthbook: "growthbook";
186
+ posthog: "posthog";
187
+ }>>;
182
188
  analytics: z.ZodOptional<z.ZodEnum<{
183
189
  none: "none";
184
190
  plausible: "plausible";
@@ -523,7 +529,7 @@ declare const router: {
523
529
  frontend: ("none" | "tanstack-router" | "react-router" | "tanstack-start" | "next" | "nuxt" | "native-bare" | "native-uniwind" | "native-unistyles" | "svelte" | "solid" | "solid-start" | "astro" | "qwik" | "angular" | "redwood" | "fresh")[];
524
530
  addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "lefthook" | "husky" | "ruler" | "mcp" | "skills" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt" | "msw" | "storybook")[];
525
531
  examples: ("ai" | "none" | "chat-sdk")[];
526
- auth: "none" | "better-auth" | "clerk" | "nextauth" | "stack-auth" | "supabase-auth" | "auth0";
532
+ auth: "none" | "better-auth" | "go-better-auth" | "clerk" | "nextauth" | "stack-auth" | "supabase-auth" | "auth0";
527
533
  payments: "none" | "polar" | "stripe" | "lemon-squeezy" | "paddle" | "dodo";
528
534
  git: boolean;
529
535
  packageManager: "bun" | "npm" | "pnpm";
@@ -609,7 +615,7 @@ declare const router: {
609
615
  frontend: ("none" | "tanstack-router" | "react-router" | "tanstack-start" | "next" | "nuxt" | "native-bare" | "native-uniwind" | "native-unistyles" | "svelte" | "solid" | "solid-start" | "astro" | "qwik" | "angular" | "redwood" | "fresh")[];
610
616
  addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "lefthook" | "husky" | "ruler" | "mcp" | "skills" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt" | "msw" | "storybook")[];
611
617
  examples: ("ai" | "none" | "chat-sdk")[];
612
- auth: "none" | "better-auth" | "clerk" | "nextauth" | "stack-auth" | "supabase-auth" | "auth0";
618
+ auth: "none" | "better-auth" | "go-better-auth" | "clerk" | "nextauth" | "stack-auth" | "supabase-auth" | "auth0";
613
619
  payments: "none" | "polar" | "stripe" | "lemon-squeezy" | "paddle" | "dodo";
614
620
  git: boolean;
615
621
  packageManager: "bun" | "npm" | "pnpm";
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { a as builder, c as createVirtual, d as history, f as router, i as add, l as docs, n as TEMPLATE_COUNT, o as create, p as sponsors, r as VirtualFileSystem, s as createBtsCli, t as EMBEDDED_TEMPLATES, u as generateVirtualProject } from "./src-B5kV0Yns.mjs";
2
+ import { a as builder, c as createVirtual, d as history, f as router, i as add, l as docs, n as TEMPLATE_COUNT, o as create, p as sponsors, r as VirtualFileSystem, s as createBtsCli, t as EMBEDDED_TEMPLATES, u as generateVirtualProject } from "./src-Cu97R-IA.mjs";
3
3
 
4
4
  export { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generateVirtualProject, history, router, sponsors };
@@ -13,7 +13,7 @@ import { ECOSYSTEM_GROUPS, EMBEDDED_TEMPLATES, EMBEDDED_TEMPLATES as EMBEDDED_TE
13
13
  import gradient from "gradient-string";
14
14
  import path$1 from "path";
15
15
  import { writeTreeToFilesystem } from "@better-fullstack/template-generator/fs-writer";
16
- import { allowedApisForFrontends, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleUILibraries, hasWebStyling, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isWebFrontend, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility } from "@better-fullstack/types";
16
+ import { allowedApisForFrontends, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleUILibraries, getLocalWebDevPort, hasWebStyling, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isWebFrontend, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility } from "@better-fullstack/types";
17
17
  import consola, { consola as consola$1 } from "consola";
18
18
  import { AsyncLocalStorage } from "node:async_hooks";
19
19
  import { ConfirmPrompt, GroupMultiSelectPrompt, MultiSelectPrompt, SelectPrompt, isCancel as isCancel$1 } from "@clack/core";
@@ -791,61 +791,6 @@ function validateApiFrontendCompatibility(api, frontends = [], astroIntegration)
791
791
  function isFrontendAllowedWithBackend$1(frontend, backend, auth) {
792
792
  return isFrontendAllowedWithBackend(frontend, backend, auth);
793
793
  }
794
- function validateClerkCompatibility(auth, backend, frontends = []) {
795
- if (auth !== "clerk") return;
796
- if (backend === "convex") {
797
- const incompatibleFrontends = frontends.filter((f) => [
798
- "nuxt",
799
- "svelte",
800
- "solid",
801
- "solid-start"
802
- ].includes(f));
803
- if (incompatibleFrontends.length > 0) exitWithError(`In Better-Fullstack, Clerk + Convex is not compatible with the following frontends: ${incompatibleFrontends.join(", ")}. Please choose a different frontend or auth provider.`);
804
- return;
805
- }
806
- if (backend === "self") {
807
- if (frontends.some((f) => [
808
- "native-bare",
809
- "native-uniwind",
810
- "native-unistyles"
811
- ].includes(f))) exitWithError("In Better-Fullstack, Clerk with the 'self' backend is currently supported only for web-only Next.js or TanStack Start projects (no native companion app). Please remove the native frontend or choose a different auth provider.");
812
- const hasNextJs = frontends.includes("next");
813
- const hasTanStackStart = frontends.includes("tanstack-start");
814
- if (!hasNextJs && !hasTanStackStart) {
815
- if (frontends.includes("astro")) exitWithError("In Better-Fullstack, Clerk is not yet supported for Astro fullstack projects. Please use '--frontend next' or '--frontend tanstack-start' with '--backend self', or choose a different auth provider.");
816
- if (frontends.includes("nuxt")) exitWithError("In Better-Fullstack, Clerk is not yet supported for Nuxt fullstack projects. Please use '--frontend next' or '--frontend tanstack-start' with '--backend self', or choose a different auth provider.");
817
- if (frontends.includes("svelte")) exitWithError("In Better-Fullstack, Clerk is not yet supported for SvelteKit fullstack projects. Please use '--frontend next' or '--frontend tanstack-start' with '--backend self', or choose a different auth provider.");
818
- if (frontends.includes("solid-start")) exitWithError("In Better-Fullstack, Clerk is not yet supported for SolidStart fullstack projects. Please use '--frontend next' or '--frontend tanstack-start' with '--backend self', or choose a different auth provider.");
819
- exitWithError("In Better-Fullstack, Clerk with the 'self' backend currently requires the Next.js or TanStack Start frontend. Please use '--frontend next' or '--frontend tanstack-start', or choose a different auth provider.");
820
- }
821
- return;
822
- }
823
- exitWithError("In Better-Fullstack, Clerk authentication is currently supported with the Convex backend, or with the 'self' backend when using Next.js or TanStack Start. Please choose a supported backend/frontend combination or a different auth provider.");
824
- }
825
- function validateNextAuthCompatibility(auth, backend, frontends = []) {
826
- if (auth !== "nextauth") return;
827
- const hasNextJs = frontends.includes("next");
828
- if (backend !== "self") exitWithError("In Better-Fullstack, Auth.js (NextAuth) is currently supported only with the 'self' backend (fullstack Next.js). Please use '--backend self' or choose a different auth provider.");
829
- if (!hasNextJs) exitWithError("In Better-Fullstack, Auth.js (NextAuth) currently requires the Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
830
- }
831
- function validateStackAuthCompatibility(auth, backend, frontends = []) {
832
- if (auth !== "stack-auth") return;
833
- const hasNextJs = frontends.includes("next");
834
- if (backend !== "self") exitWithError("In Better-Fullstack, Stack Auth is currently supported only with the 'self' backend (fullstack Next.js). Please use '--backend self' or choose a different auth provider.");
835
- if (!hasNextJs) exitWithError("In Better-Fullstack, Stack Auth currently requires the Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
836
- }
837
- function validateSupabaseAuthCompatibility(auth, backend, frontends = []) {
838
- if (auth !== "supabase-auth") return;
839
- const hasNextJs = frontends.includes("next");
840
- if (backend !== "self") exitWithError("In Better-Fullstack, Supabase Auth is currently supported only with the 'self' backend (fullstack Next.js). Please use '--backend self' or choose a different auth provider.");
841
- if (!hasNextJs) exitWithError("In Better-Fullstack, Supabase Auth currently requires the Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
842
- }
843
- function validateAuth0Compatibility(auth, backend, frontends = []) {
844
- if (auth !== "auth0") return;
845
- const hasNextJs = frontends.includes("next");
846
- if (backend !== "self") exitWithError("In Better-Fullstack, Auth0 is currently supported only with the 'self' backend (fullstack Next.js). Please use '--backend self' or choose a different auth provider.");
847
- if (!hasNextJs) exitWithError("In Better-Fullstack, Auth0 currently requires the Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
848
- }
849
794
  function allowedApisForFrontends$1(frontends = [], astroIntegration) {
850
795
  return allowedApisForFrontends(frontends, astroIntegration);
851
796
  }
@@ -2411,12 +2356,11 @@ async function setupTauri(config) {
2411
2356
  if (!await fs.pathExists(clientPackageDir)) return;
2412
2357
  try {
2413
2358
  s.start("Setting up Tauri desktop app support...");
2414
- const hasReactRouter = frontend.includes("react-router");
2415
2359
  const hasNuxt = frontend.includes("nuxt");
2416
2360
  const hasSvelte = frontend.includes("svelte");
2417
2361
  const hasNext = frontend.includes("next");
2418
- const devUrl = hasReactRouter || hasSvelte ? "http://localhost:5173" : hasNext ? "http://localhost:3001" : "http://localhost:3001";
2419
- const frontendDist = hasNuxt ? "../.output/public" : hasSvelte ? "../build" : hasNext ? "../.next" : hasReactRouter ? "../build/client" : "../dist";
2362
+ const devUrl = `http://localhost:${getLocalWebDevPort(frontend)}`;
2363
+ const frontendDist = hasNuxt ? "../.output/public" : hasSvelte ? "../build" : hasNext ? "../.next" : frontend.includes("react-router") ? "../build/client" : "../dist";
2420
2364
  const tauriArgs = [
2421
2365
  "@tauri-apps/cli@latest",
2422
2366
  "init",
@@ -3205,103 +3149,36 @@ async function getAstroIntegrationChoice(astroIntegration) {
3205
3149
 
3206
3150
  //#endregion
3207
3151
  //#region src/prompts/auth.ts
3208
- async function getAuthChoice(auth, backend, frontend) {
3152
+ async function getAuthChoice(auth, backend, frontend, ecosystem = "typescript") {
3209
3153
  if (auth !== void 0) return auth;
3210
- if (backend === "none") return "none";
3211
- if (backend === "convex") {
3212
- const supportedBetterAuthFrontends = frontend?.some((f) => [
3213
- "tanstack-router",
3214
- "tanstack-start",
3215
- "next",
3216
- "native-bare",
3217
- "native-uniwind",
3218
- "native-unistyles"
3219
- ].includes(f));
3220
- const hasClerkCompatibleFrontends = frontend?.some((f) => [
3221
- "react-router",
3222
- "tanstack-router",
3223
- "tanstack-start",
3224
- "next",
3225
- "native-bare",
3226
- "native-uniwind",
3227
- "native-unistyles"
3228
- ].includes(f));
3229
- const options$1 = [];
3230
- if (supportedBetterAuthFrontends) options$1.push({
3231
- value: "better-auth",
3232
- label: "Better-Auth",
3233
- hint: "comprehensive auth framework for TypeScript"
3234
- });
3235
- if (hasClerkCompatibleFrontends) options$1.push({
3236
- value: "clerk",
3237
- label: "Clerk",
3238
- hint: "More than auth, Complete User Management"
3239
- });
3240
- if (options$1.length === 0) return "none";
3241
- options$1.push({
3242
- value: "none",
3243
- label: "None",
3244
- hint: "No auth"
3245
- });
3246
- const response$1 = await navigableSelect({
3247
- message: "Select authentication provider",
3248
- options: options$1,
3249
- initialValue: "none"
3250
- });
3251
- if (isCancel$1(response$1)) return exitCancelled("Operation cancelled");
3252
- return response$1;
3253
- }
3254
- const hasNextJs = frontend?.includes("next");
3255
- const hasTanStackStart = frontend?.includes("tanstack-start");
3256
- const isSelfBackend = backend === "self";
3257
- const supportsNextJsAuth = hasNextJs && isSelfBackend;
3258
- const hasNativeFrontend$2 = frontend?.some((f) => [
3259
- "native-bare",
3260
- "native-uniwind",
3261
- "native-unistyles"
3262
- ].includes(f));
3263
- const supportsClerkSelf = isSelfBackend && !hasNativeFrontend$2 && Boolean(hasNextJs || hasTanStackStart);
3264
- const options = [{
3265
- value: "better-auth",
3266
- label: "Better-Auth",
3267
- hint: "comprehensive auth framework for TypeScript"
3268
- }];
3269
- if (supportsClerkSelf) options.push({
3270
- value: "clerk",
3271
- label: "Clerk",
3272
- hint: "More than auth, Complete User Management"
3154
+ const authOptionOrder = [
3155
+ { value: "better-auth" },
3156
+ { value: "go-better-auth" },
3157
+ { value: "clerk" },
3158
+ { value: "nextauth" },
3159
+ { value: "stack-auth" },
3160
+ { value: "supabase-auth" },
3161
+ { value: "auth0" },
3162
+ { value: "none" }
3163
+ ];
3164
+ const supportedOptions = (0, types_exports.getSupportedCapabilityOptions)("auth", {
3165
+ ecosystem,
3166
+ backend,
3167
+ frontend
3273
3168
  });
3274
- if (supportsNextJsAuth) {
3275
- options.push({
3276
- value: "nextauth",
3277
- label: "Auth.js (NextAuth)",
3278
- hint: "Authentication for Next.js (formerly NextAuth.js)"
3279
- });
3280
- options.push({
3281
- value: "stack-auth",
3282
- label: "Stack Auth",
3283
- hint: "Open-source Auth0/Clerk alternative"
3284
- });
3285
- options.push({
3286
- value: "supabase-auth",
3287
- label: "Supabase Auth",
3288
- hint: "Auth with Supabase platform integration"
3289
- });
3290
- options.push({
3291
- value: "auth0",
3292
- label: "Auth0",
3293
- hint: "Flexible identity platform for authentication"
3294
- });
3295
- }
3296
- options.push({
3297
- value: "none",
3298
- label: "None",
3299
- hint: "No authentication"
3169
+ const options = authOptionOrder.flatMap(({ value }) => {
3170
+ const option = supportedOptions.find((candidate) => candidate.id === value);
3171
+ return option ? [option] : [];
3300
3172
  });
3173
+ if (options.length === 1 && options[0]?.id === "none") return "none";
3301
3174
  const response = await navigableSelect({
3302
3175
  message: "Select authentication provider",
3303
- options,
3304
- initialValue: DEFAULT_CONFIG.auth
3176
+ options: options.map((option) => ({
3177
+ value: option.id,
3178
+ label: option.label,
3179
+ hint: option.promptHint
3180
+ })),
3181
+ initialValue: options.some((option) => option.id === DEFAULT_CONFIG.auth) ? DEFAULT_CONFIG.auth : options.find((option) => option.id !== "none")?.id ?? "none"
3305
3182
  });
3306
3183
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
3307
3184
  return response;
@@ -3976,8 +3853,8 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
3976
3853
  },
3977
3854
  {
3978
3855
  value: "svelte",
3979
- label: "Svelte",
3980
- hint: "web development for the rest of us"
3856
+ label: "SvelteKit",
3857
+ hint: "Full-stack Svelte framework with SSR and server routes"
3981
3858
  },
3982
3859
  {
3983
3860
  value: "solid",
@@ -4627,6 +4504,11 @@ async function getPythonAiChoice(pythonAi) {
4627
4504
  const response = await navigableMultiselect({
4628
4505
  message: "Select Python AI/ML frameworks",
4629
4506
  options: [
4507
+ {
4508
+ value: "none",
4509
+ label: "None",
4510
+ hint: "No AI/ML framework"
4511
+ },
4630
4512
  {
4631
4513
  value: "langchain",
4632
4514
  label: "LangChain",
@@ -4662,6 +4544,7 @@ async function getPythonAiChoice(pythonAi) {
4662
4544
  initialValues: []
4663
4545
  });
4664
4546
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
4547
+ if (response.includes("none")) return [];
4665
4548
  return response;
4666
4549
  }
4667
4550
  async function getPythonTaskQueueChoice(pythonTaskQueue) {
@@ -5708,8 +5591,9 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
5708
5591
  return getApiChoice(flags.api, results.frontend, results.backend, results.astroIntegration);
5709
5592
  },
5710
5593
  auth: ({ results }) => {
5711
- if (results.ecosystem !== "typescript") return Promise.resolve("none");
5712
- return getAuthChoice(flags.auth, results.backend, results.frontend);
5594
+ if (results.ecosystem === "typescript") return getAuthChoice(flags.auth, results.backend, results.frontend, "typescript");
5595
+ if (results.ecosystem === "go") return getAuthChoice(flags.auth, void 0, void 0, "go");
5596
+ return Promise.resolve("none");
5713
5597
  },
5714
5598
  payments: ({ results }) => {
5715
5599
  if (results.ecosystem !== "typescript") return Promise.resolve("none");
@@ -6734,6 +6618,18 @@ function validateDatabaseSetup(config, providedFlags) {
6734
6618
  }
6735
6619
  }
6736
6620
  }
6621
+ function validateEcosystemAuthCompatibility(config, providedFlags) {
6622
+ const auth = config.auth;
6623
+ if (!auth || auth === "none") return;
6624
+ const normalized = (0, types_exports.normalizeCapabilitySelection)("auth", {
6625
+ ecosystem: config.ecosystem,
6626
+ backend: config.backend,
6627
+ frontend: config.frontend
6628
+ }, auth);
6629
+ if (!normalized.normalized || normalized.value === auth) return;
6630
+ config.auth = normalized.value;
6631
+ if (providedFlags?.has("auth") && normalized.reason && !isSilent()) consola.warn(pc.yellow(`Unsupported auth selection '${auth}' for the current stack: ${normalized.reason}. Falling back to '--auth ${normalized.value}'.`));
6632
+ }
6737
6633
  function validateConvexConstraints(config, providedFlags) {
6738
6634
  const { backend } = config;
6739
6635
  if (backend !== "convex") return;
@@ -6786,30 +6682,6 @@ function validateConvexConstraints(config, providedFlags) {
6786
6682
  },
6787
6683
  suggestions: ["Remove --server-deploy flag", "Set --server-deploy none"]
6788
6684
  });
6789
- if (has("auth") && config.auth === "better-auth") {
6790
- const supportedFrontends = [
6791
- "tanstack-router",
6792
- "tanstack-start",
6793
- "next",
6794
- "native-bare",
6795
- "native-uniwind",
6796
- "native-unistyles"
6797
- ];
6798
- if (!config.frontend?.some((f) => supportedFrontends.includes(f))) incompatibilityError({
6799
- message: "Better-Auth with Convex requires specific frontends.",
6800
- provided: {
6801
- backend: "convex",
6802
- auth: "better-auth",
6803
- frontend: config.frontend || []
6804
- },
6805
- suggestions: [
6806
- "Use --frontend tanstack-router",
6807
- "Use --frontend tanstack-start",
6808
- "Use --frontend next",
6809
- "Use a native frontend"
6810
- ]
6811
- });
6812
- }
6813
6685
  }
6814
6686
  function validateBackendNoneConstraints(config, providedFlags) {
6815
6687
  const { backend } = config;
@@ -6819,7 +6691,6 @@ function validateBackendNoneConstraints(config, providedFlags) {
6819
6691
  if (has("database") && config.database !== "none") exitWithError("Backend 'none' requires '--database none'. Please remove the --database flag or set it to 'none'.");
6820
6692
  if (has("orm") && config.orm !== "none") exitWithError("Backend 'none' requires '--orm none'. Please remove the --orm flag or set it to 'none'.");
6821
6693
  if (has("api") && config.api !== "none") exitWithError("Backend 'none' requires '--api none'. Please remove the --api flag or set it to 'none'.");
6822
- if (has("auth") && config.auth !== "none") exitWithError("Backend 'none' requires '--auth none'. Please remove the --auth flag or set it to 'none'.");
6823
6694
  if (has("payments") && config.payments !== "none") exitWithError("Backend 'none' requires '--payments none'. Please remove the --payments flag or set it to 'none'.");
6824
6695
  if (has("dbSetup") && config.dbSetup !== "none") exitWithError("Backend 'none' requires '--db-setup none'. Please remove the --db-setup flag or set it to 'none'.");
6825
6696
  if (has("serverDeploy") && config.serverDeploy !== "none") exitWithError("Backend 'none' requires '--server-deploy none'. Please remove the --server-deploy flag or set it to 'none'.");
@@ -6888,6 +6759,7 @@ function validateShadcnConstraints(config, providedFlags) {
6888
6759
  });
6889
6760
  }
6890
6761
  function validateFullConfig(config, providedFlags, options) {
6762
+ validateEcosystemAuthCompatibility(config, providedFlags);
6891
6763
  validateDatabaseOrmAuth(config, providedFlags);
6892
6764
  validateDatabaseSetup(config, providedFlags);
6893
6765
  validateConvexConstraints(config, providedFlags);
@@ -6909,11 +6781,6 @@ function validateFullConfig(config, providedFlags, options) {
6909
6781
  }
6910
6782
  validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? [], config.runtime, config.ai);
6911
6783
  validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend ?? []);
6912
- validateClerkCompatibility(config.auth, config.backend, config.frontend ?? []);
6913
- validateNextAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6914
- validateStackAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6915
- validateSupabaseAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6916
- validateAuth0Compatibility(config.auth, config.backend, config.frontend ?? []);
6917
6784
  validateUILibraryFrontendCompatibility(config.uiLibrary, config.frontend ?? [], config.astroIntegration);
6918
6785
  validateUILibraryCSSFrameworkCompatibility(config.uiLibrary, config.cssFramework);
6919
6786
  validateShadcnConstraints(config, providedFlags);
@@ -6921,15 +6788,11 @@ function validateFullConfig(config, providedFlags, options) {
6921
6788
  }
6922
6789
  function validateConfigForProgrammaticUse(config) {
6923
6790
  try {
6791
+ validateEcosystemAuthCompatibility(config);
6924
6792
  validateDatabaseOrmAuth(config);
6925
6793
  if (config.frontend && config.frontend.length > 0) ensureSingleWebAndNative(config.frontend);
6926
6794
  validateApiFrontendCompatibility(config.api, config.frontend, config.astroIntegration);
6927
6795
  validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend);
6928
- validateClerkCompatibility(config.auth, config.backend, config.frontend ?? []);
6929
- validateNextAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6930
- validateStackAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6931
- validateSupabaseAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6932
- validateAuth0Compatibility(config.auth, config.backend, config.frontend ?? []);
6933
6796
  if (config.addons && config.addons.length > 0) validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth);
6934
6797
  validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? [], config.runtime, config.ai);
6935
6798
  validateUILibraryFrontendCompatibility(config.uiLibrary, config.frontend ?? [], config.astroIntegration);
@@ -7037,6 +6900,8 @@ async function formatCode(filePath, content) {
7037
6900
  }
7038
6901
  async function formatProject(projectDir) {
7039
6902
  async function formatDirectory(dir) {
6903
+ const denoConfigPath = path.join(dir, "deno.json");
6904
+ if (await fs.pathExists(denoConfigPath)) return;
7040
6905
  const entries = await fs.readdir(dir, { withFileTypes: true });
7041
6906
  await Promise.all(entries.map(async (entry) => {
7042
6907
  const fullPath = path.join(dir, entry.name);
@@ -8260,13 +8125,13 @@ async function displayPostInstallInstructions(config) {
8260
8125
  const hasNative = frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles");
8261
8126
  const bunWebNativeWarning = packageManager === "bun" && hasNative && hasWeb ? getBunWebNativeWarning() : "";
8262
8127
  const noOrmWarning = !isConvex && database !== "none" && orm === "none" ? getNoOrmWarning() : "";
8263
- const hasReactRouter = frontend?.includes("react-router");
8264
- const hasSvelte = frontend?.includes("svelte");
8265
- const webPort = hasReactRouter || hasSvelte ? "5173" : "3001";
8128
+ const hasFresh = frontend?.includes("fresh");
8129
+ const webPort = String(getLocalWebDevPort(frontend ?? []));
8266
8130
  const betterAuthConvexInstructions = isConvex && config.auth === "better-auth" ? getBetterAuthConvexInstructions(hasWeb ?? false, webPort, packageManager) : "";
8267
8131
  let output = `${pc.bold("Next steps")}\n${pc.cyan("1.")} ${cdCmd}\n`;
8268
8132
  let stepCounter = 2;
8269
8133
  if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} ${packageManager} install\n`;
8134
+ if (hasFresh) output += `${pc.yellow("NOTE:")} Fresh projects require ${pc.white("deno")} on your PATH\n`;
8270
8135
  if (database === "sqlite" && dbSetup !== "d1") output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} db:local\n${pc.dim(" (optional - starts local SQLite database)")}\n`;
8271
8136
  if (isConvex) {
8272
8137
  output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev:setup\n${pc.dim(" (this will guide you through Convex project setup)")}\n`;
@@ -8908,7 +8773,7 @@ const router = os.router({
8908
8773
  yes: z.boolean().optional().default(false).describe("Use default configuration"),
8909
8774
  yolo: z.boolean().optional().default(false).describe("(WARNING - NOT RECOMMENDED) Bypass validations and compatibility checks"),
8910
8775
  verbose: z.boolean().optional().default(false).describe("Show detailed result information"),
8911
- ecosystem: types_exports.EcosystemSchema.optional().describe("Language ecosystem (typescript, rust, or python)"),
8776
+ ecosystem: types_exports.EcosystemSchema.optional().describe("Language ecosystem (typescript, rust, python, or go)"),
8912
8777
  database: types_exports.DatabaseSchema.optional(),
8913
8778
  orm: types_exports.ORMSchema.optional(),
8914
8779
  auth: types_exports.AuthSchema.optional(),
@@ -8926,6 +8791,7 @@ const router = os.router({
8926
8791
  animation: types_exports.AnimationSchema.optional(),
8927
8792
  logging: types_exports.LoggingSchema.optional(),
8928
8793
  observability: types_exports.ObservabilitySchema.optional(),
8794
+ featureFlags: types_exports.FeatureFlagsSchema.optional().describe("Feature flags provider"),
8929
8795
  analytics: types_exports.AnalyticsSchema.optional().describe("Privacy-focused analytics"),
8930
8796
  cms: types_exports.CMSSchema.optional().describe("Headless CMS solution"),
8931
8797
  caching: types_exports.CachingSchema.optional().describe("Caching solution"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-fullstack",
3
- "version": "1.4.6",
3
+ "version": "1.4.8",
4
4
  "description": "A CLI-first toolkit for building Full Stack applications. Skip the configuration. Ship the code.",
5
5
  "keywords": [
6
6
  "better-auth",
@@ -76,8 +76,8 @@
76
76
  "prepublishOnly": "npm run build"
77
77
  },
78
78
  "dependencies": {
79
- "@better-fullstack/template-generator": "^1.4.6",
80
- "@better-fullstack/types": "^1.4.6",
79
+ "@better-fullstack/template-generator": "^1.4.8",
80
+ "@better-fullstack/types": "^1.4.8",
81
81
  "@clack/core": "^0.5.0",
82
82
  "@clack/prompts": "^1.0.0-alpha.8",
83
83
  "@orpc/server": "^1.13.0",