create-better-fullstack 2.1.8 → 2.3.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.
Files changed (29) hide show
  1. package/README.md +4 -4
  2. package/dist/{add-handler-ztNjzoMN.mjs → add-handler-z4NCxoq6.mjs} +9 -8
  3. package/dist/addons-setup-COE1e1db.mjs +7 -0
  4. package/dist/{addons-setup-LaAj43NP.mjs → addons-setup-DKtiNexf.mjs} +1 -1
  5. package/dist/{analytics-DVltG11u.mjs → analytics-BD8hZvIj.mjs} +1 -1
  6. package/dist/{bts-config-DQVWvPDs.mjs → bts-config-Bwd6GB7B.mjs} +59 -0
  7. package/dist/cli.mjs +2 -2
  8. package/dist/command-exists-DtX9ldL8.mjs +15 -0
  9. package/dist/{config-processing-D9-F2Us9.mjs → config-processing-B-RT_mVE.mjs} +32 -3
  10. package/dist/{doctor-a4ca3SMd.mjs → doctor-LmNs-hDr.mjs} +4 -3
  11. package/dist/{file-formatter-gvmrpd-g.mjs → file-formatter-DxF56-mO.mjs} +550 -24
  12. package/dist/{gen-CCClL7Ve.mjs → gen-CQfQU0uZ.mjs} +1 -1
  13. package/dist/{generated-checks-BV9jol5h.mjs → generated-checks-BUcI5VM2.mjs} +55 -22
  14. package/dist/index.d.mts +741 -211
  15. package/dist/index.mjs +30 -9
  16. package/dist/{install-dependencies-RoUyaE8o.mjs → install-dependencies-CJiUklm3.mjs} +132 -23
  17. package/dist/{mcp-492OkjcS.mjs → mcp-BBammItk.mjs} +5 -5
  18. package/dist/mcp-entry.mjs +76 -236
  19. package/dist/{registry-DSf2CEaU.mjs → registry-D0JfLCoH.mjs} +1 -1
  20. package/dist/{run-T6g1jkfy.mjs → run-BAIeghcU.mjs} +1948 -318
  21. package/dist/run-CAl4L4uU.mjs +16 -0
  22. package/dist/scaffold-manifest-CQwvyttq.mjs +4 -0
  23. package/dist/{scaffold-manifest-Dyi0voqE.mjs → scaffold-manifest-Dr3Anmlf.mjs} +34 -5
  24. package/dist/{update-DJ8CI5KW.mjs → update-CnrBdWrh.mjs} +182 -25
  25. package/package.json +24 -7
  26. package/dist/addons-setup-DnLjAzTw.mjs +0 -7
  27. package/dist/run-CD8f7PHh.mjs +0 -15
  28. package/dist/scaffold-manifest-DGRyepdb.mjs +0 -4
  29. /package/dist/{update-deps-aD-iQw4U.mjs → update-deps-G3FgqBlW.mjs} +0 -0
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { b as types_exports } from "./bts-config-DQVWvPDs.mjs";
2
+ import { b as types_exports } from "./bts-config-Bwd6GB7B.mjs";
3
3
  import { c as isSilent, i as exitWithError, t as CLIError } from "./errors-ns_o2OKg.mjs";
4
4
  import pc from "picocolors";
5
5
  import z from "zod";
@@ -54,6 +54,7 @@ const CreateCommandOptionsSchema = z.object({
54
54
  mobilePush: types_exports.MobilePushSchema.optional().describe("Mobile push notifications (expo-notifications)"),
55
55
  mobileOTA: types_exports.MobileOTASchema.optional().describe("Mobile OTA updates (expo-updates)"),
56
56
  mobileDeepLinking: types_exports.MobileDeepLinkingSchema.optional().describe("Mobile deep linking (expo-linking)"),
57
+ mobileLibraries: z.array(types_exports.MobileLibrariesSchema).optional().describe("Mobile application libraries"),
57
58
  frontend: z.array(types_exports.FrontendSchema).optional(),
58
59
  astroIntegration: types_exports.AstroIntegrationSchema.optional().describe("Astro UI framework integration (react, vue, svelte, solid)"),
59
60
  addons: z.array(types_exports.AddonsSchema).optional(),
@@ -110,18 +111,31 @@ const CreateCommandOptionsSchema = z.object({
110
111
  pythonRealtime: types_exports.PythonRealtimeSchema.optional().describe("Python realtime (python-socketio, websockets)"),
111
112
  pythonObservability: types_exports.PythonObservabilitySchema.optional().describe("Python observability (opentelemetry)"),
112
113
  pythonCli: z.array(types_exports.PythonCliSchema).optional().describe("Python CLI tooling (typer, click, rich)"),
113
- goWebFramework: types_exports.GoWebFrameworkSchema.optional().describe("Go web framework (gin, echo, fiber)"),
114
- goOrm: types_exports.GoOrmSchema.optional().describe("Go ORM/database (gorm, sqlc)"),
115
- goApi: types_exports.GoApiSchema.optional().describe("Go API layer (grpc-go)"),
114
+ pythonCloudSdk: types_exports.PythonCloudSdkSchema.optional().describe("Python cloud SDK (boto3)"),
115
+ pythonHttpClient: types_exports.PythonHttpClientSchema.optional().describe("Python HTTP client (requests)"),
116
+ pythonData: z.array(types_exports.PythonDataSchema).optional().describe("Python data and scientific libraries (numpy, pandas, scipy)"),
117
+ pythonMedia: types_exports.PythonMediaSchema.optional().describe("Python media library (pillow)"),
118
+ pythonServer: types_exports.PythonServerSchema.optional().describe("Python production server (gunicorn)"),
119
+ pythonPackageManager: types_exports.PythonPackageManagerSchema.optional().describe("Python package manager (uv, poetry)"),
120
+ pythonMessageQueue: types_exports.PythonMessageQueueSchema.optional().describe("Python message queue client (confluent-kafka)"),
121
+ goWebFramework: types_exports.GoWebFrameworkSchema.optional().describe("Go web framework"),
122
+ goOrm: types_exports.GoOrmSchema.optional().describe("Go ORM/database layer"),
123
+ goApi: types_exports.GoApiSchema.optional().describe("Go API layer"),
116
124
  goCli: types_exports.GoCliSchema.optional().describe("Go CLI tools (cobra, bubbletea, urfave-cli)"),
117
125
  goLogging: types_exports.GoLoggingSchema.optional().describe("Go logging (zap, zerolog, slog)"),
118
- goAuth: types_exports.GoAuthSchema.optional().describe("Go auth (casbin, jwt, goth)"),
119
- goTesting: z.array(types_exports.GoTestingSchema).optional().describe("Go testing libraries (testify, gomock)"),
126
+ goAuth: types_exports.GoAuthSchema.optional().describe("Go authentication library"),
127
+ goTesting: z.array(types_exports.GoTestingSchema).optional().describe("Go testing libraries"),
120
128
  goRealtime: types_exports.GoRealtimeSchema.optional().describe("Go realtime library (gorilla-websocket, centrifuge)"),
121
- goMessageQueue: types_exports.GoMessageQueueSchema.optional().describe("Go message queue (nats, watermill)"),
129
+ goMessageQueue: types_exports.GoMessageQueueSchema.optional().describe("Go message queue"),
122
130
  goCaching: types_exports.GoCachingSchema.optional().describe("Go caching library (redis, ristretto)"),
123
131
  goConfig: types_exports.GoConfigSchema.optional().describe("Go config management (viper, koanf)"),
124
- goObservability: types_exports.GoObservabilitySchema.optional().describe("Go observability (opentelemetry)"),
132
+ goObservability: types_exports.GoObservabilitySchema.optional().describe("Go observability"),
133
+ goValidation: types_exports.GoValidationSchema.optional().describe("Go validation"),
134
+ goQuality: types_exports.GoQualitySchema.optional().describe("Go code quality"),
135
+ goMigrations: types_exports.GoMigrationsSchema.optional().describe("Go database migrations"),
136
+ goTemplating: types_exports.GoTemplatingSchema.optional().describe("Go templating"),
137
+ goProtoTooling: types_exports.GoProtoToolingSchema.optional().describe("Go protobuf tooling"),
138
+ goDI: types_exports.GoDISchema.optional().describe("Go dependency injection"),
125
139
  javaWebFramework: types_exports.JavaWebFrameworkSchema.optional().describe("Java web framework (spring-boot, quarkus, none)"),
126
140
  javaLanguage: types_exports.JavaLanguageSchema.optional().describe("JVM language (java, kotlin)"),
127
141
  javaBuildTool: types_exports.JavaBuildToolSchema.optional().describe("Java build tool (maven, gradle, none)"),
@@ -142,6 +156,7 @@ const CreateCommandOptionsSchema = z.object({
142
156
  dotnetValidation: types_exports.DotnetValidationSchema.optional().describe(".NET validation (fluentvalidation, data-annotations)"),
143
157
  dotnetCaching: types_exports.DotnetCachingSchema.optional().describe(".NET caching (redis, memory-cache, none)"),
144
158
  dotnetDeploy: types_exports.DotnetDeploySchema.optional().describe(".NET deploy target (docker, azure, aws, none)"),
159
+ dotnetLibraries: z.array(types_exports.DotnetLibrariesSchema).optional().describe(".NET application libraries"),
145
160
  elixirWebFramework: types_exports.ElixirWebFrameworkSchema.optional().describe("Elixir web framework (phoenix, phoenix-live-view, none)"),
146
161
  elixirOrm: types_exports.ElixirOrmSchema.optional().describe("Elixir ORM/database (ecto, ecto-sql, none)"),
147
162
  elixirAuth: types_exports.ElixirAuthSchema.optional().describe("Elixir auth (phx-gen-auth, ueberauth, guardian, none)"),
@@ -156,6 +171,11 @@ const CreateCommandOptionsSchema = z.object({
156
171
  elixirObservability: types_exports.ElixirObservabilitySchema.optional().describe("Elixir observability (telemetry, opentelemetry, prom_ex, none)"),
157
172
  elixirTesting: types_exports.ElixirTestingSchema.optional().describe("Elixir testing (ex_unit, mox, bypass, wallaby, none)"),
158
173
  elixirQuality: types_exports.ElixirQualitySchema.optional().describe("Elixir code quality (credo, dialyxir, sobelow, none)"),
174
+ elixirI18n: types_exports.ElixirI18nSchema.optional().describe("Elixir localization (gettext, none)"),
175
+ elixirHttpServer: types_exports.ElixirHttpServerSchema.optional().describe("Elixir HTTP server (bandit, cowboy, none)"),
176
+ elixirApplicationFramework: types_exports.ElixirApplicationFrameworkSchema.optional().describe("Elixir application framework (ash, none)"),
177
+ elixirDocumentation: types_exports.ElixirDocumentationSchema.optional().describe("Elixir documentation tooling (ex_doc, none)"),
178
+ elixirClustering: types_exports.ElixirClusteringSchema.optional().describe("Elixir clustering (libcluster, none)"),
159
179
  elixirDeploy: types_exports.ElixirDeploySchema.optional().describe("Elixir deploy target (docker, fly, gigalixir, mix-release, none)"),
160
180
  elixirLibraries: z.array(types_exports.ElixirLibrariesSchema).optional().describe("Elixir libraries (broadway, nx)"),
161
181
  aiDocs: z.array(types_exports.AiDocsSchema).optional().describe("AI documentation files (claude-md, agents-md, cursorrules)")
@@ -350,9 +370,25 @@ function validateWebDeployFrontendTemplates(webDeploy, frontends = []) {
350
370
  function validateServerDeployRequiresBackend(serverDeploy, backend, hasGraphBackend = false) {
351
371
  if (serverDeploy && serverDeploy !== "none" && !hasGraphBackend && (!backend || backend === "none")) exitWithError("'--server-deploy' requires a backend. Please select a backend or set '--server-deploy none'.");
352
372
  }
353
- function validateAddonCompatibility$1(addon, frontend, _auth, backend, runtime, ecosystem, rustFrontend, javaWebFramework, database) {
373
+ function validateAddonCompatibility$1(addon, frontend, _auth, backend, runtime, ecosystem, rustFrontend, javaWebFramework, database, api) {
354
374
  const baseCompatibility = validateAddonCompatibility(addon, frontend, _auth);
355
375
  if (!baseCompatibility.isCompatible) return baseCompatibility;
376
+ if ((addon === "graphql-codegen" || addon === "apollo-client") && api !== void 0 && ![
377
+ "garph",
378
+ "graphql-yoga",
379
+ "apollo-server"
380
+ ].includes(api) && !(addon === "graphql-codegen" && frontend.includes("redwood"))) return {
381
+ isCompatible: false,
382
+ reason: `${addon} requires a GraphQL API selection`
383
+ };
384
+ if (addon === "openapi-typescript" && api !== void 0 && api !== "openapi") return {
385
+ isCompatible: false,
386
+ reason: "openapi-typescript requires the OpenAPI API selection"
387
+ };
388
+ if (addon === "openapi-typescript" && backend === "self") return {
389
+ isCompatible: false,
390
+ reason: "openapi-typescript requires a standalone backend that exposes an OpenAPI schema"
391
+ };
356
392
  if (addon === "backend-utils") {
357
393
  if (ecosystem !== void 0 && ecosystem !== "typescript") return {
358
394
  isCompatible: false,
@@ -400,29 +436,31 @@ function validateAddonCompatibility$1(addon, frontend, _auth, backend, runtime,
400
436
  isCompatible: false,
401
437
  reason: `${title} for Java currently requires Spring Boot`
402
438
  };
403
- if (ecosystem === "python" && database && database !== "none" && database !== "sqlite" && database !== "postgres") return {
439
+ if (ecosystem === "python" && database && database !== "none" && database !== "sqlite" && database !== "postgres" && database !== "mongodb") return {
404
440
  isCompatible: false,
405
- reason: `${title} for Python ORM projects currently supports SQLite defaults or Postgres`
441
+ reason: `${title} for Python ORM projects currently supports SQLite, Postgres, or MongoDB`
406
442
  };
407
443
  }
408
444
  return { isCompatible: true };
409
445
  }
410
- function getCompatibleAddons$1(allAddons, frontend, existingAddons = [], auth, backend, runtime) {
446
+ function getCompatibleAddons$1(allAddons, frontend, existingAddons = [], auth, backend, runtime, api) {
411
447
  return getCompatibleAddons(allAddons, frontend, existingAddons, auth).filter((addon) => {
412
- const { isCompatible } = validateAddonCompatibility$1(addon, frontend, auth, backend, runtime);
448
+ const { isCompatible } = validateAddonCompatibility$1(addon, frontend, auth, backend, runtime, void 0, void 0, void 0, void 0, api);
413
449
  return isCompatible;
414
450
  });
415
451
  }
416
- function validateAddonsAgainstFrontends(addons = [], frontends = [], auth, backend, runtime, ecosystem, rustFrontend, javaWebFramework, database) {
452
+ function validateAddonsAgainstFrontends(addons = [], frontends = [], auth, backend, runtime, ecosystem, rustFrontend, javaWebFramework, database, api) {
417
453
  if (addons.includes("nx") && addons.includes("turborepo")) exitWithError("Nx and Turborepo are alternative workspace runners. Choose one addon.");
418
454
  for (const addon of addons) {
419
455
  if (addon === "none") continue;
420
- const { isCompatible, reason } = validateAddonCompatibility$1(addon, frontends, auth, backend, runtime, ecosystem, rustFrontend, javaWebFramework, database);
456
+ const { isCompatible, reason } = validateAddonCompatibility$1(addon, frontends, auth, backend, runtime, ecosystem, rustFrontend, javaWebFramework, database, api);
421
457
  if (!isCompatible) exitWithError(`Incompatible addon/frontend combination: ${reason}`);
422
458
  }
423
459
  }
424
- function validatePaymentsCompatibility(payments, auth, _backend, frontends = []) {
460
+ function validatePaymentsCompatibility(payments, auth, backend, frontends = []) {
425
461
  if (!payments || payments === "none") return;
462
+ if (payments === "paypal" && !frontends.some((frontend) => frontend !== "none" && isWebFrontend$1(frontend))) exitWithError("PayPal requires a web frontend. Please choose a web frontend or a different payments provider.");
463
+ if (payments === "paypal" && (backend === "none" || backend === "convex")) exitWithError("PayPal checkout requires a standalone or fullstack backend. Please choose a server backend or a different payments provider.");
426
464
  if (payments === "dodo" && frontends.includes("react-vite")) exitWithError("Dodo Payments are not yet supported for React + Vite projects.");
427
465
  if (payments === "polar") {
428
466
  if (!auth || auth === "none" || auth !== "better-auth" && auth !== "better-auth-organizations") exitWithError("Polar payments requires Better Auth. Please use '--auth better-auth' or choose a different payments provider.");
@@ -471,6 +509,25 @@ function validateAIFrontendCompatibility(ai, frontends = []) {
471
509
  if (!issue) return;
472
510
  exitWithError(issue.message);
473
511
  }
512
+ function validateAIBackendCompatibility(ai, backend) {
513
+ if (ai && ["openai-sdk", "anthropic-sdk"].includes(ai) && (backend === "none" || backend === "convex")) exitWithError("Direct AI provider SDKs require a standalone or fullstack backend. Please choose a server backend or another AI integration.");
514
+ }
515
+ function validateRealtimeCompatibility(realtime, backend) {
516
+ if (realtime === "ws" && backend !== "express") exitWithError("The ws integration is currently wired for the Express backend.");
517
+ }
518
+ function validateCSSFrameworkFrontendCompatibility(cssFramework, frontends = []) {
519
+ if (cssFramework !== "styled-components") return;
520
+ const reactFrontends = [
521
+ "tanstack-router",
522
+ "react-router",
523
+ "react-vite",
524
+ "tanstack-start",
525
+ "next",
526
+ "vinext",
527
+ "redwood"
528
+ ];
529
+ if (!frontends.some((frontend) => reactFrontends.includes(frontend))) exitWithError("styled-components requires a React frontend.");
530
+ }
474
531
  /**
475
532
  * Validates that a UI library is compatible with the selected frontend(s)
476
533
  */
@@ -521,8 +578,8 @@ function getCompatibleUILibraries$1(frontends = [], astroIntegration) {
521
578
  /**
522
579
  * Gets list of CSS frameworks compatible with the selected UI library
523
580
  */
524
- function getCompatibleCSSFrameworks$1(uiLibrary) {
525
- return getCompatibleCSSFrameworks(uiLibrary);
581
+ function getCompatibleCSSFrameworks$1(uiLibrary, frontends = []) {
582
+ return getCompatibleCSSFrameworks(uiLibrary, frontends);
526
583
  }
527
584
  /**
528
585
  * Checks if a frontend has web styling (excludes native-only frontends)
@@ -530,6 +587,346 @@ function getCompatibleCSSFrameworks$1(uiLibrary) {
530
587
  function hasWebStyling$1(frontends = []) {
531
588
  return hasWebStyling(frontends);
532
589
  }
590
+ function validateRustExpansionCompatibility(config) {
591
+ if (config.ecosystem !== "rust") return;
592
+ const framework = config.rustWebFramework ?? "none";
593
+ const api = config.rustApi ?? "none";
594
+ const auth = config.rustAuth ?? "none";
595
+ if ((framework === "warp" || framework === "salvo") && !["none", "jsonrpsee"].includes(api)) incompatibilityError({
596
+ message: "Warp and Salvo currently support REST or the standalone jsonrpsee server.",
597
+ provided: {
598
+ "rust-web-framework": framework,
599
+ "rust-api": api
600
+ },
601
+ suggestions: ["Use --rust-api jsonrpsee or --rust-api none", "Use Axum, Actix Web, Rocket, or Poem for Tonic/async-graphql"]
602
+ });
603
+ if (framework === "loco" && api === "jsonrpsee") incompatibilityError({
604
+ message: "Loco owns the server boot sequence and cannot start the generated jsonrpsee server.",
605
+ provided: {
606
+ "rust-web-framework": framework,
607
+ "rust-api": api
608
+ },
609
+ suggestions: ["Use --rust-api none", "Choose Axum, Actix Web, Rocket, Poem, Warp, or Salvo"]
610
+ });
611
+ if (auth === "tower-sessions" && framework !== "axum") incompatibilityError({
612
+ message: "The generated tower-sessions middleware is wired specifically for Axum.",
613
+ provided: {
614
+ "rust-web-framework": framework,
615
+ "rust-auth": auth
616
+ },
617
+ suggestions: ["Use --rust-web-framework axum", "Choose --rust-auth openidconnect or none"]
618
+ });
619
+ const orm = config.rustOrm ?? "none";
620
+ if (auth === "torii" && orm === "rusqlite") incompatibilityError({
621
+ message: "Torii's sqlx-based SQLite storage conflicts with rusqlite: both link the native sqlite3 library and cargo permits only one linker.",
622
+ provided: {
623
+ "rust-orm": orm,
624
+ "rust-auth": auth
625
+ },
626
+ suggestions: ["Use --rust-orm sqlx, sea-orm, or diesel with Torii", "Choose --rust-auth none"]
627
+ });
628
+ }
629
+
630
+ //#endregion
631
+ //#region src/utils/stack-compatibility.ts
632
+ function asString(value, fallback = "none") {
633
+ return typeof value === "string" ? value : fallback;
634
+ }
635
+ function asStringArray(value) {
636
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
637
+ }
638
+ function getCompatibilityBackend(config, webFrontend) {
639
+ if (config.backend !== "self") return asString(config.backend, "hono");
640
+ if (webFrontend.includes("next")) return "self-next";
641
+ if (webFrontend.includes("vinext")) return "self-vinext";
642
+ if (webFrontend.includes("tanstack-start")) return "self-tanstack-start";
643
+ if (webFrontend.includes("astro")) return "self-astro";
644
+ if (webFrontend.includes("nuxt")) return "self-nuxt";
645
+ if (webFrontend.includes("svelte")) return "self-svelte";
646
+ if (webFrontend.includes("solid-start")) return "self-solid-start";
647
+ return "self";
648
+ }
649
+ function getProjectBackendFromCompatibility(backend) {
650
+ return backend.startsWith("self-") ? "self" : backend;
651
+ }
652
+ function hasSelectedTypeScriptBackendPart(config) {
653
+ return config.stackParts?.some((part) => part.source !== "provided" && !part.ownerPartId && part.role === "backend" && part.ecosystem === "typescript" && part.toolId !== "none") ?? false;
654
+ }
655
+ function getCompatibilityEcosystem(config) {
656
+ if (config.ecosystem === "react-native" && hasSelectedTypeScriptBackendPart(config)) return "typescript";
657
+ return config.ecosystem ?? "typescript";
658
+ }
659
+ function buildCompatibilityInputFromConfig(config) {
660
+ const frontend = asStringArray(config.frontend);
661
+ const addons = asStringArray(config.addons);
662
+ const webFrontend = frontend.filter((item) => !item.startsWith("native-") && item !== "none");
663
+ const nativeFrontend = frontend.filter((item) => item.startsWith("native-"));
664
+ const codeQuality = [];
665
+ const documentation = [];
666
+ const appPlatforms = [];
667
+ for (const addon of addons) {
668
+ const binding = (0, types_exports.getAddonStackPartBinding)(addon);
669
+ if (binding?.role === "codeQuality") codeQuality.push(addon);
670
+ else if (binding?.role === "documentation") documentation.push(addon);
671
+ else if (addon !== "none") appPlatforms.push(addon);
672
+ }
673
+ return {
674
+ ecosystem: getCompatibilityEcosystem(config),
675
+ projectName: config.projectName ?? null,
676
+ webFrontend,
677
+ nativeFrontend,
678
+ astroIntegration: asString(config.astroIntegration),
679
+ runtime: asString(config.runtime, "bun"),
680
+ backend: getCompatibilityBackend(config, webFrontend),
681
+ database: asString(config.database),
682
+ orm: asString(config.orm),
683
+ dbSetup: asString(config.dbSetup),
684
+ auth: asString(config.auth),
685
+ payments: asString(config.payments),
686
+ email: asString(config.email),
687
+ fileUpload: asString(config.fileUpload),
688
+ logging: asString(config.logging),
689
+ observability: asString(config.observability),
690
+ featureFlags: asString(config.featureFlags),
691
+ analytics: asString(config.analytics),
692
+ backendLibraries: asString(config.effect),
693
+ stateManagement: asString(config.stateManagement),
694
+ forms: asString(config.forms),
695
+ validation: asString(config.validation),
696
+ testing: asString(config.testing),
697
+ realtime: asString(config.realtime),
698
+ jobQueue: asString(config.jobQueue),
699
+ caching: asString(config.caching),
700
+ rateLimit: asString(config.rateLimit),
701
+ animation: asString(config.animation),
702
+ cssFramework: asString(config.cssFramework),
703
+ uiLibrary: asString(config.uiLibrary),
704
+ shadcnBase: asString(config.shadcnBase, "radix"),
705
+ shadcnStyle: asString(config.shadcnStyle, "nova"),
706
+ shadcnIconLibrary: asString(config.shadcnIconLibrary, "lucide"),
707
+ shadcnColorTheme: asString(config.shadcnColorTheme, "neutral"),
708
+ shadcnBaseColor: asString(config.shadcnBaseColor, "neutral"),
709
+ shadcnFont: asString(config.shadcnFont, "inter"),
710
+ shadcnRadius: asString(config.shadcnRadius, "default"),
711
+ cms: asString(config.cms),
712
+ i18n: asString(config.i18n),
713
+ search: asString(config.search),
714
+ vectorDb: asString(config.vectorDb),
715
+ fileStorage: asString(config.fileStorage),
716
+ mobileNavigation: asString(config.mobileNavigation),
717
+ mobileUI: asString(config.mobileUI),
718
+ mobileStorage: asString(config.mobileStorage),
719
+ mobileTesting: asString(config.mobileTesting),
720
+ mobilePush: asString(config.mobilePush),
721
+ mobileOTA: asString(config.mobileOTA),
722
+ mobileDeepLinking: asString(config.mobileDeepLinking),
723
+ mobileLibraries: asStringArray(config.mobileLibraries),
724
+ codeQuality,
725
+ documentation,
726
+ appPlatforms,
727
+ packageManager: asString(config.packageManager, "bun"),
728
+ workspaceShape: asString(config.workspaceShape, "monorepo"),
729
+ versionChannel: asString(config.versionChannel, "stable"),
730
+ examples: asStringArray(config.examples),
731
+ aiSdk: asString(config.ai),
732
+ aiDocs: asStringArray(config.aiDocs),
733
+ git: "false",
734
+ install: "false",
735
+ api: asString(config.api),
736
+ webDeploy: asString(config.webDeploy),
737
+ serverDeploy: asString(config.serverDeploy),
738
+ yolo: "false",
739
+ rustWebFramework: asString(config.rustWebFramework),
740
+ rustFrontend: asString(config.rustFrontend),
741
+ rustOrm: asString(config.rustOrm),
742
+ rustApi: asString(config.rustApi),
743
+ rustCli: asString(config.rustCli),
744
+ rustLibraries: asStringArray(config.rustLibraries),
745
+ rustLogging: asString(config.rustLogging),
746
+ rustErrorHandling: asString(config.rustErrorHandling),
747
+ rustCaching: asString(config.rustCaching),
748
+ rustAuth: asString(config.rustAuth),
749
+ rustRealtime: asString(config.rustRealtime),
750
+ rustMessageQueue: asString(config.rustMessageQueue),
751
+ rustObservability: asString(config.rustObservability),
752
+ rustTemplating: asString(config.rustTemplating),
753
+ pythonWebFramework: asString(config.pythonWebFramework),
754
+ pythonOrm: asString(config.pythonOrm),
755
+ pythonValidation: asString(config.pythonValidation),
756
+ pythonAi: asStringArray(config.pythonAi),
757
+ pythonAuth: asString(config.pythonAuth),
758
+ pythonApi: asString(config.pythonApi),
759
+ pythonTaskQueue: asString(config.pythonTaskQueue),
760
+ pythonGraphql: asString(config.pythonGraphql),
761
+ pythonQuality: asString(config.pythonQuality),
762
+ pythonTesting: asStringArray(config.pythonTesting),
763
+ pythonCaching: asString(config.pythonCaching),
764
+ pythonRealtime: asString(config.pythonRealtime),
765
+ pythonObservability: asString(config.pythonObservability),
766
+ pythonCli: asStringArray(config.pythonCli),
767
+ pythonCloudSdk: asString(config.pythonCloudSdk),
768
+ pythonHttpClient: asString(config.pythonHttpClient),
769
+ pythonData: asStringArray(config.pythonData),
770
+ pythonMedia: asString(config.pythonMedia),
771
+ pythonServer: asString(config.pythonServer),
772
+ pythonPackageManager: asString(config.pythonPackageManager),
773
+ pythonMessageQueue: asString(config.pythonMessageQueue),
774
+ goWebFramework: asString(config.goWebFramework),
775
+ goOrm: asString(config.goOrm),
776
+ goApi: asString(config.goApi),
777
+ goCli: asString(config.goCli),
778
+ goLogging: asString(config.goLogging),
779
+ goAuth: asString(config.goAuth),
780
+ goTesting: asStringArray(config.goTesting),
781
+ goRealtime: asString(config.goRealtime),
782
+ goMessageQueue: asString(config.goMessageQueue),
783
+ goCaching: asString(config.goCaching),
784
+ goConfig: asString(config.goConfig),
785
+ goObservability: asString(config.goObservability),
786
+ goValidation: asString(config.goValidation),
787
+ goQuality: asString(config.goQuality),
788
+ goMigrations: asString(config.goMigrations),
789
+ goTemplating: asString(config.goTemplating),
790
+ goProtoTooling: asString(config.goProtoTooling),
791
+ goDI: asString(config.goDI),
792
+ javaLanguage: asString(config.javaLanguage, "java"),
793
+ javaWebFramework: asString(config.javaWebFramework),
794
+ javaBuildTool: asString(config.javaBuildTool),
795
+ javaOrm: asString(config.javaOrm),
796
+ javaAuth: asString(config.javaAuth),
797
+ javaApi: asString(config.javaApi),
798
+ javaLogging: asString(config.javaLogging),
799
+ javaLibraries: asStringArray(config.javaLibraries),
800
+ javaTestingLibraries: asStringArray(config.javaTestingLibraries),
801
+ dotnetWebFramework: asString(config.dotnetWebFramework),
802
+ dotnetOrm: asString(config.dotnetOrm),
803
+ dotnetAuth: asString(config.dotnetAuth),
804
+ dotnetApi: asString(config.dotnetApi),
805
+ dotnetTesting: asStringArray(config.dotnetTesting),
806
+ dotnetJobQueue: asString(config.dotnetJobQueue),
807
+ dotnetRealtime: asString(config.dotnetRealtime),
808
+ dotnetObservability: asStringArray(config.dotnetObservability),
809
+ dotnetValidation: asString(config.dotnetValidation),
810
+ dotnetCaching: asString(config.dotnetCaching),
811
+ dotnetDeploy: asString(config.dotnetDeploy),
812
+ dotnetLibraries: asStringArray(config.dotnetLibraries),
813
+ elixirWebFramework: asString(config.elixirWebFramework),
814
+ elixirOrm: asString(config.elixirOrm),
815
+ elixirAuth: asString(config.elixirAuth),
816
+ elixirApi: asString(config.elixirApi),
817
+ elixirRealtime: asString(config.elixirRealtime),
818
+ elixirJobs: asString(config.elixirJobs),
819
+ elixirValidation: asString(config.elixirValidation),
820
+ elixirHttp: asString(config.elixirHttp),
821
+ elixirJson: asString(config.elixirJson),
822
+ elixirEmail: asString(config.elixirEmail),
823
+ elixirCaching: asString(config.elixirCaching),
824
+ elixirObservability: asString(config.elixirObservability),
825
+ elixirTesting: asString(config.elixirTesting),
826
+ elixirQuality: asString(config.elixirQuality),
827
+ elixirI18n: asString(config.elixirI18n),
828
+ elixirHttpServer: asString(config.elixirHttpServer),
829
+ elixirApplicationFramework: asString(config.elixirApplicationFramework),
830
+ elixirDocumentation: asString(config.elixirDocumentation),
831
+ elixirClustering: asString(config.elixirClustering),
832
+ elixirDeploy: asString(config.elixirDeploy),
833
+ elixirLibraries: asStringArray(config.elixirLibraries)
834
+ };
835
+ }
836
+ function compatibilityChangesToProjectConfig(adjusted) {
837
+ const frontend = [...adjusted.webFrontend, ...adjusted.nativeFrontend];
838
+ const ignoredCompatibilityKeys = new Set([
839
+ "webFrontend",
840
+ "nativeFrontend",
841
+ "codeQuality",
842
+ "documentation",
843
+ "appPlatforms",
844
+ "aiSdk",
845
+ "backendLibraries",
846
+ "projectName",
847
+ "git",
848
+ "install",
849
+ "yolo"
850
+ ]);
851
+ const changes = {};
852
+ for (const [key, value] of Object.entries(adjusted)) if (!ignoredCompatibilityKeys.has(key)) changes[key] = value;
853
+ changes.frontend = frontend;
854
+ changes.addons = [
855
+ ...adjusted.codeQuality,
856
+ ...adjusted.documentation,
857
+ ...adjusted.appPlatforms
858
+ ];
859
+ changes.ai = adjusted.aiSdk;
860
+ changes.effect = adjusted.backendLibraries;
861
+ changes.backend = getProjectBackendFromCompatibility(adjusted.backend);
862
+ return changes;
863
+ }
864
+ const EMPTY_ADJUSTMENT_RESULT = {
865
+ changes: {},
866
+ adjustments: []
867
+ };
868
+ const EXPLICIT_NONE_ARRAY_KEYS = new Set([
869
+ "frontend",
870
+ "addons",
871
+ "examples",
872
+ "aiDocs"
873
+ ]);
874
+ const COMPAT_KEY_DISPLAY = {
875
+ webFrontend: "frontend",
876
+ nativeFrontend: "frontend",
877
+ aiSdk: "ai",
878
+ backendLibraries: "effect"
879
+ };
880
+ function formatCompatValue(value) {
881
+ if (Array.isArray(value)) {
882
+ const items = value.filter((item) => item !== "none");
883
+ return items.length > 0 ? items.join(", ") : "none";
884
+ }
885
+ return String(value);
886
+ }
887
+ /**
888
+ * Runs the same auto-adjust engine the web builder and MCP flows use over a
889
+ * (possibly partial) ProjectConfig and maps the result back to config keys.
890
+ *
891
+ * - Only TypeScript/React Native configs are analyzed (mirrors stack-update).
892
+ * - Graph-driven configs (`--part`) are skipped; the stack graph owns those.
893
+ * - With `onlyDefinedKeys`, adjustments are applied only to keys the caller
894
+ * actually set (used for the flag path, where unset keys are resolved by
895
+ * prompts/defaults later and must not be pinned by the engine's defaults).
896
+ */
897
+ function resolveCompatibilityAdjustments(config, options = {}) {
898
+ const ecosystem = config.ecosystem ?? "typescript";
899
+ if (ecosystem !== "typescript" && ecosystem !== "react-native") return EMPTY_ADJUSTMENT_RESULT;
900
+ if (config.stackParts?.length) return EMPTY_ADJUSTMENT_RESULT;
901
+ const input = buildCompatibilityInputFromConfig(config);
902
+ const result = (0, types_exports.analyzeStackCompatibility)(input);
903
+ if (!result.adjustedStack) return EMPTY_ADJUSTMENT_RESULT;
904
+ const mapped = compatibilityChangesToProjectConfig(result.adjustedStack);
905
+ const mappedInput = compatibilityChangesToProjectConfig(input);
906
+ const changes = {};
907
+ for (const [key, value] of Object.entries(mapped)) {
908
+ if (value === void 0) continue;
909
+ if (options.onlyDefinedKeys && config[key] === void 0) continue;
910
+ const next = Array.isArray(value) ? value.filter((item) => item !== "none") : value;
911
+ const before = mappedInput[key];
912
+ const previous = Array.isArray(before) ? before.filter((item) => item !== "none") : before;
913
+ if (JSON.stringify(next) !== JSON.stringify(previous)) changes[key] = Array.isArray(next) && next.length === 0 && EXPLICIT_NONE_ARRAY_KEYS.has(key) ? ["none"] : next;
914
+ }
915
+ if (Object.keys(changes).length === 0) return EMPTY_ADJUSTMENT_RESULT;
916
+ const adjustedStack = result.adjustedStack;
917
+ const inputRecord = input;
918
+ return {
919
+ changes,
920
+ adjustments: result.changes.map((change) => {
921
+ const label = COMPAT_KEY_DISPLAY[change.category] ?? change.category;
922
+ const from = inputRecord[change.category];
923
+ const to = adjustedStack[change.category];
924
+ const fromLabel = formatCompatValue(from);
925
+ const toLabel = formatCompatValue(to);
926
+ return from !== void 0 && fromLabel !== toLabel ? `${label}: ${fromLabel} → ${toLabel} — ${change.message}` : `${label}: ${change.message}`;
927
+ })
928
+ };
929
+ }
533
930
 
534
931
  //#endregion
535
932
  //#region src/utils/peer-dependency-conflicts.ts
@@ -1073,6 +1470,28 @@ function validateEffectBackendConstraints(config) {
1073
1470
  suggestions: ["Use --validation effect-schema"]
1074
1471
  });
1075
1472
  }
1473
+ function validateScopedLibraryFlags(config) {
1474
+ const mobileLibraries = (config.mobileLibraries ?? []).filter((lib) => lib !== "none");
1475
+ const hasNativeFrontend = (config.frontend ?? []).some((f) => String(f).startsWith("native-")) || config.stackParts?.some((part) => part.ecosystem === "react-native");
1476
+ if (mobileLibraries.length > 0 && !hasNativeFrontend) incompatibilityError({
1477
+ message: "Mobile libraries require a native Expo frontend.",
1478
+ provided: {
1479
+ frontend: (config.frontend ?? []).join(" ") || "none",
1480
+ "mobile-libraries": mobileLibraries.join(" ")
1481
+ },
1482
+ suggestions: ["Add a native frontend (native-bare, native-uniwind, native-unistyles)", "Remove --mobile-libraries for web-only stacks"]
1483
+ });
1484
+ const dotnetLibraries = (config.dotnetLibraries ?? []).filter((lib) => lib !== "none");
1485
+ const hasDotnetPart = config.ecosystem === "dotnet" || config.stackParts?.some((part) => part.ecosystem === "dotnet");
1486
+ if (dotnetLibraries.length > 0 && !hasDotnetPart) incompatibilityError({
1487
+ message: ".NET libraries require a .NET backend.",
1488
+ provided: {
1489
+ ecosystem: config.ecosystem ?? "none",
1490
+ "dotnet-libraries": dotnetLibraries.join(" ")
1491
+ },
1492
+ suggestions: ["Use --ecosystem dotnet (or add a .NET graph part) with --dotnet-libraries", "Remove --dotnet-libraries for non-.NET stacks"]
1493
+ });
1494
+ }
1076
1495
  function validateJavaConstraints(config, providedFlags = /* @__PURE__ */ new Set()) {
1077
1496
  if (config.ecosystem !== "java") return;
1078
1497
  const hasSpringBoot = config.javaWebFramework === "spring-boot";
@@ -1115,7 +1534,11 @@ function validateElixirConstraints(config) {
1115
1534
  if (config.ecosystem !== "elixir") return;
1116
1535
  const hasPhoenix = config.elixirWebFramework !== "none";
1117
1536
  const hasEcto = config.elixirOrm !== "none";
1118
- const hasEctoSql = config.elixirOrm === "ecto-sql";
1537
+ const hasEctoSql = [
1538
+ "ecto-sql",
1539
+ "myxql",
1540
+ "ecto_sqlite3"
1541
+ ].includes(config.elixirOrm ?? "none");
1119
1542
  if (!hasPhoenix) {
1120
1543
  const phoenixOnlySelections = [
1121
1544
  {
@@ -1160,13 +1583,51 @@ function validateElixirConstraints(config) {
1160
1583
  provided: { "elixir-json": "none" },
1161
1584
  suggestions: ["Use --elixir-json jason"]
1162
1585
  });
1586
+ if (hasPhoenix && config.elixirHttpServer === "none") incompatibilityError({
1587
+ message: "Phoenix requires an HTTP server adapter.",
1588
+ provided: {
1589
+ "elixir-web-framework": config.elixirWebFramework ?? "none",
1590
+ "elixir-http-server": "none"
1591
+ },
1592
+ suggestions: [
1593
+ "Use --elixir-http-server bandit",
1594
+ "Use --elixir-http-server cowboy",
1595
+ "Use --elixir-web-framework none"
1596
+ ]
1597
+ });
1163
1598
  if (config.elixirAuth === "phx-gen-auth" && !hasEctoSql) incompatibilityError({
1164
- message: "phx.gen.auth requires Ecto SQL with PostgreSQL in the generated Phoenix scaffold.",
1599
+ message: "phx.gen.auth requires an Ecto SQL repository in the generated Phoenix scaffold.",
1165
1600
  provided: {
1166
1601
  "elixir-auth": "phx-gen-auth",
1167
1602
  "elixir-orm": config.elixirOrm ?? "none"
1168
1603
  },
1169
- suggestions: ["Use --elixir-orm ecto-sql", "Use --elixir-auth none"]
1604
+ suggestions: [
1605
+ "Use --elixir-orm ecto-sql",
1606
+ "Use --elixir-orm myxql",
1607
+ "Use --elixir-orm ecto_sqlite3",
1608
+ "Use --elixir-auth none"
1609
+ ]
1610
+ });
1611
+ if (config.elixirAuth === "pow" && (!hasPhoenix || !hasEctoSql)) incompatibilityError({
1612
+ message: "Pow requires Phoenix and an Ecto SQL repository.",
1613
+ provided: {
1614
+ "elixir-web-framework": config.elixirWebFramework ?? "none",
1615
+ "elixir-auth": "pow",
1616
+ "elixir-orm": config.elixirOrm ?? "none"
1617
+ },
1618
+ suggestions: [
1619
+ "Use --elixir-web-framework phoenix",
1620
+ "Use --elixir-orm ecto-sql",
1621
+ "Use --elixir-auth none"
1622
+ ]
1623
+ });
1624
+ if (config.elixirTesting === "ex_machina" && !hasEctoSql) incompatibilityError({
1625
+ message: "ExMachina requires an Ecto SQL repository.",
1626
+ provided: {
1627
+ "elixir-testing": "ex_machina",
1628
+ "elixir-orm": config.elixirOrm ?? "none"
1629
+ },
1630
+ suggestions: ["Use --elixir-orm ecto-sql", "Use --elixir-testing none"]
1170
1631
  });
1171
1632
  if (config.elixirJobs === "oban" && config.elixirOrm !== "ecto-sql") incompatibilityError({
1172
1633
  message: "Oban requires Ecto SQL with PostgreSQL in the generated Phoenix scaffold.",
@@ -1343,6 +1804,59 @@ function validatePythonApiConstraints(config) {
1343
1804
  suggestions: ["Use --python-web-framework django with --python-api django-rest-framework or django-ninja", "Set --python-api none for FastAPI, Flask, Litestar, or no Python web framework"]
1344
1805
  });
1345
1806
  }
1807
+ function validatePythonExpansionConstraints(config) {
1808
+ const pythonConfig = config.ecosystem === "python" ? config : config.stackParts?.some((part) => part.role === "backend" && part.ecosystem === "python" && part.source !== "provided") ? (0, types_exports.stackGraphToLegacyProjectConfigForEcosystem)(config, "python") : void 0;
1809
+ if (!pythonConfig) return;
1810
+ config = pythonConfig;
1811
+ if (config.pythonOrm === "pymongo" && config.database !== "mongodb") incompatibilityError({
1812
+ message: "PyMongo requires --database mongodb.",
1813
+ provided: {
1814
+ database: config.database || "none",
1815
+ "python-orm": "pymongo"
1816
+ },
1817
+ suggestions: ["Add --database mongodb when using --python-orm pymongo", "Choose another --python-orm for relational databases"]
1818
+ });
1819
+ if (config.database === "mongodb" && config.pythonOrm !== "pymongo" && config.pythonOrm !== "none" && config.pythonOrm !== void 0) incompatibilityError({
1820
+ message: "MongoDB requires --python-orm pymongo (relational ORMs cannot use it).",
1821
+ provided: {
1822
+ database: "mongodb",
1823
+ "python-orm": config.pythonOrm
1824
+ },
1825
+ suggestions: ["Use --python-orm pymongo with --database mongodb", "Choose a relational database (postgres, sqlite, mysql) for this ORM"]
1826
+ });
1827
+ if ((config.pythonWebFramework === "none" || config.pythonWebFramework === "aiohttp" || config.pythonWebFramework === "starlette" || config.pythonWebFramework === "streamlit") && config.pythonGraphql !== void 0 && config.pythonGraphql !== "none") incompatibilityError({
1828
+ message: "Python GraphQL is only wired for FastAPI, Django, Flask, and Litestar.",
1829
+ provided: {
1830
+ "python-web-framework": config.pythonWebFramework,
1831
+ "python-graphql": config.pythonGraphql
1832
+ },
1833
+ suggestions: ["Use FastAPI, Django, Flask, or Litestar with --python-graphql", "Set --python-graphql none"]
1834
+ });
1835
+ if ((config.pythonWebFramework === "none" || config.pythonWebFramework === "aiohttp" || config.pythonWebFramework === "starlette" || config.pythonWebFramework === "streamlit") && config.pythonAuth !== void 0 && config.pythonAuth !== "none") incompatibilityError({
1836
+ message: `Python auth routes are not wired for ${config.pythonWebFramework}.`,
1837
+ provided: {
1838
+ "python-web-framework": config.pythonWebFramework,
1839
+ "python-auth": config.pythonAuth
1840
+ },
1841
+ suggestions: ["Use FastAPI, Django, Flask, or Litestar with --python-auth", "Set --python-auth none"]
1842
+ });
1843
+ if ((config.pythonWebFramework === "streamlit" || config.pythonWebFramework === "none") && config.pythonObservability === "prometheus-client") incompatibilityError({
1844
+ message: "prometheus-client needs an HTTP server framework to expose /metrics.",
1845
+ provided: {
1846
+ "python-web-framework": config.pythonWebFramework,
1847
+ "python-observability": "prometheus-client"
1848
+ },
1849
+ suggestions: ["Use FastAPI, Django, Flask, Litestar, Starlette, or aiohttp", "Set --python-observability none"]
1850
+ });
1851
+ if (config.pythonServer === "gunicorn" && (config.pythonWebFramework === "streamlit" || config.pythonWebFramework === "none")) incompatibilityError({
1852
+ message: "Gunicorn requires a WSGI, ASGI, or aiohttp Python application.",
1853
+ provided: {
1854
+ "python-web-framework": config.pythonWebFramework,
1855
+ "python-server": "gunicorn"
1856
+ },
1857
+ suggestions: ["Use FastAPI, Django, Flask, Litestar, or aiohttp with --python-server gunicorn", "Set --python-server none for Streamlit or framework-free projects"]
1858
+ });
1859
+ }
1346
1860
  function validateI18nConstraints(config) {
1347
1861
  if (config.i18n !== "intlayer") return;
1348
1862
  const { web } = splitFrontends$1(config.frontend ?? []);
@@ -1374,6 +1888,8 @@ function validateFullConfig(config, providedFlags, options) {
1374
1888
  validateFrontendConstraints(config, providedFlags);
1375
1889
  validateApiConstraints(config, options);
1376
1890
  validatePythonApiConstraints(config);
1891
+ validatePythonExpansionConstraints(config);
1892
+ validateRustExpansionCompatibility(config);
1377
1893
  validateEmailConstraints(config);
1378
1894
  validateObservabilityConstraints(config);
1379
1895
  validateCachingConstraints(config);
@@ -1381,6 +1897,7 @@ function validateFullConfig(config, providedFlags, options) {
1381
1897
  validateSearchConstraints(config);
1382
1898
  validateJavaConstraints(config, providedFlags);
1383
1899
  validateElixirConstraints(config);
1900
+ validateScopedLibraryFlags(config);
1384
1901
  validateI18nConstraints(config);
1385
1902
  const hasGraphBackend = config.stackParts?.some((part) => part.role === "backend" && !part.ownerPartId && part.source !== "provided" && part.ecosystem !== "typescript" && part.ecosystem !== "react-native" && part.ecosystem !== "universal");
1386
1903
  if (!(providedFlags.has("serverDeploy") && !options.yes && !options.part?.length && options.ecosystem === void 0 && options.backend === void 0 && config.stackParts === void 0)) validateServerDeployRequiresBackend(config.serverDeploy, config.backend, Boolean(hasGraphBackend));
@@ -1419,12 +1936,15 @@ function validateFullConfig(config, providedFlags, options) {
1419
1936
  });
1420
1937
  }
1421
1938
  if (config.addons && config.addons.length > 0) {
1422
- validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth, config.backend, config.runtime, config.ecosystem, config.rustFrontend, config.javaWebFramework, config.database);
1939
+ validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth, config.backend, config.runtime, config.ecosystem, config.rustFrontend, config.javaWebFramework, config.database, config.api);
1423
1940
  config.addons = [...new Set(config.addons)];
1424
1941
  }
1425
1942
  validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? [], config.runtime, config.ai);
1426
1943
  validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend ?? []);
1427
1944
  validateAIFrontendCompatibility(config.ai, config.frontend ?? []);
1945
+ validateAIBackendCompatibility(config.ai, config.backend);
1946
+ validateRealtimeCompatibility(config.realtime, config.backend);
1947
+ validateCSSFrameworkFrontendCompatibility(config.cssFramework, config.frontend ?? []);
1428
1948
  validateUILibraryFrontendCompatibility(config.uiLibrary, config.frontend ?? [], config.astroIntegration);
1429
1949
  validateUILibraryCSSFrameworkCompatibility(config.uiLibrary, config.cssFramework);
1430
1950
  validateShadcnConstraints(config, providedFlags);
@@ -1442,6 +1962,7 @@ function validateConfigForProgrammaticUse(config) {
1442
1962
  if (config.frontend && config.frontend.length > 0) ensureSingleWebAndNative(config.frontend);
1443
1963
  validateApiFrontendCompatibility(config.api, config.frontend, config.astroIntegration);
1444
1964
  validatePythonApiConstraints(config);
1965
+ validatePythonExpansionConstraints(config);
1445
1966
  validateEmailConstraints(config);
1446
1967
  validateObservabilityConstraints(config);
1447
1968
  validateCachingConstraints(config);
@@ -1449,11 +1970,16 @@ function validateConfigForProgrammaticUse(config) {
1449
1970
  validateSearchConstraints(config);
1450
1971
  validateJavaConstraints(config);
1451
1972
  validateElixirConstraints(config);
1973
+ validateRustExpansionCompatibility(config);
1974
+ validateScopedLibraryFlags(config);
1452
1975
  validateI18nConstraints(config);
1453
1976
  validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend);
1454
- if (config.addons && config.addons.length > 0) validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth, config.backend, config.runtime, config.ecosystem, config.rustFrontend, config.javaWebFramework, config.database);
1977
+ if (config.addons && config.addons.length > 0) validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth, config.backend, config.runtime, config.ecosystem, config.rustFrontend, config.javaWebFramework, config.database, config.api);
1455
1978
  validateExamplesCompatibility(config.examples ?? [], config.backend, config.frontend ?? [], config.runtime, config.ai);
1456
1979
  validateAIFrontendCompatibility(config.ai, config.frontend ?? []);
1980
+ validateAIBackendCompatibility(config.ai, config.backend);
1981
+ validateRealtimeCompatibility(config.realtime, config.backend);
1982
+ validateCSSFrameworkFrontendCompatibility(config.cssFramework, config.frontend ?? []);
1457
1983
  validateUILibraryFrontendCompatibility(config.uiLibrary, config.frontend ?? [], config.astroIntegration);
1458
1984
  validateUILibraryCSSFrameworkCompatibility(config.uiLibrary, config.cssFramework);
1459
1985
  validatePeerDependencies(config);
@@ -1497,4 +2023,4 @@ async function formatProject(projectDir) {
1497
2023
  }
1498
2024
 
1499
2025
  //#endregion
1500
- export { CreateCommandInputSchema as _, allowedApisForFrontends$1 as a, getCompatibleUILibraries$1 as c, isExampleChatSdkAllowed$1 as d, isFrontendAllowedWithBackend$1 as f, validateAddonCompatibility$1 as g, splitFrontends$1 as h, validateFullConfig as i, hasWebStyling$1 as l, requiresChatSdkVercelAI as m, formatProject as n, getCompatibleAddons$1 as o, isWebFrontend$1 as p, validateConfigForProgrammaticUse as r, getCompatibleCSSFrameworks$1 as s, formatCode as t, isExampleAIAllowed$1 as u, CreateCommandOptionsSchema as v };
2026
+ export { CreateCommandInputSchema as C, validateAddonCompatibility$1 as S, isExampleChatSdkAllowed$1 as _, asString as a, requiresChatSdkVercelAI as b, compatibilityChangesToProjectConfig as c, allowedApisForFrontends$1 as d, getCompatibleAddons$1 as f, isExampleAIAllowed$1 as g, hasWebStyling$1 as h, validateFullConfig as i, getCompatibilityBackend as l, getCompatibleUILibraries$1 as m, formatProject as n, asStringArray as o, getCompatibleCSSFrameworks$1 as p, validateConfigForProgrammaticUse as r, buildCompatibilityInputFromConfig as s, formatCode as t, resolveCompatibilityAdjustments as u, isFrontendAllowedWithBackend$1 as v, CreateCommandOptionsSchema as w, splitFrontends$1 as x, isWebFrontend$1 as y };