feat: add @better-t-stack/types package

This commit is contained in:
Aman Varshney
2025-08-04 22:48:19 +05:30
parent f650774042
commit 19b625c5c7
8 changed files with 270 additions and 197 deletions

View File

@@ -53,6 +53,7 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
"@better-t-stack/types": "workspace:*",
"@clack/prompts": "^0.11.0",
"consola": "^3.4.2",
"execa": "^9.6.0",
@@ -62,15 +63,15 @@
"handlebars": "^4.7.8",
"jsonc-parser": "^3.3.1",
"picocolors": "^1.1.1",
"posthog-node": "^5.5.0",
"trpc-cli": "^0.10.0",
"posthog-node": "^5.6.0",
"trpc-cli": "^0.10.2",
"ts-morph": "^26.0.0",
"zod": "^4.0.5"
"zod": "^4.0.14"
},
"devDependencies": {
"@types/fs-extra": "^11.0.4",
"@types/node": "^24.0.13",
"tsdown": "^0.12.9",
"typescript": "^5.8.3"
"@types/node": "^24.2.0",
"tsdown": "^0.13.3",
"typescript": "^5.9.2"
}
}

View File

@@ -1,180 +1 @@
import z from "zod";
export const DatabaseSchema = z
.enum(["none", "sqlite", "postgres", "mysql", "mongodb"])
.describe("Database type");
export type Database = z.infer<typeof DatabaseSchema>;
export const ORMSchema = z
.enum(["drizzle", "prisma", "mongoose", "none"])
.describe("ORM type");
export type ORM = z.infer<typeof ORMSchema>;
export const BackendSchema = z
.enum(["hono", "express", "fastify", "next", "elysia", "convex", "none"])
.describe("Backend framework");
export type Backend = z.infer<typeof BackendSchema>;
export const RuntimeSchema = z
.enum(["bun", "node", "workers", "none"])
.describe(
"Runtime environment (workers only available with hono backend and drizzle orm)",
);
export type Runtime = z.infer<typeof RuntimeSchema>;
export const FrontendSchema = z
.enum([
"tanstack-router",
"react-router",
"tanstack-start",
"next",
"nuxt",
"native-nativewind",
"native-unistyles",
"svelte",
"solid",
"none",
])
.describe("Frontend framework");
export type Frontend = z.infer<typeof FrontendSchema>;
export const AddonsSchema = z
.enum([
"pwa",
"tauri",
"starlight",
"biome",
"husky",
"turborepo",
"fumadocs",
"ultracite",
"oxlint",
"none",
])
.describe("Additional addons");
export type Addons = z.infer<typeof AddonsSchema>;
export const ExamplesSchema = z
.enum(["todo", "ai", "none"])
.describe("Example templates to include");
export type Examples = z.infer<typeof ExamplesSchema>;
export const PackageManagerSchema = z
.enum(["npm", "pnpm", "bun"])
.describe("Package manager");
export type PackageManager = z.infer<typeof PackageManagerSchema>;
export const DatabaseSetupSchema = z
.enum([
"turso",
"neon",
"prisma-postgres",
"mongodb-atlas",
"supabase",
"d1",
"docker",
"none",
])
.describe("Database hosting setup");
export type DatabaseSetup = z.infer<typeof DatabaseSetupSchema>;
export const APISchema = z.enum(["trpc", "orpc", "none"]).describe("API type");
export type API = z.infer<typeof APISchema>;
export const ProjectNameSchema = z
.string()
.min(1, "Project name cannot be empty")
.max(255, "Project name must be less than 255 characters")
.refine(
(name) => name === "." || !name.startsWith("."),
"Project name cannot start with a dot (except for '.')",
)
.refine(
(name) => name === "." || !name.startsWith("-"),
"Project name cannot start with a dash",
)
.refine((name) => {
const invalidChars = ["<", ">", ":", '"', "|", "?", "*"];
return !invalidChars.some((char) => name.includes(char));
}, "Project name contains invalid characters")
.refine(
(name) => name.toLowerCase() !== "node_modules",
"Project name is reserved",
)
.describe("Project name or path");
export type ProjectName = z.infer<typeof ProjectNameSchema>;
export const WebDeploySchema = z
.enum(["workers", "none"])
.describe("Web deployment");
export type WebDeploy = z.infer<typeof WebDeploySchema>;
export type CreateInput = {
projectName?: string;
yes?: boolean;
database?: Database;
orm?: ORM;
auth?: boolean;
frontend?: Frontend[];
addons?: Addons[];
examples?: Examples[];
git?: boolean;
packageManager?: PackageManager;
install?: boolean;
dbSetup?: DatabaseSetup;
backend?: Backend;
runtime?: Runtime;
api?: API;
webDeploy?: WebDeploy;
};
export type AddInput = {
addons?: Addons[];
webDeploy?: WebDeploy;
projectDir?: string;
install?: boolean;
packageManager?: PackageManager;
};
export type CLIInput = CreateInput & {
projectDirectory?: string;
};
export interface ProjectConfig {
projectName: string;
projectDir: string;
relativePath: string;
database: Database;
orm: ORM;
backend: Backend;
runtime: Runtime;
frontend: Frontend[];
addons: Addons[];
examples: Examples[];
auth: boolean;
git: boolean;
packageManager: PackageManager;
install: boolean;
dbSetup: DatabaseSetup;
api: API;
webDeploy: WebDeploy;
}
export interface BetterTStackConfig {
version: string;
createdAt: string;
database: Database;
orm: ORM;
backend: Backend;
runtime: Runtime;
frontend: Frontend[];
addons: Addons[];
examples: Examples[];
auth: boolean;
packageManager: PackageManager;
dbSetup: DatabaseSetup;
api: API;
webDeploy: WebDeploy;
}
export type AvailablePackageManagers = "npm" | "pnpm" | "bun";
export * from "@better-t-stack/types";

View File

@@ -16,6 +16,7 @@
},
"dependencies": {
"@better-t-stack/backend": "workspace:*",
"@better-t-stack/types": "workspace:*",
"@erquhart/convex-oss-stats": "^0.8.1",
"@number-flow/react": "^0.5.10",
"@opennextjs/cloudflare": "^1.6.3",

View File

@@ -14,7 +14,7 @@ import {
PackageManagerSchema,
RuntimeSchema,
WebDeploySchema,
} from "../../cli/src/types";
} from "@better-t-stack/types";
const DATABASE_VALUES = DatabaseSchema.options;
const ORM_VALUES = ORMSchema.options;

View File

@@ -19,6 +19,7 @@
"create-better-t-stack": "dist/index.js",
},
"dependencies": {
"@better-t-stack/types": "workspace:*",
"@clack/prompts": "^0.11.0",
"consola": "^3.4.2",
"execa": "^9.6.0",
@@ -28,16 +29,16 @@
"handlebars": "^4.7.8",
"jsonc-parser": "^3.3.1",
"picocolors": "^1.1.1",
"posthog-node": "^5.5.0",
"trpc-cli": "^0.10.0",
"posthog-node": "^5.6.0",
"trpc-cli": "^0.10.2",
"ts-morph": "^26.0.0",
"zod": "^4.0.5",
"zod": "^4.0.14",
},
"devDependencies": {
"@types/fs-extra": "^11.0.4",
"@types/node": "^24.0.13",
"tsdown": "^0.12.9",
"typescript": "^5.8.3",
"@types/node": "^24.2.0",
"tsdown": "^0.13.3",
"typescript": "^5.9.2",
},
},
"apps/web": {
@@ -45,6 +46,7 @@
"version": "0.0.0",
"dependencies": {
"@better-t-stack/backend": "workspace:*",
"@better-t-stack/types": "workspace:*",
"@erquhart/convex-oss-stats": "^0.8.1",
"@number-flow/react": "^0.5.10",
"@opennextjs/cloudflare": "^1.6.3",
@@ -101,6 +103,16 @@
"typescript": "^5.9.2",
},
},
"packages/types": {
"name": "@better-t-stack/types",
"version": "0.0.0",
"dependencies": {
"zod": "^4.0.14",
},
"devDependencies": {
"typescript": "5.9.2",
},
},
},
"packages": {
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
@@ -241,6 +253,8 @@
"@better-t-stack/backend": ["@better-t-stack/backend@workspace:packages/backend"],
"@better-t-stack/types": ["@better-t-stack/types@workspace:packages/types"],
"@biomejs/biome": ["@biomejs/biome@2.1.2", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.1.2", "@biomejs/cli-darwin-x64": "2.1.2", "@biomejs/cli-linux-arm64": "2.1.2", "@biomejs/cli-linux-arm64-musl": "2.1.2", "@biomejs/cli-linux-x64": "2.1.2", "@biomejs/cli-linux-x64-musl": "2.1.2", "@biomejs/cli-win32-arm64": "2.1.2", "@biomejs/cli-win32-x64": "2.1.2" }, "bin": { "biome": "bin/biome" } }, "sha512-yq8ZZuKuBVDgAS76LWCfFKHSYIAgqkxVB3mGVVpOe2vSkUTs7xG46zXZeNPRNVjiJuw0SZ3+J2rXiYx0RUpfGg=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.1.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-leFAks64PEIjc7MY/cLjE8u5OcfBKkcDB0szxsWUB4aDfemBep1WVKt0qrEyqZBOW8LPHzrFMyDl3FhuuA0E7g=="],
@@ -959,7 +973,7 @@
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
"@types/node": ["@types/node@24.2.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw=="],
"@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="],
@@ -2219,7 +2233,7 @@
"rolldown": ["rolldown@1.0.0-beta.9-commit.d91dfb5", "", { "dependencies": { "@oxc-project/runtime": "0.71.0", "@oxc-project/types": "0.71.0", "@rolldown/pluginutils": "1.0.0-beta.9-commit.d91dfb5", "ansis": "^4.0.0" }, "optionalDependencies": { "@rolldown/binding-darwin-arm64": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-darwin-x64": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-freebsd-x64": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-linux-x64-musl": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-wasm32-wasi": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.9-commit.d91dfb5", "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.9-commit.d91dfb5" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-FHkj6gGEiEgmAXQchglofvUUdwj2Oiw603Rs+zgFAnn9Cb7T7z3fiaEc0DbN3ja4wYkW6sF2rzMEtC1V4BGx/g=="],
"rolldown-plugin-dts": ["rolldown-plugin-dts@0.13.14", "", { "dependencies": { "@babel/generator": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/types": "^7.28.1", "ast-kit": "^2.1.1", "birpc": "^2.5.0", "debug": "^4.4.1", "dts-resolver": "^2.1.1", "get-tsconfig": "^4.10.1" }, "peerDependencies": { "@typescript/native-preview": ">=7.0.0-dev.20250601.1", "rolldown": "^1.0.0-beta.9", "typescript": "^5.0.0", "vue-tsc": "^2.2.0 || ^3.0.0" }, "optionalPeers": ["@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-wjNhHZz9dlN6PTIXyizB6u/mAg1wEFMW9yw7imEVe3CxHSRnNHVyycIX0yDEOVJfDNISLPbkCIPEpFpizy5+PQ=="],
"rolldown-plugin-dts": ["rolldown-plugin-dts@0.15.3", "", { "dependencies": { "@babel/generator": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/types": "^7.28.2", "ast-kit": "^2.1.1", "birpc": "^2.5.0", "debug": "^4.4.1", "dts-resolver": "^2.1.1", "get-tsconfig": "^4.10.1" }, "peerDependencies": { "@typescript/native-preview": ">=7.0.0-dev.20250601.1", "rolldown": "^1.0.0-beta.9", "typescript": "^5.0.0", "vue-tsc": "~3.0.3" }, "optionalPeers": ["@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-qILn8tXV828UpzgSN7R3KeCl1lfc2eRhPJDGO78C6PztEQH51gBTG3tyQDIVIAYY58afhOsWW/zTYpfewTGCdg=="],
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
@@ -2387,6 +2401,8 @@
"tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
"tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
"trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
"trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
@@ -2401,7 +2417,7 @@
"tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="],
"tsdown": ["tsdown@0.12.9", "", { "dependencies": { "ansis": "^4.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "debug": "^4.4.1", "diff": "^8.0.2", "empathic": "^2.0.0", "hookable": "^5.5.3", "rolldown": "^1.0.0-beta.19", "rolldown-plugin-dts": "^0.13.12", "semver": "^7.7.2", "tinyexec": "^1.0.1", "tinyglobby": "^0.2.14", "unconfig": "^7.3.2" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "publint": "^0.3.0", "typescript": "^5.0.0", "unplugin-lightningcss": "^0.4.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "publint", "typescript", "unplugin-lightningcss", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-MfrXm9PIlT3saovtWKf/gCJJ/NQCdE0SiREkdNC+9Qy6UHhdeDPxnkFaBD7xttVUmgp0yUHtGirpoLB+OVLuLA=="],
"tsdown": ["tsdown@0.13.3", "", { "dependencies": { "ansis": "^4.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "debug": "^4.4.1", "diff": "^8.0.2", "empathic": "^2.0.0", "hookable": "^5.5.3", "rolldown": "^1.0.0-beta.31", "rolldown-plugin-dts": "^0.15.3", "semver": "^7.7.2", "tinyexec": "^1.0.1", "tinyglobby": "^0.2.14", "tree-kill": "^1.2.2", "unconfig": "^7.3.2" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "publint": "^0.3.0", "typescript": "^5.0.0", "unplugin-lightningcss": "^0.4.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "publint", "typescript", "unplugin-lightningcss", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-3ujweLJB70DdWXX3v7xnzrFhzW1F/6/99XhGeKzh1UCmZ+ttFmF7Czha7VaunA5Dq/u+z4aNz3n4GH748uivYg=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
@@ -2447,7 +2463,7 @@
"undici": ["undici@7.13.0", "", {}, "sha512-l+zSMssRqrzDcb3fjMkjjLGmuiiK2pMIcV++mJaAc9vhjSGpvM7h43QgP+OAMb1GImHmbPyG2tBXeuyG5iY4gA=="],
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
"undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
"unenv": ["unenv@2.0.0-rc.19", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA=="],
@@ -3065,6 +3081,8 @@
"@better-t-stack/backend/typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"@better-t-stack/types/typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"@changesets/apply-release-plan/fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="],
"@changesets/apply-release-plan/prettier": ["prettier@2.8.8", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="],
@@ -3211,6 +3229,14 @@
"@ts-morph/common/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
"@types/fs-extra/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
"@types/jsonfile/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
"@types/node-fetch/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
"@types/papaparse/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"body-parser/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
@@ -3219,6 +3245,8 @@
"cloudflare/@types/node": ["@types/node@18.19.121", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ=="],
"convex-helpers/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"create-better-t-stack/typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"dir-glob/path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
@@ -3319,6 +3347,8 @@
"trpc-cli/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"web/@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
"web/typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
@@ -3825,6 +3855,14 @@
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="],
"@types/fs-extra/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
"@types/jsonfile/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
"@types/node-fetch/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
"@types/papaparse/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
"cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
@@ -3939,6 +3977,8 @@
"string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"web/@types/node/undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
"wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"wrap-ansi-cjs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],

View File

@@ -0,0 +1,17 @@
{
"name": "@better-t-stack/types",
"version": "0.0.0",
"type": "module",
"private": true,
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"typescript": "5.9.2"
},
"dependencies": {
"zod": "^4.0.14"
}
}

180
packages/types/src/index.ts Normal file
View File

@@ -0,0 +1,180 @@
import z from "zod";
export const DatabaseSchema = z
.enum(["none", "sqlite", "postgres", "mysql", "mongodb"])
.describe("Database type");
export type Database = z.infer<typeof DatabaseSchema>;
export const ORMSchema = z
.enum(["drizzle", "prisma", "mongoose", "none"])
.describe("ORM type");
export type ORM = z.infer<typeof ORMSchema>;
export const BackendSchema = z
.enum(["hono", "express", "fastify", "next", "elysia", "convex", "none"])
.describe("Backend framework");
export type Backend = z.infer<typeof BackendSchema>;
export const RuntimeSchema = z
.enum(["bun", "node", "workers", "none"])
.describe(
"Runtime environment (workers only available with hono backend and drizzle orm)",
);
export type Runtime = z.infer<typeof RuntimeSchema>;
export const FrontendSchema = z
.enum([
"tanstack-router",
"react-router",
"tanstack-start",
"next",
"nuxt",
"native-nativewind",
"native-unistyles",
"svelte",
"solid",
"none",
])
.describe("Frontend framework");
export type Frontend = z.infer<typeof FrontendSchema>;
export const AddonsSchema = z
.enum([
"pwa",
"tauri",
"starlight",
"biome",
"husky",
"turborepo",
"fumadocs",
"ultracite",
"oxlint",
"none",
])
.describe("Additional addons");
export type Addons = z.infer<typeof AddonsSchema>;
export const ExamplesSchema = z
.enum(["todo", "ai", "none"])
.describe("Example templates to include");
export type Examples = z.infer<typeof ExamplesSchema>;
export const PackageManagerSchema = z
.enum(["npm", "pnpm", "bun"])
.describe("Package manager");
export type PackageManager = z.infer<typeof PackageManagerSchema>;
export const DatabaseSetupSchema = z
.enum([
"turso",
"neon",
"prisma-postgres",
"mongodb-atlas",
"supabase",
"d1",
"docker",
"none",
])
.describe("Database hosting setup");
export type DatabaseSetup = z.infer<typeof DatabaseSetupSchema>;
export const APISchema = z.enum(["trpc", "orpc", "none"]).describe("API type");
export type API = z.infer<typeof APISchema>;
export const ProjectNameSchema = z
.string()
.min(1, "Project name cannot be empty")
.max(255, "Project name must be less than 255 characters")
.refine(
(name) => name === "." || !name.startsWith("."),
"Project name cannot start with a dot (except for '.')",
)
.refine(
(name) => name === "." || !name.startsWith("-"),
"Project name cannot start with a dash",
)
.refine((name) => {
const invalidChars = ["<", ">", ":", '"', "|", "?", "*"];
return !invalidChars.some((char) => name.includes(char));
}, "Project name contains invalid characters")
.refine(
(name) => name.toLowerCase() !== "node_modules",
"Project name is reserved",
)
.describe("Project name or path");
export type ProjectName = z.infer<typeof ProjectNameSchema>;
export const WebDeploySchema = z
.enum(["workers", "none"])
.describe("Web deployment");
export type WebDeploy = z.infer<typeof WebDeploySchema>;
export type CreateInput = {
projectName?: string;
yes?: boolean;
database?: Database;
orm?: ORM;
auth?: boolean;
frontend?: Frontend[];
addons?: Addons[];
examples?: Examples[];
git?: boolean;
packageManager?: PackageManager;
install?: boolean;
dbSetup?: DatabaseSetup;
backend?: Backend;
runtime?: Runtime;
api?: API;
webDeploy?: WebDeploy;
};
export type AddInput = {
addons?: Addons[];
webDeploy?: WebDeploy;
projectDir?: string;
install?: boolean;
packageManager?: PackageManager;
};
export type CLIInput = CreateInput & {
projectDirectory?: string;
};
export interface ProjectConfig {
projectName: string;
projectDir: string;
relativePath: string;
database: Database;
orm: ORM;
backend: Backend;
runtime: Runtime;
frontend: Frontend[];
addons: Addons[];
examples: Examples[];
auth: boolean;
git: boolean;
packageManager: PackageManager;
install: boolean;
dbSetup: DatabaseSetup;
api: API;
webDeploy: WebDeploy;
}
export interface BetterTStackConfig {
version: string;
createdAt: string;
database: Database;
orm: ORM;
backend: Backend;
runtime: Runtime;
frontend: Frontend[];
addons: Addons[];
examples: Examples[];
auth: boolean;
packageManager: PackageManager;
dbSetup: DatabaseSetup;
api: API;
webDeploy: WebDeploy;
}
export type AvailablePackageManagers = "npm" | "pnpm" | "bun";

View File

@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"verbatimModuleSyntax": true,
"strict": true,
"skipLibCheck": true,
"noEmit": true
},
"include": ["src/**/*"]
}