Squash merge beta into main

This commit is contained in:
Aman Varshney
2025-04-19 17:30:59 +05:30
parent 724d32b913
commit 0de49d4e45
27 changed files with 113 additions and 130 deletions

View File

@@ -0,0 +1,5 @@
---
"create-better-t-stack": patch
---
remove none option in api

View File

@@ -0,0 +1,5 @@
---
"create-better-t-stack": patch
---
Only add tRPC server adapters when API is tRPC

9
.changeset/pre.json Normal file
View File

@@ -0,0 +1,9 @@
{
"mode": "exit",
"tag": "beta",
"initialVersions": {
"create-better-t-stack": "2.0.5",
"web": "0.0.0"
},
"changesets": ["dirty-seas-train", "polite-mirrors-love"]
}

View File

@@ -4,6 +4,7 @@ on:
push: push:
branches: branches:
- main - main
- beta
paths: paths:
- 'apps/cli/**' - 'apps/cli/**'
- '.changeset/**' - '.changeset/**'
@@ -16,12 +17,20 @@ jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - name: Checkout Code
- uses: oven-sh/setup-bun@v2 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with: with:
bun-version: latest bun-version: latest
- run: bun install --frozen-lockfile
- name: Create Release Pull Request - name: Install Dependencies
run: bun install --frozen-lockfile
- name: Create Release Pull Request or Publish
id: changesets id: changesets
uses: changesets/action@v1 uses: changesets/action@v1
with: with:

View File

@@ -1,5 +1,17 @@
# create-better-t-stack # create-better-t-stack
## 2.0.6-beta.1
### Patch Changes
- 9d9bd1d: remove none option in api
## 2.0.6-beta.0
### Patch Changes
- 0a4813b: Only add tRPC server adapters when API is tRPC
## 2.0.5 ## 2.0.5
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
{ {
"name": "create-better-t-stack", "name": "create-better-t-stack",
"version": "2.0.5", "version": "2.0.6-beta.1",
"description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations", "description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",

View File

@@ -8,7 +8,7 @@ import { setupTauri } from "./tauri-setup";
import type { ProjectConfig } from "../types"; import type { ProjectConfig } from "../types";
export async function setupAddons(config: ProjectConfig) { export async function setupAddons(config: ProjectConfig) {
const { projectName, addons, packageManager, frontend } = config; const { projectName, addons, frontend } = config;
const projectDir = path.resolve(process.cwd(), projectName); const projectDir = path.resolve(process.cwd(), projectName);
const hasWebFrontend = const hasWebFrontend =
frontend.includes("react-router") || frontend.includes("tanstack-router"); frontend.includes("react-router") || frontend.includes("tanstack-router");

View File

@@ -1,9 +1,8 @@
import * as path from "node:path"; import * as path from "node:path";
import type { ProjectApi, ProjectConfig } from "../types"; import type { ProjectConfig } from "../types";
import { addPackageDependency } from "../utils/add-package-deps"; import { addPackageDependency } from "../utils/add-package-deps";
export async function setupApi(config: ProjectConfig): Promise<void> { export async function setupApi(config: ProjectConfig): Promise<void> {
if (config.api === "none") return;
const { api, projectName } = config; const { api, projectName } = config;
const projectDir = path.resolve(process.cwd(), projectName); const projectDir = path.resolve(process.cwd(), projectName);
const webDir = path.join(projectDir, "apps/web"); const webDir = path.join(projectDir, "apps/web");

View File

@@ -1,7 +1,6 @@
import path from "node:path"; import path from "node:path";
import consola from "consola"; import consola from "consola";
import pc from "picocolors"; import pc from "picocolors";
import type { ProjectFrontend } from "../types";
import { addPackageDependency } from "../utils/add-package-deps"; import { addPackageDependency } from "../utils/add-package-deps";
export function generateAuthSecret(length = 32): string { export function generateAuthSecret(length = 32): string {

View File

@@ -1,6 +1,5 @@
import path from "node:path"; import path from "node:path";
import type { AvailableDependencies } from "../constants"; import type { AvailableDependencies } from "../constants";
import type { ProjectBackend, ProjectRuntime } from "../types";
import { addPackageDependency } from "../utils/add-package-deps"; import { addPackageDependency } from "../utils/add-package-deps";
import type { ProjectConfig } from "../types"; import type { ProjectConfig } from "../types";
@@ -8,7 +7,7 @@ import type { ProjectConfig } from "../types";
export async function setupBackendDependencies( export async function setupBackendDependencies(
config: ProjectConfig, config: ProjectConfig,
): Promise<void> { ): Promise<void> {
const { projectName, backend, runtime } = config; const { projectName, backend, runtime, api } = config;
const projectDir = path.resolve(process.cwd(), projectName); const projectDir = path.resolve(process.cwd(), projectName);
const framework = backend; const framework = backend;
const serverDir = path.join(projectDir, "apps/server"); const serverDir = path.join(projectDir, "apps/server");
@@ -17,15 +16,20 @@ export async function setupBackendDependencies(
const devDependencies: AvailableDependencies[] = []; const devDependencies: AvailableDependencies[] = [];
if (framework === "hono") { if (framework === "hono") {
dependencies.push("hono", "@hono/trpc-server"); dependencies.push("hono");
if (api === "trpc") {
dependencies.push("@hono/trpc-server");
}
if (runtime === "node") { if (runtime === "node") {
dependencies.push("@hono/node-server"); dependencies.push("@hono/node-server");
devDependencies.push("tsx", "@types/node"); devDependencies.push("tsx", "@types/node");
} }
} else if (framework === "elysia") { } else if (framework === "elysia") {
dependencies.push("elysia", "@elysiajs/cors", "@elysiajs/trpc"); dependencies.push("elysia", "@elysiajs/cors");
if (api === "trpc") {
dependencies.push("@elysiajs/trpc");
}
if (runtime === "node") { if (runtime === "node") {
dependencies.push("@elysiajs/node"); dependencies.push("@elysiajs/node");
devDependencies.push("tsx", "@types/node"); devDependencies.push("tsx", "@types/node");

View File

@@ -1,13 +1,8 @@
import path from "node:path"; import path from "node:path";
import { log, spinner } from "@clack/prompts"; import { spinner } from "@clack/prompts";
import consola from "consola"; import consola from "consola";
import fs from "fs-extra"; import fs from "fs-extra";
import pc from "picocolors"; import pc from "picocolors";
import type {
ProjectDatabase,
ProjectOrm,
ProjectPackageManager,
} from "../types";
import { addPackageDependency } from "../utils/add-package-deps"; import { addPackageDependency } from "../utils/add-package-deps";
import { setupMongoDBAtlas } from "./mongodb-atlas-setup"; import { setupMongoDBAtlas } from "./mongodb-atlas-setup";
import { setupPrismaPostgres } from "./prisma-postgres-setup"; import { setupPrismaPostgres } from "./prisma-postgres-setup";
@@ -18,7 +13,7 @@ import { setupNeonPostgres } from "./neon-setup";
import type { ProjectConfig } from "../types"; import type { ProjectConfig } from "../types";
export async function setupDatabase(config: ProjectConfig): Promise<void> { export async function setupDatabase(config: ProjectConfig): Promise<void> {
const { projectName, database, orm, packageManager, dbSetup } = config; const { projectName, database, orm, dbSetup } = config;
const projectDir = path.resolve(process.cwd(), projectName); const projectDir = path.resolve(process.cwd(), projectName);
const s = spinner(); const s = spinner();
const serverDir = path.join(projectDir, "apps/server"); const serverDir = path.join(projectDir, "apps/server");

View File

@@ -1,23 +1,9 @@
import path from "node:path"; import path from "node:path";
import fs from "fs-extra"; import type { ProjectConfig } from "../types";
import { PKG_ROOT } from "../constants";
import type {
ProjectBackend,
ProjectConfig,
ProjectFrontend,
ProjectOrm,
} from "../types";
import { addPackageDependency } from "../utils/add-package-deps"; import { addPackageDependency } from "../utils/add-package-deps";
export async function setupExamples(config: ProjectConfig): Promise<void> { export async function setupExamples(config: ProjectConfig): Promise<void> {
const { const { projectName, examples } = config;
projectName,
examples,
orm,
auth,
backend,
frontend = ["tanstack-router"],
} = config;
const projectDir = path.resolve(process.cwd(), projectName); const projectDir = path.resolve(process.cwd(), projectName);
if (examples.includes("ai")) { if (examples.includes("ai")) {

View File

@@ -1,14 +1,6 @@
import { consola } from "consola"; import { consola } from "consola";
import pc from "picocolors"; import pc from "picocolors";
import type { import type { ProjectDatabase, ProjectOrm, ProjectRuntime } from "../types";
ProjectAddons,
ProjectDBSetup,
ProjectDatabase,
ProjectFrontend,
ProjectOrm,
ProjectPackageManager,
ProjectRuntime,
} from "../types";
import { getPackageExecutionCommand } from "../utils/get-package-execution-command"; import { getPackageExecutionCommand } from "../utils/get-package-execution-command";
import type { ProjectConfig } from "../types"; import type { ProjectConfig } from "../types";
@@ -25,7 +17,6 @@ export function displayPostInstallInstructions(
addons, addons,
runtime, runtime,
frontend, frontend,
dbSetup,
} = config; } = config;
const runCmd = packageManager === "npm" ? "npm run" : packageManager; const runCmd = packageManager === "npm" ? "npm run" : packageManager;
const cdCmd = `cd ${projectName}`; const cdCmd = `cd ${projectName}`;

View File

@@ -22,7 +22,6 @@ async function updateRootPackageJson(
const packageJson = await fs.readJson(rootPackageJsonPath); const packageJson = await fs.readJson(rootPackageJsonPath);
packageJson.name = options.projectName; packageJson.name = options.projectName;
// Define script sets
const turboScripts = { const turboScripts = {
dev: "turbo dev", dev: "turbo dev",
build: "turbo build", build: "turbo build",

View File

@@ -1,6 +1,6 @@
import path from "node:path"; import path from "node:path";
import fs from "fs-extra"; import fs from "fs-extra";
import type { ProjectBackend, ProjectConfig, ProjectRuntime } from "../types"; import type { ProjectBackend, ProjectConfig } from "../types";
import { addPackageDependency } from "../utils/add-package-deps"; import { addPackageDependency } from "../utils/add-package-deps";
export async function setupRuntime(config: ProjectConfig): Promise<void> { export async function setupRuntime(config: ProjectConfig): Promise<void> {

View File

@@ -89,7 +89,6 @@ export async function setupFrontendTemplates(
} }
} }
if (context.api !== "none") {
const webFramework = webFrontends[0]; const webFramework = webFrontends[0];
const apiWebBaseDir = path.join( const apiWebBaseDir = path.join(
@@ -105,13 +104,7 @@ export async function setupFrontendTemplates(
`templates/api/${context.api}/web/${webFramework}`, `templates/api/${context.api}/web/${webFramework}`,
); );
if (await fs.pathExists(apiWebFrameworkDir)) { if (await fs.pathExists(apiWebFrameworkDir)) {
await processAndCopyFiles( await processAndCopyFiles("**/*", apiWebFrameworkDir, webAppDir, context);
"**/*",
apiWebFrameworkDir,
webAppDir,
context,
);
}
} }
} }
@@ -124,23 +117,16 @@ export async function setupFrontendTemplates(
await processAndCopyFiles("**/*", nativeBaseDir, nativeAppDir, context); await processAndCopyFiles("**/*", nativeBaseDir, nativeAppDir, context);
} }
if (context.api !== "none") {
const apiNativeSrcDir = path.join( const apiNativeSrcDir = path.join(
PKG_ROOT, PKG_ROOT,
`templates/api/${context.api}/native`, `templates/api/${context.api}/native`,
); );
if (await fs.pathExists(apiNativeSrcDir)) { if (await fs.pathExists(apiNativeSrcDir)) {
await processAndCopyFiles( await processAndCopyFiles("**/*", apiNativeSrcDir, nativeAppDir, context);
"**/*",
apiNativeSrcDir,
nativeAppDir,
context,
);
} else { } else {
} }
} }
}
} }
export async function setupBackendFramework( export async function setupBackendFramework(
@@ -175,18 +161,12 @@ export async function setupBackendFramework(
); );
} }
if (context.api !== "none") {
const apiServerBaseDir = path.join( const apiServerBaseDir = path.join(
PKG_ROOT, PKG_ROOT,
`templates/api/${context.api}/server/base`, `templates/api/${context.api}/server/base`,
); );
if (await fs.pathExists(apiServerBaseDir)) { if (await fs.pathExists(apiServerBaseDir)) {
await processAndCopyFiles( await processAndCopyFiles("**/*", apiServerBaseDir, serverAppDir, context);
"**/*",
apiServerBaseDir,
serverAppDir,
context,
);
} }
const apiServerFrameworkDir = path.join( const apiServerFrameworkDir = path.join(
@@ -201,7 +181,6 @@ export async function setupBackendFramework(
context, context,
); );
} }
}
} }
export async function setupDbOrmTemplates( export async function setupDbOrmTemplates(

View File

@@ -4,10 +4,10 @@ import { DEFAULT_CONFIG } from "../constants";
import type { ProjectAddons, ProjectFrontend } from "../types"; import type { ProjectAddons, ProjectFrontend } from "../types";
export async function getAddonsChoice( export async function getAddonsChoice(
Addons?: ProjectAddons[], addons?: ProjectAddons[],
frontends?: ProjectFrontend[], frontends?: ProjectFrontend[],
): Promise<ProjectAddons[]> { ): Promise<ProjectAddons[]> {
if (Addons !== undefined) return Addons; if (addons !== undefined) return addons;
const hasCompatibleWebFrontend = const hasCompatibleWebFrontend =
frontends?.includes("react-router") || frontends?.includes("react-router") ||
@@ -50,7 +50,7 @@ export async function getAddonsChoice(
]; ];
const options = hasCompatibleWebFrontend const options = hasCompatibleWebFrontend
? [...webAddonOptions, ...addonOptions] ? [...addonOptions, ...webAddonOptions]
: addonOptions; : addonOptions;
const initialValues = DEFAULT_CONFIG.addons.filter( const initialValues = DEFAULT_CONFIG.addons.filter(

View File

@@ -22,11 +22,6 @@ export async function getApiChoice(
label: "oRPC", label: "oRPC",
hint: "End-to-end type-safe APIs that adhere to OpenAPI standards", hint: "End-to-end type-safe APIs that adhere to OpenAPI standards",
}, },
{
value: "none" as const,
label: "None",
hint: "No API integration (skip API setup)",
},
]; ];
if (includesNative) { if (includesNative) {

View File

@@ -1,7 +1,6 @@
import { cancel, confirm, isCancel, log } from "@clack/prompts"; import { cancel, confirm, isCancel } from "@clack/prompts";
import pc from "picocolors"; import pc from "picocolors";
import { DEFAULT_CONFIG } from "../constants"; import { DEFAULT_CONFIG } from "../constants";
import type { ProjectFrontend } from "../types";
export async function getAuthChoice( export async function getAuthChoice(
auth: boolean | undefined, auth: boolean | undefined,

View File

@@ -19,7 +19,7 @@ export async function getDatabaseChoice(
{ {
value: "sqlite", value: "sqlite",
label: "SQLite", label: "SQLite",
hint: "lightweight, server-less, embedded relational database management system", hint: "lightweight, server-less, embedded relational database",
}, },
{ {
value: "postgres", value: "postgres",

View File

@@ -2,6 +2,7 @@ import { cancel, isCancel, multiselect } from "@clack/prompts";
import pc from "picocolors"; import pc from "picocolors";
import { DEFAULT_CONFIG } from "../constants"; import { DEFAULT_CONFIG } from "../constants";
import type { import type {
ProjectApi,
ProjectBackend, ProjectBackend,
ProjectDatabase, ProjectDatabase,
ProjectExamples, ProjectExamples,

View File

@@ -30,7 +30,7 @@ export type ProjectDBSetup =
| "mongodb-atlas" | "mongodb-atlas"
| "neon" | "neon"
| "none"; | "none";
export type ProjectApi = "trpc" | "orpc" | "none"; export type ProjectApi = "trpc" | "orpc";
export interface ProjectConfig { export interface ProjectConfig {
projectName: string; projectName: string;

View File

@@ -1,4 +1,5 @@
import path from "node:path"; import path from "node:path";
import consola from "consola";
import fs from "fs-extra"; import fs from "fs-extra";
import handlebars from "handlebars"; import handlebars from "handlebars";
import type { ProjectConfig } from "../types"; import type { ProjectConfig } from "../types";
@@ -22,7 +23,7 @@ export async function processTemplate(
await fs.ensureDir(path.dirname(destPath)); await fs.ensureDir(path.dirname(destPath));
await fs.writeFile(destPath, processedContent); await fs.writeFile(destPath, processedContent);
} catch (error) { } catch (error) {
console.error(`Error processing template ${srcPath}:`, error); consola.error(`Error processing template ${srcPath}:`, error);
throw new Error(`Failed to process template ${srcPath}`); throw new Error(`Failed to process template ${srcPath}`);
} }
} }

View File

@@ -20,6 +20,7 @@ export const appRouter = {
todo: todoRouter, todo: todoRouter,
{{/if}} {{/if}}
}; };
export type AppRouter = typeof appRouter;
{{/if}} {{/if}}
{{#if (eq api "trpc")}} {{#if (eq api "trpc")}}
@@ -47,5 +48,5 @@ export const appRouter = router({
todo: todoRouter, todo: todoRouter,
{{/if}} {{/if}}
}); });
{{/if}}
export type AppRouter = typeof appRouter; export type AppRouter = typeof appRouter;
{{/if}}

View File

@@ -17,6 +17,7 @@
"typedRoutes": true, "typedRoutes": true,
"tsconfigPaths": true "tsconfigPaths": true
}, },
"newArchEnabled": true,
"orientation": "portrait", "orientation": "portrait",
"icon": "./assets/icon.png", "icon": "./assets/icon.png",
"userInterfaceStyle": "light", "userInterfaceStyle": "light",

View File

@@ -15,13 +15,6 @@ export const TECH_OPTIONS = {
icon: "🧩", icon: "🧩",
color: "from-indigo-400 to-indigo-600", color: "from-indigo-400 to-indigo-600",
}, },
{
id: "none",
name: "No API",
description: "Skip API layer integration",
icon: "🚫",
color: "from-gray-400 to-gray-600",
},
], ],
frontend: [ frontend: [
{ {

View File

@@ -14,7 +14,7 @@
}, },
"apps/cli": { "apps/cli": {
"name": "create-better-t-stack", "name": "create-better-t-stack",
"version": "2.0.1", "version": "2.0.6-beta.0",
"bin": { "bin": {
"create-better-t-stack": "dist/index.js", "create-better-t-stack": "dist/index.js",
}, },