create-better-t-stack 3.46.1 → 3.48.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 +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{src-_HMF_A8q.mjs → src-DswDqMzo.mjs} +216 -142
- 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";
|
|
@@ -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";
|
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,
|
|
@@ -8078,19 +8131,21 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
8078
8131
|
}
|
|
8079
8132
|
//#endregion
|
|
8080
8133
|
//#region src/helpers/database-providers/supabase-setup.ts
|
|
8134
|
+
const SUPABASE_CLI_PACKAGE = "supabase@2.121.0";
|
|
8135
|
+
const supabaseEnv = { SUPABASE_EXPERIMENTAL_STACK: "0" };
|
|
8136
|
+
const statusSchema = z$1.object({ DB_URL: z$1.url().refine((value) => ["postgres:", "postgresql:"].includes(new URL(value).protocol)) });
|
|
8137
|
+
/** Save a verified database URL in the app that consumes the database. */
|
|
8081
8138
|
async function writeSupabaseEnvFile(projectDir, backend, databaseUrl) {
|
|
8082
8139
|
return Result.tryPromise({
|
|
8083
8140
|
try: async () => {
|
|
8084
8141
|
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
8085
|
-
|
|
8086
|
-
const dbUrlToUse = databaseUrl || "postgresql://postgres:postgres@127.0.0.1:54322/postgres";
|
|
8087
|
-
await addEnvVariablesToFile(envPath, [{
|
|
8142
|
+
await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
|
|
8088
8143
|
key: "DATABASE_URL",
|
|
8089
|
-
value:
|
|
8144
|
+
value: databaseUrl,
|
|
8090
8145
|
condition: true
|
|
8091
8146
|
}, {
|
|
8092
8147
|
key: "DIRECT_URL",
|
|
8093
|
-
value:
|
|
8148
|
+
value: databaseUrl,
|
|
8094
8149
|
condition: true
|
|
8095
8150
|
}]);
|
|
8096
8151
|
},
|
|
@@ -8101,28 +8156,38 @@ async function writeSupabaseEnvFile(projectDir, backend, databaseUrl) {
|
|
|
8101
8156
|
})
|
|
8102
8157
|
});
|
|
8103
8158
|
}
|
|
8104
|
-
|
|
8105
|
-
return statusEnv.match(/^DB_URL="(postgresql:\/\/[^"]+)"$/m)?.[1] ?? null;
|
|
8106
|
-
}
|
|
8159
|
+
/** Read Docker status with cancellation and a bounded wait. */
|
|
8107
8160
|
async function readSupabaseStatus(serverDir, packageManager) {
|
|
8108
|
-
const statusArgs = getPackageExecutionArgs(packageManager,
|
|
8109
|
-
|
|
8161
|
+
const statusArgs = getPackageExecutionArgs(packageManager, `${SUPABASE_CLI_PACKAGE} status --agent no --output json`);
|
|
8162
|
+
return Result.tryPromise({
|
|
8110
8163
|
try: async () => {
|
|
8111
|
-
const { stdout } = await execa(statusArgs[0], statusArgs.slice(1), {
|
|
8112
|
-
|
|
8164
|
+
const { stdout } = await execa(statusArgs[0], statusArgs.slice(1), {
|
|
8165
|
+
cwd: serverDir,
|
|
8166
|
+
env: supabaseEnv,
|
|
8167
|
+
cancelSignal: getInterruptSignal(),
|
|
8168
|
+
timeout: 12e4
|
|
8169
|
+
});
|
|
8170
|
+
return statusSchema.parse(JSON.parse(stdout)).DB_URL;
|
|
8113
8171
|
},
|
|
8114
|
-
catch: () =>
|
|
8172
|
+
catch: (e) => new DatabaseSetupError({
|
|
8173
|
+
provider: "supabase",
|
|
8174
|
+
message: "Could not read the Supabase database URL. Run Supabase status and configure DATABASE_URL and DIRECT_URL manually.",
|
|
8175
|
+
cause: e
|
|
8176
|
+
})
|
|
8115
8177
|
});
|
|
8116
|
-
return result.isOk() ? result.value : "";
|
|
8117
8178
|
}
|
|
8179
|
+
/** Initialize missing configuration without overwriting an existing project. */
|
|
8118
8180
|
async function initializeSupabase(serverDir, packageManager) {
|
|
8119
8181
|
cliLog.info("Initializing Supabase project...");
|
|
8120
8182
|
return Result.tryPromise({
|
|
8121
8183
|
try: async () => {
|
|
8122
|
-
|
|
8184
|
+
if (await fs.pathExists(path.join(serverDir, "supabase/config.toml"))) return;
|
|
8185
|
+
const supabaseInitArgs = getPackageExecutionArgs(packageManager, `${SUPABASE_CLI_PACKAGE} init --agent no`);
|
|
8123
8186
|
await execa(supabaseInitArgs[0], supabaseInitArgs.slice(1), {
|
|
8124
8187
|
cwd: serverDir,
|
|
8125
|
-
stdio: "inherit"
|
|
8188
|
+
stdio: "inherit",
|
|
8189
|
+
env: supabaseEnv,
|
|
8190
|
+
cancelSignal: getInterruptSignal()
|
|
8126
8191
|
});
|
|
8127
8192
|
cliLog.success("Supabase project initialized");
|
|
8128
8193
|
},
|
|
@@ -8130,18 +8195,23 @@ async function initializeSupabase(serverDir, packageManager) {
|
|
|
8130
8195
|
const error = e;
|
|
8131
8196
|
return new DatabaseSetupError({
|
|
8132
8197
|
provider: "supabase",
|
|
8133
|
-
message: error.message?.includes("ENOENT") ? "
|
|
8198
|
+
message: error.message?.includes("ENOENT") ? "Could not run the Supabase CLI. Ensure your selected package manager is installed and available in PATH." : `Failed to initialize Supabase project: ${error.message ?? String(e)}`,
|
|
8134
8199
|
cause: e
|
|
8135
8200
|
});
|
|
8136
8201
|
}
|
|
8137
8202
|
});
|
|
8138
8203
|
}
|
|
8204
|
+
/** Start the standard Docker runtime and stream its progress to the CLI. */
|
|
8139
8205
|
async function startSupabase(serverDir, packageManager) {
|
|
8140
8206
|
cliLog.info("Starting Supabase services (this may take a moment)...");
|
|
8141
|
-
const supabaseStartArgs = getPackageExecutionArgs(packageManager,
|
|
8207
|
+
const supabaseStartArgs = getPackageExecutionArgs(packageManager, `${SUPABASE_CLI_PACKAGE} start --agent no`);
|
|
8142
8208
|
return Result.tryPromise({
|
|
8143
8209
|
try: async () => {
|
|
8144
|
-
const subprocess = execa(supabaseStartArgs[0], supabaseStartArgs.slice(1), {
|
|
8210
|
+
const subprocess = execa(supabaseStartArgs[0], supabaseStartArgs.slice(1), {
|
|
8211
|
+
cwd: serverDir,
|
|
8212
|
+
env: supabaseEnv,
|
|
8213
|
+
cancelSignal: getInterruptSignal()
|
|
8214
|
+
});
|
|
8145
8215
|
let stdoutData = "";
|
|
8146
8216
|
if (subprocess.stdout) subprocess.stdout.on("data", (data) => {
|
|
8147
8217
|
const text = data.toString();
|
|
@@ -8150,7 +8220,6 @@ async function startSupabase(serverDir, packageManager) {
|
|
|
8150
8220
|
});
|
|
8151
8221
|
if (subprocess.stderr) subprocess.stderr.pipe(process.stderr);
|
|
8152
8222
|
await subprocess;
|
|
8153
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
8154
8223
|
return stdoutData;
|
|
8155
8224
|
},
|
|
8156
8225
|
catch: (e) => {
|
|
@@ -8163,18 +8232,21 @@ async function startSupabase(serverDir, packageManager) {
|
|
|
8163
8232
|
}
|
|
8164
8233
|
});
|
|
8165
8234
|
}
|
|
8166
|
-
|
|
8235
|
+
/** Print pinned setup commands without changing configuration or credentials. */
|
|
8236
|
+
function displayManualSupabaseInstructions(targetApp, packageManager, output) {
|
|
8237
|
+
const command = getPackageExecutionCommand(packageManager, SUPABASE_CLI_PACKAGE);
|
|
8167
8238
|
cliLog.info(`"Manual Supabase Setup Instructions:"
|
|
8168
|
-
1.
|
|
8169
|
-
2.
|
|
8170
|
-
3.
|
|
8171
|
-
4. Run
|
|
8172
|
-
5.
|
|
8239
|
+
1. Open your project's \`packages/db\` directory.
|
|
8240
|
+
2. Run \`${command} init\` if \`supabase/config.toml\` does not exist.
|
|
8241
|
+
3. Ensure Docker or a Docker-compatible container runtime is installed and running.
|
|
8242
|
+
4. Run \`${command} start\`.
|
|
8243
|
+
5. Run \`${command} status --output json\` and copy \`DB_URL\`.${output ? `
|
|
8173
8244
|
${pc.bold("Relevant output from `supabase start`:")}
|
|
8174
8245
|
${pc.dim(output)}` : ""}
|
|
8175
|
-
6. Add the database URL to the .env file in \`${targetApp}/.env\` as \`DATABASE_URL\`:
|
|
8176
|
-
${pc.gray("DATABASE_URL=\"your_supabase_db_url\"")}`);
|
|
8246
|
+
6. Add the database URL to the .env file in \`${targetApp}/.env\` as \`DATABASE_URL\` and \`DIRECT_URL\`:
|
|
8247
|
+
${pc.gray("DATABASE_URL=\"your_supabase_db_url\"\nDIRECT_URL=\"your_supabase_db_url\"")}`);
|
|
8177
8248
|
}
|
|
8249
|
+
/** Configure local Supabase, preserving credentials until automatic setup succeeds. */
|
|
8178
8250
|
async function setupSupabase(config, cliInput) {
|
|
8179
8251
|
const { projectDir, packageManager, backend } = config;
|
|
8180
8252
|
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
@@ -8193,8 +8265,8 @@ async function setupSupabase(config, cliInput) {
|
|
|
8193
8265
|
});
|
|
8194
8266
|
if (ensureDirResult.isErr()) return ensureDirResult;
|
|
8195
8267
|
if (setupMode === "manual") {
|
|
8196
|
-
displayManualSupabaseInstructions(targetApp);
|
|
8197
|
-
return
|
|
8268
|
+
displayManualSupabaseInstructions(targetApp, packageManager);
|
|
8269
|
+
return Result.ok();
|
|
8198
8270
|
}
|
|
8199
8271
|
let mode = setupMode;
|
|
8200
8272
|
if (!mode) {
|
|
@@ -8218,35 +8290,35 @@ async function setupSupabase(config, cliInput) {
|
|
|
8218
8290
|
}
|
|
8219
8291
|
}
|
|
8220
8292
|
if (mode === "manual") {
|
|
8221
|
-
displayManualSupabaseInstructions(targetApp);
|
|
8222
|
-
return
|
|
8293
|
+
displayManualSupabaseInstructions(targetApp, packageManager);
|
|
8294
|
+
return Result.ok();
|
|
8223
8295
|
}
|
|
8224
8296
|
const initResult = await initializeSupabase(serverDir, packageManager);
|
|
8225
8297
|
if (initResult.isErr()) {
|
|
8226
8298
|
cliLog.error(pc.red(initResult.error.message));
|
|
8227
|
-
displayManualSupabaseInstructions(targetApp);
|
|
8228
|
-
return
|
|
8299
|
+
displayManualSupabaseInstructions(targetApp, packageManager);
|
|
8300
|
+
return initResult;
|
|
8229
8301
|
}
|
|
8230
8302
|
const startResult = await startSupabase(serverDir, packageManager);
|
|
8231
8303
|
if (startResult.isErr()) {
|
|
8232
8304
|
cliLog.error(pc.red(startResult.error.message));
|
|
8233
|
-
displayManualSupabaseInstructions(targetApp);
|
|
8234
|
-
return
|
|
8305
|
+
displayManualSupabaseInstructions(targetApp, packageManager);
|
|
8306
|
+
return startResult;
|
|
8235
8307
|
}
|
|
8236
8308
|
const supabaseOutput = startResult.value;
|
|
8237
|
-
const
|
|
8238
|
-
if (
|
|
8239
|
-
const envResult = await writeSupabaseEnvFile(projectDir, backend,
|
|
8309
|
+
const statusResult = await readSupabaseStatus(serverDir, packageManager);
|
|
8310
|
+
if (statusResult.isOk()) {
|
|
8311
|
+
const envResult = await writeSupabaseEnvFile(projectDir, backend, statusResult.value);
|
|
8240
8312
|
if (envResult.isOk()) cliLog.success(pc.green("Supabase local development setup ready!"));
|
|
8241
8313
|
else {
|
|
8242
8314
|
cliLog.error(pc.red("Supabase setup completed, but failed to update .env automatically."));
|
|
8243
|
-
displayManualSupabaseInstructions(targetApp, supabaseOutput);
|
|
8315
|
+
displayManualSupabaseInstructions(targetApp, packageManager, supabaseOutput);
|
|
8244
8316
|
}
|
|
8245
8317
|
return envResult;
|
|
8246
8318
|
}
|
|
8247
8319
|
cliLog.error(pc.yellow("Supabase started, but could not extract DB URL automatically."));
|
|
8248
|
-
displayManualSupabaseInstructions(targetApp, supabaseOutput);
|
|
8249
|
-
return
|
|
8320
|
+
displayManualSupabaseInstructions(targetApp, packageManager, supabaseOutput);
|
|
8321
|
+
return statusResult;
|
|
8250
8322
|
}
|
|
8251
8323
|
//#endregion
|
|
8252
8324
|
//#region src/helpers/database-providers/turso-setup.ts
|
|
@@ -8766,7 +8838,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
8766
8838
|
let output = `${pc.cyan("1.")} ${cdCmd}\n`;
|
|
8767
8839
|
let stepCounter = 2;
|
|
8768
8840
|
if (!depsInstalled) output += `${pc.cyan(`${stepCounter++}.`)} ${packageManager} install\n`;
|
|
8769
|
-
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`;
|
|
8770
8842
|
const hasAlchemyD1 = dbSetup === "d1" && (serverDeploy === "cloudflare" || isBackendSelf && webDeploy === "cloudflare");
|
|
8771
8843
|
const hasWranglerLocalD1 = (0, types_exports.getLocalD1Owner)(config) === "wrangler";
|
|
8772
8844
|
if (orm === "prisma" && !hasAlchemyD1) output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} db:generate\n`;
|
|
@@ -9169,7 +9241,8 @@ async function* runPostScaffoldSteps(options, cliInput, projectDir, isConvex) {
|
|
|
9169
9241
|
projectDir,
|
|
9170
9242
|
install,
|
|
9171
9243
|
installError,
|
|
9172
|
-
interrupted: wasAnyStepInterrupted()
|
|
9244
|
+
interrupted: wasAnyStepInterrupted(),
|
|
9245
|
+
stepFailures: getStepFailures()
|
|
9173
9246
|
});
|
|
9174
9247
|
}
|
|
9175
9248
|
async function setPackageManagerVersion(projectDir, packageManager, version) {
|
|
@@ -9438,6 +9511,7 @@ async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
|
|
|
9438
9511
|
await trackProjectCreation(config, input.disableAnalytics, mode);
|
|
9439
9512
|
const warnings = [];
|
|
9440
9513
|
if (created.interrupted) warnings.push("One or more setup steps were cancelled.");
|
|
9514
|
+
warnings.push(...created.stepFailures);
|
|
9441
9515
|
if (created.installError) {
|
|
9442
9516
|
warnings.push(created.installError.message);
|
|
9443
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.48.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.48.0",
|
|
74
|
+
"@better-t-stack/types": "^3.48.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",
|