create-better-fullstack 1.1.0 → 1.1.1

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/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { o as createBtsCli } from "./src-BkBCdTQg.mjs";
2
+ import { o as createBtsCli } from "./src-uKym6_H1.mjs";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createBtsCli().run();
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { a as create, c as docs, d as sponsors, i as builder, l as generateVirtualProject, n as TEMPLATE_COUNT, o as createBtsCli, r as VirtualFileSystem, s as createVirtual, t as EMBEDDED_TEMPLATES, u as router } from "./src-BkBCdTQg.mjs";
2
+ import { a as create, c as docs, d as sponsors, i as builder, l as generateVirtualProject, n as TEMPLATE_COUNT, o as createBtsCli, r as VirtualFileSystem, s as createVirtual, t as EMBEDDED_TEMPLATES, u as router } from "./src-uKym6_H1.mjs";
3
3
 
4
4
  export { EMBEDDED_TEMPLATES, TEMPLATE_COUNT, VirtualFileSystem, builder, create, createBtsCli, createVirtual, docs, generateVirtualProject, router, sponsors };
@@ -1157,19 +1157,34 @@ async function getApiChoice(Api, frontend, backend, astroIntegration) {
1157
1157
  if (backend === "convex" || backend === "none") return "none";
1158
1158
  const allowed = allowedApisForFrontends(frontend ?? [], astroIntegration);
1159
1159
  if (Api) return allowed.includes(Api) ? Api : allowed[0];
1160
- const apiOptions = allowed.map((a) => a === "trpc" ? {
1161
- value: "trpc",
1162
- label: "tRPC",
1163
- hint: "End-to-end typesafe APIs made easy"
1164
- } : a === "orpc" ? {
1165
- value: "orpc",
1166
- label: "oRPC",
1167
- hint: "End-to-end type-safe APIs that adhere to OpenAPI standards"
1168
- } : {
1169
- value: "none",
1170
- label: "None",
1171
- hint: "No API layer (e.g. for full-stack frameworks like Next.js with Route Handlers)"
1172
- });
1160
+ const apiOptionMap = {
1161
+ trpc: {
1162
+ value: "trpc",
1163
+ label: "tRPC",
1164
+ hint: "End-to-end typesafe APIs made easy"
1165
+ },
1166
+ orpc: {
1167
+ value: "orpc",
1168
+ label: "oRPC",
1169
+ hint: "End-to-end type-safe APIs that adhere to OpenAPI standards"
1170
+ },
1171
+ "ts-rest": {
1172
+ value: "ts-rest",
1173
+ label: "ts-rest",
1174
+ hint: "RPC-like client, contract, and server implementation for REST APIs"
1175
+ },
1176
+ garph: {
1177
+ value: "garph",
1178
+ label: "Garph",
1179
+ hint: "Fullstack GraphQL framework with end-to-end type safety"
1180
+ },
1181
+ none: {
1182
+ value: "none",
1183
+ label: "None",
1184
+ hint: "No API layer (e.g. for full-stack frameworks like Next.js with Route Handlers)"
1185
+ }
1186
+ };
1187
+ const apiOptions = allowed.map((a) => apiOptionMap[a]);
1173
1188
  const apiType = await navigableSelect({
1174
1189
  message: "Select API type",
1175
1190
  options: apiOptions,
@@ -1241,41 +1256,54 @@ async function getAuthChoice(auth, backend, frontend) {
1241
1256
  "native-uniwind",
1242
1257
  "native-unistyles"
1243
1258
  ].includes(f));
1244
- const options = [];
1245
- if (supportedBetterAuthFrontends) options.push({
1259
+ const options$1 = [];
1260
+ if (supportedBetterAuthFrontends) options$1.push({
1246
1261
  value: "better-auth",
1247
1262
  label: "Better-Auth",
1248
1263
  hint: "comprehensive auth framework for TypeScript"
1249
1264
  });
1250
- if (hasClerkCompatibleFrontends) options.push({
1265
+ if (hasClerkCompatibleFrontends) options$1.push({
1251
1266
  value: "clerk",
1252
1267
  label: "Clerk",
1253
1268
  hint: "More than auth, Complete User Management"
1254
1269
  });
1255
- if (options.length === 0) return "none";
1256
- options.push({
1270
+ if (options$1.length === 0) return "none";
1271
+ options$1.push({
1257
1272
  value: "none",
1258
1273
  label: "None",
1259
1274
  hint: "No auth"
1260
1275
  });
1261
1276
  const response$1 = await navigableSelect({
1262
1277
  message: "Select authentication provider",
1263
- options,
1278
+ options: options$1,
1264
1279
  initialValue: "none"
1265
1280
  });
1266
1281
  if (isCancel$1(response$1)) return exitCancelled("Operation cancelled");
1267
1282
  return response$1;
1268
1283
  }
1284
+ const supportsNextAuth = frontend?.includes("next") && backend === "self";
1285
+ const options = [{
1286
+ value: "better-auth",
1287
+ label: "Better-Auth",
1288
+ hint: "comprehensive auth framework for TypeScript"
1289
+ }, {
1290
+ value: "clerk",
1291
+ label: "Clerk",
1292
+ hint: "More than auth, Complete User Management"
1293
+ }];
1294
+ if (supportsNextAuth) options.push({
1295
+ value: "nextauth",
1296
+ label: "Auth.js (NextAuth)",
1297
+ hint: "Authentication for Next.js (formerly NextAuth.js)"
1298
+ });
1299
+ options.push({
1300
+ value: "none",
1301
+ label: "None",
1302
+ hint: "No authentication"
1303
+ });
1269
1304
  const response = await navigableSelect({
1270
1305
  message: "Select authentication provider",
1271
- options: [{
1272
- value: "better-auth",
1273
- label: "Better-Auth",
1274
- hint: "comprehensive auth framework for TypeScript"
1275
- }, {
1276
- value: "none",
1277
- label: "None"
1278
- }],
1306
+ options,
1279
1307
  initialValue: DEFAULT_CONFIG.auth
1280
1308
  });
1281
1309
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
@@ -1319,6 +1347,22 @@ async function getBackendFrameworkChoice(backendFramework, frontends) {
1319
1347
  value: "fets",
1320
1348
  label: "feTS",
1321
1349
  hint: "TypeScript HTTP Framework with e2e type-safety"
1350
+ }, {
1351
+ value: "nestjs",
1352
+ label: "NestJS",
1353
+ hint: "Progressive Node.js framework for scalable applications"
1354
+ }, {
1355
+ value: "adonisjs",
1356
+ label: "AdonisJS",
1357
+ hint: "Full-featured MVC framework for Node.js"
1358
+ }, {
1359
+ value: "nitro",
1360
+ label: "Nitro",
1361
+ hint: "Universal server framework from UnJS"
1362
+ }, {
1363
+ value: "encore",
1364
+ label: "Encore",
1365
+ hint: "Backend development platform with built-in infrastructure"
1322
1366
  });
1323
1367
  if (!hasIncompatibleFrontend) backendOptions.push({
1324
1368
  value: "convex",
@@ -1577,6 +1621,27 @@ async function getDBSetupChoice(databaseType, dbSetup, _orm, backend, runtime) {
1577
1621
  return response;
1578
1622
  }
1579
1623
 
1624
+ //#endregion
1625
+ //#region src/prompts/ecosystem.ts
1626
+ async function getEcosystemChoice(ecosystem) {
1627
+ if (ecosystem !== void 0) return ecosystem;
1628
+ const response = await navigableSelect({
1629
+ message: "Select ecosystem",
1630
+ options: [{
1631
+ value: "typescript",
1632
+ label: "TypeScript",
1633
+ hint: "Full-stack TypeScript with React, Vue, Svelte, and more"
1634
+ }, {
1635
+ value: "rust",
1636
+ label: "Rust",
1637
+ hint: "Rust ecosystem with Axum, Leptos, and more"
1638
+ }],
1639
+ initialValue: "typescript"
1640
+ });
1641
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
1642
+ return response;
1643
+ }
1644
+
1580
1645
  //#endregion
1581
1646
  //#region src/prompts/effect.ts
1582
1647
  async function getEffectChoice(effect) {
@@ -1625,6 +1690,36 @@ async function getEmailChoice(email, backend) {
1625
1690
  label: "React Email",
1626
1691
  hint: "Build emails using React components (no sending service)."
1627
1692
  },
1693
+ {
1694
+ value: "nodemailer",
1695
+ label: "Nodemailer",
1696
+ hint: "Classic Node.js email sending library."
1697
+ },
1698
+ {
1699
+ value: "postmark",
1700
+ label: "Postmark",
1701
+ hint: "Transactional email service with high deliverability."
1702
+ },
1703
+ {
1704
+ value: "sendgrid",
1705
+ label: "SendGrid",
1706
+ hint: "Email delivery and marketing platform by Twilio."
1707
+ },
1708
+ {
1709
+ value: "aws-ses",
1710
+ label: "AWS SES",
1711
+ hint: "Amazon Simple Email Service for scalable email."
1712
+ },
1713
+ {
1714
+ value: "mailgun",
1715
+ label: "Mailgun",
1716
+ hint: "Email API service for sending and tracking emails."
1717
+ },
1718
+ {
1719
+ value: "plunk",
1720
+ label: "Plunk",
1721
+ hint: "Open-source email platform for developers."
1722
+ },
1628
1723
  {
1629
1724
  value: "none",
1630
1725
  label: "None",
@@ -1825,6 +1920,26 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
1825
1920
  value: "tanstack-start",
1826
1921
  label: "TanStack Start",
1827
1922
  hint: "SSR, Server Functions, API Routes and more with TanStack Router"
1923
+ },
1924
+ {
1925
+ value: "qwik",
1926
+ label: "Qwik",
1927
+ hint: "Resumable framework with instant load times"
1928
+ },
1929
+ {
1930
+ value: "angular",
1931
+ label: "Angular",
1932
+ hint: "Enterprise-grade TypeScript framework by Google"
1933
+ },
1934
+ {
1935
+ value: "redwood",
1936
+ label: "RedwoodJS",
1937
+ hint: "Opinionated fullstack (React + GraphQL + Prisma)"
1938
+ },
1939
+ {
1940
+ value: "fresh",
1941
+ label: "Fresh",
1942
+ hint: "Deno-native framework with islands architecture"
1828
1943
  }
1829
1944
  ].filter((option) => isFrontendAllowedWithBackend(option.value, backend, auth)),
1830
1945
  initialValue: DEFAULT_CONFIG.frontend[0]
@@ -2141,18 +2256,37 @@ async function getPackageManagerChoice(packageManager) {
2141
2256
  async function getPaymentsChoice(payments, auth, backend, frontends) {
2142
2257
  if (payments !== void 0) return payments;
2143
2258
  if (backend === "none") return "none";
2144
- if (!(auth === "better-auth" && backend !== "convex" && (frontends?.length === 0 || splitFrontends(frontends).web.length > 0))) return "none";
2259
+ const isPolarCompatible = auth === "better-auth" && backend !== "convex" && (frontends?.length === 0 || splitFrontends(frontends).web.length > 0);
2260
+ const options = [];
2261
+ if (isPolarCompatible) options.push({
2262
+ value: "polar",
2263
+ label: "Polar",
2264
+ hint: "Turn your software into a business. 6 lines of code."
2265
+ });
2266
+ options.push({
2267
+ value: "stripe",
2268
+ label: "Stripe",
2269
+ hint: "Payment processing platform for internet businesses."
2270
+ }, {
2271
+ value: "lemon-squeezy",
2272
+ label: "Lemon Squeezy",
2273
+ hint: "All-in-one platform for SaaS, digital products, and subscriptions."
2274
+ }, {
2275
+ value: "paddle",
2276
+ label: "Paddle",
2277
+ hint: "Complete payments infrastructure for SaaS."
2278
+ }, {
2279
+ value: "dodo",
2280
+ label: "Dodo Payments",
2281
+ hint: "Simple payment infrastructure for developers."
2282
+ }, {
2283
+ value: "none",
2284
+ label: "None",
2285
+ hint: "No payments integration"
2286
+ });
2145
2287
  const response = await navigableSelect({
2146
2288
  message: "Select payments provider",
2147
- options: [{
2148
- value: "polar",
2149
- label: "Polar",
2150
- hint: "Turn your software into a business. 6 lines of code."
2151
- }, {
2152
- value: "none",
2153
- label: "None",
2154
- hint: "No payments integration"
2155
- }],
2289
+ options,
2156
2290
  initialValue: DEFAULT_CONFIG.payments
2157
2291
  });
2158
2292
  if (isCancel$1(response)) return exitCancelled("Operation cancelled");
@@ -2237,6 +2371,181 @@ async function getRuntimeChoice(runtime, backend) {
2237
2371
  return response;
2238
2372
  }
2239
2373
 
2374
+ //#endregion
2375
+ //#region src/prompts/rust-ecosystem.ts
2376
+ async function getRustWebFrameworkChoice(rustWebFramework) {
2377
+ if (rustWebFramework !== void 0) return rustWebFramework;
2378
+ const response = await navigableSelect({
2379
+ message: "Select Rust web framework",
2380
+ options: [
2381
+ {
2382
+ value: "axum",
2383
+ label: "Axum",
2384
+ hint: "Ergonomic and modular web framework from Tokio"
2385
+ },
2386
+ {
2387
+ value: "actix-web",
2388
+ label: "Actix Web",
2389
+ hint: "Powerful, pragmatic, and extremely fast web framework"
2390
+ },
2391
+ {
2392
+ value: "none",
2393
+ label: "None",
2394
+ hint: "No web framework"
2395
+ }
2396
+ ],
2397
+ initialValue: "axum"
2398
+ });
2399
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2400
+ return response;
2401
+ }
2402
+ async function getRustFrontendChoice(rustFrontend) {
2403
+ if (rustFrontend !== void 0) return rustFrontend;
2404
+ const response = await navigableSelect({
2405
+ message: "Select Rust frontend framework",
2406
+ options: [
2407
+ {
2408
+ value: "leptos",
2409
+ label: "Leptos",
2410
+ hint: "Build fast web applications with Rust"
2411
+ },
2412
+ {
2413
+ value: "dioxus",
2414
+ label: "Dioxus",
2415
+ hint: "Fullstack, cross-platform UI library for Rust"
2416
+ },
2417
+ {
2418
+ value: "none",
2419
+ label: "None",
2420
+ hint: "No Rust frontend (API only)"
2421
+ }
2422
+ ],
2423
+ initialValue: "none"
2424
+ });
2425
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2426
+ return response;
2427
+ }
2428
+ async function getRustOrmChoice(rustOrm) {
2429
+ if (rustOrm !== void 0) return rustOrm;
2430
+ const response = await navigableSelect({
2431
+ message: "Select Rust ORM/database layer",
2432
+ options: [
2433
+ {
2434
+ value: "sea-orm",
2435
+ label: "SeaORM",
2436
+ hint: "Async & dynamic ORM for Rust"
2437
+ },
2438
+ {
2439
+ value: "sqlx",
2440
+ label: "SQLx",
2441
+ hint: "Async SQL toolkit with compile-time checked queries"
2442
+ },
2443
+ {
2444
+ value: "none",
2445
+ label: "None",
2446
+ hint: "No database layer"
2447
+ }
2448
+ ],
2449
+ initialValue: "none"
2450
+ });
2451
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2452
+ return response;
2453
+ }
2454
+ async function getRustApiChoice(rustApi) {
2455
+ if (rustApi !== void 0) return rustApi;
2456
+ const response = await navigableSelect({
2457
+ message: "Select Rust API layer",
2458
+ options: [
2459
+ {
2460
+ value: "tonic",
2461
+ label: "Tonic",
2462
+ hint: "gRPC implementation for Rust"
2463
+ },
2464
+ {
2465
+ value: "async-graphql",
2466
+ label: "async-graphql",
2467
+ hint: "High-performance GraphQL server library"
2468
+ },
2469
+ {
2470
+ value: "none",
2471
+ label: "None",
2472
+ hint: "REST API only"
2473
+ }
2474
+ ],
2475
+ initialValue: "none"
2476
+ });
2477
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2478
+ return response;
2479
+ }
2480
+ async function getRustCliChoice(rustCli) {
2481
+ if (rustCli !== void 0) return rustCli;
2482
+ const response = await navigableSelect({
2483
+ message: "Select Rust CLI tools",
2484
+ options: [
2485
+ {
2486
+ value: "clap",
2487
+ label: "Clap",
2488
+ hint: "Command Line Argument Parser for Rust"
2489
+ },
2490
+ {
2491
+ value: "ratatui",
2492
+ label: "Ratatui",
2493
+ hint: "Build rich terminal user interfaces"
2494
+ },
2495
+ {
2496
+ value: "none",
2497
+ label: "None",
2498
+ hint: "No CLI tools"
2499
+ }
2500
+ ],
2501
+ initialValue: "none"
2502
+ });
2503
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2504
+ return response;
2505
+ }
2506
+ async function getRustLibrariesChoice(rustLibraries) {
2507
+ if (rustLibraries !== void 0) return rustLibraries;
2508
+ const response = await navigableMultiselect({
2509
+ message: "Select Rust libraries",
2510
+ options: [
2511
+ {
2512
+ value: "serde",
2513
+ label: "Serde",
2514
+ hint: "Serialization framework for Rust"
2515
+ },
2516
+ {
2517
+ value: "validator",
2518
+ label: "Validator",
2519
+ hint: "Struct validation derive macros"
2520
+ },
2521
+ {
2522
+ value: "jsonwebtoken",
2523
+ label: "jsonwebtoken",
2524
+ hint: "JWT encoding/decoding library"
2525
+ },
2526
+ {
2527
+ value: "argon2",
2528
+ label: "Argon2",
2529
+ hint: "Password hashing library"
2530
+ },
2531
+ {
2532
+ value: "tokio-test",
2533
+ label: "Tokio Test",
2534
+ hint: "Testing utilities for Tokio"
2535
+ },
2536
+ {
2537
+ value: "mockall",
2538
+ label: "Mockall",
2539
+ hint: "Powerful mocking library for Rust"
2540
+ }
2541
+ ],
2542
+ required: false,
2543
+ initialValues: ["serde"]
2544
+ });
2545
+ if (isCancel$1(response)) return exitCancelled("Operation cancelled");
2546
+ return response;
2547
+ }
2548
+
2240
2549
  //#endregion
2241
2550
  //#region src/prompts/server-deploy.ts
2242
2551
  async function getServerDeploymentChoice(deployment, runtime, backend, _webDeploy) {
@@ -2520,46 +2829,158 @@ async function getDeploymentChoice(deployment, _runtime, _backend, frontend = []
2520
2829
  //#region src/prompts/config-prompts.ts
2521
2830
  async function gatherConfig(flags, projectName, projectDir, relativePath) {
2522
2831
  const result = await navigableGroup({
2523
- frontend: () => getFrontendChoice(flags.frontend, flags.backend, flags.auth),
2832
+ ecosystem: () => getEcosystemChoice(flags.ecosystem),
2833
+ frontend: ({ results }) => {
2834
+ if (results.ecosystem === "rust") return Promise.resolve([]);
2835
+ return getFrontendChoice(flags.frontend, flags.backend, flags.auth);
2836
+ },
2524
2837
  astroIntegration: ({ results }) => {
2838
+ if (results.ecosystem === "rust") return Promise.resolve(void 0);
2525
2839
  if (results.frontend?.includes("astro")) return getAstroIntegrationChoice(flags.astroIntegration);
2526
2840
  return Promise.resolve(void 0);
2527
2841
  },
2528
2842
  uiLibrary: ({ results }) => {
2843
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2529
2844
  if (hasWebStyling(results.frontend)) return getUILibraryChoice(flags.uiLibrary, results.frontend);
2530
2845
  return Promise.resolve("none");
2531
2846
  },
2532
2847
  cssFramework: ({ results }) => {
2848
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2533
2849
  if (hasWebStyling(results.frontend)) return getCSSFrameworkChoice(flags.cssFramework, results.uiLibrary);
2534
2850
  return Promise.resolve("none");
2535
2851
  },
2536
- backend: ({ results }) => getBackendFrameworkChoice(flags.backend, results.frontend),
2537
- runtime: ({ results }) => getRuntimeChoice(flags.runtime, results.backend),
2538
- database: ({ results }) => getDatabaseChoice(flags.database, results.backend, results.runtime),
2539
- orm: ({ results }) => getORMChoice(flags.orm, results.database !== "none", results.database, results.backend, results.runtime),
2540
- api: ({ results }) => getApiChoice(flags.api, results.frontend, results.backend, results.astroIntegration),
2541
- auth: ({ results }) => getAuthChoice(flags.auth, results.backend, results.frontend),
2542
- payments: ({ results }) => getPaymentsChoice(flags.payments, results.auth, results.backend, results.frontend),
2543
- email: ({ results }) => getEmailChoice(flags.email, results.backend),
2544
- effect: () => getEffectChoice(flags.effect),
2545
- addons: ({ results }) => getAddonsChoice(flags.addons, results.frontend, results.auth),
2546
- examples: ({ results }) => getExamplesChoice(flags.examples, results.database, results.frontend, results.backend, results.api),
2547
- dbSetup: ({ results }) => getDBSetupChoice(results.database ?? "none", flags.dbSetup, results.orm, results.backend, results.runtime),
2548
- webDeploy: ({ results }) => getDeploymentChoice(flags.webDeploy, results.runtime, results.backend, results.frontend),
2549
- serverDeploy: ({ results }) => getServerDeploymentChoice(flags.serverDeploy, results.runtime, results.backend, results.webDeploy),
2550
- ai: () => getAIChoice(flags.ai),
2551
- validation: () => getValidationChoice(flags.validation),
2552
- forms: ({ results }) => getFormsChoice(flags.forms, results.frontend),
2553
- stateManagement: ({ results }) => getStateManagementChoice(flags.stateManagement, results.frontend),
2554
- animation: ({ results }) => getAnimationChoice(flags.animation, results.frontend),
2555
- testing: () => getTestingChoice(flags.testing),
2556
- realtime: ({ results }) => getRealtimeChoice(flags.realtime, results.backend),
2557
- jobQueue: ({ results }) => getJobQueueChoice(flags.jobQueue, results.backend),
2558
- fileUpload: ({ results }) => getFileUploadChoice(flags.fileUpload, results.backend),
2559
- logging: ({ results }) => getLoggingChoice(flags.logging, results.backend),
2560
- observability: ({ results }) => getObservabilityChoice(flags.observability, results.backend),
2561
- cms: ({ results }) => getCMSChoice(flags.cms, results.backend),
2562
- caching: ({ results }) => getCachingChoice(flags.caching, results.backend),
2852
+ backend: ({ results }) => {
2853
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2854
+ return getBackendFrameworkChoice(flags.backend, results.frontend);
2855
+ },
2856
+ runtime: ({ results }) => {
2857
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2858
+ return getRuntimeChoice(flags.runtime, results.backend);
2859
+ },
2860
+ database: ({ results }) => {
2861
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2862
+ return getDatabaseChoice(flags.database, results.backend, results.runtime);
2863
+ },
2864
+ orm: ({ results }) => {
2865
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2866
+ return getORMChoice(flags.orm, results.database !== "none", results.database, results.backend, results.runtime);
2867
+ },
2868
+ api: ({ results }) => {
2869
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2870
+ return getApiChoice(flags.api, results.frontend, results.backend, results.astroIntegration);
2871
+ },
2872
+ auth: ({ results }) => {
2873
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2874
+ return getAuthChoice(flags.auth, results.backend, results.frontend);
2875
+ },
2876
+ payments: ({ results }) => {
2877
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2878
+ return getPaymentsChoice(flags.payments, results.auth, results.backend, results.frontend);
2879
+ },
2880
+ email: ({ results }) => {
2881
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2882
+ return getEmailChoice(flags.email, results.backend);
2883
+ },
2884
+ effect: ({ results }) => {
2885
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2886
+ return getEffectChoice(flags.effect);
2887
+ },
2888
+ addons: ({ results }) => {
2889
+ if (results.ecosystem === "rust") return Promise.resolve([]);
2890
+ return getAddonsChoice(flags.addons, results.frontend, results.auth);
2891
+ },
2892
+ examples: ({ results }) => {
2893
+ if (results.ecosystem === "rust") return Promise.resolve([]);
2894
+ return getExamplesChoice(flags.examples, results.database, results.frontend, results.backend, results.api);
2895
+ },
2896
+ dbSetup: ({ results }) => {
2897
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2898
+ return getDBSetupChoice(results.database ?? "none", flags.dbSetup, results.orm, results.backend, results.runtime);
2899
+ },
2900
+ webDeploy: ({ results }) => {
2901
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2902
+ return getDeploymentChoice(flags.webDeploy, results.runtime, results.backend, results.frontend);
2903
+ },
2904
+ serverDeploy: ({ results }) => {
2905
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2906
+ return getServerDeploymentChoice(flags.serverDeploy, results.runtime, results.backend, results.webDeploy);
2907
+ },
2908
+ ai: ({ results }) => {
2909
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2910
+ return getAIChoice(flags.ai);
2911
+ },
2912
+ validation: ({ results }) => {
2913
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2914
+ return getValidationChoice(flags.validation);
2915
+ },
2916
+ forms: ({ results }) => {
2917
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2918
+ return getFormsChoice(flags.forms, results.frontend);
2919
+ },
2920
+ stateManagement: ({ results }) => {
2921
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2922
+ return getStateManagementChoice(flags.stateManagement, results.frontend);
2923
+ },
2924
+ animation: ({ results }) => {
2925
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2926
+ return getAnimationChoice(flags.animation, results.frontend);
2927
+ },
2928
+ testing: ({ results }) => {
2929
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2930
+ return getTestingChoice(flags.testing);
2931
+ },
2932
+ realtime: ({ results }) => {
2933
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2934
+ return getRealtimeChoice(flags.realtime, results.backend);
2935
+ },
2936
+ jobQueue: ({ results }) => {
2937
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2938
+ return getJobQueueChoice(flags.jobQueue, results.backend);
2939
+ },
2940
+ fileUpload: ({ results }) => {
2941
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2942
+ return getFileUploadChoice(flags.fileUpload, results.backend);
2943
+ },
2944
+ logging: ({ results }) => {
2945
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2946
+ return getLoggingChoice(flags.logging, results.backend);
2947
+ },
2948
+ observability: ({ results }) => {
2949
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2950
+ return getObservabilityChoice(flags.observability, results.backend);
2951
+ },
2952
+ cms: ({ results }) => {
2953
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2954
+ return getCMSChoice(flags.cms, results.backend);
2955
+ },
2956
+ caching: ({ results }) => {
2957
+ if (results.ecosystem === "rust") return Promise.resolve("none");
2958
+ return getCachingChoice(flags.caching, results.backend);
2959
+ },
2960
+ rustWebFramework: ({ results }) => {
2961
+ if (results.ecosystem === "typescript") return Promise.resolve("none");
2962
+ return getRustWebFrameworkChoice(flags.rustWebFramework);
2963
+ },
2964
+ rustFrontend: ({ results }) => {
2965
+ if (results.ecosystem === "typescript") return Promise.resolve("none");
2966
+ return getRustFrontendChoice(flags.rustFrontend);
2967
+ },
2968
+ rustOrm: ({ results }) => {
2969
+ if (results.ecosystem === "typescript") return Promise.resolve("none");
2970
+ return getRustOrmChoice(flags.rustOrm);
2971
+ },
2972
+ rustApi: ({ results }) => {
2973
+ if (results.ecosystem === "typescript") return Promise.resolve("none");
2974
+ return getRustApiChoice(flags.rustApi);
2975
+ },
2976
+ rustCli: ({ results }) => {
2977
+ if (results.ecosystem === "typescript") return Promise.resolve("none");
2978
+ return getRustCliChoice(flags.rustCli);
2979
+ },
2980
+ rustLibraries: ({ results }) => {
2981
+ if (results.ecosystem === "typescript") return Promise.resolve([]);
2982
+ return getRustLibrariesChoice(flags.rustLibraries);
2983
+ },
2563
2984
  git: () => getGitChoice(flags.git),
2564
2985
  packageManager: () => getPackageManagerChoice(flags.packageManager),
2565
2986
  install: () => getinstallChoice(flags.install)
@@ -2602,13 +3023,13 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
2602
3023
  observability: result.observability,
2603
3024
  cms: result.cms,
2604
3025
  caching: result.caching,
2605
- ecosystem: flags.ecosystem ?? "typescript",
2606
- rustWebFramework: flags.rustWebFramework ?? "none",
2607
- rustFrontend: flags.rustFrontend ?? "none",
2608
- rustOrm: flags.rustOrm ?? "none",
2609
- rustApi: flags.rustApi ?? "none",
2610
- rustCli: flags.rustCli ?? "none",
2611
- rustLibraries: flags.rustLibraries ?? []
3026
+ ecosystem: result.ecosystem,
3027
+ rustWebFramework: result.rustWebFramework,
3028
+ rustFrontend: result.rustFrontend,
3029
+ rustOrm: result.rustOrm,
3030
+ rustApi: result.rustApi,
3031
+ rustCli: result.rustCli,
3032
+ rustLibraries: result.rustLibraries
2612
3033
  };
2613
3034
  }
2614
3035
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-fullstack",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "A CLI-first toolkit for building Full Stack applications. Skip the configuration. Ship the code.",
5
5
  "keywords": [
6
6
  "better-auth",
@@ -62,7 +62,7 @@
62
62
  "scripts": {
63
63
  "build": "tsdown --publint",
64
64
  "dev": "tsdown --watch",
65
- "lint": "oxlint . && tsc --noEmit",
65
+ "lint": "oxlint . && tsc --noEmit && bun test test/cli-builder-sync.test.ts",
66
66
  "check-types": "tsc --noEmit",
67
67
  "test": "bun run build && bun test",
68
68
  "test:watch": "bun run build && bun test --watch",
@@ -72,8 +72,8 @@
72
72
  "prepublishOnly": "npm run build"
73
73
  },
74
74
  "dependencies": {
75
- "@better-fullstack/template-generator": "^1.1.0",
76
- "@better-fullstack/types": "^1.1.0",
75
+ "@better-fullstack/template-generator": "^1.1.1",
76
+ "@better-fullstack/types": "^1.1.1",
77
77
  "@clack/core": "^0.5.0",
78
78
  "@clack/prompts": "^1.0.0-alpha.8",
79
79
  "@orpc/server": "^1.13.0",