create-better-t-stack 3.47.0 → 3.49.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 +3 -3
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +1 -1
- package/dist/{src-CC7QNkfh.mjs → src-DswDqMzo.mjs} +155 -100
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -94,9 +94,9 @@ Options:
|
|
|
94
94
|
|
|
95
95
|
```bash
|
|
96
96
|
# Raw JSON payload input (agent-friendly)
|
|
97
|
-
create-better-t-stack create-json --
|
|
98
|
-
create-better-t-stack add-json --
|
|
99
|
-
create-better-t-stack create-json --
|
|
97
|
+
create-better-t-stack create-json --json '{"projectName":"my-app","yes":true,"dryRun":true}'
|
|
98
|
+
create-better-t-stack add-json --json '{"projectDir":"./my-app","addons":["wxt"],"addonOptions":{"wxt":{"template":"react"}}}'
|
|
99
|
+
create-better-t-stack create-json --json '{"projectName":"db-app","database":"postgres","orm":"drizzle","dbSetup":"neon","dbSetupOptions":{"mode":"manual"}}'
|
|
100
100
|
|
|
101
101
|
# Runtime schema/introspection output
|
|
102
102
|
create-better-t-stack schema --name all
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { D as setProcessMode, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as types_exports, y as getLatestCLIVersion } from "./src-
|
|
2
|
+
import { D as setProcessMode, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as types_exports, y as getLatestCLIVersion } from "./src-DswDqMzo.mjs";
|
|
3
3
|
import { lineByLineConsoleLogger } from "trpc-cli";
|
|
4
4
|
import z from "zod";
|
|
5
5
|
import { McpServer } from "@modelcontextprotocol/server";
|
package/dist/index.d.mts
CHANGED
|
@@ -592,7 +592,7 @@ export declare const router: {
|
|
|
592
592
|
"expo/skills": "expo/skills";
|
|
593
593
|
"prisma/skills": "prisma/skills";
|
|
594
594
|
"elysiajs/skills": "elysiajs/skills";
|
|
595
|
-
"
|
|
595
|
+
"get-convex/agent-skills": "get-convex/agent-skills";
|
|
596
596
|
"msmps/opentui-skill": "msmps/opentui-skill";
|
|
597
597
|
"haydenbleasel/ultracite": "haydenbleasel/ultracite";
|
|
598
598
|
"https://www.evlog.dev": "https://www.evlog.dev";
|
|
@@ -606,7 +606,6 @@ export declare const router: {
|
|
|
606
606
|
oxlint: "oxlint";
|
|
607
607
|
}>>;
|
|
608
608
|
editors: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
609
|
-
void: "void";
|
|
610
609
|
antigravity: "antigravity";
|
|
611
610
|
cursor: "cursor";
|
|
612
611
|
vscode: "vscode";
|
|
@@ -617,6 +616,7 @@ export declare const router: {
|
|
|
617
616
|
codebuddy: "codebuddy";
|
|
618
617
|
devin: "devin";
|
|
619
618
|
trae: "trae";
|
|
619
|
+
void: "void";
|
|
620
620
|
kiro: "kiro";
|
|
621
621
|
}>>>;
|
|
622
622
|
agents: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
@@ -1119,7 +1119,7 @@ export declare const router: {
|
|
|
1119
1119
|
"expo/skills": "expo/skills";
|
|
1120
1120
|
"prisma/skills": "prisma/skills";
|
|
1121
1121
|
"elysiajs/skills": "elysiajs/skills";
|
|
1122
|
-
"
|
|
1122
|
+
"get-convex/agent-skills": "get-convex/agent-skills";
|
|
1123
1123
|
"msmps/opentui-skill": "msmps/opentui-skill";
|
|
1124
1124
|
"haydenbleasel/ultracite": "haydenbleasel/ultracite";
|
|
1125
1125
|
"https://www.evlog.dev": "https://www.evlog.dev";
|
|
@@ -1133,7 +1133,6 @@ export declare const router: {
|
|
|
1133
1133
|
oxlint: "oxlint";
|
|
1134
1134
|
}>>;
|
|
1135
1135
|
editors: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
1136
|
-
void: "void";
|
|
1137
1136
|
antigravity: "antigravity";
|
|
1138
1137
|
cursor: "cursor";
|
|
1139
1138
|
vscode: "vscode";
|
|
@@ -1144,6 +1143,7 @@ export declare const router: {
|
|
|
1144
1143
|
codebuddy: "codebuddy";
|
|
1145
1144
|
devin: "devin";
|
|
1146
1145
|
trae: "trae";
|
|
1146
|
+
void: "void";
|
|
1147
1147
|
kiro: "kiro";
|
|
1148
1148
|
}>>>;
|
|
1149
1149
|
agents: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as DirectoryConflictError, E as ValidationError, S as DatabaseSetupError, T as UserCancelledError, _ as ProjectLauncherSchema, a as TEMPLATE_COUNT, b as CLIError, c as builder, d as createVirtual, f as docs, g as sponsors, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as ProjectCreationError, x as CompatibilityError } from "./src-
|
|
2
|
+
import { C as DirectoryConflictError, E as ValidationError, S as DatabaseSetupError, T as UserCancelledError, _ as ProjectLauncherSchema, a as TEMPLATE_COUNT, b as CLIError, c as builder, d as createVirtual, f as docs, g as sponsors, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as ProjectCreationError, x as CompatibilityError } from "./src-DswDqMzo.mjs";
|
|
3
3
|
export { CLIError, CompatibilityError, DatabaseSetupError, DirectoryConflictError, EMBEDDED_TEMPLATES, GeneratorError, ProjectCreationError, ProjectLauncherSchema, Result, SchemaNameSchema, TEMPLATE_COUNT, UserCancelledError, ValidationError, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generate, getSchemaResult, router, sponsors };
|
|
@@ -228,7 +228,8 @@ function defaultContext() {
|
|
|
228
228
|
silent: false,
|
|
229
229
|
verbose: false,
|
|
230
230
|
promptShown: false,
|
|
231
|
-
analyticsDisabled: false
|
|
231
|
+
analyticsDisabled: false,
|
|
232
|
+
stepFailures: []
|
|
232
233
|
};
|
|
233
234
|
}
|
|
234
235
|
function getContext() {
|
|
@@ -290,7 +291,8 @@ function createContext(options) {
|
|
|
290
291
|
analyticsDisabled: options.analyticsDisabled ?? false,
|
|
291
292
|
projectDir: options.projectDir,
|
|
292
293
|
projectName: options.projectName,
|
|
293
|
-
packageManager: options.packageManager
|
|
294
|
+
packageManager: options.packageManager,
|
|
295
|
+
stepFailures: []
|
|
294
296
|
};
|
|
295
297
|
}
|
|
296
298
|
async function runWithContextAsync(options, fn) {
|
|
@@ -337,6 +339,8 @@ function beginInterruptibleScope() {
|
|
|
337
339
|
endInterruptibleScope();
|
|
338
340
|
stepInterrupted = false;
|
|
339
341
|
anyStepInterrupted = false;
|
|
342
|
+
const ctx = tryGetContext();
|
|
343
|
+
if (ctx) ctx.stepFailures = [];
|
|
340
344
|
listener = () => {
|
|
341
345
|
stepInterrupted = true;
|
|
342
346
|
anyStepInterrupted = true;
|
|
@@ -360,6 +364,13 @@ function wasInterrupted() {
|
|
|
360
364
|
function wasAnyStepInterrupted() {
|
|
361
365
|
return anyStepInterrupted;
|
|
362
366
|
}
|
|
367
|
+
/** Records an optional step that failed, so silent/JSON callers can report it. */
|
|
368
|
+
function recordStepFailure(message) {
|
|
369
|
+
tryGetContext()?.stepFailures.push(message);
|
|
370
|
+
}
|
|
371
|
+
function getStepFailures() {
|
|
372
|
+
return [...tryGetContext()?.stepFailures ?? []];
|
|
373
|
+
}
|
|
363
374
|
function getInterruptSignal() {
|
|
364
375
|
return controller?.signal;
|
|
365
376
|
}
|
|
@@ -1697,10 +1708,6 @@ function parseBtsConfig(content) {
|
|
|
1697
1708
|
const errors = [];
|
|
1698
1709
|
const value = parse(content, errors, { allowTrailingComma: true });
|
|
1699
1710
|
if (errors.length > 0) throw new Error("Invalid JSONC in bts.jsonc");
|
|
1700
|
-
const selections = value?.addonOptions?.skills?.selections;
|
|
1701
|
-
if (Array.isArray(selections)) {
|
|
1702
|
-
for (const selection of selections) if (selection?.source === "yusukebe/hono-skill") selection.source = "honojs/skills";
|
|
1703
|
-
}
|
|
1704
1711
|
return BetterTStackConfigSchema.parse(value);
|
|
1705
1712
|
}
|
|
1706
1713
|
async function readBtsConfig(projectDir) {
|
|
@@ -1888,7 +1895,7 @@ function getNodeToolingRequirements(config) {
|
|
|
1888
1895
|
addNodeRequirement(requirements, ">=22.12.0", "Astro 7");
|
|
1889
1896
|
break;
|
|
1890
1897
|
case "nuxt":
|
|
1891
|
-
addNodeRequirement(requirements, "^22.
|
|
1898
|
+
addNodeRequirement(requirements, "^22.22.3 || ^24.15.0 || >=26.0.0", "Nuxt 4.6");
|
|
1892
1899
|
break;
|
|
1893
1900
|
case "solid":
|
|
1894
1901
|
addNodeRequirement(requirements, ">=24.0.0", "Solid");
|
|
@@ -1897,6 +1904,8 @@ function getNodeToolingRequirements(config) {
|
|
|
1897
1904
|
addNodeRequirement(requirements, ">=22.22.0", "React Router 8");
|
|
1898
1905
|
break;
|
|
1899
1906
|
case "svelte":
|
|
1907
|
+
addNodeRequirement(requirements, ">=22.17.0", "SvelteKit 3");
|
|
1908
|
+
break;
|
|
1900
1909
|
case "tanstack-router":
|
|
1901
1910
|
addNodeRequirement(requirements, "^20.19.0 || >=22.12.0", "Vite 8");
|
|
1902
1911
|
break;
|
|
@@ -1951,11 +1960,8 @@ function getBaselineRequirements(packageManager, hostRuntime) {
|
|
|
1951
1960
|
}
|
|
1952
1961
|
function getLocalVersionRequirements(config, hostRuntime) {
|
|
1953
1962
|
const requirements = getBaselineRequirements(config.packageManager, hostRuntime);
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
requirements.push(...getAddonNodeRequirements(config));
|
|
1957
|
-
if (config.runtime === "node") addNodeRequirement(requirements, ">=22.0.0", "the selected Node.js server runtime");
|
|
1958
|
-
}
|
|
1963
|
+
requirements.push(...getNodeToolingRequirements(config));
|
|
1964
|
+
if (config.runtime === "node") addNodeRequirement(requirements, ">=22.0.0", "the selected Node.js server runtime");
|
|
1959
1965
|
return requirements;
|
|
1960
1966
|
}
|
|
1961
1967
|
function formatRequirementError(requirement, rawVersion) {
|
|
@@ -2082,6 +2088,7 @@ async function runOptionalStep(step, cancelledMessage) {
|
|
|
2082
2088
|
cliLog.warn(pc.yellow(cancelledMessage));
|
|
2083
2089
|
return;
|
|
2084
2090
|
}
|
|
2091
|
+
recordStepFailure(result.error.message);
|
|
2085
2092
|
cliConsola.error(pc.red(result.error.message));
|
|
2086
2093
|
}
|
|
2087
2094
|
//#endregion
|
|
@@ -2278,9 +2285,24 @@ function addNuxtEvlogSetup(content, serviceName) {
|
|
|
2278
2285
|
return nextContent;
|
|
2279
2286
|
}
|
|
2280
2287
|
function addSvelteViteEvlogSetup(content, serviceName) {
|
|
2281
|
-
|
|
2288
|
+
const nextContent = prependMissingImports(content, ["import evlog from \"evlog/vite\";"]);
|
|
2282
2289
|
if (nextContent.includes("evlog({")) return nextContent;
|
|
2283
|
-
|
|
2290
|
+
const source = ts.createSourceFile("vite.config.ts", nextContent, ts.ScriptTarget.Latest);
|
|
2291
|
+
let insertion;
|
|
2292
|
+
function visit(node) {
|
|
2293
|
+
if (insertion !== void 0) return;
|
|
2294
|
+
if (ts.isPropertyAssignment(node) && node.name.getText(source) === "plugins" && ts.isArrayLiteralExpression(node.initializer)) {
|
|
2295
|
+
const kitPlugin = node.initializer.elements.find((element) => ts.isCallExpression(element) && element.expression.getText(source) === "sveltekit");
|
|
2296
|
+
if (kitPlugin) {
|
|
2297
|
+
insertion = kitPlugin.getEnd();
|
|
2298
|
+
return;
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
ts.forEachChild(node, visit);
|
|
2302
|
+
}
|
|
2303
|
+
visit(source);
|
|
2304
|
+
if (insertion === void 0) return nextContent;
|
|
2305
|
+
return `${nextContent.slice(0, insertion)},\n evlog({ service: ${JSON.stringify(serviceName)} })${nextContent.slice(insertion)}`;
|
|
2284
2306
|
}
|
|
2285
2307
|
function getSvelteEvlogHooksCall(fsDrain, axiom = false) {
|
|
2286
2308
|
if (axiom) return "createEvlogHooks({ drain: createAxiomDrain() })";
|
|
@@ -2292,7 +2314,7 @@ function addSvelteHooksEvlogSetup(content, fsDrain, axiom) {
|
|
|
2292
2314
|
...fsDrain ? ["import { createFsDrain } from \"evlog/fs\";"] : [],
|
|
2293
2315
|
...axiom ? ["import { createAxiomDrain } from \"evlog/axiom\";"] : []
|
|
2294
2316
|
]);
|
|
2295
|
-
if (fsDrain) nextContent = addNamedImport(nextContent, "$app/
|
|
2317
|
+
if (fsDrain) nextContent = addNamedImport(nextContent, "$app/env", ["dev"]);
|
|
2296
2318
|
const hooksCall = getSvelteEvlogHooksCall(fsDrain, axiom);
|
|
2297
2319
|
if (fsDrain || axiom) nextContent = nextContent.replaceAll("createEvlogHooks()", hooksCall);
|
|
2298
2320
|
if (!nextContent.includes("export const handle") && !nextContent.includes("const authHandle")) {
|
|
@@ -2302,7 +2324,7 @@ function addSvelteHooksEvlogSetup(content, fsDrain, axiom) {
|
|
|
2302
2324
|
nextContent = prependMissingImports(nextContent, ["import { sequence } from \"@sveltejs/kit/hooks\";"]);
|
|
2303
2325
|
if (!nextContent.includes("const { handle: evlogHandle, handleError }")) nextContent = nextContent.replace(/((?:import .+\n)+)/, `$1\nconst { handle: evlogHandle, handleError } = ${hooksCall};\n\n`);
|
|
2304
2326
|
nextContent = nextContent.replace(/export const handle(:\s*Handle)?\s*=\s*async/, (_match, typeAnnotation) => `const authHandle${typeAnnotation ?? ""} = async`);
|
|
2305
|
-
if (!nextContent.includes("sequence(evlogHandle, authHandle)")) nextContent = `${nextContent.trimEnd()}\n\nexport const handle = sequence(evlogHandle
|
|
2327
|
+
if (!nextContent.includes("sequence(evlogHandle, authHandle)")) nextContent = `${nextContent.trimEnd()}\n\nexport const handle = sequence(evlogHandle, authHandle);\nexport { handleError };\n`;
|
|
2306
2328
|
return nextContent;
|
|
2307
2329
|
}
|
|
2308
2330
|
function addSvelteLocalsType(content) {
|
|
@@ -2398,7 +2420,7 @@ function addNextBetterAuthToRoute(content) {
|
|
|
2398
2420
|
}
|
|
2399
2421
|
function addSvelteBetterAuthEvlogSetup(content, config) {
|
|
2400
2422
|
if (!content.includes("authHandle") || content.includes("evlogAuthHandle")) return content;
|
|
2401
|
-
let nextContent = addNamedImport(content, "evlog/better-auth", ["createAuthMiddleware"
|
|
2423
|
+
let nextContent = addNamedImport(content, "evlog/better-auth", ["createAuthMiddleware"]);
|
|
2402
2424
|
if (!nextContent.includes("from \"./services\"")) nextContent = prependMissingImports(nextContent, [getAuthImportLine(config, "./services")]);
|
|
2403
2425
|
let environmentBinding = "ENV";
|
|
2404
2426
|
if (usesCreateAuthFactory(config) && config.webDeploy === "cloudflare") {
|
|
@@ -2411,10 +2433,10 @@ function addSvelteBetterAuthEvlogSetup(content, config) {
|
|
|
2411
2433
|
}
|
|
2412
2434
|
const authExpression = getAuthExpression(config);
|
|
2413
2435
|
const authOptions = "{ exclude: [\"/api/auth/**\"], maskEmail: true }";
|
|
2414
|
-
const authHandleSnippet = usesCreateAuthFactory(config) && config.webDeploy === "cloudflare" ? `const evlogAuthHandle: Handle = async ({ event, resolve }) => {\n\tif (building) {\n\t\treturn resolve(event);\n\t}\n\n\tconst authEnv =
|
|
2436
|
+
const authHandleSnippet = usesCreateAuthFactory(config) && config.webDeploy === "cloudflare" ? `const evlogAuthHandle: Handle = async ({ event, resolve }) => {\n\tif (building) {\n\t\treturn resolve(event);\n\t}\n\n\tconst authEnv = ${environmentBinding};\n\tconst identifyUser = createAuthMiddleware(await createAuth(authEnv), ${authOptions});\n\tawait identifyUser(event.locals.log, event.request.headers, event.url.pathname);\n\treturn resolve(event);\n};\n\n` : `const identifyUser = createAuthMiddleware(${authExpression}, ${authOptions});\n\nconst evlogAuthHandle: Handle = async ({ event, resolve }) => {\n\tawait identifyUser(event.locals.log, event.request.headers, event.url.pathname);\n\treturn resolve(event);\n};\n\n`;
|
|
2415
2437
|
const evlogHandleDeclaration = nextContent.match(/const \{ handle: evlogHandle, handleError \} = createEvlogHooks\([\s\S]*?\);\n\n/)?.[0];
|
|
2416
2438
|
if (evlogHandleDeclaration) nextContent = insertAfterOnce(nextContent, evlogHandleDeclaration, authHandleSnippet, "evlogAuthHandle");
|
|
2417
|
-
return nextContent.replace("sequence(evlogHandle as Handle, authHandle)", "sequence(evlogHandle
|
|
2439
|
+
return nextContent.replace("sequence(evlogHandle as Handle, authHandle)", "sequence(evlogHandle, evlogAuthHandle, authHandle)").replace("sequence(evlogHandle, authHandle)", "sequence(evlogHandle, evlogAuthHandle, authHandle)");
|
|
2418
2440
|
}
|
|
2419
2441
|
function addAstroBetterAuthEvlogSetup(content, config) {
|
|
2420
2442
|
if (content.includes("createAuthMiddleware(")) return content;
|
|
@@ -2447,14 +2469,16 @@ export const { register, onRequestError } = createInstrumentation({
|
|
|
2447
2469
|
});
|
|
2448
2470
|
`;
|
|
2449
2471
|
}
|
|
2472
|
+
const NITRO_V3_PLUGIN_IMPORT = "import { definePlugin as defineNitroPlugin } from \"nitro\";\n";
|
|
2450
2473
|
function getNitroEvlogDrainFile(axiom = false, nitroV3 = false) {
|
|
2451
|
-
|
|
2474
|
+
const pluginImport = nitroV3 ? NITRO_V3_PLUGIN_IMPORT : "";
|
|
2475
|
+
if (axiom) return `${pluginImport}import { createAxiomDrain } from "evlog/axiom";
|
|
2452
2476
|
|
|
2453
2477
|
export default defineNitroPlugin((nitroApp) => {
|
|
2454
2478
|
nitroApp.hooks.hook("evlog:drain", createAxiomDrain());
|
|
2455
2479
|
});
|
|
2456
2480
|
`;
|
|
2457
|
-
return
|
|
2481
|
+
return `${pluginImport}import { createFsDrain } from "evlog/fs";
|
|
2458
2482
|
|
|
2459
2483
|
export default defineNitroPlugin((nitroApp) => {
|
|
2460
2484
|
if (!import.meta.dev) return;
|
|
@@ -2505,31 +2529,32 @@ export async function identifyEvlogUser(request: Request) {
|
|
|
2505
2529
|
}
|
|
2506
2530
|
`;
|
|
2507
2531
|
}
|
|
2508
|
-
function
|
|
2532
|
+
function getTanstackStartEvlogAuthMiddlewareFile(config) {
|
|
2509
2533
|
if (usesCreateAuthFactory(config)) return `${getAuthImportLine(config, "../../src/services")}
|
|
2510
|
-
import {
|
|
2534
|
+
import { createAuthMiddleware, type BetterAuthInstance } from "evlog/better-auth";
|
|
2535
|
+
import { useLogger } from "evlog/nitro/v3";
|
|
2536
|
+
import { defineHandler } from "nitro";
|
|
2511
2537
|
|
|
2512
|
-
export default
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
maskEmail: true,
|
|
2517
|
-
});
|
|
2518
|
-
await identify(event);
|
|
2538
|
+
export default defineHandler(async (event) => {
|
|
2539
|
+
const identifyUser = createAuthMiddleware(${getAuthExpression(config)} as BetterAuthInstance, {
|
|
2540
|
+
exclude: ["/api/auth/**"],
|
|
2541
|
+
maskEmail: true,
|
|
2519
2542
|
});
|
|
2543
|
+
await identifyUser(useLogger(event), event.req.headers, event.url.pathname);
|
|
2520
2544
|
});
|
|
2521
2545
|
`;
|
|
2522
2546
|
return `${getAuthImportLine(config, "../../src/services")}
|
|
2523
|
-
import {
|
|
2547
|
+
import { createAuthMiddleware, type BetterAuthInstance } from "evlog/better-auth";
|
|
2548
|
+
import { useLogger } from "evlog/nitro/v3";
|
|
2549
|
+
import { defineHandler } from "nitro";
|
|
2524
2550
|
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
);
|
|
2551
|
+
const identifyUser = createAuthMiddleware(${getAuthExpression(config)} as BetterAuthInstance, {
|
|
2552
|
+
exclude: ["/api/auth/**"],
|
|
2553
|
+
maskEmail: true,
|
|
2554
|
+
});
|
|
2555
|
+
|
|
2556
|
+
export default defineHandler(async (event) => {
|
|
2557
|
+
await identifyUser(useLogger(event), event.req.headers, event.url.pathname);
|
|
2533
2558
|
});
|
|
2534
2559
|
`;
|
|
2535
2560
|
}
|
|
@@ -2664,10 +2689,6 @@ async function setupNuxtEvlog(config, serviceName) {
|
|
|
2664
2689
|
if (!await fs.pathExists(drainPath)) await writeFileIfChanged(drainPath, getNitroEvlogDrainFile(usesAxiom(config), config.frontend.includes("tanstack-start")));
|
|
2665
2690
|
}
|
|
2666
2691
|
if (shouldIdentifyWebAuth(config)) {
|
|
2667
|
-
const oldAuthPluginPath = path.join(webDir, "server/plugins/evlog-auth.ts");
|
|
2668
|
-
if (await fs.pathExists(oldAuthPluginPath)) {
|
|
2669
|
-
if ((await fs.readFile(oldAuthPluginPath, "utf-8")).includes("evlog/better-auth")) await fs.remove(oldAuthPluginPath);
|
|
2670
|
-
}
|
|
2671
2692
|
const authMiddlewarePath = path.join(webDir, "server/middleware/evlog-auth.ts");
|
|
2672
2693
|
if (!await fs.pathExists(authMiddlewarePath)) await writeFileIfChanged(authMiddlewarePath, getNuxtEvlogAuthMiddlewareFile(config));
|
|
2673
2694
|
}
|
|
@@ -2683,7 +2704,7 @@ async function setupSvelteEvlog(config, serviceName) {
|
|
|
2683
2704
|
else await writeFileIfChanged(hooksPath, `import { createEvlogHooks } from "evlog/sveltekit";
|
|
2684
2705
|
${fsDrain ? "import { createFsDrain } from \"evlog/fs\";\n" : ""}
|
|
2685
2706
|
${axiom ? "import { createAxiomDrain } from \"evlog/axiom\";\n" : ""}
|
|
2686
|
-
${fsDrain ? "import { dev } from \"$app/
|
|
2707
|
+
${fsDrain ? "import { dev } from \"$app/env\";\n" : ""}
|
|
2687
2708
|
|
|
2688
2709
|
export const { handle, handleError } = ${getSvelteEvlogHooksCall(fsDrain, axiom)};
|
|
2689
2710
|
`);
|
|
@@ -2725,8 +2746,8 @@ async function setupTanstackStartEvlog(config, serviceName) {
|
|
|
2725
2746
|
if (!await fs.pathExists(drainPath)) await writeFileIfChanged(drainPath, getNitroEvlogDrainFile(usesAxiom(config), config.frontend.includes("tanstack-start")));
|
|
2726
2747
|
}
|
|
2727
2748
|
if (shouldIdentifyWebAuth(config)) {
|
|
2728
|
-
const
|
|
2729
|
-
if (!await fs.pathExists(
|
|
2749
|
+
const authMiddlewarePath = path.join(webDir, "server/middleware/evlog-auth.ts");
|
|
2750
|
+
if (!await fs.pathExists(authMiddlewarePath)) await writeFileIfChanged(authMiddlewarePath, getTanstackStartEvlogAuthMiddlewareFile(config));
|
|
2730
2751
|
}
|
|
2731
2752
|
if (config.examples.includes("ai")) await updateFileIfExists(path.join(webDir, "src/routes/api/ai/$.ts"), addTanstackStartAiEvlogSetup);
|
|
2732
2753
|
}
|
|
@@ -3607,7 +3628,7 @@ const SKILL_SOURCES = {
|
|
|
3607
3628
|
"expo/skills": { label: "Expo" },
|
|
3608
3629
|
"prisma/skills": { label: "Prisma" },
|
|
3609
3630
|
"elysiajs/skills": { label: "ElysiaJS" },
|
|
3610
|
-
"
|
|
3631
|
+
"get-convex/agent-skills": { label: "Convex" },
|
|
3611
3632
|
"msmps/opentui-skill": { label: "OpenTUI Platform" },
|
|
3612
3633
|
"haydenbleasel/ultracite": { label: "Ultracite" },
|
|
3613
3634
|
"https://www.evlog.dev": { label: "evlog" }
|
|
@@ -3994,7 +4015,7 @@ function getRecommendedSourceKeys(config) {
|
|
|
3994
4015
|
if (addons.includes("turborepo")) sources.push("vercel/turborepo");
|
|
3995
4016
|
if (backend === "hono") sources.push("honojs/skills");
|
|
3996
4017
|
if (backend === "elysia") sources.push("elysiajs/skills");
|
|
3997
|
-
if (backend === "convex") sources.push("
|
|
4018
|
+
if (backend === "convex") sources.push("get-convex/agent-skills");
|
|
3998
4019
|
if (addons.includes("opentui")) sources.push("msmps/opentui-skill");
|
|
3999
4020
|
if (addons.includes("ultracite")) sources.push("haydenbleasel/ultracite");
|
|
4000
4021
|
if (addons.includes("evlog") || addons.includes("axiom")) sources.push("https://www.evlog.dev");
|
|
@@ -4051,36 +4072,32 @@ const CURATED_SKILLS_BY_SOURCE = {
|
|
|
4051
4072
|
if (config.database === "mysql") return ["mysql", "vitess"];
|
|
4052
4073
|
return [];
|
|
4053
4074
|
},
|
|
4054
|
-
"expo/skills": (
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
];
|
|
4064
|
-
if (config.frontend.includes("native-uniwind")) skills.push("expo-tailwind-setup");
|
|
4065
|
-
return skills;
|
|
4066
|
-
},
|
|
4075
|
+
"expo/skills": () => [
|
|
4076
|
+
"expo-overview",
|
|
4077
|
+
"expo-router",
|
|
4078
|
+
"expo-dev-client",
|
|
4079
|
+
"expo-native-ui",
|
|
4080
|
+
"expo-data-fetching",
|
|
4081
|
+
"eas-app-stores",
|
|
4082
|
+
"eas-workflows"
|
|
4083
|
+
],
|
|
4067
4084
|
"prisma/skills": (config) => {
|
|
4068
4085
|
const skills = [];
|
|
4069
|
-
if (config.orm === "prisma") skills.push("prisma-cli", "prisma-client-api", "prisma-
|
|
4070
|
-
if (config.dbSetup === "prisma-postgres") skills.push("prisma-postgres");
|
|
4086
|
+
if (config.orm === "prisma") skills.push("prisma-cli", "prisma-client-api", "prisma-orm-setup");
|
|
4087
|
+
if (config.dbSetup === "prisma-postgres") skills.push("prisma-postgres-setup");
|
|
4071
4088
|
return skills;
|
|
4072
4089
|
},
|
|
4073
4090
|
"elysiajs/skills": () => ["elysiajs"],
|
|
4074
|
-
"
|
|
4075
|
-
"convex
|
|
4076
|
-
"convex-
|
|
4077
|
-
"convex-
|
|
4078
|
-
"convex-
|
|
4079
|
-
"convex-
|
|
4080
|
-
"convex-
|
|
4081
|
-
"convex-
|
|
4082
|
-
"convex-
|
|
4083
|
-
"convex-
|
|
4091
|
+
"get-convex/agent-skills": () => [
|
|
4092
|
+
"convex",
|
|
4093
|
+
"convex-design",
|
|
4094
|
+
"convex-docs",
|
|
4095
|
+
"convex-reviewer",
|
|
4096
|
+
"convex-authz",
|
|
4097
|
+
"convex-crons",
|
|
4098
|
+
"convex-migrate",
|
|
4099
|
+
"convex-env",
|
|
4100
|
+
"convex-test"
|
|
4084
4101
|
],
|
|
4085
4102
|
"msmps/opentui-skill": () => ["opentui"],
|
|
4086
4103
|
"haydenbleasel/ultracite": () => ["ultracite"],
|
|
@@ -4189,31 +4206,43 @@ async function setupSkills(config) {
|
|
|
4189
4206
|
const runner = getPackageRunnerPrefix(packageManager);
|
|
4190
4207
|
const globalFlags = scope === "global" ? ["-g"] : [];
|
|
4191
4208
|
const agentTargets = expandSkillsAgentTargets(selectedAgents);
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4209
|
+
const failures = [];
|
|
4210
|
+
for (const [source, skills] of Object.entries(skillsBySource)) {
|
|
4211
|
+
const installResult = await Result.tryPromise({
|
|
4212
|
+
try: async () => {
|
|
4213
|
+
const args = [
|
|
4214
|
+
...runner,
|
|
4215
|
+
"skills@latest",
|
|
4216
|
+
"add",
|
|
4217
|
+
source,
|
|
4218
|
+
...globalFlags,
|
|
4219
|
+
"--skill",
|
|
4220
|
+
...skills,
|
|
4221
|
+
"--agent",
|
|
4222
|
+
...agentTargets,
|
|
4223
|
+
"-y"
|
|
4224
|
+
];
|
|
4225
|
+
await $({
|
|
4226
|
+
cwd: projectDir,
|
|
4227
|
+
env: { CI: "true" }
|
|
4228
|
+
})`${args}`;
|
|
4229
|
+
},
|
|
4230
|
+
catch: (e) => new AddonSetupError({
|
|
4231
|
+
addon: "skills",
|
|
4232
|
+
message: `Failed to install skills from ${source}: ${e instanceof Error ? e.message : String(e)}`,
|
|
4233
|
+
cause: e
|
|
4234
|
+
})
|
|
4235
|
+
});
|
|
4236
|
+
if (installResult.isErr()) failures.push(installResult.error);
|
|
4237
|
+
}
|
|
4238
|
+
if (failures.length > 0) {
|
|
4239
|
+
installSpinner.stop(pc.red("Failed to install skills"));
|
|
4240
|
+
return Result.err(new AddonSetupError({
|
|
4212
4241
|
addon: "skills",
|
|
4213
|
-
message:
|
|
4214
|
-
cause:
|
|
4215
|
-
})
|
|
4216
|
-
}
|
|
4242
|
+
message: failures.map((failure) => failure.message).join("\n"),
|
|
4243
|
+
cause: failures.map((failure) => failure.cause)
|
|
4244
|
+
}));
|
|
4245
|
+
}
|
|
4217
4246
|
installSpinner.stop("Skills installed");
|
|
4218
4247
|
return Result.ok(void 0);
|
|
4219
4248
|
}
|
|
@@ -5301,7 +5330,31 @@ async function addHandlerInternal(input) {
|
|
|
5301
5330
|
});
|
|
5302
5331
|
}
|
|
5303
5332
|
});
|
|
5304
|
-
|
|
5333
|
+
const cleanupReservedPackage = async () => {
|
|
5334
|
+
if (!reservedPackageDir) return void 0;
|
|
5335
|
+
const dir = reservedPackageDir;
|
|
5336
|
+
return (await Result.tryPromise({
|
|
5337
|
+
try: () => fs.remove(dir),
|
|
5338
|
+
catch: (cause) => new CLIError({
|
|
5339
|
+
message: `Failed to remove ${dir}`,
|
|
5340
|
+
cause
|
|
5341
|
+
})
|
|
5342
|
+
})).isErr() ? `Also failed to remove ${dir}; delete it before retrying.` : void 0;
|
|
5343
|
+
};
|
|
5344
|
+
if (setupResult.isErr()) {
|
|
5345
|
+
const cleanupNote = await cleanupReservedPackage();
|
|
5346
|
+
if (!cleanupNote) return Result.err(setupResult.error);
|
|
5347
|
+
return Result.err(new CLIError({
|
|
5348
|
+
message: `${setupResult.error.message}\n${cleanupNote}`,
|
|
5349
|
+
cause: setupResult.error
|
|
5350
|
+
}));
|
|
5351
|
+
}
|
|
5352
|
+
const stepFailures = getStepFailures();
|
|
5353
|
+
if (stepFailures.length > 0) {
|
|
5354
|
+
const cleanupNote = await cleanupReservedPackage();
|
|
5355
|
+
const message = isSilent() ? stepFailures.join("\n") : "Addon setup failed";
|
|
5356
|
+
return Result.err(new CLIError({ message: cleanupNote ? `${message}\n${cleanupNote}` : message }));
|
|
5357
|
+
}
|
|
5305
5358
|
if (addonsToAdd.length > 0) {
|
|
5306
5359
|
const configResult = await updateBtsConfig(projectDir, {
|
|
5307
5360
|
addons: updatedAddons,
|
|
@@ -8785,7 +8838,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
8785
8838
|
let output = `${pc.cyan("1.")} ${cdCmd}\n`;
|
|
8786
8839
|
let stepCounter = 2;
|
|
8787
8840
|
if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} ${packageManager} install\n`;
|
|
8788
|
-
if (
|
|
8841
|
+
if ((0, types_exports.usesTursoDevServer)(config)) output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} db:local\n${pc.dim(dbSetup === "turso" ? " (optional - starts a local Turso database)" : " (starts the local SQLite server)")}\n`;
|
|
8789
8842
|
const hasAlchemyD1 = dbSetup === "d1" && (serverDeploy === "cloudflare" || isBackendSelf && webDeploy === "cloudflare");
|
|
8790
8843
|
const hasWranglerLocalD1 = (0, types_exports.getLocalD1Owner)(config) === "wrangler";
|
|
8791
8844
|
if (orm === "prisma" && !hasAlchemyD1) output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} db:generate\n`;
|
|
@@ -9188,7 +9241,8 @@ async function* runPostScaffoldSteps(options, cliInput, projectDir, isConvex) {
|
|
|
9188
9241
|
projectDir,
|
|
9189
9242
|
install,
|
|
9190
9243
|
installError,
|
|
9191
|
-
interrupted: wasAnyStepInterrupted()
|
|
9244
|
+
interrupted: wasAnyStepInterrupted(),
|
|
9245
|
+
stepFailures: getStepFailures()
|
|
9192
9246
|
});
|
|
9193
9247
|
}
|
|
9194
9248
|
async function setPackageManagerVersion(projectDir, packageManager, version) {
|
|
@@ -9457,6 +9511,7 @@ async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
|
|
|
9457
9511
|
await trackProjectCreation(config, input.disableAnalytics, mode);
|
|
9458
9512
|
const warnings = [];
|
|
9459
9513
|
if (created.interrupted) warnings.push("One or more setup steps were cancelled.");
|
|
9514
|
+
warnings.push(...created.stepFailures);
|
|
9460
9515
|
if (created.installError) {
|
|
9461
9516
|
warnings.push(created.installError.message);
|
|
9462
9517
|
await reportDiagnostic("cli_failed", {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.49.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
|
"keywords": [
|
|
6
6
|
"better-auth",
|
|
@@ -64,17 +64,17 @@
|
|
|
64
64
|
"dev": "tsdown --watch",
|
|
65
65
|
"check-types": "tsc --noEmit",
|
|
66
66
|
"check-test-types": "tsc --noEmit -p tsconfig.tests.json",
|
|
67
|
-
"test": "bun test",
|
|
68
|
-
"test:ci": "bun run build && BTS_SKIP_EXTERNAL_COMMANDS=1 BTS_TEST_MODE=1 bun test --bail=5",
|
|
69
|
-
"test:complete": "cd ../.. && bun run build && cd apps/cli &&
|
|
67
|
+
"test": "bun test ./test",
|
|
68
|
+
"test:ci": "bun run build && BTS_SKIP_EXTERNAL_COMMANDS=1 BTS_TEST_MODE=1 bun run test --bail=5",
|
|
69
|
+
"test:complete": "cd ../.. && bun run build && cd apps/cli && BTS_BUILD_SAMPLES=1 bun run test --bail=5",
|
|
70
70
|
"prepublishOnly": "npm run build"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@better-t-stack/template-generator": "^3.
|
|
74
|
-
"@better-t-stack/types": "^3.
|
|
73
|
+
"@better-t-stack/template-generator": "^3.49.0",
|
|
74
|
+
"@better-t-stack/types": "^3.49.0",
|
|
75
75
|
"@clack/core": "^1.5.0",
|
|
76
76
|
"@clack/prompts": "^1.8.0",
|
|
77
|
-
"@modelcontextprotocol/server": "2.
|
|
77
|
+
"@modelcontextprotocol/server": "2.3.1",
|
|
78
78
|
"@orpc/server": "^1.15.6",
|
|
79
79
|
"better-result": "^3.0.1",
|
|
80
80
|
"consola": "^3.4.2",
|
|
@@ -94,9 +94,9 @@
|
|
|
94
94
|
"zod": "^4.5.4"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
97
|
-
"@modelcontextprotocol/client": "2.
|
|
97
|
+
"@modelcontextprotocol/client": "2.3.1",
|
|
98
98
|
"@playwright/test": "1.63.0",
|
|
99
|
-
"@types/bun": "^1.4.
|
|
99
|
+
"@types/bun": "^1.4.3",
|
|
100
100
|
"@types/fs-extra": "^11.0.4",
|
|
101
101
|
"@types/node": "^26.5.0",
|
|
102
102
|
"@types/semver": "^7.8.0",
|