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 +3 -3
- package/dist/cli.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-p8a66ui5.mjs → src-BVuxTUEs.mjs} +102 -53
- package/package.json +3 -3
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>•
|
|
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
|
|
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-
|
|
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-
|
|
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"
|
|
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
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
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
|
-
|
|
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" &&
|
|
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 =
|
|
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
|
|
6144
|
-
|
|
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.
|
|
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.
|
|
74
|
-
"@better-t-stack/types": "^3.
|
|
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",
|