create-better-fullstack 1.3.17 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { s as createBtsCli } from "./src-BYQLJiGD.mjs";
2
+ import { s as createBtsCli } from "./src-p54ND5wJ.mjs";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createBtsCli().run();
package/dist/index.d.mts CHANGED
@@ -252,6 +252,7 @@ declare const router: {
252
252
  examples: z.ZodOptional<z.ZodArray<z.ZodEnum<{
253
253
  none: "none";
254
254
  ai: "ai";
255
+ "chat-sdk": "chat-sdk";
255
256
  }>>>;
256
257
  git: z.ZodOptional<z.ZodBoolean>;
257
258
  packageManager: z.ZodOptional<z.ZodEnum<{
@@ -452,7 +453,7 @@ declare const router: {
452
453
  runtime: "none" | "bun" | "node" | "workers";
453
454
  frontend: ("none" | "tanstack-router" | "react-router" | "tanstack-start" | "next" | "nuxt" | "native-bare" | "native-uniwind" | "native-unistyles" | "svelte" | "solid" | "astro" | "qwik" | "angular" | "redwood" | "fresh")[];
454
455
  addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "lefthook" | "husky" | "ruler" | "mcp" | "skills" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt" | "msw" | "storybook")[];
455
- examples: ("ai" | "none")[];
456
+ examples: ("ai" | "none" | "chat-sdk")[];
456
457
  auth: "none" | "better-auth" | "clerk" | "nextauth" | "stack-auth" | "supabase-auth" | "auth0";
457
458
  payments: "none" | "polar" | "stripe" | "lemon-squeezy" | "paddle" | "dodo";
458
459
  git: boolean;
@@ -531,7 +532,7 @@ declare const router: {
531
532
  runtime: "none" | "bun" | "node" | "workers";
532
533
  frontend: ("none" | "tanstack-router" | "react-router" | "tanstack-start" | "next" | "nuxt" | "native-bare" | "native-uniwind" | "native-unistyles" | "svelte" | "solid" | "astro" | "qwik" | "angular" | "redwood" | "fresh")[];
533
534
  addons: ("none" | "pwa" | "tauri" | "starlight" | "biome" | "lefthook" | "husky" | "ruler" | "mcp" | "skills" | "turborepo" | "fumadocs" | "ultracite" | "oxlint" | "opentui" | "wxt" | "msw" | "storybook")[];
534
- examples: ("ai" | "none")[];
535
+ examples: ("ai" | "none" | "chat-sdk")[];
535
536
  auth: "none" | "better-auth" | "clerk" | "nextauth" | "stack-auth" | "supabase-auth" | "auth0";
536
537
  payments: "none" | "polar" | "stripe" | "lemon-squeezy" | "paddle" | "dodo";
537
538
  git: boolean;
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-BYQLJiGD.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-p54ND5wJ.mjs";
3
3
 
4
4
  export { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generateVirtualProject, history, router, sponsors };
@@ -18,8 +18,8 @@ import { AsyncLocalStorage } from "node:async_hooks";
18
18
  import { ConfirmPrompt, GroupMultiSelectPrompt, MultiSelectPrompt, SelectPrompt, isCancel as isCancel$1 } from "@clack/core";
19
19
  import * as JSONC from "jsonc-parser";
20
20
  import { $, execa } from "execa";
21
- import { format } from "oxfmt";
22
21
  import os$1 from "node:os";
22
+ import { format } from "oxfmt";
23
23
 
24
24
  //#region src/utils/get-package-manager.ts
25
25
  const getUserPkgManager = () => {
@@ -929,7 +929,7 @@ const WORKERS_COMPATIBLE_BACKENDS = [
929
929
  ];
930
930
  function validateWorkersCompatibility(providedFlags, options, config) {
931
931
  if (providedFlags.has("runtime") && options.runtime === "workers" && config.backend && !WORKERS_COMPATIBLE_BACKENDS.includes(config.backend)) incompatibilityError({
932
- message: "Cloudflare Workers runtime requires a compatible backend.",
932
+ message: "In Better-Fullstack, Cloudflare Workers runtime is currently supported only with compatible backends (Hono, Nitro, or Fets).",
933
933
  provided: {
934
934
  runtime: "workers",
935
935
  backend: config.backend
@@ -942,7 +942,7 @@ function validateWorkersCompatibility(providedFlags, options, config) {
942
942
  ]
943
943
  });
944
944
  if (providedFlags.has("backend") && config.backend && !WORKERS_COMPATIBLE_BACKENDS.includes(config.backend) && config.runtime === "workers") incompatibilityError({
945
- message: `Backend '${config.backend}' is not compatible with Workers runtime.`,
945
+ message: `In Better-Fullstack, backend '${config.backend}' is currently not available with Cloudflare Workers runtime.`,
946
946
  provided: {
947
947
  backend: config.backend,
948
948
  runtime: "workers"
@@ -950,7 +950,7 @@ function validateWorkersCompatibility(providedFlags, options, config) {
950
950
  suggestions: ["Use --backend hono, --backend nitro, or --backend fets", "Choose a different runtime (node, bun)"]
951
951
  });
952
952
  if (providedFlags.has("runtime") && options.runtime === "workers" && config.database === "mongodb") incompatibilityError({
953
- message: "Cloudflare Workers runtime is not compatible with MongoDB.",
953
+ message: "In Better-Fullstack, Cloudflare Workers runtime is currently not available with MongoDB.",
954
954
  provided: {
955
955
  runtime: "workers",
956
956
  database: "mongodb"
@@ -958,7 +958,7 @@ function validateWorkersCompatibility(providedFlags, options, config) {
958
958
  suggestions: ["Use a different database (postgres, sqlite, mysql)", "Choose a different runtime (node, bun)"]
959
959
  });
960
960
  if (providedFlags.has("runtime") && options.runtime === "workers" && config.dbSetup === "docker") incompatibilityError({
961
- message: "Cloudflare Workers runtime is not compatible with Docker setup.",
961
+ message: "In Better-Fullstack, Cloudflare Workers runtime is currently not available with Docker database setup.",
962
962
  provided: {
963
963
  runtime: "workers",
964
964
  "db-setup": "docker"
@@ -966,7 +966,7 @@ function validateWorkersCompatibility(providedFlags, options, config) {
966
966
  suggestions: ["Use --db-setup d1 for SQLite", "Choose a different runtime (node, bun)"]
967
967
  });
968
968
  if (providedFlags.has("database") && config.database === "mongodb" && config.runtime === "workers") incompatibilityError({
969
- message: "MongoDB is not compatible with Cloudflare Workers runtime.",
969
+ message: "In Better-Fullstack, MongoDB is currently not available with Cloudflare Workers runtime.",
970
970
  provided: {
971
971
  database: "mongodb",
972
972
  runtime: "workers"
@@ -1062,6 +1062,9 @@ function isFrontendAllowedWithBackend(frontend, backend, auth) {
1062
1062
  "solid"
1063
1063
  ].includes(frontend)) return false;
1064
1064
  }
1065
+ if (auth === "clerk" && backend === "self") {
1066
+ if (!["next", "tanstack-start"].includes(frontend)) return false;
1067
+ }
1065
1068
  if (auth === "nextauth") {
1066
1069
  if (frontend !== "next") return false;
1067
1070
  if (backend !== "self") return false;
@@ -1072,29 +1075,57 @@ function isFrontendAllowedWithBackend(frontend, backend, auth) {
1072
1075
  }
1073
1076
  return true;
1074
1077
  }
1078
+ function validateClerkCompatibility(auth, backend, frontends = []) {
1079
+ if (auth !== "clerk") return;
1080
+ if (backend === "convex") {
1081
+ const incompatibleFrontends = frontends.filter((f) => [
1082
+ "nuxt",
1083
+ "svelte",
1084
+ "solid"
1085
+ ].includes(f));
1086
+ 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.`);
1087
+ return;
1088
+ }
1089
+ if (backend === "self") {
1090
+ if (frontends.some((f) => [
1091
+ "native-bare",
1092
+ "native-uniwind",
1093
+ "native-unistyles"
1094
+ ].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.");
1095
+ const hasNextJs = frontends.includes("next");
1096
+ const hasTanStackStart = frontends.includes("tanstack-start");
1097
+ if (!hasNextJs && !hasTanStackStart) {
1098
+ 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.");
1099
+ 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.");
1100
+ 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.");
1101
+ }
1102
+ return;
1103
+ }
1104
+ 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.");
1105
+ }
1075
1106
  function validateNextAuthCompatibility(auth, backend, frontends = []) {
1076
1107
  if (auth !== "nextauth") return;
1077
1108
  const hasNextJs = frontends.includes("next");
1078
- if (backend !== "self") exitWithError("Auth.js (NextAuth) is only supported with the 'self' backend (fullstack Next.js). Please use '--backend self' or choose a different auth provider.");
1079
- if (!hasNextJs) exitWithError("Auth.js (NextAuth) requires Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
1109
+ 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.");
1110
+ 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.");
1080
1111
  }
1081
1112
  function validateStackAuthCompatibility(auth, backend, frontends = []) {
1082
1113
  if (auth !== "stack-auth") return;
1083
1114
  const hasNextJs = frontends.includes("next");
1084
- if (backend !== "self") exitWithError("Stack Auth is only supported with the 'self' backend (fullstack Next.js). Please use '--backend self' or choose a different auth provider.");
1085
- if (!hasNextJs) exitWithError("Stack Auth requires Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
1115
+ 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.");
1116
+ if (!hasNextJs) exitWithError("In Better-Fullstack, Stack Auth currently requires the Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
1086
1117
  }
1087
1118
  function validateSupabaseAuthCompatibility(auth, backend, frontends = []) {
1088
1119
  if (auth !== "supabase-auth") return;
1089
1120
  const hasNextJs = frontends.includes("next");
1090
- if (backend !== "self") exitWithError("Supabase Auth is only supported with the 'self' backend (fullstack Next.js). Please use '--backend self' or choose a different auth provider.");
1091
- if (!hasNextJs) exitWithError("Supabase Auth requires Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
1121
+ 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.");
1122
+ if (!hasNextJs) exitWithError("In Better-Fullstack, Supabase Auth currently requires the Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
1092
1123
  }
1093
1124
  function validateAuth0Compatibility(auth, backend, frontends = []) {
1094
1125
  if (auth !== "auth0") return;
1095
1126
  const hasNextJs = frontends.includes("next");
1096
- if (backend !== "self") exitWithError("Auth0 is only supported with the 'self' backend (fullstack Next.js). Please use '--backend self' or choose a different auth provider.");
1097
- if (!hasNextJs) exitWithError("Auth0 requires Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
1127
+ 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.");
1128
+ if (!hasNextJs) exitWithError("In Better-Fullstack, Auth0 currently requires the Next.js frontend. Please use '--frontend next' or choose a different auth provider.");
1098
1129
  }
1099
1130
  function allowedApisForFrontends(frontends = [], astroIntegration) {
1100
1131
  const includesNuxt = frontends.includes("nuxt");
@@ -1129,6 +1160,24 @@ function isExampleAIAllowed(backend, frontends = []) {
1129
1160
  }
1130
1161
  return true;
1131
1162
  }
1163
+ function hasExampleChatSdkSelfFrontend(frontends = []) {
1164
+ return frontends.some((f) => [
1165
+ "next",
1166
+ "tanstack-start",
1167
+ "nuxt"
1168
+ ].includes(f));
1169
+ }
1170
+ function isExampleChatSdkAllowed(backend, frontends = [], runtime) {
1171
+ if (!backend || backend === "none" || backend === "convex") return false;
1172
+ if (backend === "self") return hasExampleChatSdkSelfFrontend(frontends);
1173
+ if (backend === "hono") return runtime === "node";
1174
+ return false;
1175
+ }
1176
+ function requiresChatSdkVercelAI(backend, frontends = [], runtime) {
1177
+ if (backend === "self" && frontends.includes("nuxt")) return true;
1178
+ if (backend === "hono" && runtime === "node") return true;
1179
+ return false;
1180
+ }
1132
1181
  function validateWebDeployRequiresWebFrontend(webDeploy, hasWebFrontendFlag) {
1133
1182
  if (webDeploy && webDeploy !== "none" && !hasWebFrontendFlag) exitWithError("'--web-deploy' requires a web frontend. Please select a web frontend or set '--web-deploy none'.");
1134
1183
  }
@@ -1168,7 +1217,7 @@ function validatePaymentsCompatibility(payments, auth, _backend, frontends = [])
1168
1217
  if (web.length === 0 && frontends.length > 0) exitWithError("Polar payments requires a web frontend or no frontend. Please select a web frontend or choose a different payments provider.");
1169
1218
  }
1170
1219
  }
1171
- function validateExamplesCompatibility(examples, backend, frontend) {
1220
+ function validateExamplesCompatibility(examples, backend, frontend, runtime, ai) {
1172
1221
  const examplesArr = examples ?? [];
1173
1222
  if (examplesArr.length === 0 || examplesArr.includes("none")) return;
1174
1223
  if (examplesArr.includes("ai") && (frontend ?? []).includes("solid")) exitWithError("The 'ai' example is not compatible with the Solid frontend.");
@@ -1178,6 +1227,17 @@ function validateExamplesCompatibility(examples, backend, frontend) {
1178
1227
  const includesSvelte = frontendArr.includes("svelte");
1179
1228
  if (includesNuxt || includesSvelte) exitWithError("The 'ai' example with Convex backend only supports React-based frontends (Next.js, TanStack Router, TanStack Start, React Router). Svelte and Nuxt are not supported with Convex AI.");
1180
1229
  }
1230
+ if (examplesArr.includes("chat-sdk")) {
1231
+ const frontendArr = frontend ?? [];
1232
+ if (!isExampleChatSdkAllowed(backend, frontendArr, runtime)) {
1233
+ if (backend === "none") exitWithError("The 'chat-sdk' example requires a backend.");
1234
+ if (backend === "convex") exitWithError("The 'chat-sdk' example is not supported with the Convex backend in v1. Use self backend (Next.js, TanStack Start, Nuxt) or Hono with Node runtime.");
1235
+ if (backend === "self") exitWithError("The 'chat-sdk' example with self backend only supports Next.js, TanStack Start, or Nuxt frontends in v1.");
1236
+ if (backend === "hono" && runtime !== "node") exitWithError("The 'chat-sdk' example with Hono requires '--runtime node' in v1 (Bun/Workers not supported yet).");
1237
+ exitWithError("The 'chat-sdk' example is only supported with self backend (Next.js, TanStack Start, Nuxt) or Hono with Node runtime in v1.");
1238
+ }
1239
+ if (requiresChatSdkVercelAI(backend, frontendArr, runtime) && ai && ai !== "vercel-ai") exitWithError("The 'chat-sdk' example requires '--ai vercel-ai' for the selected stack in v1 (Nuxt Discord and Hono GitHub profiles).");
1240
+ }
1181
1241
  }
1182
1242
  /**
1183
1243
  * Validates that a UI library is compatible with the selected frontend(s)
@@ -2408,7 +2468,8 @@ const SKILL_SOURCES = {
2408
2468
  "prisma/skills": { label: "Prisma" },
2409
2469
  "elysiajs/skills": { label: "ElysiaJS" },
2410
2470
  "waynesutton/convexskills": { label: "Convex" },
2411
- "msmps/opentui-skill": { label: "OpenTUI Platform" }
2471
+ "msmps/opentui-skill": { label: "OpenTUI Platform" },
2472
+ "haydenbleasel/ultracite": { label: "Ultracite" }
2412
2473
  };
2413
2474
  const AVAILABLE_AGENTS = [
2414
2475
  {
@@ -2540,6 +2601,7 @@ function getRecommendedSourceKeys(config) {
2540
2601
  if (backend === "elysia") sources.push("elysiajs/skills");
2541
2602
  if (backend === "convex") sources.push("waynesutton/convexskills");
2542
2603
  if (addons.includes("opentui")) sources.push("msmps/opentui-skill");
2604
+ if (addons.includes("ultracite")) sources.push("haydenbleasel/ultracite");
2543
2605
  return sources;
2544
2606
  }
2545
2607
  const CURATED_SKILLS_BY_SOURCE = {
@@ -2597,7 +2659,8 @@ const CURATED_SKILLS_BY_SOURCE = {
2597
2659
  "convex-migrations",
2598
2660
  "convex-security-check"
2599
2661
  ],
2600
- "msmps/opentui-skill": () => ["opentui"]
2662
+ "msmps/opentui-skill": () => ["opentui"],
2663
+ "haydenbleasel/ultracite": () => ["ultracite"]
2601
2664
  };
2602
2665
  function getCuratedSkillNamesForSourceKey(sourceKey, config) {
2603
2666
  return CURATED_SKILLS_BY_SOURCE[sourceKey](config);
@@ -3567,16 +3630,26 @@ async function getAuthChoice(auth, backend, frontend) {
3567
3630
  if (isCancel$1(response$1)) return exitCancelled("Operation cancelled");
3568
3631
  return response$1;
3569
3632
  }
3570
- const supportsNextJsAuth = frontend?.includes("next") && backend === "self";
3633
+ const hasNextJs = frontend?.includes("next");
3634
+ const hasTanStackStart = frontend?.includes("tanstack-start");
3635
+ const isSelfBackend = backend === "self";
3636
+ const supportsNextJsAuth = hasNextJs && isSelfBackend;
3637
+ const hasNativeFrontend$2 = frontend?.some((f) => [
3638
+ "native-bare",
3639
+ "native-uniwind",
3640
+ "native-unistyles"
3641
+ ].includes(f));
3642
+ const supportsClerkSelf = isSelfBackend && !hasNativeFrontend$2 && Boolean(hasNextJs || hasTanStackStart);
3571
3643
  const options = [{
3572
3644
  value: "better-auth",
3573
3645
  label: "Better-Auth",
3574
3646
  hint: "comprehensive auth framework for TypeScript"
3575
- }, {
3647
+ }];
3648
+ if (supportsClerkSelf) options.push({
3576
3649
  value: "clerk",
3577
3650
  label: "Clerk",
3578
3651
  hint: "More than auth, Complete User Management"
3579
- }];
3652
+ });
3580
3653
  if (supportsNextJsAuth) {
3581
3654
  options.push({
3582
3655
  value: "nextauth",
@@ -4080,7 +4153,7 @@ async function getEmailChoice(email, backend) {
4080
4153
 
4081
4154
  //#endregion
4082
4155
  //#region src/prompts/examples.ts
4083
- async function getExamplesChoice(examples, frontends, backend) {
4156
+ async function getExamplesChoice(examples, frontends, backend, runtime) {
4084
4157
  if (examples !== void 0) return examples;
4085
4158
  if (backend === "none") return [];
4086
4159
  let response = [];
@@ -4090,6 +4163,11 @@ async function getExamplesChoice(examples, frontends, backend) {
4090
4163
  label: "AI Chat",
4091
4164
  hint: "A simple AI chat interface using AI SDK"
4092
4165
  });
4166
+ if (isExampleChatSdkAllowed(backend, frontends ?? [], runtime)) options.push({
4167
+ value: "chat-sdk",
4168
+ label: "Chat SDK Bots",
4169
+ hint: "Framework-specific Chat SDK bot example (Slack/Discord/GitHub depending on stack)"
4170
+ });
4093
4171
  if (options.length === 0) return [];
4094
4172
  response = await navigableMultiselect({
4095
4173
  message: "Include examples",
@@ -5625,7 +5703,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
5625
5703
  },
5626
5704
  examples: ({ results }) => {
5627
5705
  if (results.ecosystem !== "typescript") return Promise.resolve([]);
5628
- return getExamplesChoice(flags.examples, results.frontend, results.backend);
5706
+ return getExamplesChoice(flags.examples, results.frontend, results.backend, results.runtime);
5629
5707
  },
5630
5708
  dbSetup: ({ results }) => {
5631
5709
  if (results.ecosystem !== "typescript") return Promise.resolve("none");
@@ -5641,6 +5719,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
5641
5719
  },
5642
5720
  ai: ({ results }) => {
5643
5721
  if (results.ecosystem !== "typescript") return Promise.resolve("none");
5722
+ if (flags.ai === void 0 && results.examples?.includes("chat-sdk") && requiresChatSdkVercelAI(results.backend, results.frontend, results.runtime)) return Promise.resolve("vercel-ai");
5644
5723
  return getAIChoice(flags.ai);
5645
5724
  },
5646
5725
  validation: ({ results }) => {
@@ -6514,7 +6593,7 @@ function validateDatabaseOrmAuth(cfg, flags) {
6514
6593
  suggestions: ["Use --orm mongoose or --orm prisma for MongoDB", "Choose a different database (postgres, sqlite, mysql)"]
6515
6594
  });
6516
6595
  if (has("database") && has("orm") && db === "mongodb" && orm && orm !== "mongoose" && orm !== "prisma" && orm !== "none") incompatibilityError({
6517
- message: "MongoDB only works with Mongoose or Prisma ORM.",
6596
+ message: "In Better-Fullstack, MongoDB is currently supported only with Mongoose or Prisma ORM.",
6518
6597
  provided: {
6519
6598
  database: "mongodb",
6520
6599
  orm
@@ -6597,7 +6676,7 @@ function validateDatabaseSetup(config, providedFlags) {
6597
6676
  runtime: "workers",
6598
6677
  errorMessage: "Cloudflare D1 setup requires SQLite database and Cloudflare Workers runtime."
6599
6678
  },
6600
- docker: { errorMessage: "Docker setup is not compatible with SQLite database or Cloudflare Workers runtime." },
6679
+ docker: { errorMessage: "In Better-Fullstack, Docker setup is currently not available with SQLite database or Cloudflare Workers runtime." },
6601
6680
  none: { errorMessage: "" }
6602
6681
  };
6603
6682
  if (dbSetup && dbSetup !== "none") {
@@ -6607,8 +6686,8 @@ function validateDatabaseSetup(config, providedFlags) {
6607
6686
  } else if (validation.database && database !== validation.database) exitWithError(validation.errorMessage);
6608
6687
  if (validation.runtime && runtime !== validation.runtime) exitWithError(validation.errorMessage);
6609
6688
  if (dbSetup === "docker") {
6610
- if (database === "sqlite") exitWithError("Docker setup is not compatible with SQLite database. SQLite is file-based and doesn't require Docker. Please use '--database postgres', '--database mysql', '--database mongodb', or choose a different setup.");
6611
- if (runtime === "workers") exitWithError("Docker setup is not compatible with Cloudflare Workers runtime. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.");
6689
+ if (database === "sqlite") exitWithError("In Better-Fullstack, Docker setup is currently not available with SQLite database. SQLite is file-based and doesn't require Docker. Please use '--database postgres', '--database mysql', '--database mongodb', or choose a different setup.");
6690
+ if (runtime === "workers") exitWithError("In Better-Fullstack, Docker setup is currently not available with Cloudflare Workers runtime. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.");
6612
6691
  }
6613
6692
  }
6614
6693
  }
@@ -6727,15 +6806,6 @@ function validateAdonisJSConstraints(config, providedFlags) {
6727
6806
  }
6728
6807
  function validateBackendConstraints(config, providedFlags, options) {
6729
6808
  const { backend } = config;
6730
- if (config.auth === "clerk" && backend !== "convex") exitWithError("Clerk authentication is only supported with the Convex backend. Please use '--backend convex' or choose a different auth provider.");
6731
- if (backend === "convex" && config.auth === "clerk" && config.frontend) {
6732
- const incompatibleFrontends = config.frontend.filter((f) => [
6733
- "nuxt",
6734
- "svelte",
6735
- "solid"
6736
- ].includes(f));
6737
- if (incompatibleFrontends.length > 0) exitWithError(`Clerk authentication is not compatible with the following frontends: ${incompatibleFrontends.join(", ")}. Please choose a different frontend or auth provider.`);
6738
- }
6739
6809
  if (providedFlags.has("backend") && backend && backend !== "convex" && backend !== "none" && backend !== "self" && backend !== "encore") {
6740
6810
  if (providedFlags.has("runtime") && options.runtime === "none") exitWithError("'--runtime none' is only supported with '--backend convex', '--backend none', '--backend self', or '--backend encore'. Please choose 'bun', 'node', or remove the --runtime flag.");
6741
6811
  }
@@ -6774,8 +6844,9 @@ function validateFullConfig(config, providedFlags, options) {
6774
6844
  validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth);
6775
6845
  config.addons = [...new Set(config.addons)];
6776
6846
  }
6777
- validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? []);
6847
+ validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? [], config.runtime, config.ai);
6778
6848
  validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend ?? []);
6849
+ validateClerkCompatibility(config.auth, config.backend, config.frontend ?? []);
6779
6850
  validateNextAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6780
6851
  validateStackAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6781
6852
  validateSupabaseAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
@@ -6790,12 +6861,13 @@ function validateConfigForProgrammaticUse(config) {
6790
6861
  if (config.frontend && config.frontend.length > 0) ensureSingleWebAndNative(config.frontend);
6791
6862
  validateApiFrontendCompatibility(config.api, config.frontend, config.astroIntegration);
6792
6863
  validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend);
6864
+ validateClerkCompatibility(config.auth, config.backend, config.frontend ?? []);
6793
6865
  validateNextAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6794
6866
  validateStackAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6795
6867
  validateSupabaseAuthCompatibility(config.auth, config.backend, config.frontend ?? []);
6796
6868
  validateAuth0Compatibility(config.auth, config.backend, config.frontend ?? []);
6797
6869
  if (config.addons && config.addons.length > 0) validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth);
6798
- validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? []);
6870
+ validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? [], config.runtime, config.ai);
6799
6871
  validateUILibraryFrontendCompatibility(config.uiLibrary, config.frontend ?? [], config.astroIntegration);
6800
6872
  validateUILibraryCSSFrameworkCompatibility(config.uiLibrary, config.cssFramework);
6801
6873
  validatePeerDependencies(config);
@@ -8117,7 +8189,7 @@ async function displayPostInstallInstructions(config) {
8117
8189
  const nativeInstructions = (frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles")) && backend !== "none" ? getNativeInstructions(isConvex, isBackendSelf, frontend || [], runCmd) : "";
8118
8190
  const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
8119
8191
  const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
8120
- const clerkInstructions = isConvex && config.auth === "clerk" ? getClerkInstructions() : "";
8192
+ const clerkInstructions = config.auth === "clerk" ? getClerkInstructions(config.backend, config.frontend ?? []) : "";
8121
8193
  const polarInstructions = config.payments === "polar" && config.auth === "better-auth" ? getPolarInstructions(backend) : "";
8122
8194
  const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend);
8123
8195
  const hasWeb = frontend?.some((f) => WEB_FRAMEWORKS.includes(f));
@@ -8248,8 +8320,13 @@ function getNoOrmWarning() {
8248
8320
  function getBunWebNativeWarning() {
8249
8321
  return `\n${pc.yellow("WARNING:")} 'bun' might cause issues with web + native apps in a monorepo.\n Use 'pnpm' if problems arise.`;
8250
8322
  }
8251
- function getClerkInstructions() {
8252
- return `${pc.bold("Clerk Authentication Setup:")}\n${pc.cyan("•")} Follow the guide: ${pc.underline("https://docs.convex.dev/auth/clerk")}\n${pc.cyan("•")} Set CLERK_JWT_ISSUER_DOMAIN in Convex Dashboard\n${pc.cyan("•")} Set CLERK_PUBLISHABLE_KEY in apps/*/.env`;
8323
+ function getClerkInstructions(backend, frontend) {
8324
+ if (backend === "convex") return `${pc.bold("Clerk Authentication Setup:")}\n${pc.cyan("•")} Follow the guide: ${pc.underline("https://docs.convex.dev/auth/clerk")}\n${pc.cyan("•")} Set CLERK_JWT_ISSUER_DOMAIN in Convex Dashboard\n${pc.cyan("•")} Set CLERK_PUBLISHABLE_KEY in apps/*/.env`;
8325
+ if (backend === "self" && (frontend.includes("next") || frontend.includes("tanstack-start"))) {
8326
+ const publishableKeyVar = frontend.includes("next") ? "NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY" : "VITE_CLERK_PUBLISHABLE_KEY";
8327
+ return `${pc.bold("Clerk Authentication Setup:")}\n${pc.cyan("•")} Create an application in ${pc.underline("https://dashboard.clerk.com/")}\n${pc.cyan("•")} Set ${publishableKeyVar} in ${pc.white("apps/web/.env")}\n${pc.cyan("•")} Set CLERK_SECRET_KEY in ${pc.white("apps/web/.env")}\n${pc.cyan("•")} Clerk middleware and a protected dashboard route are already generated`;
8328
+ }
8329
+ return "";
8253
8330
  }
8254
8331
  function getBetterAuthConvexInstructions(hasWeb, webPort, packageManager) {
8255
8332
  const cmd = packageManager === "npm" ? "npx" : packageManager;
@@ -8437,7 +8514,7 @@ async function setPackageManagerVersion(projectDir, packageManager) {
8437
8514
  const pkgJsonPath = path.join(projectDir, "package.json");
8438
8515
  if (!await fs.pathExists(pkgJsonPath)) return;
8439
8516
  try {
8440
- const { stdout } = await $`${packageManager} -v`;
8517
+ const { stdout } = await $({ cwd: os$1.tmpdir() })`${packageManager} -v`;
8441
8518
  const version = stdout.trim();
8442
8519
  const pkgJson = await fs.readJson(pkgJsonPath);
8443
8520
  pkgJson.packageManager = `${packageManager}@${version}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-fullstack",
3
- "version": "1.3.17",
3
+ "version": "1.4.0",
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.3.17",
80
- "@better-fullstack/types": "^1.3.17",
79
+ "@better-fullstack/template-generator": "^1.4.0",
80
+ "@better-fullstack/types": "^1.4.0",
81
81
  "@clack/core": "^0.5.0",
82
82
  "@clack/prompts": "^1.0.0-alpha.8",
83
83
  "@orpc/server": "^1.13.0",