create-better-t-stack 3.25.5 → 3.26.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/README.md CHANGED
@@ -32,14 +32,14 @@ Follow the prompts to configure your project or use the `--yes` flag for default
32
32
  | Category | Options |
33
33
  | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
34
34
  | **TypeScript** | End-to-end type safety across all parts of your application |
35
- | **Frontend** | • React with TanStack Router<br>• React with React Router<br>• React with TanStack Start (SSR)<br>• Next.js<br>• SvelteKit<br>• Nuxt (Vue)<br>• SolidJS<br>• React Native with NativeWind (via Expo)<br>• React Native with Unistyles (via Expo)<br>• None |
36
- | **Backend** | • Hono<br>• Express<br>• Elysia<br>• Next.js API routes<br>• Convex<br>• Fastify<br>• None |
35
+ | **Frontend** | • React with TanStack Router<br>• React with React Router<br>• React with TanStack Start (SSR)<br>• Next.js<br>• SvelteKit<br>• Nuxt (Vue)<br>• SolidJS<br>• Astro<br>• React Native bare Expo<br>• React Native with NativeWind (via Expo)<br>• React Native with Unistyles (via Expo)<br>• None |
36
+ | **Backend** | • Hono<br>• Express<br>• Elysia<br>• Fastify<br>• Self (fullstack inside the web app)<br>• Convex<br>• None |
37
37
  | **API Layer** | • tRPC (type-safe APIs)<br>• oRPC (OpenAPI-compatible type-safe APIs)<br>• None |
38
38
  | **Runtime** | • Bun<br>• Node.js<br>• Cloudflare Workers<br>• None |
39
39
  | **Database** | • SQLite<br>• PostgreSQL<br>• MySQL<br>• MongoDB<br>• None |
40
40
  | **ORM** | • Drizzle (TypeScript-first)<br>• Prisma (feature-rich)<br>• Mongoose (for MongoDB)<br>• None |
41
41
  | **Database Setup** | • Turso (SQLite)<br>• Cloudflare D1 (SQLite)<br>• Neon (PostgreSQL)<br>• Supabase (PostgreSQL)<br>• Prisma Postgres<br>• MongoDB Atlas<br>• None (manual setup) |
42
- | **Authentication** | Better-Auth (email/password, with more options coming soon) |
42
+ | **Authentication** | Better Auth<br>• Clerk |
43
43
  | **Styling** | Tailwind CSS with a shared shadcn/ui package for React web apps |
44
44
  | **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Electrobun (lightweight desktop shell)<br>• Starlight and Fumadocs (documentation sites)<br>• Biome, Oxlint, Ultracite (linting and formatting)<br>• Lefthook, Husky (Git hooks)<br>• MCP, Skills (agent tooling)<br>• OpenTUI, WXT (platform extensions)<br>• Turborepo or Nx (monorepo orchestration) |
45
45
  | **Examples** | • Todo app<br>• AI Chat interface (using Vercel AI SDK) |
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { _ as types_exports, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as getLatestCLIVersion } from "./src-p8a66ui5.mjs";
2
+ import { _ as types_exports, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as getLatestCLIVersion } from "./src-BVuxTUEs.mjs";
3
3
  import z from "zod";
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import { C as ProjectCreationError, S as DirectoryConflictError, T as ValidationError, a as TEMPLATE_COUNT, b as CompatibilityError, c as builder, d as createVirtual, f as docs, g as sponsors, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as UserCancelledError, x as DatabaseSetupError, y as CLIError } from "./src-p8a66ui5.mjs";
2
+ import { C as ProjectCreationError, S as DirectoryConflictError, T as ValidationError, a as TEMPLATE_COUNT, b as CompatibilityError, c as builder, d as createVirtual, f as docs, g as sponsors, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as UserCancelledError, x as DatabaseSetupError, y as CLIError } from "./src-BVuxTUEs.mjs";
3
3
  export { CLIError, CompatibilityError, DatabaseSetupError, DirectoryConflictError, EMBEDDED_TEMPLATES, GeneratorError, ProjectCreationError, Result, SchemaNameSchema, TEMPLATE_COUNT, UserCancelledError, ValidationError, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generate, getSchemaResult, router, sponsors };
@@ -782,7 +782,7 @@ function validateApiFrontendCompatibility(api, frontends = []) {
782
782
  }
783
783
  function isFrontendAllowedWithBackend(frontend, backend, auth) {
784
784
  if (backend === "convex" && (frontend === "solid" || frontend === "astro")) return false;
785
- if (auth === "clerk" && backend === "convex") {
785
+ if (auth === "clerk") {
786
786
  if ([
787
787
  "nuxt",
788
788
  "svelte",
@@ -3218,60 +3218,53 @@ async function getApiChoice(Api, frontend, backend) {
3218
3218
  async function getAuthChoice(auth, backend, frontend) {
3219
3219
  if (auth !== void 0) return auth;
3220
3220
  if (backend === "none") return "none";
3221
+ const supportedBetterAuthFrontends = frontend?.some((f) => [
3222
+ "tanstack-router",
3223
+ "tanstack-start",
3224
+ "next",
3225
+ "nuxt",
3226
+ "svelte",
3227
+ "solid",
3228
+ "native-bare",
3229
+ "native-uniwind",
3230
+ "native-unistyles"
3231
+ ].includes(f));
3232
+ const hasClerkCompatibleFrontends = frontend?.some((f) => [
3233
+ "react-router",
3234
+ "tanstack-router",
3235
+ "tanstack-start",
3236
+ "next",
3237
+ "native-bare",
3238
+ "native-uniwind",
3239
+ "native-unistyles"
3240
+ ].includes(f));
3241
+ const options = [];
3221
3242
  if (backend === "convex") {
3222
- const supportedBetterAuthFrontends = frontend?.some((f) => [
3223
- "tanstack-router",
3224
- "tanstack-start",
3225
- "next",
3226
- "native-bare",
3227
- "native-uniwind",
3228
- "native-unistyles"
3229
- ].includes(f));
3230
- const hasClerkCompatibleFrontends = frontend?.some((f) => [
3231
- "react-router",
3232
- "tanstack-router",
3233
- "tanstack-start",
3234
- "next",
3235
- "native-bare",
3236
- "native-uniwind",
3237
- "native-unistyles"
3238
- ].includes(f));
3239
- const options = [];
3240
3243
  if (supportedBetterAuthFrontends) options.push({
3241
3244
  value: "better-auth",
3242
3245
  label: "Better-Auth",
3243
3246
  hint: "comprehensive auth framework for TypeScript"
3244
3247
  });
3245
- if (hasClerkCompatibleFrontends) options.push({
3246
- value: "clerk",
3247
- label: "Clerk",
3248
- hint: "More than auth, Complete User Management"
3249
- });
3250
- if (options.length === 0) return "none";
3251
- options.push({
3252
- value: "none",
3253
- label: "None",
3254
- hint: "No auth"
3255
- });
3256
- const response = await navigableSelect({
3257
- message: "Select authentication provider",
3258
- options,
3259
- initialValue: "none"
3260
- });
3261
- if (isCancel$1(response)) throw new UserCancelledError({ message: "Operation cancelled" });
3262
- return response;
3263
- }
3248
+ } else options.push({
3249
+ value: "better-auth",
3250
+ label: "Better-Auth",
3251
+ hint: "comprehensive auth framework for TypeScript"
3252
+ });
3253
+ if (hasClerkCompatibleFrontends) options.push({
3254
+ value: "clerk",
3255
+ label: "Clerk",
3256
+ hint: "More than auth, Complete User Management"
3257
+ });
3258
+ if (options.length === 0) return "none";
3259
+ options.push({
3260
+ value: "none",
3261
+ label: "None",
3262
+ hint: "No auth"
3263
+ });
3264
3264
  const response = await navigableSelect({
3265
3265
  message: "Select authentication provider",
3266
- options: [{
3267
- value: "better-auth",
3268
- label: "Better-Auth",
3269
- hint: "comprehensive auth framework for TypeScript"
3270
- }, {
3271
- value: "none",
3272
- label: "None"
3273
- }],
3274
- initialValue: DEFAULT_CONFIG.auth
3266
+ options,
3267
+ initialValue: options.some((option) => option.value === DEFAULT_CONFIG.auth) ? DEFAULT_CONFIG.auth : "none"
3275
3268
  });
3276
3269
  if (isCancel$1(response)) throw new UserCancelledError({ message: "Operation cancelled" });
3277
3270
  return response;
@@ -4398,12 +4391,12 @@ function validateSelfBackendConstraints(config, providedFlags) {
4398
4391
  }
4399
4392
  function validateBackendConstraints(config, providedFlags, options) {
4400
4393
  const { backend } = config;
4401
- if (config.auth === "clerk" && backend !== "convex") return validationErr("Clerk authentication is only supported with the Convex backend. Please use '--backend convex' or choose a different auth provider.");
4402
- if (backend === "convex" && config.auth === "clerk" && config.frontend) {
4394
+ if (config.auth === "clerk" && config.frontend) {
4403
4395
  const incompatibleFrontends = config.frontend.filter((f) => [
4404
4396
  "nuxt",
4405
4397
  "svelte",
4406
- "solid"
4398
+ "solid",
4399
+ "astro"
4407
4400
  ].includes(f));
4408
4401
  if (incompatibleFrontends.length > 0) return validationErr(`Clerk authentication is not compatible with the following frontends: ${incompatibleFrontends.join(", ")}. Please choose a different frontend or auth provider.`);
4409
4402
  }
@@ -5999,7 +5992,7 @@ async function displayPostInstallInstructions(config) {
5999
5992
  const nativeInstructions = (frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles")) && backend !== "none" ? getNativeInstructions(isConvex, isBackendSelf, frontend || [], runCmd) : "";
6000
5993
  const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
6001
5994
  const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
6002
- const clerkInstructions = isConvex && config.auth === "clerk" ? getClerkInstructions() : "";
5995
+ const clerkInstructions = config.auth === "clerk" ? getClerkInstructions(frontend || [], backend, api) : "";
6003
5996
  const polarInstructions = config.payments === "polar" && config.auth === "better-auth" ? getPolarInstructions(backend) : "";
6004
5997
  const alchemyDeployInstructions = getAlchemyDeployInstructions(runCmd, webDeploy, serverDeploy, backend);
6005
5998
  const hasWeb = frontend?.some((f) => types_exports.desktopWebFrontends.includes(f));
@@ -6140,8 +6133,64 @@ function getNoOrmWarning() {
6140
6133
  function getBunWebNativeWarning() {
6141
6134
  return `\n${pc.yellow("WARNING:")} 'bun' might cause issues with web + native apps in a monorepo.\n Use 'pnpm' if problems arise.`;
6142
6135
  }
6143
- function getClerkInstructions() {
6144
- 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`;
6136
+ function getClerkQuickstartUrl(frontend) {
6137
+ if (frontend.includes("next")) return "https://clerk.com/docs/nextjs/getting-started/quickstart";
6138
+ if (frontend.includes("react-router")) return "https://clerk.com/docs/react-router/getting-started/quickstart";
6139
+ if (frontend.includes("tanstack-start")) return "https://clerk.com/docs/tanstack-react-start/getting-started/quickstart";
6140
+ if (frontend.includes("tanstack-router")) return "https://clerk.com/docs/react/getting-started/quickstart";
6141
+ if (frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles")) return "https://clerk.com/docs/expo/getting-started/quickstart";
6142
+ return "https://clerk.com/docs";
6143
+ }
6144
+ function getClerkInstructionLines(frontend, backend, api) {
6145
+ const lines = [];
6146
+ if (frontend.includes("next")) lines.push("Set NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY in apps/web/.env");
6147
+ if (frontend.some((value) => [
6148
+ "react-router",
6149
+ "tanstack-router",
6150
+ "tanstack-start"
6151
+ ].includes(value))) lines.push("Set VITE_CLERK_PUBLISHABLE_KEY in apps/web/.env");
6152
+ if (frontend.some((value) => [
6153
+ "native-bare",
6154
+ "native-uniwind",
6155
+ "native-unistyles"
6156
+ ].includes(value))) lines.push("Set EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY in apps/native/.env");
6157
+ if (backend === "convex") return [
6158
+ "Set CLERK_JWT_ISSUER_DOMAIN in Convex Dashboard",
6159
+ ...lines,
6160
+ ...frontend.some((value) => [
6161
+ "next",
6162
+ "react-router",
6163
+ "tanstack-start"
6164
+ ].includes(value)) ? ["Set CLERK_SECRET_KEY in apps/web/.env for Clerk server middleware"] : []
6165
+ ];
6166
+ const hasClerkServerFrontend = frontend.some((value) => [
6167
+ "next",
6168
+ "react-router",
6169
+ "tanstack-start"
6170
+ ].includes(value));
6171
+ const serverEnvPath = backend === "self" ? "apps/web/.env" : "apps/server/.env";
6172
+ const needsServerSideClerkAuth = backend !== "none";
6173
+ const needsClerkBackendPublishableKey = ["express", "fastify"].includes(backend);
6174
+ const needsClerkRequestVerification = api !== "none" && [
6175
+ "self",
6176
+ "hono",
6177
+ "elysia"
6178
+ ].includes(backend);
6179
+ if (hasClerkServerFrontend && backend === "self") lines.push("Set CLERK_SECRET_KEY in apps/web/.env for Clerk server middleware and server-side Clerk auth");
6180
+ else {
6181
+ if (hasClerkServerFrontend) lines.push("Set CLERK_SECRET_KEY in apps/web/.env for Clerk server middleware");
6182
+ if (needsServerSideClerkAuth) lines.push(`Set CLERK_SECRET_KEY in ${serverEnvPath} for server-side Clerk auth`);
6183
+ }
6184
+ if (needsClerkRequestVerification) lines.push(`Set CLERK_PUBLISHABLE_KEY in ${serverEnvPath} for server-side Clerk request verification`);
6185
+ if (needsClerkBackendPublishableKey) lines.push(`Set CLERK_PUBLISHABLE_KEY in ${serverEnvPath} for Clerk backend middleware`);
6186
+ return lines;
6187
+ }
6188
+ function getClerkInstructions(frontend, backend, api) {
6189
+ return [
6190
+ `${pc.bold("Clerk Authentication Setup:")}`,
6191
+ `${pc.cyan("•")} Follow the guide: ${pc.underline(getClerkQuickstartUrl(frontend))}`,
6192
+ ...getClerkInstructionLines(frontend, backend, api).map((line) => `${pc.cyan("•")} ${line}`)
6193
+ ].join("\n");
6145
6194
  }
6146
6195
  function getBetterAuthConvexInstructions(hasWeb, webPort, packageManager) {
6147
6196
  const cmd = packageManager === "npm" ? "npx" : packageManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "3.25.5",
3
+ "version": "3.26.0",
4
4
  "description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
5
5
  "keywords": [
6
6
  "better-auth",
@@ -70,8 +70,8 @@
70
70
  "prepublishOnly": "npm run build"
71
71
  },
72
72
  "dependencies": {
73
- "@better-t-stack/template-generator": "^3.25.5",
74
- "@better-t-stack/types": "^3.25.5",
73
+ "@better-t-stack/template-generator": "^3.26.0",
74
+ "@better-t-stack/types": "^3.26.0",
75
75
  "@clack/core": "^1.1.0",
76
76
  "@clack/prompts": "^1.1.0",
77
77
  "@modelcontextprotocol/sdk": "1.27.1",