create-better-t-stack 3.9.0 → 3.11.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 +2 -1
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +7 -3
- package/dist/index.mjs +1 -1
- package/dist/{src-DLvUK0Qf.mjs → src-XVvJUQ_h.mjs} +270 -93
- package/package.json +44 -44
- package/templates/auth/better-auth/convex/backend/convex/auth.config.ts.hbs +5 -7
- package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +17 -17
- package/templates/auth/better-auth/convex/backend/convex/http.ts.hbs +4 -4
- package/templates/auth/better-auth/convex/web/react/next/src/app/api/auth/[...all]/route.ts.hbs +2 -2
- package/templates/auth/better-auth/convex/web/react/next/src/components/user-menu.tsx.hbs +10 -10
- package/templates/auth/better-auth/convex/web/react/next/src/lib/auth-server.ts.hbs +13 -5
- package/templates/auth/better-auth/convex/web/react/tanstack-router/src/components/user-menu.tsx.hbs +14 -12
- package/templates/auth/better-auth/convex/web/react/tanstack-start/src/components/user-menu.tsx.hbs +13 -16
- package/templates/auth/better-auth/convex/web/react/tanstack-start/src/lib/auth-server.ts.hbs +11 -5
- package/templates/auth/better-auth/convex/web/react/tanstack-start/src/routes/api/auth/$.ts.hbs +4 -4
- package/templates/auth/better-auth/fullstack/tanstack-start/src/routes/api/auth/$.ts.hbs +1 -1
- package/templates/auth/better-auth/web/react/next/src/components/user-menu.tsx.hbs +17 -15
- package/templates/auth/better-auth/web/react/react-router/src/components/user-menu.tsx.hbs +16 -15
- package/templates/auth/better-auth/web/react/tanstack-router/src/components/{user-menu.tsx → user-menu.tsx.hbs} +16 -15
- package/templates/auth/better-auth/web/react/tanstack-start/src/components/{user-menu.tsx → user-menu.tsx.hbs} +16 -15
- package/templates/backend/convex/packages/backend/convex/README.md +4 -4
- package/templates/backend/convex/packages/backend/convex/convex.config.ts.hbs +17 -0
- package/templates/backend/convex/packages/backend/convex/tsconfig.json.hbs +1 -1
- package/templates/examples/ai/convex/packages/backend/convex/agent.ts.hbs +9 -0
- package/templates/examples/ai/convex/packages/backend/convex/chat.ts.hbs +67 -0
- package/templates/examples/ai/native/bare/app/(drawer)/ai.tsx.hbs +301 -3
- package/templates/examples/ai/native/unistyles/app/(drawer)/ai.tsx.hbs +296 -10
- package/templates/examples/ai/native/uniwind/app/(drawer)/ai.tsx.hbs +180 -1
- package/templates/examples/ai/web/react/next/src/app/ai/page.tsx.hbs +172 -9
- package/templates/examples/ai/web/react/react-router/src/routes/ai.tsx.hbs +156 -6
- package/templates/examples/ai/web/react/tanstack-router/src/routes/ai.tsx.hbs +156 -4
- package/templates/examples/ai/web/react/tanstack-start/src/routes/ai.tsx.hbs +159 -6
- package/templates/frontend/react/next/package.json.hbs +8 -7
- package/templates/frontend/react/next/src/app/layout.tsx.hbs +28 -1
- package/templates/frontend/react/next/src/components/mode-toggle.tsx.hbs +4 -6
- package/templates/frontend/react/next/src/components/providers.tsx.hbs +14 -4
- package/templates/frontend/react/react-router/package.json.hbs +2 -1
- package/templates/frontend/react/{tanstack-router/src/components/mode-toggle.tsx → react-router/src/components/mode-toggle.tsx.hbs} +4 -6
- package/templates/frontend/react/tanstack-router/package.json.hbs +2 -1
- package/templates/frontend/react/{react-router/src/components/mode-toggle.tsx → tanstack-router/src/components/mode-toggle.tsx.hbs} +4 -6
- package/templates/frontend/react/tanstack-start/package.json.hbs +2 -1
- package/templates/frontend/react/tanstack-start/src/router.tsx.hbs +6 -0
- package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +13 -14
- package/templates/frontend/react/tanstack-start/vite.config.ts.hbs +5 -0
- package/templates/frontend/react/web-base/components.json +5 -2
- package/templates/frontend/react/web-base/src/components/ui/button.tsx.hbs +57 -0
- package/templates/frontend/react/web-base/src/components/ui/card.tsx.hbs +103 -0
- package/templates/frontend/react/web-base/src/components/ui/checkbox.tsx.hbs +26 -0
- package/templates/frontend/react/web-base/src/components/ui/dropdown-menu.tsx.hbs +262 -0
- package/templates/frontend/react/web-base/src/components/ui/input.tsx.hbs +20 -0
- package/templates/frontend/react/web-base/src/components/ui/label.tsx.hbs +20 -0
- package/templates/frontend/react/web-base/src/components/ui/skeleton.tsx.hbs +13 -0
- package/templates/frontend/react/web-base/src/components/ui/sonner.tsx.hbs +44 -0
- package/templates/frontend/react/web-base/src/index.css.hbs +58 -64
- package/templates/auth/better-auth/convex/backend/convex/convex.config.ts.hbs +0 -7
- package/templates/examples/ai/web/react/base/src/components/response.tsx.hbs +0 -22
- package/templates/frontend/react/web-base/src/components/ui/button.tsx +0 -56
- package/templates/frontend/react/web-base/src/components/ui/card.tsx +0 -75
- package/templates/frontend/react/web-base/src/components/ui/checkbox.tsx +0 -27
- package/templates/frontend/react/web-base/src/components/ui/dropdown-menu.tsx +0 -228
- package/templates/frontend/react/web-base/src/components/ui/input.tsx +0 -21
- package/templates/frontend/react/web-base/src/components/ui/label.tsx +0 -19
- package/templates/frontend/react/web-base/src/components/ui/skeleton.tsx +0 -13
- package/templates/frontend/react/web-base/src/components/ui/sonner.tsx +0 -25
- /package/templates/auth/better-auth/web/react/tanstack-router/src/components/{sign-in-form.tsx → sign-in-form.tsx.hbs} +0 -0
- /package/templates/auth/better-auth/web/react/tanstack-router/src/components/{sign-up-form.tsx → sign-up-form.tsx.hbs} +0 -0
- /package/templates/auth/better-auth/web/react/tanstack-router/src/routes/{login.tsx → login.tsx.hbs} +0 -0
- /package/templates/auth/better-auth/web/react/tanstack-start/src/components/{sign-in-form.tsx → sign-in-form.tsx.hbs} +0 -0
- /package/templates/auth/better-auth/web/react/tanstack-start/src/components/{sign-up-form.tsx → sign-up-form.tsx.hbs} +0 -0
- /package/templates/auth/better-auth/web/react/tanstack-start/src/routes/{login.tsx → login.tsx.hbs} +0 -0
- /package/templates/auth/better-auth/web/solid/src/components/{sign-in-form.tsx → sign-in-form.tsx.hbs} +0 -0
- /package/templates/auth/better-auth/web/solid/src/components/{sign-up-form.tsx → sign-up-form.tsx.hbs} +0 -0
- /package/templates/auth/better-auth/web/solid/src/routes/{login.tsx → login.tsx.hbs} +0 -0
- /package/templates/frontend/react/react-router/src/components/{theme-provider.tsx → theme-provider.tsx.hbs} +0 -0
- /package/templates/frontend/react/tanstack-router/src/components/{theme-provider.tsx → theme-provider.tsx.hbs} +0 -0
- /package/templates/frontend/react/web-base/src/lib/{utils.ts → utils.ts.hbs} +0 -0
|
@@ -95,7 +95,7 @@ const dependencyVersionMap = {
|
|
|
95
95
|
"@vite-pwa/assets-generator": "^1.0.0",
|
|
96
96
|
"@tauri-apps/cli": "^2.4.0",
|
|
97
97
|
"@biomejs/biome": "^2.2.0",
|
|
98
|
-
oxlint: "^1.
|
|
98
|
+
oxlint: "^1.34.0",
|
|
99
99
|
oxfmt: "^0.19.0",
|
|
100
100
|
husky: "^9.1.7",
|
|
101
101
|
"lint-staged": "^16.1.2",
|
|
@@ -117,7 +117,7 @@ const dependencyVersionMap = {
|
|
|
117
117
|
"@fastify/cors": "^11.0.1",
|
|
118
118
|
turbo: "^2.6.3",
|
|
119
119
|
ai: "^5.0.49",
|
|
120
|
-
"@ai-sdk/google": "^2.0.
|
|
120
|
+
"@ai-sdk/google": "^2.0.51",
|
|
121
121
|
"@ai-sdk/vue": "^2.0.49",
|
|
122
122
|
"@ai-sdk/svelte": "^3.0.39",
|
|
123
123
|
"@ai-sdk/react": "^2.0.39",
|
|
@@ -132,12 +132,13 @@ const dependencyVersionMap = {
|
|
|
132
132
|
"@trpc/server": "^11.7.2",
|
|
133
133
|
"@trpc/client": "^11.7.2",
|
|
134
134
|
next: "^16.0.10",
|
|
135
|
-
convex: "^1.
|
|
135
|
+
convex: "^1.31.2",
|
|
136
136
|
"@convex-dev/react-query": "^0.1.0",
|
|
137
|
+
"@convex-dev/agent": "^0.3.2",
|
|
137
138
|
"convex-svelte": "^0.0.12",
|
|
138
139
|
"convex-nuxt": "0.1.5",
|
|
139
140
|
"convex-vue": "^0.1.5",
|
|
140
|
-
"@convex-dev/better-auth": "^0.
|
|
141
|
+
"@convex-dev/better-auth": "^0.10.6",
|
|
141
142
|
"@tanstack/svelte-query": "^5.85.3",
|
|
142
143
|
"@tanstack/svelte-query-devtools": "^5.85.3",
|
|
143
144
|
"@tanstack/vue-query-devtools": "^5.90.2",
|
|
@@ -184,6 +185,8 @@ const ADDON_COMPATIBILITY = {
|
|
|
184
185
|
ruler: [],
|
|
185
186
|
oxlint: [],
|
|
186
187
|
fumadocs: [],
|
|
188
|
+
opentui: [],
|
|
189
|
+
wxt: [],
|
|
187
190
|
none: []
|
|
188
191
|
};
|
|
189
192
|
|
|
@@ -289,8 +292,12 @@ function isExampleTodoAllowed(backend, database) {
|
|
|
289
292
|
return !(backend !== "convex" && backend !== "none" && database === "none");
|
|
290
293
|
}
|
|
291
294
|
function isExampleAIAllowed(backend, frontends = []) {
|
|
292
|
-
if (backend === "convex") return false;
|
|
293
295
|
if (frontends.includes("solid")) return false;
|
|
296
|
+
if (backend === "convex") {
|
|
297
|
+
const includesNuxt = frontends.includes("nuxt");
|
|
298
|
+
const includesSvelte = frontends.includes("svelte");
|
|
299
|
+
if (includesNuxt || includesSvelte) return false;
|
|
300
|
+
}
|
|
294
301
|
return true;
|
|
295
302
|
}
|
|
296
303
|
function validateWebDeployRequiresWebFrontend(webDeploy, hasWebFrontendFlag) {
|
|
@@ -336,8 +343,13 @@ function validateExamplesCompatibility(examples, backend, database, frontend) {
|
|
|
336
343
|
const examplesArr = examples ?? [];
|
|
337
344
|
if (examplesArr.length === 0 || examplesArr.includes("none")) return;
|
|
338
345
|
if (examplesArr.includes("todo") && backend !== "convex" && backend !== "none" && database === "none") exitWithError("The 'todo' example requires a database if a backend (other than Convex) is present. Cannot use --examples todo when database is 'none' and a backend is selected.");
|
|
339
|
-
if (examplesArr.includes("ai") && backend === "convex") exitWithError("The 'ai' example is not yet available with Convex backend.");
|
|
340
346
|
if (examplesArr.includes("ai") && (frontend ?? []).includes("solid")) exitWithError("The 'ai' example is not compatible with the Solid frontend.");
|
|
347
|
+
if (examplesArr.includes("ai") && backend === "convex") {
|
|
348
|
+
const frontendArr = frontend ?? [];
|
|
349
|
+
const includesNuxt = frontendArr.includes("nuxt");
|
|
350
|
+
const includesSvelte = frontendArr.includes("svelte");
|
|
351
|
+
if (includesNuxt || includesSvelte) exitWithError("The 'ai' example with Convex backend only supports React-based frontends (Next.js, TanStack Router, TanStack Start, React Router). Svelte and Nuxt are not supported with Convex AI.");
|
|
352
|
+
}
|
|
341
353
|
}
|
|
342
354
|
|
|
343
355
|
//#endregion
|
|
@@ -386,6 +398,14 @@ function getAddonDisplay(addon) {
|
|
|
386
398
|
label = "Fumadocs";
|
|
387
399
|
hint = "Build excellent documentation site";
|
|
388
400
|
break;
|
|
401
|
+
case "opentui":
|
|
402
|
+
label = "OpenTUI";
|
|
403
|
+
hint = "Build terminal user interfaces";
|
|
404
|
+
break;
|
|
405
|
+
case "wxt":
|
|
406
|
+
label = "WXT";
|
|
407
|
+
hint = "Build browser extensions";
|
|
408
|
+
break;
|
|
389
409
|
default:
|
|
390
410
|
label = addon;
|
|
391
411
|
hint = `Add ${addon}`;
|
|
@@ -404,10 +424,12 @@ const ADDON_GROUPS = {
|
|
|
404
424
|
],
|
|
405
425
|
Other: [
|
|
406
426
|
"ruler",
|
|
407
|
-
"turborepo",
|
|
408
427
|
"pwa",
|
|
409
428
|
"tauri",
|
|
410
|
-
"husky"
|
|
429
|
+
"husky",
|
|
430
|
+
"opentui",
|
|
431
|
+
"wxt",
|
|
432
|
+
"turborepo"
|
|
411
433
|
]
|
|
412
434
|
};
|
|
413
435
|
async function getAddonsChoice(addons, frontends, auth) {
|
|
@@ -434,6 +456,12 @@ async function getAddonsChoice(addons, frontends, auth) {
|
|
|
434
456
|
}
|
|
435
457
|
Object.keys(groupedOptions).forEach((group$1) => {
|
|
436
458
|
if (groupedOptions[group$1].length === 0) delete groupedOptions[group$1];
|
|
459
|
+
else {
|
|
460
|
+
const groupOrder = ADDON_GROUPS[group$1] || [];
|
|
461
|
+
groupedOptions[group$1].sort((a, b) => {
|
|
462
|
+
return groupOrder.indexOf(a.value) - groupOrder.indexOf(b.value);
|
|
463
|
+
});
|
|
464
|
+
}
|
|
437
465
|
});
|
|
438
466
|
const response = await groupMultiselect({
|
|
439
467
|
message: "Select addons",
|
|
@@ -466,6 +494,12 @@ async function getAddonsToAdd(frontend, existingAddons = [], auth) {
|
|
|
466
494
|
}
|
|
467
495
|
Object.keys(groupedOptions).forEach((group$1) => {
|
|
468
496
|
if (groupedOptions[group$1].length === 0) delete groupedOptions[group$1];
|
|
497
|
+
else {
|
|
498
|
+
const groupOrder = ADDON_GROUPS[group$1] || [];
|
|
499
|
+
groupedOptions[group$1].sort((a, b) => {
|
|
500
|
+
return groupOrder.indexOf(a.value) - groupOrder.indexOf(b.value);
|
|
501
|
+
});
|
|
502
|
+
}
|
|
469
503
|
});
|
|
470
504
|
if (Object.keys(groupedOptions).length === 0) return [];
|
|
471
505
|
const response = await groupMultiselect({
|
|
@@ -1966,7 +2000,7 @@ function getPackageExecutionCommand(packageManager, commandWithArgs) {
|
|
|
1966
2000
|
|
|
1967
2001
|
//#endregion
|
|
1968
2002
|
//#region src/helpers/addons/fumadocs-setup.ts
|
|
1969
|
-
const TEMPLATES = {
|
|
2003
|
+
const TEMPLATES$2 = {
|
|
1970
2004
|
"next-mdx": {
|
|
1971
2005
|
label: "Next.js: Fumadocs MDX",
|
|
1972
2006
|
hint: "Recommended template with MDX support",
|
|
@@ -1999,7 +2033,7 @@ async function setupFumadocs(config) {
|
|
|
1999
2033
|
log.info("Setting up Fumadocs...");
|
|
2000
2034
|
const template = await select({
|
|
2001
2035
|
message: "Choose a template",
|
|
2002
|
-
options: Object.entries(TEMPLATES).map(([key, template$1]) => ({
|
|
2036
|
+
options: Object.entries(TEMPLATES$2).map(([key, template$1]) => ({
|
|
2003
2037
|
value: key,
|
|
2004
2038
|
label: template$1.label,
|
|
2005
2039
|
hint: template$1.hint
|
|
@@ -2007,7 +2041,7 @@ async function setupFumadocs(config) {
|
|
|
2007
2041
|
initialValue: "next-mdx"
|
|
2008
2042
|
});
|
|
2009
2043
|
if (isCancel(template)) return exitCancelled("Operation cancelled");
|
|
2010
|
-
const fumadocsInitCommand = getPackageExecutionCommand(packageManager, `create-fumadocs-app@latest fumadocs --template ${TEMPLATES[template].value} --src --pm ${packageManager} --no-git`);
|
|
2044
|
+
const fumadocsInitCommand = getPackageExecutionCommand(packageManager, `create-fumadocs-app@latest fumadocs --template ${TEMPLATES$2[template].value} --src --pm ${packageManager} --no-git`);
|
|
2011
2045
|
const appsDir = path.join(projectDir, "apps");
|
|
2012
2046
|
await fs.ensureDir(appsDir);
|
|
2013
2047
|
const s = spinner();
|
|
@@ -2235,6 +2269,53 @@ async function setupTauri(config) {
|
|
|
2235
2269
|
}
|
|
2236
2270
|
}
|
|
2237
2271
|
|
|
2272
|
+
//#endregion
|
|
2273
|
+
//#region src/helpers/addons/tui-setup.ts
|
|
2274
|
+
const TEMPLATES$1 = {
|
|
2275
|
+
core: {
|
|
2276
|
+
label: "Core",
|
|
2277
|
+
hint: "Basic OpenTUI template"
|
|
2278
|
+
},
|
|
2279
|
+
react: {
|
|
2280
|
+
label: "React",
|
|
2281
|
+
hint: "React-based OpenTUI template"
|
|
2282
|
+
},
|
|
2283
|
+
solid: {
|
|
2284
|
+
label: "Solid",
|
|
2285
|
+
hint: "SolidJS-based OpenTUI template"
|
|
2286
|
+
}
|
|
2287
|
+
};
|
|
2288
|
+
async function setupTui(config) {
|
|
2289
|
+
const { packageManager, projectDir } = config;
|
|
2290
|
+
try {
|
|
2291
|
+
log.info("Setting up OpenTUI...");
|
|
2292
|
+
const template = await select({
|
|
2293
|
+
message: "Choose a template",
|
|
2294
|
+
options: Object.entries(TEMPLATES$1).map(([key, template$1]) => ({
|
|
2295
|
+
value: key,
|
|
2296
|
+
label: template$1.label,
|
|
2297
|
+
hint: template$1.hint
|
|
2298
|
+
})),
|
|
2299
|
+
initialValue: "core"
|
|
2300
|
+
});
|
|
2301
|
+
if (isCancel(template)) return exitCancelled("Operation cancelled");
|
|
2302
|
+
const tuiInitCommand = getPackageExecutionCommand(packageManager, `create-tui@latest --template ${template} --no-git --no-install tui`);
|
|
2303
|
+
const appsDir = path.join(projectDir, "apps");
|
|
2304
|
+
await fs.ensureDir(appsDir);
|
|
2305
|
+
const s = spinner();
|
|
2306
|
+
s.start("Running OpenTUI create command...");
|
|
2307
|
+
await execa(tuiInitCommand, {
|
|
2308
|
+
cwd: appsDir,
|
|
2309
|
+
env: { CI: "true" },
|
|
2310
|
+
shell: true
|
|
2311
|
+
});
|
|
2312
|
+
s.stop("OpenTUI setup complete!");
|
|
2313
|
+
} catch (error) {
|
|
2314
|
+
log.error(pc.red("Failed to set up OpenTUI"));
|
|
2315
|
+
if (error instanceof Error) console.error(pc.red(error.message));
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2238
2319
|
//#endregion
|
|
2239
2320
|
//#region src/helpers/addons/ultracite-setup.ts
|
|
2240
2321
|
const EDITORS = {
|
|
@@ -2347,9 +2428,72 @@ async function setupUltracite(config, hasHusky) {
|
|
|
2347
2428
|
}
|
|
2348
2429
|
}
|
|
2349
2430
|
|
|
2431
|
+
//#endregion
|
|
2432
|
+
//#region src/helpers/addons/wxt-setup.ts
|
|
2433
|
+
const TEMPLATES = {
|
|
2434
|
+
vanilla: {
|
|
2435
|
+
label: "Vanilla",
|
|
2436
|
+
hint: "Vanilla JavaScript template"
|
|
2437
|
+
},
|
|
2438
|
+
vue: {
|
|
2439
|
+
label: "Vue",
|
|
2440
|
+
hint: "Vue.js template"
|
|
2441
|
+
},
|
|
2442
|
+
react: {
|
|
2443
|
+
label: "React",
|
|
2444
|
+
hint: "React template"
|
|
2445
|
+
},
|
|
2446
|
+
solid: {
|
|
2447
|
+
label: "Solid",
|
|
2448
|
+
hint: "SolidJS template"
|
|
2449
|
+
},
|
|
2450
|
+
svelte: {
|
|
2451
|
+
label: "Svelte",
|
|
2452
|
+
hint: "Svelte template"
|
|
2453
|
+
}
|
|
2454
|
+
};
|
|
2455
|
+
async function setupWxt(config) {
|
|
2456
|
+
const { packageManager, projectDir } = config;
|
|
2457
|
+
try {
|
|
2458
|
+
log.info("Setting up WXT...");
|
|
2459
|
+
const template = await select({
|
|
2460
|
+
message: "Choose a template",
|
|
2461
|
+
options: Object.entries(TEMPLATES).map(([key, template$1]) => ({
|
|
2462
|
+
value: key,
|
|
2463
|
+
label: template$1.label,
|
|
2464
|
+
hint: template$1.hint
|
|
2465
|
+
})),
|
|
2466
|
+
initialValue: "react"
|
|
2467
|
+
});
|
|
2468
|
+
if (isCancel(template)) return exitCancelled("Operation cancelled");
|
|
2469
|
+
const wxtInitCommand = getPackageExecutionCommand(packageManager, `wxt@latest init extension --template ${template} --pm ${packageManager}`);
|
|
2470
|
+
const appsDir = path.join(projectDir, "apps");
|
|
2471
|
+
await fs.ensureDir(appsDir);
|
|
2472
|
+
const s = spinner();
|
|
2473
|
+
s.start("Running WXT init command...");
|
|
2474
|
+
await execa(wxtInitCommand, {
|
|
2475
|
+
cwd: appsDir,
|
|
2476
|
+
env: { CI: "true" },
|
|
2477
|
+
shell: true
|
|
2478
|
+
});
|
|
2479
|
+
const extensionDir = path.join(projectDir, "apps", "extension");
|
|
2480
|
+
const packageJsonPath = path.join(extensionDir, "package.json");
|
|
2481
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
2482
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
2483
|
+
packageJson.name = "extension";
|
|
2484
|
+
if (packageJson.scripts?.dev) packageJson.scripts.dev = `${packageJson.scripts.dev} --port 5555`;
|
|
2485
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
2486
|
+
}
|
|
2487
|
+
s.stop("WXT setup complete!");
|
|
2488
|
+
} catch (error) {
|
|
2489
|
+
log.error(pc.red("Failed to set up WXT"));
|
|
2490
|
+
if (error instanceof Error) console.error(pc.red(error.message));
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2350
2494
|
//#endregion
|
|
2351
2495
|
//#region src/utils/ts-morph.ts
|
|
2352
|
-
const tsProject = new Project({
|
|
2496
|
+
const tsProject$1 = new Project({
|
|
2353
2497
|
useInMemoryFileSystem: false,
|
|
2354
2498
|
skipAddingFilesFromTsConfig: true,
|
|
2355
2499
|
manipulationSettings: {
|
|
@@ -2367,7 +2511,7 @@ function ensureArrayProperty(obj, name) {
|
|
|
2367
2511
|
//#endregion
|
|
2368
2512
|
//#region src/helpers/addons/vite-pwa-setup.ts
|
|
2369
2513
|
async function addPwaToViteConfig(viteConfigPath, projectName) {
|
|
2370
|
-
const sourceFile = tsProject.addSourceFileAtPathIfExists(viteConfigPath);
|
|
2514
|
+
const sourceFile = tsProject$1.addSourceFileAtPathIfExists(viteConfigPath);
|
|
2371
2515
|
if (!sourceFile) throw new Error("vite config not found");
|
|
2372
2516
|
if (!sourceFile.getImportDeclarations().some((imp) => imp.getModuleSpecifierValue() === "vite-plugin-pwa")) sourceFile.insertImportDeclaration(0, {
|
|
2373
2517
|
namedImports: ["VitePWA"],
|
|
@@ -2392,7 +2536,7 @@ async function addPwaToViteConfig(viteConfigPath, projectName) {
|
|
|
2392
2536
|
pwaAssets: { disabled: false, config: true },
|
|
2393
2537
|
devOptions: { enabled: true },
|
|
2394
2538
|
})`);
|
|
2395
|
-
await tsProject.save();
|
|
2539
|
+
await tsProject$1.save();
|
|
2396
2540
|
}
|
|
2397
2541
|
|
|
2398
2542
|
//#endregion
|
|
@@ -2437,6 +2581,8 @@ ${pc.cyan("Docs:")} ${pc.underline("https://turborepo.com/docs")}
|
|
|
2437
2581
|
if (addons.includes("starlight")) await setupStarlight(config);
|
|
2438
2582
|
if (addons.includes("ruler")) await setupRuler(config);
|
|
2439
2583
|
if (addons.includes("fumadocs")) await setupFumadocs(config);
|
|
2584
|
+
if (addons.includes("opentui")) await setupTui(config);
|
|
2585
|
+
if (addons.includes("wxt")) await setupWxt(config);
|
|
2440
2586
|
}
|
|
2441
2587
|
function getWebAppDir(projectDir, frontends) {
|
|
2442
2588
|
if (frontends.some((f) => [
|
|
@@ -2623,7 +2769,7 @@ handlebars.registerHelper("includes", (array, value) => Array.isArray(array) &&
|
|
|
2623
2769
|
|
|
2624
2770
|
//#endregion
|
|
2625
2771
|
//#region src/helpers/deployment/alchemy/env-dts-setup.ts
|
|
2626
|
-
const tsProject
|
|
2772
|
+
const tsProject = new Project({
|
|
2627
2773
|
useInMemoryFileSystem: false,
|
|
2628
2774
|
skipAddingFilesFromTsConfig: true
|
|
2629
2775
|
});
|
|
@@ -2642,7 +2788,7 @@ function determineImportPath(envDtsPath, projectDir, config) {
|
|
|
2642
2788
|
async function setupEnvDtsImport(envDtsPath, projectDir, config) {
|
|
2643
2789
|
if (!await fs.pathExists(envDtsPath)) return;
|
|
2644
2790
|
const importPath = determineImportPath(envDtsPath, projectDir, config);
|
|
2645
|
-
const sourceFile = tsProject
|
|
2791
|
+
const sourceFile = tsProject.addSourceFileAtPath(envDtsPath);
|
|
2646
2792
|
if (!sourceFile.getImportDeclarations().some((imp) => imp.getModuleSpecifierValue() === importPath && imp.getNamedImports().some((named) => named.getName() === "server"))) sourceFile.insertImportDeclaration(0, {
|
|
2647
2793
|
moduleSpecifier: importPath,
|
|
2648
2794
|
namedImports: [{
|
|
@@ -3071,10 +3217,6 @@ async function setupExamplesTemplate(projectDir, context) {
|
|
|
3071
3217
|
if (hasReactWeb) {
|
|
3072
3218
|
const exampleWebSrc = path.join(exampleBaseDir, "web/react");
|
|
3073
3219
|
if (await fs.pathExists(exampleWebSrc)) {
|
|
3074
|
-
if (example === "ai") {
|
|
3075
|
-
const exampleWebBaseSrc = path.join(exampleWebSrc, "base");
|
|
3076
|
-
if (await fs.pathExists(exampleWebBaseSrc)) await processAndCopyFiles("**/*", exampleWebBaseSrc, webAppDir, context, false);
|
|
3077
|
-
}
|
|
3078
3220
|
const reactFramework = context.frontend.find((f) => [
|
|
3079
3221
|
"next",
|
|
3080
3222
|
"react-router",
|
|
@@ -3836,62 +3978,84 @@ async function updatePackageJsonsWithCatalogs(packagesInfo, catalog) {
|
|
|
3836
3978
|
//#endregion
|
|
3837
3979
|
//#region src/helpers/addons/examples-setup.ts
|
|
3838
3980
|
async function setupExamples(config) {
|
|
3839
|
-
const { examples,
|
|
3840
|
-
if (
|
|
3981
|
+
const { examples, backend } = config;
|
|
3982
|
+
if (!examples || examples.length === 0 || examples[0] === "none") return;
|
|
3983
|
+
if (examples.includes("todo") && backend !== "convex" && backend !== "none") await setupTodoDependencies(config);
|
|
3984
|
+
if (examples.includes("ai")) await setupAIDependencies(config);
|
|
3985
|
+
}
|
|
3986
|
+
async function setupTodoDependencies(config) {
|
|
3987
|
+
const { projectDir, orm, database, backend } = config;
|
|
3841
3988
|
const apiDir = path.join(projectDir, "packages/api");
|
|
3842
|
-
if (await fs.pathExists(apiDir)
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
projectDir: apiDir
|
|
3849
|
-
});
|
|
3850
|
-
} else if (orm === "prisma") await addPackageDependency({
|
|
3851
|
-
dependencies: ["@prisma/client"],
|
|
3852
|
-
projectDir: apiDir
|
|
3853
|
-
});
|
|
3854
|
-
else if (orm === "mongoose") await addPackageDependency({
|
|
3855
|
-
dependencies: ["mongoose"],
|
|
3989
|
+
if (!await fs.pathExists(apiDir) || backend === "none") return;
|
|
3990
|
+
if (orm === "drizzle") {
|
|
3991
|
+
const dependencies = ["drizzle-orm"];
|
|
3992
|
+
if (database === "postgres") dependencies.push("@types/pg");
|
|
3993
|
+
await addPackageDependency({
|
|
3994
|
+
dependencies,
|
|
3856
3995
|
projectDir: apiDir
|
|
3857
3996
|
});
|
|
3858
|
-
}
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3997
|
+
} else if (orm === "prisma") await addPackageDependency({
|
|
3998
|
+
dependencies: ["@prisma/client"],
|
|
3999
|
+
projectDir: apiDir
|
|
4000
|
+
});
|
|
4001
|
+
else if (orm === "mongoose") await addPackageDependency({
|
|
4002
|
+
dependencies: ["mongoose"],
|
|
4003
|
+
projectDir: apiDir
|
|
4004
|
+
});
|
|
4005
|
+
}
|
|
4006
|
+
async function setupAIDependencies(config) {
|
|
4007
|
+
const { frontend, backend, projectDir } = config;
|
|
4008
|
+
const webClientDir = path.join(projectDir, "apps/web");
|
|
4009
|
+
const nativeClientDir = path.join(projectDir, "apps/native");
|
|
4010
|
+
const serverDir = path.join(projectDir, "apps/server");
|
|
4011
|
+
const convexBackendDir = path.join(projectDir, "packages/backend");
|
|
4012
|
+
const webClientDirExists = await fs.pathExists(webClientDir);
|
|
4013
|
+
const nativeClientDirExists = await fs.pathExists(nativeClientDir);
|
|
4014
|
+
const serverDirExists = await fs.pathExists(serverDir);
|
|
4015
|
+
const convexBackendDirExists = await fs.pathExists(convexBackendDir);
|
|
4016
|
+
const hasReactWeb = frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("next") || frontend.includes("tanstack-start");
|
|
4017
|
+
const hasNuxt = frontend.includes("nuxt");
|
|
4018
|
+
const hasSvelte = frontend.includes("svelte");
|
|
4019
|
+
const hasReactNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
|
|
4020
|
+
if (backend === "convex" && convexBackendDirExists) await addPackageDependency({
|
|
4021
|
+
dependencies: [
|
|
4022
|
+
"@convex-dev/agent",
|
|
4023
|
+
"ai",
|
|
4024
|
+
"@ai-sdk/google"
|
|
4025
|
+
],
|
|
4026
|
+
projectDir: convexBackendDir
|
|
4027
|
+
});
|
|
4028
|
+
else if (backend === "self" && webClientDirExists) await addPackageDependency({
|
|
4029
|
+
dependencies: ["ai", "@ai-sdk/google"],
|
|
4030
|
+
projectDir: webClientDir
|
|
4031
|
+
});
|
|
4032
|
+
else if (serverDirExists && backend !== "none") await addPackageDependency({
|
|
4033
|
+
dependencies: ["ai", "@ai-sdk/google"],
|
|
4034
|
+
projectDir: serverDir
|
|
4035
|
+
});
|
|
4036
|
+
if (webClientDirExists) {
|
|
4037
|
+
const dependencies = [];
|
|
4038
|
+
if (backend === "convex") {
|
|
4039
|
+
if (hasReactWeb) dependencies.push("@convex-dev/agent", "streamdown");
|
|
4040
|
+
} else {
|
|
4041
|
+
dependencies.push("ai");
|
|
3873
4042
|
if (hasNuxt) dependencies.push("@ai-sdk/vue");
|
|
3874
4043
|
else if (hasSvelte) dependencies.push("@ai-sdk/svelte");
|
|
3875
4044
|
else if (hasReactWeb) dependencies.push("@ai-sdk/react", "streamdown");
|
|
3876
|
-
if (hasNext) dependencies.push("shiki");
|
|
3877
|
-
await addPackageDependency({
|
|
3878
|
-
dependencies,
|
|
3879
|
-
projectDir: webClientDir
|
|
3880
|
-
});
|
|
3881
4045
|
}
|
|
3882
|
-
if (
|
|
3883
|
-
dependencies
|
|
3884
|
-
projectDir: nativeClientDir
|
|
3885
|
-
});
|
|
3886
|
-
if (apiDirExists && backend !== "none") await addPackageDependency({
|
|
3887
|
-
dependencies: ["ai", "@ai-sdk/google"],
|
|
3888
|
-
projectDir: apiDir$1
|
|
3889
|
-
});
|
|
3890
|
-
if (backend === "self" && webClientDirExists) await addPackageDependency({
|
|
3891
|
-
dependencies: ["ai", "@ai-sdk/google"],
|
|
4046
|
+
if (dependencies.length > 0) await addPackageDependency({
|
|
4047
|
+
dependencies,
|
|
3892
4048
|
projectDir: webClientDir
|
|
3893
4049
|
});
|
|
3894
4050
|
}
|
|
4051
|
+
if (nativeClientDirExists && hasReactNative) if (backend === "convex") await addPackageDependency({
|
|
4052
|
+
dependencies: ["@convex-dev/agent"],
|
|
4053
|
+
projectDir: nativeClientDir
|
|
4054
|
+
});
|
|
4055
|
+
else await addPackageDependency({
|
|
4056
|
+
dependencies: ["ai", "@ai-sdk/react"],
|
|
4057
|
+
projectDir: nativeClientDir
|
|
4058
|
+
});
|
|
3895
4059
|
}
|
|
3896
4060
|
|
|
3897
4061
|
//#endregion
|
|
@@ -4089,7 +4253,7 @@ async function setupApi(config) {
|
|
|
4089
4253
|
//#endregion
|
|
4090
4254
|
//#region src/helpers/core/backend-setup.ts
|
|
4091
4255
|
async function setupBackendDependencies(config) {
|
|
4092
|
-
const { backend, runtime, api, auth,
|
|
4256
|
+
const { backend, runtime, api, auth, projectDir } = config;
|
|
4093
4257
|
if (backend === "convex") {
|
|
4094
4258
|
await addPackageDependency({
|
|
4095
4259
|
dependencies: ["convex"],
|
|
@@ -4117,7 +4281,6 @@ async function setupBackendDependencies(config) {
|
|
|
4117
4281
|
else if (framework === "elysia") dependencies.push("@elysiajs/trpc");
|
|
4118
4282
|
} else if (api === "orpc") dependencies.push("@orpc/server", "@orpc/openapi", "@orpc/zod");
|
|
4119
4283
|
if (auth === "better-auth") dependencies.push("better-auth");
|
|
4120
|
-
if (examples.includes("ai")) dependencies.push("ai", "@ai-sdk/google");
|
|
4121
4284
|
if (runtime === "node") devDependencies.push("tsx", "@types/node");
|
|
4122
4285
|
else if (runtime === "bun") devDependencies.push("@types/bun");
|
|
4123
4286
|
if (dependencies.length > 0 || devDependencies.length > 0) await addPackageDependency({
|
|
@@ -4131,7 +4294,7 @@ async function setupBackendDependencies(config) {
|
|
|
4131
4294
|
//#region src/utils/better-auth-plugin-setup.ts
|
|
4132
4295
|
async function setupBetterAuthPlugins(projectDir, config) {
|
|
4133
4296
|
const authIndexPath = `${projectDir}/packages/auth/src/index.ts`;
|
|
4134
|
-
const authIndexFile = tsProject.addSourceFileAtPath(authIndexPath);
|
|
4297
|
+
const authIndexFile = tsProject$1.addSourceFileAtPath(authIndexPath);
|
|
4135
4298
|
if (!authIndexFile) return;
|
|
4136
4299
|
const pluginsToAdd = [];
|
|
4137
4300
|
const importsToAdd = [];
|
|
@@ -4204,12 +4367,12 @@ async function setupAuth(config) {
|
|
|
4204
4367
|
if (convexBackendDirExists) {
|
|
4205
4368
|
await addPackageDependency({
|
|
4206
4369
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4207
|
-
customDependencies: { "better-auth": "1.
|
|
4370
|
+
customDependencies: { "better-auth": "1.4.7" },
|
|
4208
4371
|
projectDir: convexBackendDir
|
|
4209
4372
|
});
|
|
4210
4373
|
if (hasNativeForBA) await addPackageDependency({
|
|
4211
4374
|
dependencies: ["@better-auth/expo"],
|
|
4212
|
-
customDependencies: { "@better-auth/expo": "1.
|
|
4375
|
+
customDependencies: { "@better-auth/expo": "1.4.7" },
|
|
4213
4376
|
projectDir: convexBackendDir
|
|
4214
4377
|
});
|
|
4215
4378
|
}
|
|
@@ -4219,17 +4382,17 @@ async function setupAuth(config) {
|
|
|
4219
4382
|
const hasViteReactOther = frontend.some((f) => ["tanstack-router", "react-router"].includes(f));
|
|
4220
4383
|
if (hasNextJs) await addPackageDependency({
|
|
4221
4384
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4222
|
-
customDependencies: { "better-auth": "1.
|
|
4385
|
+
customDependencies: { "better-auth": "1.4.7" },
|
|
4223
4386
|
projectDir: clientDir
|
|
4224
4387
|
});
|
|
4225
4388
|
else if (hasTanStackStart) await addPackageDependency({
|
|
4226
4389
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4227
|
-
customDependencies: { "better-auth": "1.
|
|
4390
|
+
customDependencies: { "better-auth": "1.4.7" },
|
|
4228
4391
|
projectDir: clientDir
|
|
4229
4392
|
});
|
|
4230
4393
|
else if (hasViteReactOther) await addPackageDependency({
|
|
4231
4394
|
dependencies: ["better-auth", "@convex-dev/better-auth"],
|
|
4232
|
-
customDependencies: { "better-auth": "1.
|
|
4395
|
+
customDependencies: { "better-auth": "1.4.7" },
|
|
4233
4396
|
projectDir: clientDir
|
|
4234
4397
|
});
|
|
4235
4398
|
}
|
|
@@ -4243,8 +4406,8 @@ async function setupAuth(config) {
|
|
|
4243
4406
|
"@convex-dev/better-auth"
|
|
4244
4407
|
],
|
|
4245
4408
|
customDependencies: {
|
|
4246
|
-
"better-auth": "1.
|
|
4247
|
-
"@better-auth/expo": "1.
|
|
4409
|
+
"better-auth": "1.4.7",
|
|
4410
|
+
"@better-auth/expo": "1.4.7"
|
|
4248
4411
|
},
|
|
4249
4412
|
projectDir: nativeDir
|
|
4250
4413
|
});
|
|
@@ -4479,20 +4642,32 @@ async function setupEnvironmentVariables(config) {
|
|
|
4479
4642
|
}
|
|
4480
4643
|
}
|
|
4481
4644
|
if (backend === "convex") {
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4645
|
+
const convexBackendDir = path.join(projectDir, "packages/backend");
|
|
4646
|
+
if (await fs.pathExists(convexBackendDir)) {
|
|
4647
|
+
const envLocalPath = path.join(convexBackendDir, ".env.local");
|
|
4648
|
+
let commentBlocks = "";
|
|
4649
|
+
if (examples?.includes("ai")) commentBlocks += `# Set Google AI API key for AI agent
|
|
4650
|
+
# npx convex env set GOOGLE_GENERATIVE_AI_API_KEY=your_google_api_key
|
|
4651
|
+
|
|
4652
|
+
`;
|
|
4653
|
+
if (auth === "better-auth") commentBlocks += `# Set Convex environment variables
|
|
4654
|
+
# npx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)
|
|
4655
|
+
${hasWebFrontend$1 ? "# npx convex env set SITE_URL http://localhost:3001\n" : ""}`;
|
|
4656
|
+
if (commentBlocks) {
|
|
4657
|
+
let existingContent = "";
|
|
4658
|
+
if (await fs.pathExists(envLocalPath)) existingContent = await fs.readFile(envLocalPath, "utf8");
|
|
4659
|
+
await fs.writeFile(envLocalPath, commentBlocks + existingContent);
|
|
4660
|
+
}
|
|
4661
|
+
const convexBackendVars = [];
|
|
4662
|
+
if (examples?.includes("ai")) convexBackendVars.push({
|
|
4663
|
+
key: "GOOGLE_GENERATIVE_AI_API_KEY",
|
|
4664
|
+
value: "",
|
|
4665
|
+
condition: true,
|
|
4666
|
+
comment: "Google AI API key for AI agent"
|
|
4667
|
+
});
|
|
4668
|
+
if (auth === "better-auth") {
|
|
4486
4669
|
const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
|
|
4487
4670
|
const hasWeb = hasWebFrontend$1;
|
|
4488
|
-
if (!await fs.pathExists(envLocalPath) || !(await fs.readFile(envLocalPath, "utf8")).includes("npx convex env set")) {
|
|
4489
|
-
const convexCommands = `# Set Convex environment variables
|
|
4490
|
-
# npx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)
|
|
4491
|
-
${hasWeb ? "# npx convex env set SITE_URL http://localhost:3001\n" : ""}
|
|
4492
|
-
`;
|
|
4493
|
-
await fs.appendFile(envLocalPath, convexCommands);
|
|
4494
|
-
}
|
|
4495
|
-
const convexBackendVars = [];
|
|
4496
4671
|
if (hasNative) convexBackendVars.push({
|
|
4497
4672
|
key: "EXPO_PUBLIC_CONVEX_SITE_URL",
|
|
4498
4673
|
value: "",
|
|
@@ -4507,10 +4682,11 @@ ${hasWeb ? "# npx convex env set SITE_URL http://localhost:3001\n" : ""}
|
|
|
4507
4682
|
}, {
|
|
4508
4683
|
key: "SITE_URL",
|
|
4509
4684
|
value: "http://localhost:3001",
|
|
4510
|
-
condition: true
|
|
4685
|
+
condition: true,
|
|
4686
|
+
comment: "Web app URL for authentication"
|
|
4511
4687
|
});
|
|
4512
|
-
await addEnvVariablesToFile(envLocalPath, convexBackendVars);
|
|
4513
4688
|
}
|
|
4689
|
+
if (convexBackendVars.length > 0) await addEnvVariablesToFile(envLocalPath, convexBackendVars);
|
|
4514
4690
|
}
|
|
4515
4691
|
return;
|
|
4516
4692
|
}
|
|
@@ -6148,7 +6324,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6148
6324
|
const tauriInstructions = addons?.includes("tauri") ? getTauriInstructions(runCmd) : "";
|
|
6149
6325
|
const huskyInstructions = hasHusky ? getHuskyInstructions(runCmd) : "";
|
|
6150
6326
|
const lintingInstructions = hasLinting ? getLintingInstructions(runCmd) : "";
|
|
6151
|
-
const nativeInstructions = (frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles")) && backend !== "none" ? getNativeInstructions(isConvex, isBackendSelf, frontend || []) : "";
|
|
6327
|
+
const nativeInstructions = (frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles")) && backend !== "none" ? getNativeInstructions(isConvex, isBackendSelf, frontend || [], runCmd) : "";
|
|
6152
6328
|
const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
|
|
6153
6329
|
const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
|
|
6154
6330
|
const clerkInstructions = isConvex && config.auth === "clerk" ? getClerkInstructions() : "";
|
|
@@ -6214,13 +6390,14 @@ async function displayPostInstallInstructions(config) {
|
|
|
6214
6390
|
output += pc.cyan("https://github.com/AmanVarshney01/create-better-t-stack");
|
|
6215
6391
|
consola$1.box(output);
|
|
6216
6392
|
}
|
|
6217
|
-
function getNativeInstructions(isConvex, isBackendSelf,
|
|
6393
|
+
function getNativeInstructions(isConvex, isBackendSelf, frontend, runCmd) {
|
|
6218
6394
|
const envVar = isConvex ? "EXPO_PUBLIC_CONVEX_URL" : "EXPO_PUBLIC_SERVER_URL";
|
|
6219
6395
|
const exampleUrl = isConvex ? "https://<YOUR_CONVEX_URL>" : isBackendSelf ? "http://<YOUR_LOCAL_IP>:3001" : "http://<YOUR_LOCAL_IP>:3000";
|
|
6220
6396
|
const envFileName = ".env";
|
|
6221
6397
|
const ipNote = isConvex ? "your Convex deployment URL (find after running 'dev:setup')" : "your local IP address";
|
|
6222
6398
|
let instructions = `${pc.yellow("NOTE:")} For Expo connectivity issues, update\n apps/native/${envFileName} with ${ipNote}:\n ${`${envVar}=${exampleUrl}`}\n`;
|
|
6223
6399
|
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`;
|
|
6400
|
+
if (frontend.includes("native-unistyles")) instructions += `\n${pc.yellow("NOTE:")} Unistyles requires a development build.\n cd apps/native and run ${runCmd} android or ${runCmd} ios\n`;
|
|
6224
6401
|
return instructions;
|
|
6225
6402
|
}
|
|
6226
6403
|
function getHuskyInstructions(runCmd) {
|
|
@@ -6594,8 +6771,8 @@ async function createProject(options, cliInput) {
|
|
|
6594
6771
|
if (!isConvex) {
|
|
6595
6772
|
if (needsServerSetup) await setupRuntime(options);
|
|
6596
6773
|
await setupDatabase(options, cliInput);
|
|
6597
|
-
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamples(options);
|
|
6598
6774
|
}
|
|
6775
|
+
if (options.examples.length > 0 && options.examples[0] !== "none") await setupExamples(options);
|
|
6599
6776
|
if (options.addons.length > 0 && options.addons[0] !== "none") await setupAddons(options);
|
|
6600
6777
|
if (options.auth && options.auth !== "none") await setupAuth(options);
|
|
6601
6778
|
if (options.payments && options.payments !== "none") await setupPayments(options);
|