create-better-t-stack 3.8.3-pr730.1784e47 → 3.9.0
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/README.md +15 -15
- package/dist/cli.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-GZpht_dQ.mjs → src-DLvUK0Qf.mjs} +77 -95
- package/package.json +3 -4
- package/templates/auth/better-auth/convex/backend/convex/auth.config.ts.hbs +7 -5
- package/templates/auth/better-auth/convex/web/react/tanstack-start/src/lib/auth-server.ts.hbs +5 -11
- package/templates/auth/better-auth/fullstack/tanstack-start/src/routes/api/auth/$.ts.hbs +10 -6
- package/templates/auth/better-auth/web/react/base/src/lib/auth-client.ts.hbs +0 -1
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ You can disable telemetry by setting the `BTS_TELEMETRY_DISABLED` environment va
|
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
92
|
# Disable telemetry for a single run
|
|
93
|
-
BTS_TELEMETRY_DISABLED=1 npx create-better-t-stack
|
|
93
|
+
BTS_TELEMETRY_DISABLED=1 npx create-better-t-stack
|
|
94
94
|
|
|
95
95
|
# Disable telemetry globally in your shell profile (.bashrc, .zshrc, etc.)
|
|
96
96
|
export BTS_TELEMETRY_DISABLED=1
|
|
@@ -101,85 +101,85 @@ export BTS_TELEMETRY_DISABLED=1
|
|
|
101
101
|
Create a project with default configuration:
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
|
-
npx create-better-t-stack
|
|
104
|
+
npx create-better-t-stack --yes
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
Create a project with specific options:
|
|
108
108
|
|
|
109
109
|
```bash
|
|
110
|
-
npx create-better-t-stack
|
|
110
|
+
npx create-better-t-stack --database postgres --orm drizzle --auth --addons pwa biome
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
Create a project with Elysia backend and Node.js runtime:
|
|
114
114
|
|
|
115
115
|
```bash
|
|
116
|
-
npx create-better-t-stack
|
|
116
|
+
npx create-better-t-stack --backend elysia --runtime node
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
Create a project with multiple frontend options (one web + one native):
|
|
120
120
|
|
|
121
121
|
```bash
|
|
122
|
-
npx create-better-t-stack
|
|
122
|
+
npx create-better-t-stack --frontend tanstack-router native-bare
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
Create a project with examples:
|
|
126
126
|
|
|
127
127
|
```bash
|
|
128
|
-
npx create-better-t-stack
|
|
128
|
+
npx create-better-t-stack --examples todo ai
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
Create a project with Turso database setup:
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
|
-
npx create-better-t-stack
|
|
134
|
+
npx create-better-t-stack --database sqlite --orm drizzle --db-setup turso
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
Create a project with Supabase PostgreSQL setup:
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
|
-
npx create-better-t-stack
|
|
140
|
+
npx create-better-t-stack --database postgres --orm drizzle --db-setup supabase --auth
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
Create a project with Convex backend:
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
|
-
npx create-better-t-stack
|
|
146
|
+
npx create-better-t-stack --backend convex --frontend tanstack-router
|
|
147
147
|
```
|
|
148
148
|
|
|
149
149
|
Create a project with documentation site:
|
|
150
150
|
|
|
151
151
|
```bash
|
|
152
|
-
npx create-better-t-stack
|
|
152
|
+
npx create-better-t-stack --addons starlight
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
Create a minimal TypeScript project with no backend:
|
|
156
156
|
|
|
157
157
|
```bash
|
|
158
|
-
npx create-better-t-stack
|
|
158
|
+
npx create-better-t-stack --backend none --frontend tanstack-router
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
Create a backend-only project with no frontend:
|
|
162
162
|
|
|
163
163
|
```bash
|
|
164
|
-
npx create-better-t-stack
|
|
164
|
+
npx create-better-t-stack --frontend none --backend hono --database postgres --orm drizzle
|
|
165
165
|
```
|
|
166
166
|
|
|
167
167
|
Create a simple frontend-only project:
|
|
168
168
|
|
|
169
169
|
```bash
|
|
170
|
-
npx create-better-t-stack
|
|
170
|
+
npx create-better-t-stack --backend none --frontend next --addons none --examples none
|
|
171
171
|
```
|
|
172
172
|
|
|
173
173
|
Create a Cloudflare Workers project:
|
|
174
174
|
|
|
175
175
|
```bash
|
|
176
|
-
npx create-better-t-stack
|
|
176
|
+
npx create-better-t-stack --backend hono --runtime workers --database sqlite --orm drizzle --db-setup d1
|
|
177
177
|
```
|
|
178
178
|
|
|
179
179
|
Create a minimal API-only project:
|
|
180
180
|
|
|
181
181
|
```bash
|
|
182
|
-
npx create-better-t-stack
|
|
182
|
+
npx create-better-t-stack --frontend none --backend hono --api trpc --database none --addons none
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
## Compatibility Notes
|
package/dist/cli.mjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as router, i as init, n as createBtsCli, o as sponsors, r as docs, t as builder } from "./src-
|
|
2
|
+
import { a as router, i as init, n as createBtsCli, o as sponsors, r as docs, t as builder } from "./src-DLvUK0Qf.mjs";
|
|
3
3
|
|
|
4
4
|
export { builder, createBtsCli, docs, init, router, sponsors };
|
|
@@ -15,7 +15,7 @@ import { $, execa } from "execa";
|
|
|
15
15
|
import { IndentationText, Node, Project, QuoteKind, SyntaxKind } from "ts-morph";
|
|
16
16
|
import { glob } from "tinyglobby";
|
|
17
17
|
import handlebars from "handlebars";
|
|
18
|
-
import {
|
|
18
|
+
import { format } from "oxfmt";
|
|
19
19
|
import yaml from "yaml";
|
|
20
20
|
import os$1 from "node:os";
|
|
21
21
|
|
|
@@ -96,6 +96,7 @@ const dependencyVersionMap = {
|
|
|
96
96
|
"@tauri-apps/cli": "^2.4.0",
|
|
97
97
|
"@biomejs/biome": "^2.2.0",
|
|
98
98
|
oxlint: "^1.32.0",
|
|
99
|
+
oxfmt: "^0.19.0",
|
|
99
100
|
husky: "^9.1.7",
|
|
100
101
|
"lint-staged": "^16.1.2",
|
|
101
102
|
tsx: "^4.19.2",
|
|
@@ -136,7 +137,7 @@ const dependencyVersionMap = {
|
|
|
136
137
|
"convex-svelte": "^0.0.12",
|
|
137
138
|
"convex-nuxt": "0.1.5",
|
|
138
139
|
"convex-vue": "^0.1.5",
|
|
139
|
-
"@convex-dev/better-auth": "^0.
|
|
140
|
+
"@convex-dev/better-auth": "^0.9.7",
|
|
140
141
|
"@tanstack/svelte-query": "^5.85.3",
|
|
141
142
|
"@tanstack/svelte-query-devtools": "^5.85.3",
|
|
142
143
|
"@tanstack/vue-query-devtools": "^5.90.2",
|
|
@@ -363,7 +364,7 @@ function getAddonDisplay(addon) {
|
|
|
363
364
|
break;
|
|
364
365
|
case "oxlint":
|
|
365
366
|
label = "Oxlint";
|
|
366
|
-
hint = "
|
|
367
|
+
hint = "Oxlint + Oxfmt (linting & formatting)";
|
|
367
368
|
break;
|
|
368
369
|
case "ultracite":
|
|
369
370
|
label = "Ultracite";
|
|
@@ -1233,7 +1234,7 @@ const getLatestCLIVersion = () => {
|
|
|
1233
1234
|
*/
|
|
1234
1235
|
function isTelemetryEnabled() {
|
|
1235
1236
|
const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
|
|
1236
|
-
const BTS_TELEMETRY = "
|
|
1237
|
+
const BTS_TELEMETRY = "1";
|
|
1237
1238
|
if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
|
|
1238
1239
|
if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
|
|
1239
1240
|
return true;
|
|
@@ -1241,7 +1242,16 @@ function isTelemetryEnabled() {
|
|
|
1241
1242
|
|
|
1242
1243
|
//#endregion
|
|
1243
1244
|
//#region src/utils/analytics.ts
|
|
1244
|
-
|
|
1245
|
+
const CONVEX_INGEST_URL = "https://striped-seahorse-863.convex.site/api/analytics/ingest";
|
|
1246
|
+
async function sendConvexEvent(payload) {
|
|
1247
|
+
try {
|
|
1248
|
+
await fetch(CONVEX_INGEST_URL, {
|
|
1249
|
+
method: "POST",
|
|
1250
|
+
headers: { "Content-Type": "application/json" },
|
|
1251
|
+
body: JSON.stringify(payload)
|
|
1252
|
+
});
|
|
1253
|
+
} catch {}
|
|
1254
|
+
}
|
|
1245
1255
|
async function trackProjectCreation(config, disableAnalytics = false) {
|
|
1246
1256
|
if (!isTelemetryEnabled() || disableAnalytics) return;
|
|
1247
1257
|
const { projectName: _projectName, projectDir: _projectDir, relativePath: _relativePath, ...safeConfig } = config;
|
|
@@ -2022,6 +2032,38 @@ async function setupFumadocs(config) {
|
|
|
2022
2032
|
}
|
|
2023
2033
|
}
|
|
2024
2034
|
|
|
2035
|
+
//#endregion
|
|
2036
|
+
//#region src/helpers/addons/oxlint-setup.ts
|
|
2037
|
+
async function setupOxlint(projectDir, packageManager) {
|
|
2038
|
+
await addPackageDependency({
|
|
2039
|
+
devDependencies: ["oxlint", "oxfmt"],
|
|
2040
|
+
projectDir
|
|
2041
|
+
});
|
|
2042
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
2043
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
2044
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
2045
|
+
packageJson.scripts = {
|
|
2046
|
+
...packageJson.scripts,
|
|
2047
|
+
check: "oxlint && oxfmt --write"
|
|
2048
|
+
};
|
|
2049
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
2050
|
+
}
|
|
2051
|
+
const s = spinner();
|
|
2052
|
+
const oxlintInitCommand = getPackageExecutionCommand(packageManager, "oxlint@latest --init");
|
|
2053
|
+
s.start("Initializing oxlint and oxfmt...");
|
|
2054
|
+
await execa(oxlintInitCommand, {
|
|
2055
|
+
cwd: projectDir,
|
|
2056
|
+
env: { CI: "true" },
|
|
2057
|
+
shell: true
|
|
2058
|
+
});
|
|
2059
|
+
await execa(getPackageExecutionCommand(packageManager, "oxfmt@latest --init"), {
|
|
2060
|
+
cwd: projectDir,
|
|
2061
|
+
env: { CI: "true" },
|
|
2062
|
+
shell: true
|
|
2063
|
+
});
|
|
2064
|
+
s.stop("oxlint and oxfmt initialized successfully!");
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2025
2067
|
//#endregion
|
|
2026
2068
|
//#region src/helpers/addons/ruler-setup.ts
|
|
2027
2069
|
async function setupRuler(config) {
|
|
@@ -2391,7 +2433,7 @@ ${pc.cyan("Docs:")} ${pc.underline("https://turborepo.com/docs")}
|
|
|
2391
2433
|
await setupHusky(projectDir, linter);
|
|
2392
2434
|
}
|
|
2393
2435
|
}
|
|
2394
|
-
if (
|
|
2436
|
+
if (hasOxlint) await setupOxlint(projectDir, packageManager);
|
|
2395
2437
|
if (addons.includes("starlight")) await setupStarlight(config);
|
|
2396
2438
|
if (addons.includes("ruler")) await setupRuler(config);
|
|
2397
2439
|
if (addons.includes("fumadocs")) await setupFumadocs(config);
|
|
@@ -2433,7 +2475,7 @@ async function setupHusky(projectDir, linter) {
|
|
|
2433
2475
|
...packageJson.scripts,
|
|
2434
2476
|
prepare: "husky"
|
|
2435
2477
|
};
|
|
2436
|
-
if (linter === "oxlint") packageJson["lint-staged"] = { "
|
|
2478
|
+
if (linter === "oxlint") packageJson["lint-staged"] = { "*": ["oxlint", "oxfmt --write"] };
|
|
2437
2479
|
else if (linter === "biome") packageJson["lint-staged"] = { "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}": ["biome check --write ."] };
|
|
2438
2480
|
else packageJson["lint-staged"] = { "**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx,vue,astro,svelte}": "" };
|
|
2439
2481
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
@@ -2464,30 +2506,6 @@ async function setupPwa(projectDir, frontends) {
|
|
|
2464
2506
|
const viteConfigTs = path.join(clientPackageDir, "vite.config.ts");
|
|
2465
2507
|
if (await fs.pathExists(viteConfigTs)) await addPwaToViteConfig(viteConfigTs, path.basename(projectDir));
|
|
2466
2508
|
}
|
|
2467
|
-
async function setupOxlint(projectDir, packageManager) {
|
|
2468
|
-
await addPackageDependency({
|
|
2469
|
-
devDependencies: ["oxlint"],
|
|
2470
|
-
projectDir
|
|
2471
|
-
});
|
|
2472
|
-
const packageJsonPath = path.join(projectDir, "package.json");
|
|
2473
|
-
if (await fs.pathExists(packageJsonPath)) {
|
|
2474
|
-
const packageJson = await fs.readJson(packageJsonPath);
|
|
2475
|
-
packageJson.scripts = {
|
|
2476
|
-
...packageJson.scripts,
|
|
2477
|
-
check: "oxlint"
|
|
2478
|
-
};
|
|
2479
|
-
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
2480
|
-
}
|
|
2481
|
-
const oxlintInitCommand = getPackageExecutionCommand(packageManager, "oxlint@latest --init");
|
|
2482
|
-
const s = spinner();
|
|
2483
|
-
s.start("Initializing oxlint...");
|
|
2484
|
-
await execa(oxlintInitCommand, {
|
|
2485
|
-
cwd: projectDir,
|
|
2486
|
-
env: { CI: "true" },
|
|
2487
|
-
shell: true
|
|
2488
|
-
});
|
|
2489
|
-
s.stop("oxlint initialized successfully!");
|
|
2490
|
-
}
|
|
2491
2509
|
|
|
2492
2510
|
//#endregion
|
|
2493
2511
|
//#region src/helpers/core/detect-project-config.ts
|
|
@@ -2543,61 +2561,16 @@ async function installDependencies({ projectDir, packageManager }) {
|
|
|
2543
2561
|
}
|
|
2544
2562
|
|
|
2545
2563
|
//#endregion
|
|
2546
|
-
//#region src/utils/
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
formatter: {
|
|
2553
|
-
enabled: true,
|
|
2554
|
-
indentStyle: "tab",
|
|
2555
|
-
indentWidth: 2,
|
|
2556
|
-
lineWidth: 80
|
|
2557
|
-
},
|
|
2558
|
-
linter: { enabled: false },
|
|
2559
|
-
javascript: { formatter: { enabled: true } },
|
|
2560
|
-
json: { formatter: { enabled: true } }
|
|
2561
|
-
});
|
|
2562
|
-
return {
|
|
2563
|
-
biome,
|
|
2564
|
-
projectKey
|
|
2565
|
-
};
|
|
2566
|
-
} catch {
|
|
2567
|
-
return null;
|
|
2568
|
-
}
|
|
2569
|
-
}
|
|
2570
|
-
function isSupportedFile(filePath) {
|
|
2571
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
2572
|
-
return [
|
|
2573
|
-
".js",
|
|
2574
|
-
".jsx",
|
|
2575
|
-
".ts",
|
|
2576
|
-
".tsx",
|
|
2577
|
-
".json",
|
|
2578
|
-
".jsonc"
|
|
2579
|
-
].includes(ext);
|
|
2580
|
-
}
|
|
2581
|
-
function shouldSkipFile(filePath) {
|
|
2582
|
-
const basename = path.basename(filePath);
|
|
2583
|
-
return [
|
|
2584
|
-
".hbs",
|
|
2585
|
-
"package-lock.json",
|
|
2586
|
-
"yarn.lock",
|
|
2587
|
-
"pnpm-lock.yaml",
|
|
2588
|
-
"bun.lock",
|
|
2589
|
-
".d.ts"
|
|
2590
|
-
].some((pattern) => basename.includes(pattern));
|
|
2591
|
-
}
|
|
2592
|
-
function formatFileWithBiome(filePath, content) {
|
|
2593
|
-
if (!isSupportedFile(filePath) || shouldSkipFile(filePath)) return null;
|
|
2564
|
+
//#region src/utils/file-formatter.ts
|
|
2565
|
+
const formatOptions = {
|
|
2566
|
+
experimentalSortPackageJson: true,
|
|
2567
|
+
experimentalSortImports: { order: "asc" }
|
|
2568
|
+
};
|
|
2569
|
+
async function formatFile(filePath, content) {
|
|
2594
2570
|
try {
|
|
2595
|
-
const
|
|
2596
|
-
if (
|
|
2597
|
-
|
|
2598
|
-
const result = biome.formatContent(projectKey, content, { filePath: path.basename(filePath) });
|
|
2599
|
-
if (result.diagnostics && result.diagnostics.length > 0) consola.debug(`Biome formatting diagnostics for ${filePath}:`, result.diagnostics);
|
|
2600
|
-
return result.content;
|
|
2571
|
+
const result = await format(path.basename(filePath), content, formatOptions);
|
|
2572
|
+
if (result.errors && result.errors.length > 0) return null;
|
|
2573
|
+
return result.code;
|
|
2601
2574
|
} catch {
|
|
2602
2575
|
return null;
|
|
2603
2576
|
}
|
|
@@ -2627,7 +2600,7 @@ async function processTemplate(srcPath, destPath, context) {
|
|
|
2627
2600
|
content = handlebars.compile(templateContent)(context);
|
|
2628
2601
|
} else content = await fs.readFile(srcPath, "utf-8");
|
|
2629
2602
|
try {
|
|
2630
|
-
const formattedContent = await
|
|
2603
|
+
const formattedContent = await formatFile(destPath, content);
|
|
2631
2604
|
if (formattedContent) content = formattedContent;
|
|
2632
2605
|
} catch (formatError) {
|
|
2633
2606
|
consola.debug(`Failed to format ${destPath}:`, formatError);
|
|
@@ -4231,12 +4204,12 @@ async function setupAuth(config) {
|
|
|
4231
4204
|
if (convexBackendDirExists) {
|
|
4232
4205
|
await addPackageDependency({
|
|
4233
4206
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4234
|
-
customDependencies: { "better-auth": "1.
|
|
4207
|
+
customDependencies: { "better-auth": "1.3.34" },
|
|
4235
4208
|
projectDir: convexBackendDir
|
|
4236
4209
|
});
|
|
4237
4210
|
if (hasNativeForBA) await addPackageDependency({
|
|
4238
4211
|
dependencies: ["@better-auth/expo"],
|
|
4239
|
-
customDependencies: { "@better-auth/expo": "1.
|
|
4212
|
+
customDependencies: { "@better-auth/expo": "1.3.34" },
|
|
4240
4213
|
projectDir: convexBackendDir
|
|
4241
4214
|
});
|
|
4242
4215
|
}
|
|
@@ -4246,17 +4219,17 @@ async function setupAuth(config) {
|
|
|
4246
4219
|
const hasViteReactOther = frontend.some((f) => ["tanstack-router", "react-router"].includes(f));
|
|
4247
4220
|
if (hasNextJs) await addPackageDependency({
|
|
4248
4221
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4249
|
-
customDependencies: { "better-auth": "1.
|
|
4222
|
+
customDependencies: { "better-auth": "1.3.34" },
|
|
4250
4223
|
projectDir: clientDir
|
|
4251
4224
|
});
|
|
4252
4225
|
else if (hasTanStackStart) await addPackageDependency({
|
|
4253
4226
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4254
|
-
customDependencies: { "better-auth": "1.
|
|
4227
|
+
customDependencies: { "better-auth": "1.3.34" },
|
|
4255
4228
|
projectDir: clientDir
|
|
4256
4229
|
});
|
|
4257
4230
|
else if (hasViteReactOther) await addPackageDependency({
|
|
4258
4231
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4259
|
-
customDependencies: { "better-auth": "1.
|
|
4232
|
+
customDependencies: { "better-auth": "1.3.34" },
|
|
4260
4233
|
projectDir: clientDir
|
|
4261
4234
|
});
|
|
4262
4235
|
}
|
|
@@ -4270,8 +4243,8 @@ async function setupAuth(config) {
|
|
|
4270
4243
|
"@convex-dev/better-auth"
|
|
4271
4244
|
],
|
|
4272
4245
|
customDependencies: {
|
|
4273
|
-
"better-auth": "1.
|
|
4274
|
-
"@better-auth/expo": "1.
|
|
4246
|
+
"better-auth": "1.3.34",
|
|
4247
|
+
"@better-auth/expo": "1.3.34"
|
|
4275
4248
|
},
|
|
4276
4249
|
projectDir: nativeDir
|
|
4277
4250
|
});
|
|
@@ -5940,6 +5913,7 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
|
|
|
5940
5913
|
for (const addon of addons) if (addon === "pwa") addonsList.push("- **PWA** - Progressive Web App support");
|
|
5941
5914
|
else if (addon === "tauri") addonsList.push("- **Tauri** - Build native desktop applications");
|
|
5942
5915
|
else if (addon === "biome") addonsList.push("- **Biome** - Linting and formatting");
|
|
5916
|
+
else if (addon === "oxlint") addonsList.push("- **Oxlint** - Oxlint + Oxfmt (linting & formatting)");
|
|
5943
5917
|
else if (addon === "husky") addonsList.push("- **Husky** - Git hooks for code quality");
|
|
5944
5918
|
else if (addon === "starlight") addonsList.push("- **Starlight** - Documentation site with Astro");
|
|
5945
5919
|
else if (addon === "turborepo") addonsList.push("- **Turborepo** - Optimized monorepo build system");
|
|
@@ -6015,6 +5989,8 @@ function generateScriptsList(packageManagerRunCmd, database, orm, _auth, hasNati
|
|
|
6015
5989
|
}
|
|
6016
5990
|
if (addons.includes("biome")) scripts += `
|
|
6017
5991
|
- \`${packageManagerRunCmd} check\`: Run Biome formatting and linting`;
|
|
5992
|
+
if (addons.includes("oxlint")) scripts += `
|
|
5993
|
+
- \`${packageManagerRunCmd} check\`: Run Oxlint and Oxfmt`;
|
|
6018
5994
|
if (addons.includes("pwa")) scripts += `
|
|
6019
5995
|
- \`cd apps/web && ${packageManagerRunCmd} generate-pwa-assets\`: Generate PWA assets`;
|
|
6020
5996
|
if (addons.includes("tauri")) scripts += `
|
|
@@ -6166,10 +6142,12 @@ async function displayPostInstallInstructions(config) {
|
|
|
6166
6142
|
const isBackendSelf = backend === "self";
|
|
6167
6143
|
const runCmd = packageManager === "npm" ? "npm run" : packageManager === "pnpm" ? "pnpm run" : "bun run";
|
|
6168
6144
|
const cdCmd = `cd ${relativePath}`;
|
|
6169
|
-
const
|
|
6145
|
+
const hasHusky = addons?.includes("husky");
|
|
6146
|
+
const hasLinting = addons?.includes("biome") || addons?.includes("oxlint");
|
|
6170
6147
|
const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy, backend) : "";
|
|
6171
6148
|
const tauriInstructions = addons?.includes("tauri") ? getTauriInstructions(runCmd) : "";
|
|
6172
|
-
const
|
|
6149
|
+
const huskyInstructions = hasHusky ? getHuskyInstructions(runCmd) : "";
|
|
6150
|
+
const lintingInstructions = hasLinting ? getLintingInstructions(runCmd) : "";
|
|
6173
6151
|
const nativeInstructions = (frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles")) && backend !== "none" ? getNativeInstructions(isConvex, isBackendSelf, frontend || []) : "";
|
|
6174
6152
|
const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
|
|
6175
6153
|
const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
|
|
@@ -6223,6 +6201,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6223
6201
|
if (nativeInstructions) output += `\n${nativeInstructions.trim()}\n`;
|
|
6224
6202
|
if (databaseInstructions) output += `\n${databaseInstructions.trim()}\n`;
|
|
6225
6203
|
if (tauriInstructions) output += `\n${tauriInstructions.trim()}\n`;
|
|
6204
|
+
if (huskyInstructions) output += `\n${huskyInstructions.trim()}\n`;
|
|
6226
6205
|
if (lintingInstructions) output += `\n${lintingInstructions.trim()}\n`;
|
|
6227
6206
|
if (pwaInstructions) output += `\n${pwaInstructions.trim()}\n`;
|
|
6228
6207
|
if (alchemyDeployInstructions) output += `\n${alchemyDeployInstructions.trim()}\n`;
|
|
@@ -6244,6 +6223,9 @@ function getNativeInstructions(isConvex, isBackendSelf, _frontend) {
|
|
|
6244
6223
|
if (isConvex) instructions += `\n${pc.yellow("IMPORTANT:")} When using local development with Convex and native apps,\n ensure you use your local IP address instead of localhost or 127.0.0.1\n for proper connectivity.\n`;
|
|
6245
6224
|
return instructions;
|
|
6246
6225
|
}
|
|
6226
|
+
function getHuskyInstructions(runCmd) {
|
|
6227
|
+
return `${pc.bold("Git hooks with Husky:")}\n${pc.cyan("•")} Initialize hooks: ${`${runCmd} prepare`}\n`;
|
|
6228
|
+
}
|
|
6247
6229
|
function getLintingInstructions(runCmd) {
|
|
6248
6230
|
return `${pc.bold("Linting and formatting:")}\n${pc.cyan("•")} Format and lint fix: ${`${runCmd} check`}\n`;
|
|
6249
6231
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
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",
|
|
@@ -67,9 +67,7 @@
|
|
|
67
67
|
}
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@better-t-stack/types": "3.
|
|
71
|
-
"@biomejs/js-api": "^4.0.0",
|
|
72
|
-
"@biomejs/wasm-nodejs": "^2.3.8",
|
|
70
|
+
"@better-t-stack/types": "^3.9.0",
|
|
73
71
|
"@clack/prompts": "^1.0.0-alpha.8",
|
|
74
72
|
"@orpc/server": "^1.12.2",
|
|
75
73
|
"consola": "^3.4.2",
|
|
@@ -78,6 +76,7 @@
|
|
|
78
76
|
"gradient-string": "^3.0.0",
|
|
79
77
|
"handlebars": "^4.7.8",
|
|
80
78
|
"jsonc-parser": "^3.3.1",
|
|
79
|
+
"oxfmt": "^0.19.0",
|
|
81
80
|
"picocolors": "^1.1.1",
|
|
82
81
|
"tinyglobby": "^0.2.15",
|
|
83
82
|
"trpc-cli": "^0.12.1",
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { getAuthConfigProvider } from "@convex-dev/better-auth/auth-config";
|
|
2
|
-
import type { AuthConfig } from "convex/server";
|
|
3
|
-
|
|
4
1
|
export default {
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
providers: [
|
|
3
|
+
{
|
|
4
|
+
domain: process.env.CONVEX_SITE_URL,
|
|
5
|
+
applicationID: "convex",
|
|
6
|
+
},
|
|
7
|
+
],
|
|
8
|
+
};
|
package/templates/auth/better-auth/convex/web/react/tanstack-start/src/lib/auth-server.ts.hbs
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createAuth } from "@{{projectName}}/backend/convex/auth";
|
|
2
|
+
import { setupFetchClient } from "@convex-dev/better-auth/react-start";
|
|
3
|
+
import { getCookie } from "@tanstack/react-start/server";
|
|
2
4
|
|
|
3
|
-
export const {
|
|
4
|
-
|
|
5
|
-
getToken,
|
|
6
|
-
fetchAuthQuery,
|
|
7
|
-
fetchAuthMutation,
|
|
8
|
-
fetchAuthAction,
|
|
9
|
-
} = convexBetterAuthReactStart({
|
|
10
|
-
convexUrl: process.env.VITE_CONVEX_URL!,
|
|
11
|
-
convexSiteUrl: process.env.VITE_CONVEX_SITE_URL!,
|
|
12
|
-
});
|
|
5
|
+
export const { fetchQuery, fetchMutation, fetchAction } =
|
|
6
|
+
await setupFetchClient(createAuth, getCookie);
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { auth } from '@{{projectName}}/auth'
|
|
2
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
3
3
|
|
|
4
|
-
export const Route = createFileRoute(
|
|
4
|
+
export const Route = createFileRoute('/api/auth/$')({
|
|
5
5
|
server: {
|
|
6
6
|
handlers: {
|
|
7
|
-
GET: ({ request }) =>
|
|
8
|
-
|
|
7
|
+
GET: ({ request }) => {
|
|
8
|
+
return auth.handler(request)
|
|
9
|
+
},
|
|
10
|
+
POST: ({ request }) => {
|
|
11
|
+
return auth.handler(request)
|
|
12
|
+
},
|
|
9
13
|
},
|
|
10
14
|
},
|
|
11
|
-
})
|
|
15
|
+
})
|