mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
Enhance authentication setup and improve documentation
Adds automatic auth secret generation, improves environment file handling, creates client env files, adds trusted origins configuration, enhances README generation with better structure and instructions, and updates post-installation guidance with clearer steps.
This commit is contained in:
5
.changeset/eight-candies-design.md
Normal file
5
.changeset/eight-candies-design.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"create-better-t-stack": patch
|
||||
---
|
||||
|
||||
Enhance authentication setup and improve documentation
|
||||
@@ -1,7 +1,5 @@
|
||||
import path from "node:path";
|
||||
import { log } from "@clack/prompts";
|
||||
import fs from "fs-extra";
|
||||
import pc from "picocolors";
|
||||
import type { ProjectAddons } from "../types";
|
||||
|
||||
export async function setupAddons(projectDir: string, addons: ProjectAddons[]) {
|
||||
|
||||
@@ -50,11 +50,58 @@ export async function configureAuth(
|
||||
);
|
||||
} else {
|
||||
const envPath = path.join(serverDir, ".env");
|
||||
const envExamplePath = path.join(serverDir, "_env");
|
||||
const templateEnvPath = path.join(
|
||||
PKG_ROOT,
|
||||
options.orm === "drizzle"
|
||||
? "template/with-drizzle/packages/server/_env"
|
||||
: "template/base/packages/server/_env",
|
||||
);
|
||||
|
||||
if (await fs.pathExists(envExamplePath)) {
|
||||
await fs.copy(envExamplePath, envPath);
|
||||
await fs.remove(envExamplePath);
|
||||
if (!(await fs.pathExists(envPath))) {
|
||||
if (await fs.pathExists(templateEnvPath)) {
|
||||
await fs.copy(templateEnvPath, envPath);
|
||||
} else {
|
||||
const defaultEnv = `BETTER_AUTH_SECRET=${generateAuthSecret()}
|
||||
BETTER_AUTH_URL=http://localhost:3000
|
||||
CORS_ORIGIN=http://localhost:3001
|
||||
${options.database === "sqlite" ? "TURSO_CONNECTION_URL=http://127.0.0.1:8080" : ""}
|
||||
${options.orm === "prisma" ? 'DATABASE_URL="file:./dev.db"' : ""}
|
||||
`;
|
||||
await fs.writeFile(envPath, defaultEnv);
|
||||
}
|
||||
} else {
|
||||
let envContent = await fs.readFile(envPath, "utf8");
|
||||
|
||||
if (!envContent.includes("BETTER_AUTH_SECRET")) {
|
||||
envContent += `\nBETTER_AUTH_SECRET=${generateAuthSecret()}`;
|
||||
}
|
||||
|
||||
if (!envContent.includes("BETTER_AUTH_URL")) {
|
||||
envContent += "\nBETTER_AUTH_URL=http://localhost:3000";
|
||||
}
|
||||
|
||||
if (!envContent.includes("CORS_ORIGIN")) {
|
||||
envContent += "\nCORS_ORIGIN=http://localhost:3001";
|
||||
}
|
||||
|
||||
if (
|
||||
options.database === "sqlite" &&
|
||||
!envContent.includes("TURSO_CONNECTION_URL")
|
||||
) {
|
||||
envContent += "\nTURSO_CONNECTION_URL=http://127.0.0.1:8080";
|
||||
}
|
||||
|
||||
if (options.orm === "prisma" && !envContent.includes("DATABASE_URL")) {
|
||||
envContent += '\nDATABASE_URL="file:./dev.db"';
|
||||
}
|
||||
|
||||
await fs.writeFile(envPath, envContent);
|
||||
}
|
||||
|
||||
const clientEnvPath = path.join(clientDir, ".env");
|
||||
if (!(await fs.pathExists(clientEnvPath))) {
|
||||
const clientEnvContent = "VITE_SERVER_URL=http://localhost:3000\n";
|
||||
await fs.writeFile(clientEnvPath, clientEnvContent);
|
||||
}
|
||||
|
||||
if (options.orm === "prisma") {
|
||||
@@ -71,6 +118,15 @@ export async function configureAuth(
|
||||
await fs.ensureDir(path.dirname(prismaAuthPath));
|
||||
await fs.copy(defaultPrismaAuthPath, prismaAuthPath);
|
||||
}
|
||||
|
||||
let authContent = await fs.readFile(prismaAuthPath, "utf8");
|
||||
if (!authContent.includes("trustedOrigins")) {
|
||||
authContent = authContent.replace(
|
||||
"export const auth = betterAuth({",
|
||||
"export const auth = betterAuth({\n trustedOrigins: [process.env.CORS_ORIGIN!],",
|
||||
);
|
||||
await fs.writeFile(prismaAuthPath, authContent);
|
||||
}
|
||||
} else if (options.orm === "drizzle") {
|
||||
const drizzleAuthPath = path.join(serverDir, "src/lib/auth.ts");
|
||||
const defaultDrizzleAuthPath = path.join(
|
||||
@@ -95,3 +151,14 @@ export async function configureAuth(
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function generateAuthSecret(length = 32): string {
|
||||
const characters =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let result = "";
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -37,27 +37,6 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
||||
}
|
||||
}
|
||||
|
||||
const gitignoreFiles = [
|
||||
[
|
||||
path.join(projectDir, "_gitignore"),
|
||||
path.join(projectDir, ".gitignore"),
|
||||
],
|
||||
[
|
||||
path.join(projectDir, "packages/client/_gitignore"),
|
||||
path.join(projectDir, "packages/client/.gitignore"),
|
||||
],
|
||||
[
|
||||
path.join(projectDir, "packages/server/_gitignore"),
|
||||
path.join(projectDir, "packages/server/.gitignore"),
|
||||
],
|
||||
];
|
||||
|
||||
for (const [source, target] of gitignoreFiles) {
|
||||
if (await fs.pathExists(source)) {
|
||||
await fs.move(source, target);
|
||||
}
|
||||
}
|
||||
|
||||
const envFiles = [
|
||||
[
|
||||
path.join(projectDir, "packages/server/_env"),
|
||||
@@ -112,26 +91,31 @@ export async function createProject(options: ProjectConfig): Promise<string> {
|
||||
: "bun@1.2.4";
|
||||
}
|
||||
|
||||
if (options.auth && options.database !== "none") {
|
||||
packageJson.scripts["auth:generate"] =
|
||||
"cd packages/server && npx @better-auth/cli generate --output ./src/db/auth-schema.ts";
|
||||
if (options.database !== "none") {
|
||||
if (options.database === "sqlite") {
|
||||
packageJson.scripts["db:local"] =
|
||||
"cd packages/server && turso dev --db-file local.db";
|
||||
}
|
||||
|
||||
if (options.orm === "prisma") {
|
||||
packageJson.scripts["prisma:generate"] =
|
||||
"cd packages/server && npx prisma generate";
|
||||
packageJson.scripts["prisma:push"] =
|
||||
"cd packages/server && npx prisma db push";
|
||||
packageJson.scripts["prisma:studio"] =
|
||||
"cd packages/server && npx prisma studio";
|
||||
if (options.auth) {
|
||||
packageJson.scripts["auth:generate"] =
|
||||
"cd packages/server && npx @better-auth/cli generate --output ./src/db/auth-schema.ts";
|
||||
|
||||
packageJson.scripts["db:setup"] =
|
||||
"npm run auth:generate && npm run prisma:generate && npm run prisma:push";
|
||||
} else if (options.orm === "drizzle") {
|
||||
packageJson.scripts["drizzle:migrate"] =
|
||||
"cd packages/server && npx @better-auth/cli migrate";
|
||||
|
||||
packageJson.scripts["db:setup"] =
|
||||
"npm run auth:generate && npm run drizzle:migrate";
|
||||
if (options.orm === "prisma") {
|
||||
packageJson.scripts["prisma:generate"] =
|
||||
"cd packages/server && npx prisma generate";
|
||||
packageJson.scripts["prisma:push"] =
|
||||
"cd packages/server && npx prisma db push";
|
||||
packageJson.scripts["prisma:studio"] =
|
||||
"cd packages/server && npx prisma studio";
|
||||
packageJson.scripts["db:setup"] =
|
||||
"npm run auth:generate && npm run prisma:generate && npm run prisma:push";
|
||||
} else if (options.orm === "drizzle") {
|
||||
packageJson.scripts["drizzle:migrate"] =
|
||||
"cd packages/server && npx @better-auth/cli migrate";
|
||||
packageJson.scripts["db:setup"] =
|
||||
"npm run auth:generate && npm run drizzle:migrate";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ function generateReadmeContent(options: ProjectConfig): string {
|
||||
|
||||
return `# ${projectName}
|
||||
|
||||
This project was created with [Better-T-Stack](https://github.com/better-t-stack/Better-T-Stack).
|
||||
This project was created with [Better-T-Stack](https://github.com/better-t-stack/Better-T-Stack), a modern TypeScript stack that combines React, TanStack Router, Hono, tRPC, and more.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -42,6 +42,8 @@ First, install the dependencies:
|
||||
${packageManager} install
|
||||
\`\`\`
|
||||
|
||||
${generateDatabaseSetup(database, auth, packageManagerRunCmd, orm)}
|
||||
|
||||
Then, run the development server:
|
||||
|
||||
\`\`\`bash
|
||||
@@ -51,10 +53,6 @@ ${packageManagerRunCmd} dev
|
||||
Open [http://localhost:3001](http://localhost:3001) in your browser to see the client application.
|
||||
The API is running at [http://localhost:3000](http://localhost:3000).
|
||||
|
||||
## Database Setup
|
||||
|
||||
${generateDatabaseSetup(database, auth, packageManagerRunCmd, orm)}
|
||||
|
||||
## Project Structure
|
||||
|
||||
\`\`\`
|
||||
@@ -64,9 +62,9 @@ ${projectName}/
|
||||
│ └── server/ # Backend API (Hono, tRPC)
|
||||
\`\`\`
|
||||
|
||||
## Scripts
|
||||
## Available Scripts
|
||||
|
||||
${generateScriptsList(packageManagerRunCmd)}
|
||||
${generateScriptsList(packageManagerRunCmd, database, orm, auth)}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -77,31 +75,34 @@ function generateFeaturesList(
|
||||
orm: string,
|
||||
): string {
|
||||
const featuresList = [
|
||||
"TypeScript - For type safety",
|
||||
"TanStack Router - File-based routing",
|
||||
`${orm === "drizzle" ? "Drizzle" : "Prisma"} - ORM`,
|
||||
"TailwindCSS - Utility-first CSS",
|
||||
"shadcn/ui - Reusable components",
|
||||
"Hono - Lightweight, performant server",
|
||||
"- **TypeScript** - For type safety and improved developer experience",
|
||||
"- **TanStack Router** - File-based routing with full type safety",
|
||||
"- **TailwindCSS** - Utility-first CSS for rapid UI development",
|
||||
"- **shadcn/ui** - Reusable UI components",
|
||||
"- **Hono** - Lightweight, performant server framework",
|
||||
"- **tRPC** - End-to-end type-safe APIs",
|
||||
];
|
||||
|
||||
if (database !== "none") {
|
||||
featuresList.push(
|
||||
`${database === "sqlite" ? "SQLite/Turso DB" : "PostgreSQL"} - Database`,
|
||||
`- **${orm === "drizzle" ? "Drizzle" : "Prisma"}** - TypeScript-first ORM`,
|
||||
`- **${database === "sqlite" ? "SQLite/Turso" : "PostgreSQL"}** - Database engine`,
|
||||
);
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
featuresList.push("Authentication - Email & password auth");
|
||||
featuresList.push(
|
||||
"- **Authentication** - Email & password authentication with Better Auth",
|
||||
);
|
||||
}
|
||||
|
||||
for (const feature of features) {
|
||||
if (feature === "docker") {
|
||||
featuresList.push("Docker - Containerized deployment");
|
||||
featuresList.push("- **Docker** - Containerized deployment");
|
||||
} else if (feature === "github-actions") {
|
||||
featuresList.push("GitHub Actions - CI/CD");
|
||||
featuresList.push("- **GitHub Actions** - CI/CD workflows");
|
||||
} else if (feature === "SEO") {
|
||||
featuresList.push("SEO - Search engine optimization");
|
||||
featuresList.push("- **SEO** - Search engine optimization tools");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,63 +116,90 @@ function generateDatabaseSetup(
|
||||
orm: string,
|
||||
): string {
|
||||
if (database === "none") {
|
||||
return "This project does not include a database.";
|
||||
return "";
|
||||
}
|
||||
|
||||
if (database === "sqlite") {
|
||||
return `This project uses SQLite/Turso for the database.
|
||||
let setup = "## Database Setup\n\n";
|
||||
|
||||
1. Start the local database:
|
||||
if (database === "sqlite") {
|
||||
setup += `This project uses SQLite${orm === "drizzle" ? " with Drizzle ORM" : " with Prisma"}.
|
||||
|
||||
1. Start the local SQLite database:
|
||||
\`\`\`bash
|
||||
${packageManagerRunCmd} db:local
|
||||
\`\`\`
|
||||
|
||||
2. Update your \`.env\` file with the connection details.
|
||||
2. Update your \`.env\` file with the appropriate connection details if needed.
|
||||
`;
|
||||
} else if (database === "postgres") {
|
||||
setup += `This project uses PostgreSQL${orm === "drizzle" ? " with Drizzle ORM" : " with Prisma"}.
|
||||
|
||||
${
|
||||
auth
|
||||
? `3. If using authentication, generate the auth schema:
|
||||
1. Make sure you have a PostgreSQL database set up.
|
||||
2. Update your \`packages/server/.env\` file with your PostgreSQL connection details.
|
||||
`;
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
setup += `
|
||||
3. Generate the authentication schema:
|
||||
\`\`\`bash
|
||||
${packageManagerRunCmd} auth:generate
|
||||
\`\`\`
|
||||
|
||||
4. Apply the schema to your database:
|
||||
4. ${
|
||||
orm === "prisma"
|
||||
? `Generate the Prisma client and push the schema:
|
||||
\`\`\`bash
|
||||
${packageManagerRunCmd} ${orm === "drizzle" ? "drizzle:migrate" : "prisma:push"}
|
||||
${packageManagerRunCmd} prisma:generate
|
||||
${packageManagerRunCmd} prisma:push
|
||||
\`\`\``
|
||||
: ""
|
||||
}`;
|
||||
: `Apply the Drizzle migrations:
|
||||
\`\`\`bash
|
||||
${packageManagerRunCmd} drizzle:migrate
|
||||
\`\`\``
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
if (database === "postgres") {
|
||||
return `This project uses PostgreSQL for the database.
|
||||
|
||||
1. Set up your PostgreSQL database.
|
||||
2. Update your \`.env\` file with the connection details.
|
||||
|
||||
${
|
||||
auth
|
||||
? `3. If using authentication, generate the auth schema:
|
||||
\`\`\`bash
|
||||
${packageManagerRunCmd} auth:generate
|
||||
\`\`\`
|
||||
|
||||
4. Apply the schema to your database:
|
||||
\`\`\`bash
|
||||
${packageManagerRunCmd} ${orm === "drizzle" ? "drizzle:migrate" : "prisma:push"}
|
||||
\`\`\``
|
||||
: ""
|
||||
}`;
|
||||
}
|
||||
|
||||
return "";
|
||||
return setup;
|
||||
}
|
||||
|
||||
function generateScriptsList(packageManagerRunCmd: string): string {
|
||||
return `- \`${packageManagerRunCmd} dev\`: Start both client and server in development mode
|
||||
function generateScriptsList(
|
||||
packageManagerRunCmd: string,
|
||||
database: string,
|
||||
orm: string,
|
||||
auth: boolean,
|
||||
): string {
|
||||
let scripts = `- \`${packageManagerRunCmd} dev\`: Start both client and server in development mode
|
||||
- \`${packageManagerRunCmd} build\`: Build both client and server
|
||||
- \`${packageManagerRunCmd} dev:client\`: Start only the client
|
||||
- \`${packageManagerRunCmd} dev:server\`: Start only the server
|
||||
- \`${packageManagerRunCmd} db:local\`: Start the local SQLite database (if applicable)
|
||||
- \`${packageManagerRunCmd} db:push\`: Push schema changes to the database`;
|
||||
- \`${packageManagerRunCmd} dev:server\`: Start only the server`;
|
||||
|
||||
if (database !== "none") {
|
||||
if (database === "sqlite") {
|
||||
scripts += `\n- \`${packageManagerRunCmd} db:local\`: Start the local SQLite database`;
|
||||
}
|
||||
|
||||
if (orm === "prisma") {
|
||||
scripts += `
|
||||
- \`${packageManagerRunCmd} prisma:generate\`: Generate Prisma client
|
||||
- \`${packageManagerRunCmd} prisma:push\`: Push schema changes to database
|
||||
- \`${packageManagerRunCmd} prisma:studio\`: Open Prisma Studio`;
|
||||
} else if (orm === "drizzle") {
|
||||
scripts += `
|
||||
- \`${packageManagerRunCmd} db:generate\`: Generate database schema
|
||||
- \`${packageManagerRunCmd} db:push\`: Push schema changes to database
|
||||
- \`${packageManagerRunCmd} db:studio\`: Open Drizzle Studio`;
|
||||
}
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
scripts += `\n- \`${packageManagerRunCmd} auth:generate\`: Generate authentication schema`;
|
||||
}
|
||||
|
||||
if (auth && database !== "none") {
|
||||
scripts += `\n- \`${packageManagerRunCmd} db:setup\`: Complete database setup for auth`;
|
||||
}
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@@ -10,35 +10,57 @@ export function displayPostInstallInstructions(
|
||||
orm?: string,
|
||||
) {
|
||||
const runCmd = packageManager === "npm" ? "npm run" : packageManager;
|
||||
const cdCmd = `cd ${projectName}`;
|
||||
|
||||
const steps = [];
|
||||
|
||||
if (!depsInstalled) {
|
||||
steps.push(`${pc.cyan(packageManager)} install`);
|
||||
}
|
||||
|
||||
if (hasAuth && database !== "none") {
|
||||
steps.push(`${pc.yellow("Authentication Setup:")}`);
|
||||
steps.push(
|
||||
`${pc.cyan("1.")} Generate auth schema: ${pc.green(`${runCmd} auth:generate`)}`,
|
||||
);
|
||||
|
||||
if (orm === "prisma") {
|
||||
steps.push(
|
||||
`${pc.cyan("2.")} Generate Prisma client: ${pc.green(`${runCmd} prisma:generate`)}`,
|
||||
);
|
||||
steps.push(
|
||||
`${pc.cyan("3.")} Push schema to database: ${pc.green(`${runCmd} prisma:push`)}`,
|
||||
);
|
||||
} else if (orm === "drizzle") {
|
||||
steps.push(
|
||||
`${pc.cyan("2.")} Apply migrations: ${pc.green(`${runCmd} drizzle:migrate`)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (database === "postgres") {
|
||||
steps.push(`${pc.yellow("PostgreSQL Configuration:")}`);
|
||||
steps.push(
|
||||
`Make sure to update ${pc.cyan("packages/server/.env")} with your PostgreSQL connection string.`,
|
||||
);
|
||||
} else if (database === "sqlite") {
|
||||
steps.push(`${pc.yellow("Database Configuration:")}`);
|
||||
steps.push(
|
||||
`${pc.cyan("packages/server/.env")} contains your SQLite connection details. Update if needed.`,
|
||||
);
|
||||
steps.push(
|
||||
`Start the local SQLite database with: ${pc.green(`${runCmd} db:local`)}`,
|
||||
);
|
||||
}
|
||||
|
||||
steps.push(`${pc.yellow("Start Development:")}`);
|
||||
steps.push(`${pc.green(`${runCmd} dev`)}`);
|
||||
|
||||
log.info(`${pc.cyan("Installation completed!")} Here are some next steps:
|
||||
|
||||
${
|
||||
hasAuth && database !== "none"
|
||||
? `${pc.yellow("Authentication Setup:")}
|
||||
${pc.cyan("1.")} Generate auth schema: ${pc.green(`cd ${projectName} && ${packageManager} run auth:generate`)}
|
||||
${
|
||||
orm === "prisma"
|
||||
? `${pc.cyan("2.")} Generate Prisma client: ${pc.green(`${packageManager} run prisma:generate`)}
|
||||
${pc.cyan("3.")} Push schema to database: ${pc.green(`${packageManager} run prisma:push`)}`
|
||||
: `${pc.cyan("2.")} Apply migrations: ${pc.green(`${packageManager} run drizzle:migrate`)}`
|
||||
}
|
||||
${cdCmd}
|
||||
${steps.join("\n")}
|
||||
|
||||
`
|
||||
: ""
|
||||
}${
|
||||
database === "postgres"
|
||||
? `${pc.yellow("PostgreSQL Configuration:")}
|
||||
Make sure to update ${pc.cyan("packages/server/.env")} with your PostgreSQL connection string.
|
||||
|
||||
`
|
||||
: database === "sqlite"
|
||||
? `${pc.yellow("Database Configuration:")}
|
||||
${pc.cyan("packages/server/.env")} contains your SQLite connection details. Update if needed.`
|
||||
: ""
|
||||
}
|
||||
|
||||
${pc.yellow("Start Development:")}
|
||||
${pc.cyan("cd")} ${projectName}${!depsInstalled ? `\n${pc.cyan(packageManager)} install` : ""}
|
||||
${pc.cyan(runCmd)} dev`);
|
||||
The client application will be available at ${pc.cyan("http://localhost:3001")}
|
||||
The API server will be running at ${pc.cyan("http://localhost:3000")}`);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function getDatabaseChoice(
|
||||
{
|
||||
value: "sqlite",
|
||||
label: "SQLite",
|
||||
hint: "by Turso (recommended)",
|
||||
hint: "by Turso",
|
||||
},
|
||||
{
|
||||
value: "postgres",
|
||||
|
||||
@@ -15,7 +15,7 @@ export async function getORMChoice(
|
||||
{
|
||||
value: "drizzle",
|
||||
label: "Drizzle",
|
||||
hint: "Type-safe, lightweight ORM (recommended)",
|
||||
hint: "Type-safe, lightweight ORM",
|
||||
},
|
||||
{
|
||||
value: "prisma",
|
||||
|
||||
@@ -37,7 +37,7 @@ export async function getPackageManagerChoice(
|
||||
{
|
||||
value: "bun",
|
||||
label: "bun",
|
||||
hint: "All-in-one JavaScript runtime & toolkit (recommended)",
|
||||
hint: "All-in-one JavaScript runtime & toolkit",
|
||||
},
|
||||
],
|
||||
initialValue: "bun",
|
||||
|
||||
@@ -28,6 +28,33 @@ export default function UserMenu() {
|
||||
return <Skeleton className="h-9 w-24" />;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">Sign In</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="bg-card">
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
onClick={() => {
|
||||
navigate({
|
||||
to: "/sign-in",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Sign In
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
|
||||
4
bun.lock
4
bun.lock
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"apps/cli": {
|
||||
"name": "create-better-t-stack",
|
||||
"version": "0.10.1",
|
||||
"version": "0.11.0",
|
||||
"bin": {
|
||||
"create-better-t-stack": "dist/index.js",
|
||||
},
|
||||
@@ -1085,7 +1085,7 @@
|
||||
|
||||
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
|
||||
|
||||
"lint-staged": ["lint-staged@15.4.3", "", { "dependencies": { "chalk": "^5.4.1", "commander": "^13.1.0", "debug": "^4.4.0", "execa": "^8.0.1", "lilconfig": "^3.1.3", "listr2": "^8.2.5", "micromatch": "^4.0.8", "pidtree": "^0.6.0", "string-argv": "^0.3.2", "yaml": "^2.7.0" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-FoH1vOeouNh1pw+90S+cnuoFwRfUD9ijY2GKy5h7HS3OR7JVir2N2xrsa0+Twc1B7cW72L+88geG5cW4wIhn7g=="],
|
||||
"lint-staged": ["lint-staged@15.5.0", "", { "dependencies": { "chalk": "^5.4.1", "commander": "^13.1.0", "debug": "^4.4.0", "execa": "^8.0.1", "lilconfig": "^3.1.3", "listr2": "^8.2.5", "micromatch": "^4.0.8", "pidtree": "^0.6.0", "string-argv": "^0.3.2", "yaml": "^2.7.0" }, "bin": { "lint-staged": "bin/lint-staged.js" } }, "sha512-WyCzSbfYGhK7cU+UuDDkzUiytbfbi0ZdPy2orwtM75P3WTtQBzmG40cCxIa8Ii2+XjfxzLH6Be46tUfWS85Xfg=="],
|
||||
|
||||
"listr2": ["listr2@8.2.5", "", { "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ=="],
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@changesets/cli": "^2.28.1",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^15.4.3",
|
||||
"lint-staged": "^15.5.0",
|
||||
"turbo": "^2.4.4",
|
||||
"typescript": "5.7.3"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user