diff --git a/apps/cli/package.json b/apps/cli/package.json index b2d8487..4743719 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -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" } } diff --git a/apps/cli/src/types.ts b/apps/cli/src/types.ts index 536a174..1979d5a 100644 --- a/apps/cli/src/types.ts +++ b/apps/cli/src/types.ts @@ -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; - -export const ORMSchema = z - .enum(["drizzle", "prisma", "mongoose", "none"]) - .describe("ORM type"); -export type ORM = z.infer; - -export const BackendSchema = z - .enum(["hono", "express", "fastify", "next", "elysia", "convex", "none"]) - .describe("Backend framework"); -export type Backend = z.infer; - -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; - -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; - -export const AddonsSchema = z - .enum([ - "pwa", - "tauri", - "starlight", - "biome", - "husky", - "turborepo", - "fumadocs", - "ultracite", - "oxlint", - "none", - ]) - .describe("Additional addons"); -export type Addons = z.infer; - -export const ExamplesSchema = z - .enum(["todo", "ai", "none"]) - .describe("Example templates to include"); -export type Examples = z.infer; - -export const PackageManagerSchema = z - .enum(["npm", "pnpm", "bun"]) - .describe("Package manager"); -export type PackageManager = z.infer; - -export const DatabaseSetupSchema = z - .enum([ - "turso", - "neon", - "prisma-postgres", - "mongodb-atlas", - "supabase", - "d1", - "docker", - "none", - ]) - .describe("Database hosting setup"); -export type DatabaseSetup = z.infer; - -export const APISchema = z.enum(["trpc", "orpc", "none"]).describe("API type"); -export type API = z.infer; - -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; - -export const WebDeploySchema = z - .enum(["workers", "none"]) - .describe("Web deployment"); -export type WebDeploy = z.infer; - -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"; diff --git a/apps/web/package.json b/apps/web/package.json index f462d54..8a54b52 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -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", diff --git a/apps/web/scripts/generate-schema.ts b/apps/web/scripts/generate-schema.ts index 15120fa..f045014 100644 --- a/apps/web/scripts/generate-schema.ts +++ b/apps/web/scripts/generate-schema.ts @@ -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; diff --git a/bun.lock b/bun.lock index 33c8cbc..ff7ea1d 100644 --- a/bun.lock +++ b/bun.lock @@ -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=="], diff --git a/packages/types/package.json b/packages/types/package.json new file mode 100644 index 0000000..e0560b7 --- /dev/null +++ b/packages/types/package.json @@ -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" + } +} \ No newline at end of file diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts new file mode 100644 index 0000000..536a174 --- /dev/null +++ b/packages/types/src/index.ts @@ -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; + +export const ORMSchema = z + .enum(["drizzle", "prisma", "mongoose", "none"]) + .describe("ORM type"); +export type ORM = z.infer; + +export const BackendSchema = z + .enum(["hono", "express", "fastify", "next", "elysia", "convex", "none"]) + .describe("Backend framework"); +export type Backend = z.infer; + +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; + +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; + +export const AddonsSchema = z + .enum([ + "pwa", + "tauri", + "starlight", + "biome", + "husky", + "turborepo", + "fumadocs", + "ultracite", + "oxlint", + "none", + ]) + .describe("Additional addons"); +export type Addons = z.infer; + +export const ExamplesSchema = z + .enum(["todo", "ai", "none"]) + .describe("Example templates to include"); +export type Examples = z.infer; + +export const PackageManagerSchema = z + .enum(["npm", "pnpm", "bun"]) + .describe("Package manager"); +export type PackageManager = z.infer; + +export const DatabaseSetupSchema = z + .enum([ + "turso", + "neon", + "prisma-postgres", + "mongodb-atlas", + "supabase", + "d1", + "docker", + "none", + ]) + .describe("Database hosting setup"); +export type DatabaseSetup = z.infer; + +export const APISchema = z.enum(["trpc", "orpc", "none"]).describe("API type"); +export type API = z.infer; + +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; + +export const WebDeploySchema = z + .enum(["workers", "none"]) + .describe("Web deployment"); +export type WebDeploy = z.infer; + +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"; diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json new file mode 100644 index 0000000..44705a6 --- /dev/null +++ b/packages/types/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "esModuleInterop": true, + "verbatimModuleSyntax": true, + "strict": true, + "skipLibCheck": true, + "noEmit": true + }, + "include": ["src/**/*"] +}