create-better-t-stack 3.7.3-canary.7cbb05fc → 3.7.3-canary.8e4d5716
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +19 -23
- package/src/cli.ts +3 -0
- package/src/constants.ts +188 -0
- package/src/helpers/addons/addons-setup.ts +226 -0
- package/src/helpers/addons/examples-setup.ts +104 -0
- package/src/helpers/addons/fumadocs-setup.ts +103 -0
- package/src/helpers/addons/ruler-setup.ts +139 -0
- package/src/helpers/addons/starlight-setup.ts +51 -0
- package/src/helpers/addons/tauri-setup.ts +96 -0
- package/src/helpers/addons/ultracite-setup.ts +232 -0
- package/src/helpers/addons/vite-pwa-setup.ts +59 -0
- package/src/helpers/core/add-addons.ts +85 -0
- package/src/helpers/core/add-deployment.ts +102 -0
- package/src/helpers/core/api-setup.ts +280 -0
- package/src/helpers/core/auth-setup.ts +203 -0
- package/src/helpers/core/backend-setup.ts +73 -0
- package/src/helpers/core/command-handlers.ts +354 -0
- package/src/helpers/core/convex-codegen.ts +14 -0
- package/src/helpers/core/create-project.ts +133 -0
- package/src/helpers/core/create-readme.ts +687 -0
- package/src/helpers/core/db-setup.ts +184 -0
- package/src/helpers/core/detect-project-config.ts +41 -0
- package/src/helpers/core/env-setup.ts +449 -0
- package/src/helpers/core/git.ts +31 -0
- package/src/helpers/core/install-dependencies.ts +32 -0
- package/src/helpers/core/payments-setup.ts +48 -0
- package/src/helpers/core/post-installation.ts +383 -0
- package/src/helpers/core/project-config.ts +246 -0
- package/src/helpers/core/runtime-setup.ts +76 -0
- package/src/helpers/core/template-manager.ts +917 -0
- package/src/helpers/core/workspace-setup.ts +184 -0
- package/src/helpers/database-providers/d1-setup.ts +28 -0
- package/src/helpers/database-providers/docker-compose-setup.ts +50 -0
- package/src/helpers/database-providers/mongodb-atlas-setup.ts +186 -0
- package/src/helpers/database-providers/neon-setup.ts +243 -0
- package/src/helpers/database-providers/planetscale-setup.ts +78 -0
- package/src/helpers/database-providers/prisma-postgres-setup.ts +196 -0
- package/src/helpers/database-providers/supabase-setup.ts +218 -0
- package/src/helpers/database-providers/turso-setup.ts +309 -0
- package/src/helpers/deployment/alchemy/alchemy-combined-setup.ts +80 -0
- package/src/helpers/deployment/alchemy/alchemy-next-setup.ts +51 -0
- package/src/helpers/deployment/alchemy/alchemy-nuxt-setup.ts +104 -0
- package/src/helpers/deployment/alchemy/alchemy-react-router-setup.ts +32 -0
- package/src/helpers/deployment/alchemy/alchemy-solid-setup.ts +32 -0
- package/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts +98 -0
- package/src/helpers/deployment/alchemy/alchemy-tanstack-router-setup.ts +33 -0
- package/src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts +98 -0
- package/src/helpers/deployment/alchemy/env-dts-setup.ts +76 -0
- package/src/helpers/deployment/alchemy/index.ts +7 -0
- package/src/helpers/deployment/server-deploy-setup.ts +55 -0
- package/src/helpers/deployment/web-deploy-setup.ts +58 -0
- package/src/index.ts +253 -0
- package/src/prompts/addons.ts +178 -0
- package/src/prompts/api.ts +49 -0
- package/src/prompts/auth.ts +84 -0
- package/src/prompts/backend.ts +83 -0
- package/src/prompts/config-prompts.ts +138 -0
- package/src/prompts/database-setup.ts +112 -0
- package/src/prompts/database.ts +57 -0
- package/src/prompts/examples.ts +64 -0
- package/src/prompts/frontend.ts +118 -0
- package/src/prompts/git.ts +16 -0
- package/src/prompts/install.ts +16 -0
- package/src/prompts/orm.ts +53 -0
- package/src/prompts/package-manager.ts +32 -0
- package/src/prompts/payments.ts +50 -0
- package/src/prompts/project-name.ts +86 -0
- package/src/prompts/runtime.ts +47 -0
- package/src/prompts/server-deploy.ts +91 -0
- package/src/prompts/web-deploy.ts +107 -0
- package/src/types.ts +2 -0
- package/src/utils/add-package-deps.ts +57 -0
- package/src/utils/analytics.ts +39 -0
- package/src/utils/better-auth-plugin-setup.ts +71 -0
- package/src/utils/biome-formatter.ts +82 -0
- package/src/utils/bts-config.ts +122 -0
- package/src/utils/command-exists.ts +16 -0
- package/src/utils/compatibility-rules.ts +319 -0
- package/src/utils/compatibility.ts +11 -0
- package/src/utils/config-processing.ts +130 -0
- package/src/utils/config-validation.ts +470 -0
- package/src/utils/display-config.ts +96 -0
- package/src/utils/docker-utils.ts +70 -0
- package/src/utils/errors.ts +32 -0
- package/src/utils/generate-reproducible-command.ts +53 -0
- package/src/utils/get-latest-cli-version.ts +11 -0
- package/src/utils/get-package-manager.ts +13 -0
- package/src/utils/open-url.ts +25 -0
- package/src/utils/package-runner.ts +23 -0
- package/src/utils/project-directory.ts +102 -0
- package/src/utils/project-name-validation.ts +43 -0
- package/src/utils/render-title.ts +48 -0
- package/src/utils/setup-catalogs.ts +192 -0
- package/src/utils/sponsors.ts +101 -0
- package/src/utils/telemetry.ts +19 -0
- package/src/utils/template-processor.ts +64 -0
- package/src/utils/templates.ts +94 -0
- package/src/utils/ts-morph.ts +26 -0
- package/src/validation.ts +117 -0
- package/dist/cli.d.mts +0 -1
- package/dist/cli.mjs +0 -8
- package/dist/index.d.mts +0 -347
- package/dist/index.mjs +0 -4
- package/dist/src-CxVxLS85.mjs +0 -7077
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "3.7.3-canary.
|
|
3
|
+
"version": "3.7.3-canary.8e4d5716",
|
|
4
4
|
"description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Aman Varshney",
|
|
8
8
|
"bin": {
|
|
9
|
-
"create-better-t-stack": "
|
|
9
|
+
"create-better-t-stack": "src/cli.ts"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"templates",
|
|
13
|
-
"
|
|
13
|
+
"src"
|
|
14
14
|
],
|
|
15
15
|
"keywords": [
|
|
16
16
|
"better-t-stack",
|
|
@@ -48,48 +48,44 @@
|
|
|
48
48
|
},
|
|
49
49
|
"homepage": "https://better-t-stack.dev/",
|
|
50
50
|
"scripts": {
|
|
51
|
-
"build": "tsdown --publint",
|
|
52
|
-
"dev": "tsdown --watch",
|
|
53
51
|
"check-types": "tsc --noEmit",
|
|
54
52
|
"test": "bun run build && vitest run; rm -rf .smoke || true",
|
|
55
|
-
"test:ui": "bun run build && vitest --ui"
|
|
56
|
-
"prepublishOnly": "npm run build"
|
|
53
|
+
"test:ui": "bun run build && vitest --ui"
|
|
57
54
|
},
|
|
58
55
|
"exports": {
|
|
59
56
|
".": {
|
|
60
|
-
"
|
|
61
|
-
"import": "./dist/index.mjs"
|
|
57
|
+
"import": "./src/index.ts"
|
|
62
58
|
},
|
|
63
59
|
"./cli": {
|
|
64
|
-
"import": "./
|
|
60
|
+
"import": "./src/cli.ts"
|
|
65
61
|
}
|
|
66
62
|
},
|
|
67
63
|
"dependencies": {
|
|
68
|
-
"@
|
|
69
|
-
"@biomejs/
|
|
70
|
-
"@
|
|
71
|
-
"@
|
|
72
|
-
"@orpc/server": "^1.12.2",
|
|
64
|
+
"@biomejs/js-api": "^3.0.0",
|
|
65
|
+
"@biomejs/wasm-nodejs": "^2.2.6",
|
|
66
|
+
"@clack/prompts": "^1.0.0-alpha.6",
|
|
67
|
+
"@orpc/server": "^1.10.0",
|
|
73
68
|
"consola": "^3.4.2",
|
|
74
|
-
"execa": "^9.6.
|
|
69
|
+
"execa": "^9.6.0",
|
|
75
70
|
"fs-extra": "^11.3.2",
|
|
76
71
|
"gradient-string": "^3.0.0",
|
|
77
72
|
"handlebars": "^4.7.8",
|
|
78
73
|
"jsonc-parser": "^3.3.1",
|
|
79
74
|
"picocolors": "^1.1.1",
|
|
80
75
|
"tinyglobby": "^0.2.15",
|
|
81
|
-
"trpc-cli": "^0.12.
|
|
76
|
+
"trpc-cli": "^0.12.0",
|
|
82
77
|
"ts-morph": "^27.0.2",
|
|
83
|
-
"yaml": "^2.8.
|
|
78
|
+
"yaml": "^2.8.1",
|
|
84
79
|
"zod": "^4.1.13"
|
|
85
80
|
},
|
|
86
81
|
"devDependencies": {
|
|
82
|
+
"@create-better-t-stack/types": "1.0.0",
|
|
87
83
|
"@types/fs-extra": "^11.0.4",
|
|
88
|
-
"@types/node": "^24.
|
|
89
|
-
"@vitest/ui": "^
|
|
90
|
-
"publint": "^0.3.
|
|
91
|
-
"tsdown": "^0.
|
|
84
|
+
"@types/node": "^24.9.1",
|
|
85
|
+
"@vitest/ui": "^3.2.4",
|
|
86
|
+
"publint": "^0.3.15",
|
|
87
|
+
"tsdown": "^0.15.9",
|
|
92
88
|
"typescript": "^5.9.3",
|
|
93
|
-
"vitest": "^
|
|
89
|
+
"vitest": "^3.2.4"
|
|
94
90
|
}
|
|
95
91
|
}
|
package/src/cli.ts
ADDED
package/src/constants.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { getUserPkgManager } from "./utils/get-package-manager";
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const distPath = path.dirname(__filename);
|
|
7
|
+
export const PKG_ROOT = path.join(distPath, "../");
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_CONFIG_BASE = {
|
|
10
|
+
projectName: "my-better-t-app",
|
|
11
|
+
relativePath: "my-better-t-app",
|
|
12
|
+
frontend: ["tanstack-router"],
|
|
13
|
+
database: "sqlite",
|
|
14
|
+
orm: "drizzle",
|
|
15
|
+
auth: "better-auth",
|
|
16
|
+
payments: "none",
|
|
17
|
+
addons: ["turborepo"],
|
|
18
|
+
examples: [],
|
|
19
|
+
git: true,
|
|
20
|
+
install: true,
|
|
21
|
+
dbSetup: "none",
|
|
22
|
+
backend: "hono",
|
|
23
|
+
runtime: "bun",
|
|
24
|
+
api: "trpc",
|
|
25
|
+
webDeploy: "none",
|
|
26
|
+
serverDeploy: "none",
|
|
27
|
+
} as const;
|
|
28
|
+
|
|
29
|
+
export function getDefaultConfig() {
|
|
30
|
+
return {
|
|
31
|
+
...DEFAULT_CONFIG_BASE,
|
|
32
|
+
projectDir: path.resolve(process.cwd(), DEFAULT_CONFIG_BASE.projectName),
|
|
33
|
+
packageManager: getUserPkgManager(),
|
|
34
|
+
frontend: [...DEFAULT_CONFIG_BASE.frontend],
|
|
35
|
+
addons: [...DEFAULT_CONFIG_BASE.addons],
|
|
36
|
+
examples: [...DEFAULT_CONFIG_BASE.examples],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const DEFAULT_CONFIG = getDefaultConfig();
|
|
41
|
+
|
|
42
|
+
export const dependencyVersionMap = {
|
|
43
|
+
typescript: "^5",
|
|
44
|
+
|
|
45
|
+
"better-auth": "^1.4.5",
|
|
46
|
+
"@better-auth/expo": "^1.4.5",
|
|
47
|
+
|
|
48
|
+
"@clerk/nextjs": "^6.31.5",
|
|
49
|
+
"@clerk/clerk-react": "^5.45.0",
|
|
50
|
+
"@clerk/tanstack-react-start": "^0.26.3",
|
|
51
|
+
"@clerk/clerk-expo": "^2.14.25",
|
|
52
|
+
|
|
53
|
+
"drizzle-orm": "^0.45.0",
|
|
54
|
+
"drizzle-kit": "^0.31.8",
|
|
55
|
+
"@planetscale/database": "^1.19.0",
|
|
56
|
+
|
|
57
|
+
"@libsql/client": "^0.14.0",
|
|
58
|
+
libsql: "^0.5.22",
|
|
59
|
+
|
|
60
|
+
"@neondatabase/serverless": "^1.0.2",
|
|
61
|
+
pg: "^8.16.3",
|
|
62
|
+
"@types/pg": "^8.15.6",
|
|
63
|
+
"@types/ws": "^8.18.1",
|
|
64
|
+
ws: "^8.18.3",
|
|
65
|
+
|
|
66
|
+
mysql2: "^3.14.0",
|
|
67
|
+
|
|
68
|
+
"@prisma/client": "^7.0.1",
|
|
69
|
+
prisma: "^7.0.1",
|
|
70
|
+
"@prisma/adapter-d1": "^7.0.1",
|
|
71
|
+
"@prisma/adapter-neon": "^7.0.1",
|
|
72
|
+
"@prisma/adapter-mariadb": "^7.0.1",
|
|
73
|
+
"@prisma/adapter-libsql": "^7.0.1",
|
|
74
|
+
"@prisma/adapter-better-sqlite3": "^7.0.1",
|
|
75
|
+
"@prisma/adapter-pg": "^7.0.1",
|
|
76
|
+
"@prisma/adapter-planetscale": "^7.0.1",
|
|
77
|
+
|
|
78
|
+
mongoose: "^8.14.0",
|
|
79
|
+
|
|
80
|
+
"vite-plugin-pwa": "^1.0.1",
|
|
81
|
+
"@vite-pwa/assets-generator": "^1.0.0",
|
|
82
|
+
|
|
83
|
+
"@tauri-apps/cli": "^2.4.0",
|
|
84
|
+
|
|
85
|
+
"@biomejs/biome": "^2.2.0",
|
|
86
|
+
oxlint: "^1.12.0",
|
|
87
|
+
|
|
88
|
+
husky: "^9.1.7",
|
|
89
|
+
"lint-staged": "^16.1.2",
|
|
90
|
+
|
|
91
|
+
tsx: "^4.19.2",
|
|
92
|
+
"@types/node": "^22.13.11",
|
|
93
|
+
|
|
94
|
+
"@types/bun": "^1.3.4",
|
|
95
|
+
|
|
96
|
+
"@elysiajs/node": "^1.3.1",
|
|
97
|
+
|
|
98
|
+
"@elysiajs/cors": "^1.3.3",
|
|
99
|
+
"@elysiajs/trpc": "^1.1.0",
|
|
100
|
+
elysia: "^1.3.21",
|
|
101
|
+
|
|
102
|
+
"@hono/node-server": "^1.14.4",
|
|
103
|
+
"@hono/trpc-server": "^0.4.0",
|
|
104
|
+
hono: "^4.8.2",
|
|
105
|
+
|
|
106
|
+
cors: "^2.8.5",
|
|
107
|
+
express: "^5.1.0",
|
|
108
|
+
"@types/express": "^5.0.1",
|
|
109
|
+
"@types/cors": "^2.8.17",
|
|
110
|
+
|
|
111
|
+
fastify: "^5.3.3",
|
|
112
|
+
"@fastify/cors": "^11.0.1",
|
|
113
|
+
|
|
114
|
+
turbo: "^2.5.4",
|
|
115
|
+
|
|
116
|
+
ai: "^5.0.49",
|
|
117
|
+
"@ai-sdk/google": "^2.0.13",
|
|
118
|
+
"@ai-sdk/vue": "^2.0.49",
|
|
119
|
+
"@ai-sdk/svelte": "^3.0.39",
|
|
120
|
+
"@ai-sdk/react": "^2.0.39",
|
|
121
|
+
streamdown: "^1.3.0",
|
|
122
|
+
shiki: "^3.12.2",
|
|
123
|
+
|
|
124
|
+
"@orpc/server": "^1.10.0",
|
|
125
|
+
"@orpc/client": "^1.10.0",
|
|
126
|
+
"@orpc/openapi": "^1.10.0",
|
|
127
|
+
"@orpc/zod": "^1.10.0",
|
|
128
|
+
"@orpc/tanstack-query": "^1.10.0",
|
|
129
|
+
|
|
130
|
+
"@trpc/tanstack-react-query": "^11.5.0",
|
|
131
|
+
"@trpc/server": "^11.5.0",
|
|
132
|
+
"@trpc/client": "^11.5.0",
|
|
133
|
+
|
|
134
|
+
next: "^16.0.7",
|
|
135
|
+
|
|
136
|
+
convex: "^1.29.3",
|
|
137
|
+
"@convex-dev/react-query": "^0.1.0",
|
|
138
|
+
"convex-svelte": "^0.0.12",
|
|
139
|
+
"convex-nuxt": "0.1.5",
|
|
140
|
+
"convex-vue": "^0.1.5",
|
|
141
|
+
"@convex-dev/better-auth": "^0.9.7",
|
|
142
|
+
|
|
143
|
+
"@tanstack/svelte-query": "^5.85.3",
|
|
144
|
+
"@tanstack/svelte-query-devtools": "^5.85.3",
|
|
145
|
+
|
|
146
|
+
"@tanstack/vue-query-devtools": "^5.90.2",
|
|
147
|
+
"@tanstack/vue-query": "^5.90.2",
|
|
148
|
+
|
|
149
|
+
"@tanstack/react-query-devtools": "^5.85.5",
|
|
150
|
+
"@tanstack/react-query": "^5.85.5",
|
|
151
|
+
|
|
152
|
+
"@tanstack/solid-query": "^5.87.4",
|
|
153
|
+
"@tanstack/solid-query-devtools": "^5.87.4",
|
|
154
|
+
"@tanstack/solid-router-devtools": "^1.131.44",
|
|
155
|
+
|
|
156
|
+
wrangler: "^4.40.3",
|
|
157
|
+
"@cloudflare/vite-plugin": "^1.13.8",
|
|
158
|
+
"@opennextjs/cloudflare": "^1.6.5",
|
|
159
|
+
"nitro-cloudflare-dev": "^0.2.2",
|
|
160
|
+
"@sveltejs/adapter-cloudflare": "^7.2.1",
|
|
161
|
+
"@cloudflare/workers-types": "^4.20250822.0",
|
|
162
|
+
|
|
163
|
+
alchemy: "^0.77.0",
|
|
164
|
+
|
|
165
|
+
dotenv: "^17.2.2",
|
|
166
|
+
tsdown: "^0.16.5",
|
|
167
|
+
zod: "^4.1.13",
|
|
168
|
+
srvx: "0.8.15",
|
|
169
|
+
|
|
170
|
+
"@polar-sh/better-auth": "^1.1.3",
|
|
171
|
+
"@polar-sh/sdk": "^0.34.16",
|
|
172
|
+
} as const;
|
|
173
|
+
|
|
174
|
+
export type AvailableDependencies = keyof typeof dependencyVersionMap;
|
|
175
|
+
|
|
176
|
+
export const ADDON_COMPATIBILITY = {
|
|
177
|
+
pwa: ["tanstack-router", "react-router", "solid", "next"],
|
|
178
|
+
tauri: ["tanstack-router", "react-router", "nuxt", "svelte", "solid", "next"],
|
|
179
|
+
biome: [],
|
|
180
|
+
husky: [],
|
|
181
|
+
turborepo: [],
|
|
182
|
+
starlight: [],
|
|
183
|
+
ultracite: [],
|
|
184
|
+
ruler: [],
|
|
185
|
+
oxlint: [],
|
|
186
|
+
fumadocs: [],
|
|
187
|
+
none: [],
|
|
188
|
+
} as const;
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { log, spinner } from "@clack/prompts";
|
|
3
|
+
import { execa } from "execa";
|
|
4
|
+
import fs from "fs-extra";
|
|
5
|
+
import pc from "picocolors";
|
|
6
|
+
import type { Frontend, PackageManager, ProjectConfig } from "../../types";
|
|
7
|
+
import { addPackageDependency } from "../../utils/add-package-deps";
|
|
8
|
+
import { getPackageExecutionCommand } from "../../utils/package-runner";
|
|
9
|
+
import { setupFumadocs } from "./fumadocs-setup";
|
|
10
|
+
import { setupRuler } from "./ruler-setup";
|
|
11
|
+
import { setupStarlight } from "./starlight-setup";
|
|
12
|
+
import { setupTauri } from "./tauri-setup";
|
|
13
|
+
import { setupUltracite } from "./ultracite-setup";
|
|
14
|
+
import { addPwaToViteConfig } from "./vite-pwa-setup";
|
|
15
|
+
|
|
16
|
+
export async function setupAddons(config: ProjectConfig, isAddCommand = false) {
|
|
17
|
+
const { addons, frontend, projectDir, packageManager } = config;
|
|
18
|
+
const hasReactWebFrontend =
|
|
19
|
+
frontend.includes("react-router") ||
|
|
20
|
+
frontend.includes("tanstack-router") ||
|
|
21
|
+
frontend.includes("next");
|
|
22
|
+
const hasNuxtFrontend = frontend.includes("nuxt");
|
|
23
|
+
const hasSvelteFrontend = frontend.includes("svelte");
|
|
24
|
+
const hasSolidFrontend = frontend.includes("solid");
|
|
25
|
+
const hasNextFrontend = frontend.includes("next");
|
|
26
|
+
|
|
27
|
+
if (addons.includes("turborepo")) {
|
|
28
|
+
await addPackageDependency({
|
|
29
|
+
devDependencies: ["turbo"],
|
|
30
|
+
projectDir,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (isAddCommand) {
|
|
34
|
+
log.info(`${pc.yellow("Update your package.json scripts:")}
|
|
35
|
+
|
|
36
|
+
${pc.dim("Replace:")} ${pc.yellow('"pnpm -r dev"')} ${pc.dim("→")} ${pc.green('"turbo dev"')}
|
|
37
|
+
${pc.dim("Replace:")} ${pc.yellow('"pnpm --filter web dev"')} ${pc.dim(
|
|
38
|
+
"→",
|
|
39
|
+
)} ${pc.green('"turbo -F web dev"')}
|
|
40
|
+
|
|
41
|
+
${pc.cyan("Docs:")} ${pc.underline("https://turborepo.com/docs")}
|
|
42
|
+
`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (addons.includes("pwa") && (hasReactWebFrontend || hasSolidFrontend)) {
|
|
47
|
+
await setupPwa(projectDir, frontend);
|
|
48
|
+
}
|
|
49
|
+
if (
|
|
50
|
+
addons.includes("tauri") &&
|
|
51
|
+
(hasReactWebFrontend ||
|
|
52
|
+
hasNuxtFrontend ||
|
|
53
|
+
hasSvelteFrontend ||
|
|
54
|
+
hasSolidFrontend ||
|
|
55
|
+
hasNextFrontend)
|
|
56
|
+
) {
|
|
57
|
+
await setupTauri(config);
|
|
58
|
+
}
|
|
59
|
+
const hasUltracite = addons.includes("ultracite");
|
|
60
|
+
const hasBiome = addons.includes("biome");
|
|
61
|
+
const hasHusky = addons.includes("husky");
|
|
62
|
+
const hasOxlint = addons.includes("oxlint");
|
|
63
|
+
|
|
64
|
+
if (hasUltracite) {
|
|
65
|
+
await setupUltracite(config, hasHusky);
|
|
66
|
+
} else {
|
|
67
|
+
if (hasBiome) {
|
|
68
|
+
await setupBiome(projectDir);
|
|
69
|
+
}
|
|
70
|
+
if (hasHusky) {
|
|
71
|
+
let linter: "biome" | "oxlint" | undefined;
|
|
72
|
+
if (hasOxlint) {
|
|
73
|
+
linter = "oxlint";
|
|
74
|
+
} else if (hasBiome) {
|
|
75
|
+
linter = "biome";
|
|
76
|
+
}
|
|
77
|
+
await setupHusky(projectDir, linter);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (addons.includes("oxlint")) {
|
|
82
|
+
await setupOxlint(projectDir, packageManager);
|
|
83
|
+
}
|
|
84
|
+
if (addons.includes("starlight")) {
|
|
85
|
+
await setupStarlight(config);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (addons.includes("ruler")) {
|
|
89
|
+
await setupRuler(config);
|
|
90
|
+
}
|
|
91
|
+
if (addons.includes("fumadocs")) {
|
|
92
|
+
await setupFumadocs(config);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function getWebAppDir(projectDir: string, frontends: Frontend[]) {
|
|
97
|
+
if (
|
|
98
|
+
frontends.some((f) =>
|
|
99
|
+
["react-router", "tanstack-router", "nuxt", "svelte", "solid"].includes(f),
|
|
100
|
+
)
|
|
101
|
+
) {
|
|
102
|
+
return path.join(projectDir, "apps/web");
|
|
103
|
+
}
|
|
104
|
+
return path.join(projectDir, "apps/web");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function setupBiome(projectDir: string) {
|
|
108
|
+
await addPackageDependency({
|
|
109
|
+
devDependencies: ["@biomejs/biome"],
|
|
110
|
+
projectDir,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
114
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
115
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
116
|
+
|
|
117
|
+
packageJson.scripts = {
|
|
118
|
+
...packageJson.scripts,
|
|
119
|
+
check: "biome check --write .",
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export async function setupHusky(projectDir: string, linter?: "biome" | "oxlint") {
|
|
127
|
+
await addPackageDependency({
|
|
128
|
+
devDependencies: ["husky", "lint-staged"],
|
|
129
|
+
projectDir,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
133
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
134
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
135
|
+
|
|
136
|
+
packageJson.scripts = {
|
|
137
|
+
...packageJson.scripts,
|
|
138
|
+
prepare: "husky",
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
if (linter === "oxlint") {
|
|
142
|
+
packageJson["lint-staged"] = {
|
|
143
|
+
"**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue,astro,svelte}": "oxlint",
|
|
144
|
+
};
|
|
145
|
+
} else if (linter === "biome") {
|
|
146
|
+
packageJson["lint-staged"] = {
|
|
147
|
+
"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": ["biome check --write ."],
|
|
148
|
+
};
|
|
149
|
+
} else {
|
|
150
|
+
packageJson["lint-staged"] = {
|
|
151
|
+
"**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue,astro,svelte}": "",
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function setupPwa(projectDir: string, frontends: Frontend[]) {
|
|
160
|
+
const isCompatibleFrontend = frontends.some((f) =>
|
|
161
|
+
["react-router", "tanstack-router", "solid"].includes(f),
|
|
162
|
+
);
|
|
163
|
+
if (!isCompatibleFrontend) return;
|
|
164
|
+
|
|
165
|
+
const clientPackageDir = getWebAppDir(projectDir, frontends);
|
|
166
|
+
|
|
167
|
+
if (!(await fs.pathExists(clientPackageDir))) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
await addPackageDependency({
|
|
172
|
+
dependencies: ["vite-plugin-pwa"],
|
|
173
|
+
devDependencies: ["@vite-pwa/assets-generator"],
|
|
174
|
+
projectDir: clientPackageDir,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const clientPackageJsonPath = path.join(clientPackageDir, "package.json");
|
|
178
|
+
if (await fs.pathExists(clientPackageJsonPath)) {
|
|
179
|
+
const packageJson = await fs.readJson(clientPackageJsonPath);
|
|
180
|
+
|
|
181
|
+
packageJson.scripts = {
|
|
182
|
+
...packageJson.scripts,
|
|
183
|
+
"generate-pwa-assets": "pwa-assets-generator",
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
await fs.writeJson(clientPackageJsonPath, packageJson, { spaces: 2 });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const viteConfigTs = path.join(clientPackageDir, "vite.config.ts");
|
|
190
|
+
|
|
191
|
+
if (await fs.pathExists(viteConfigTs)) {
|
|
192
|
+
await addPwaToViteConfig(viteConfigTs, path.basename(projectDir));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function setupOxlint(projectDir: string, packageManager: PackageManager) {
|
|
197
|
+
await addPackageDependency({
|
|
198
|
+
devDependencies: ["oxlint"],
|
|
199
|
+
projectDir,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
203
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
204
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
205
|
+
|
|
206
|
+
packageJson.scripts = {
|
|
207
|
+
...packageJson.scripts,
|
|
208
|
+
check: "oxlint",
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const oxlintInitCommand = getPackageExecutionCommand(packageManager, "oxlint@latest --init");
|
|
215
|
+
|
|
216
|
+
const s = spinner();
|
|
217
|
+
s.start("Initializing oxlint...");
|
|
218
|
+
|
|
219
|
+
await execa(oxlintInitCommand, {
|
|
220
|
+
cwd: projectDir,
|
|
221
|
+
env: { CI: "true" },
|
|
222
|
+
shell: true,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
s.stop("oxlint initialized successfully!");
|
|
226
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import type { AvailableDependencies } from "../../constants";
|
|
4
|
+
import type { ProjectConfig } from "../../types";
|
|
5
|
+
import { addPackageDependency } from "../../utils/add-package-deps";
|
|
6
|
+
|
|
7
|
+
export async function setupExamples(config: ProjectConfig) {
|
|
8
|
+
const { examples, frontend, backend, projectDir, orm, database } = config;
|
|
9
|
+
|
|
10
|
+
if (backend === "convex" || !examples || examples.length === 0 || examples[0] === "none") {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const apiDir = path.join(projectDir, "packages/api");
|
|
15
|
+
const apiDirExists = await fs.pathExists(apiDir);
|
|
16
|
+
|
|
17
|
+
if (apiDirExists && backend !== "none") {
|
|
18
|
+
if (orm === "drizzle") {
|
|
19
|
+
const dependencies: AvailableDependencies[] = ["drizzle-orm"];
|
|
20
|
+
if (database === "postgres") {
|
|
21
|
+
// Workaround: not sure there is a weird types error if i add it in dev dep
|
|
22
|
+
dependencies.push("@types/pg");
|
|
23
|
+
}
|
|
24
|
+
await addPackageDependency({
|
|
25
|
+
dependencies,
|
|
26
|
+
projectDir: apiDir,
|
|
27
|
+
});
|
|
28
|
+
} else if (orm === "prisma") {
|
|
29
|
+
await addPackageDependency({
|
|
30
|
+
dependencies: ["@prisma/client"],
|
|
31
|
+
projectDir: apiDir,
|
|
32
|
+
});
|
|
33
|
+
} else if (orm === "mongoose") {
|
|
34
|
+
await addPackageDependency({
|
|
35
|
+
dependencies: ["mongoose"],
|
|
36
|
+
projectDir: apiDir,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (examples.includes("ai")) {
|
|
42
|
+
const webClientDir = path.join(projectDir, "apps/web");
|
|
43
|
+
const nativeClientDir = path.join(projectDir, "apps/native");
|
|
44
|
+
const apiDir = path.join(projectDir, "packages/api");
|
|
45
|
+
|
|
46
|
+
const webClientDirExists = await fs.pathExists(webClientDir);
|
|
47
|
+
const nativeClientDirExists = await fs.pathExists(nativeClientDir);
|
|
48
|
+
const apiDirExists = await fs.pathExists(apiDir);
|
|
49
|
+
|
|
50
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
51
|
+
const hasSvelte = frontend.includes("svelte");
|
|
52
|
+
const hasReactWeb =
|
|
53
|
+
frontend.includes("react-router") ||
|
|
54
|
+
frontend.includes("tanstack-router") ||
|
|
55
|
+
frontend.includes("next") ||
|
|
56
|
+
frontend.includes("tanstack-start");
|
|
57
|
+
const hasNext = frontend.includes("next");
|
|
58
|
+
const hasReactNative =
|
|
59
|
+
frontend.includes("native-bare") ||
|
|
60
|
+
frontend.includes("native-uniwind") ||
|
|
61
|
+
frontend.includes("native-unistyles");
|
|
62
|
+
|
|
63
|
+
if (webClientDirExists) {
|
|
64
|
+
const dependencies: AvailableDependencies[] = ["ai"];
|
|
65
|
+
if (hasNuxt) {
|
|
66
|
+
dependencies.push("@ai-sdk/vue");
|
|
67
|
+
} else if (hasSvelte) {
|
|
68
|
+
dependencies.push("@ai-sdk/svelte");
|
|
69
|
+
} else if (hasReactWeb) {
|
|
70
|
+
dependencies.push("@ai-sdk/react", "streamdown");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (hasNext) {
|
|
74
|
+
dependencies.push("shiki");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
await addPackageDependency({
|
|
78
|
+
dependencies,
|
|
79
|
+
projectDir: webClientDir,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (nativeClientDirExists && hasReactNative) {
|
|
84
|
+
await addPackageDependency({
|
|
85
|
+
dependencies: ["ai", "@ai-sdk/react"],
|
|
86
|
+
projectDir: nativeClientDir,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (apiDirExists && backend !== "none") {
|
|
91
|
+
await addPackageDependency({
|
|
92
|
+
dependencies: ["ai", "@ai-sdk/google"],
|
|
93
|
+
projectDir: apiDir,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (backend === "self" && webClientDirExists) {
|
|
98
|
+
await addPackageDependency({
|
|
99
|
+
dependencies: ["ai", "@ai-sdk/google"],
|
|
100
|
+
projectDir: webClientDir,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|