@better-fullstack/types 2.3.1 → 2.5.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 (45) hide show
  1. package/LICENSE +22 -0
  2. package/dist/{defaults-Cl16mM84.mjs → defaults-BzWJP6p0.mjs} +3 -1
  3. package/dist/defaults-BzWJP6p0.mjs.map +1 -0
  4. package/dist/{defaults-BCprHCB6.d.mts → defaults-CbLlpynl.d.mts} +2 -2
  5. package/dist/defaults-CbLlpynl.d.mts.map +1 -0
  6. package/dist/defaults.d.mts +3 -3
  7. package/dist/defaults.mjs +1 -1
  8. package/dist/index.d.mts +6 -6
  9. package/dist/index.d.mts.map +1 -1
  10. package/dist/index.mjs +69 -5
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/json-schema.d.mts +518 -20
  13. package/dist/json-schema.d.mts.map +1 -1
  14. package/dist/json-schema.mjs +1 -1
  15. package/dist/{schemas-B79HRN5e.d.mts → schemas-BRAokgPa.d.mts} +520 -27
  16. package/dist/schemas-BRAokgPa.d.mts.map +1 -0
  17. package/dist/{schemas-CprYz5Sh.mjs → schemas-CtieNRfz.mjs} +74 -3
  18. package/dist/schemas-CtieNRfz.mjs.map +1 -0
  19. package/dist/schemas.d.mts +2 -2
  20. package/dist/schemas.mjs +2 -2
  21. package/dist/{stack-graph-BkHZlyKH.d.mts → stack-graph-BPw9KsNm.d.mts} +3 -3
  22. package/dist/stack-graph-BPw9KsNm.d.mts.map +1 -0
  23. package/dist/{stack-graph-DiLi3WuL.mjs → stack-graph-CXTiPofQ.mjs} +205 -27
  24. package/dist/stack-graph-CXTiPofQ.mjs.map +1 -0
  25. package/dist/stack-graph.d.mts +3 -3
  26. package/dist/stack-graph.mjs +2 -2
  27. package/dist/{stack-translation-Ay-_1mNB.mjs → stack-translation-B-zArJLM.mjs} +433 -29
  28. package/dist/stack-translation-B-zArJLM.mjs.map +1 -0
  29. package/dist/{stack-translation-BmsX82IA.d.mts → stack-translation-D7KkQm8W.d.mts} +30 -9
  30. package/dist/stack-translation-D7KkQm8W.d.mts.map +1 -0
  31. package/dist/stack-translation.d.mts +4 -4
  32. package/dist/stack-translation.mjs +3 -3
  33. package/dist/{types-BuRzqsRV.d.mts → types-Br0NsnBr.d.mts} +10 -3
  34. package/dist/types-Br0NsnBr.d.mts.map +1 -0
  35. package/dist/types.d.mts +3 -3
  36. package/package.json +3 -2
  37. package/dist/defaults-BCprHCB6.d.mts.map +0 -1
  38. package/dist/defaults-Cl16mM84.mjs.map +0 -1
  39. package/dist/schemas-B79HRN5e.d.mts.map +0 -1
  40. package/dist/schemas-CprYz5Sh.mjs.map +0 -1
  41. package/dist/stack-graph-BkHZlyKH.d.mts.map +0 -1
  42. package/dist/stack-graph-DiLi3WuL.mjs.map +0 -1
  43. package/dist/stack-translation-Ay-_1mNB.mjs.map +0 -1
  44. package/dist/stack-translation-BmsX82IA.d.mts.map +0 -1
  45. package/dist/types-BuRzqsRV.d.mts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { $r as PYTHON_MEDIA_VALUES, A as CSS_FRAMEWORK_VALUES, An as GO_TESTING_VALUES, At as ELIXIR_VALIDATION_VALUES, B as DOTNET_JOB_QUEUE_VALUES, Bi as RUST_AUTH_VALUES, Br as ORM_VALUES, Cn as GO_MIGRATIONS_VALUES, Cr as MOBILE_LIBRARIES_VALUES, Dn as GO_QUALITY_VALUES, Dr as MOBILE_STORAGE_VALUES, Dt as ELIXIR_QUALITY_VALUES, En as GO_PROTO_TOOLING_VALUES, Er as MOBILE_PUSH_VALUES, Et as ELIXIR_ORM_VALUES, G as DOTNET_TESTING_VALUES, Ga as UI_LIBRARY_VALUES, Gi as RUST_LIBRARIES_VALUES, Gr as PYTHON_API_VALUES, H as DOTNET_OBSERVABILITY_VALUES, Hi as RUST_CLI_VALUES, I as DOTNET_API_VALUES, Ia as StackPartRoleSchema, Ii as RATE_LIMIT_VALUES, Ji as RUST_OBSERVABILITY_VALUES, Jr as PYTHON_CLI_VALUES, K as DOTNET_VALIDATION_VALUES, Ka as VALIDATION_VALUES, Ki as RUST_LOGGING_VALUES, Kr as PYTHON_AUTH_VALUES, L as DOTNET_AUTH_VALUES, Li as REALTIME_VALUES, Mn as GO_WEB_FRAMEWORK_VALUES, Mt as EMAIL_VALUES, N as DATABASE_SETUP_VALUES, Nt as EXAMPLES_VALUES, O as CMS_VALUES, On as GO_REALTIME_VALUES, Or as MOBILE_TESTING_VALUES, Ot as ELIXIR_REALTIME_VALUES, P as DATABASE_VALUES, Qa as WEB_DEPLOY_VALUES, Qi as RUST_WEB_FRAMEWORK_VALUES, Qr as PYTHON_HTTP_CLIENT_VALUES, R as DOTNET_CACHING_VALUES, Ri as RUNTIME_VALUES, Rr as OBSERVABILITY_VALUES, Sn as GO_MESSAGE_QUEUE_VALUES, Sr as MOBILE_DEEP_LINKING_VALUES, St as ELIXIR_JOBS_VALUES, T as CACHING_VALUES, Ta as STATE_MANAGEMENT_VALUES, Tn as GO_ORM_VALUES, Tr as MOBILE_OTA_VALUES, Tt as ELIXIR_OBSERVABILITY_VALUES, U as DOTNET_ORM_VALUES, Ui as RUST_ERROR_HANDLING_VALUES, Ur as PAYMENTS_VALUES, V as DOTNET_LIBRARIES_VALUES, Va as TESTING_VALUES, Vi as RUST_CACHING_VALUES, W as DOTNET_REALTIME_VALUES, Wi as RUST_FRONTEND_VALUES, Wr as PYTHON_AI_VALUES, Xi as RUST_REALTIME_VALUES, Xr as PYTHON_DATA_VALUES, Yi as RUST_ORM_VALUES, Yr as PYTHON_CLOUD_SDK_VALUES, Zi as RUST_TEMPLATING_VALUES, Zn as I18N_VALUES, Zr as PYTHON_GRAPHQL_VALUES, _a as SERVER_DEPLOY_VALUES, _n as GO_CACHING_VALUES, _t as ELIXIR_DOCUMENTATION_VALUES, a as ANALYTICS_VALUES, ai as PYTHON_REALTIME_VALUES, an as FEATURE_FLAGS_VALUES, ar as JAVA_LOGGING_VALUES, bn as GO_DI_VALUES, br as LOGGING_VALUES, bt as ELIXIR_HTTP_VALUES, c as API_VALUES, ci as PYTHON_TESTING_VALUES, cn as FORMS_VALUES, cr as JAVA_WEB_FRAMEWORK_VALUES, d as AUTH_VALUES, dt as ELIXIR_API_VALUES, ei as PYTHON_MESSAGE_QUEUE_VALUES, er as JAVA_API_VALUES, ft as ELIXIR_APPLICATION_FRAMEWORK_VALUES, ga as SEARCH_VALUES, gn as GO_AUTH_VALUES, gt as ELIXIR_DEPLOY_VALUES, hn as GO_API_VALUES, ht as ELIXIR_CLUSTERING_VALUES, i as AI_VALUES, ii as PYTHON_QUALITY_VALUES, ir as JAVA_LIBRARIES_VALUES, jn as GO_VALIDATION_VALUES, jt as ELIXIR_WEB_FRAMEWORK_VALUES, kn as GO_TEMPLATING_VALUES, kr as MOBILE_UI_VALUES, kt as ELIXIR_TESTING_VALUES, l as APP_PLATFORM_ADDON_VALUES, li as PYTHON_VALIDATION_VALUES, ln as FRONTEND_VALUES, lr as JOB_QUEUE_VALUES, mt as ELIXIR_CACHING_VALUES, ni as PYTHON_ORM_VALUES, nr as JAVA_BUILD_TOOL_VALUES, o as ANIMATION_VALUES, oi as PYTHON_SERVER_VALUES, on as FILE_STORAGE_VALUES, or as JAVA_ORM_VALUES, pt as ELIXIR_AUTH_VALUES, q as DOTNET_WEB_FRAMEWORK_VALUES, qa as VECTOR_DB_VALUES, qi as RUST_MESSAGE_QUEUE_VALUES, qr as PYTHON_CACHING_VALUES, ri as PYTHON_PACKAGE_MANAGER_VALUES, rr as JAVA_LANGUAGE_VALUES, si as PYTHON_TASK_QUEUE_VALUES, sn as FILE_UPLOAD_VALUES, sr as JAVA_TESTING_LIBRARIES_VALUES, t as ADDONS_VALUES, ti as PYTHON_OBSERVABILITY_VALUES, tr as JAVA_AUTH_VALUES, ui as PYTHON_WEB_FRAMEWORK_VALUES, ut as EFFECT_VALUES, vn as GO_CLI_VALUES, vt as ELIXIR_EMAIL_VALUES, wn as GO_OBSERVABILITY_VALUES, wr as MOBILE_NAVIGATION_VALUES, wt as ELIXIR_LIBRARIES_VALUES, xn as GO_LOGGING_VALUES, xt as ELIXIR_I18N_VALUES, y as BACKEND_VALUES, yn as GO_CONFIG_VALUES, yt as ELIXIR_HTTP_SERVER_VALUES, z as DOTNET_DEPLOY_VALUES, zi as RUST_API_VALUES } from "./schemas-CprYz5Sh.mjs";
1
+ import { $i as RUST_CACHING_VALUES, A as CSS_FRAMEWORK_VALUES, An as GO_OBSERVABILITY_VALUES, At as ELIXIR_OBSERVABILITY_VALUES, B as DOTNET_DEPLOY_VALUES, Br as MOBILE_TESTING_VALUES, Cn as GO_CACHING_VALUES, Ct as ELIXIR_EMAIL_VALUES, Dn as GO_LOGGING_VALUES, Dt as ELIXIR_JOBS_VALUES, En as GO_DI_VALUES, Et as ELIXIR_I18N_VALUES, F as DATABASE_VALUES, Fn as GO_TEMPLATING_VALUES, Fr as MOBILE_LIBRARIES_VALUES, Ft as ELIXIR_VALIDATION_VALUES, G as DOTNET_ORM_VALUES, H as DOTNET_JOB_QUEUE_VALUES, In as GO_TESTING_VALUES, Ir as MOBILE_NAVIGATION_VALUES, It as ELIXIR_WEB_FRAMEWORK_VALUES, J as DOTNET_VALIDATION_VALUES, Ji as RATE_LIMIT_VALUES, K as DOTNET_REALTIME_VALUES, L as DOTNET_API_VALUES, La as STATE_MANAGEMENT_VALUES, Ln as GO_VALIDATION_VALUES, Lr as MOBILE_OTA_VALUES, Lt as EMAIL_VALUES, Mn as GO_PROTO_TOOLING_VALUES, Mr as LOGGING_VALUES, Mt as ELIXIR_QUALITY_VALUES, N as DART_MOBILE_VALUES, Nn as GO_QUALITY_VALUES, Nt as ELIXIR_REALTIME_VALUES, O as CMS_VALUES, Oa as SEARCH_VALUES, On as GO_MESSAGE_QUEUE_VALUES, Or as KOTLIN_MOBILE_LIBRARIES_VALUES, P as DATABASE_SETUP_VALUES, Pn as GO_REALTIME_VALUES, Pr as MOBILE_DEEP_LINKING_VALUES, Pt as ELIXIR_TESTING_VALUES, Qi as RUST_AUTH_VALUES, Qr as ORM_VALUES, R as DOTNET_AUTH_VALUES, Ra as SWIFT_MOBILE_VALUES, Rn as GO_WEB_FRAMEWORK_VALUES, Rr as MOBILE_PUSH_VALUES, Rt as EXAMPLES_VALUES, Si as PYTHON_WEB_FRAMEWORK_VALUES, Sn as GO_AUTH_VALUES, St as ELIXIR_DOCUMENTATION_VALUES, T as CACHING_VALUES, Tn as GO_CONFIG_VALUES, Tt as ELIXIR_HTTP_VALUES, U as DOTNET_LIBRARIES_VALUES, V as DOTNET_FRONTEND_VALUES, Vr as MOBILE_UI_VALUES, W as DOTNET_OBSERVABILITY_VALUES, Xi as RUNTIME_VALUES, Xr as OBSERVABILITY_VALUES, Y as DOTNET_WEB_FRAMEWORK_VALUES, Ya as StackPartRoleSchema, Yi as REALTIME_VALUES, Zi as RUST_API_VALUES, _i as PYTHON_REALTIME_VALUES, _r as JOB_QUEUE_VALUES, _t as ELIXIR_APPLICATION_FRAMEWORK_VALUES, a as ANALYTICS_VALUES, aa as RUST_MESSAGE_QUEUE_VALUES, ai as PYTHON_CACHING_VALUES, ao as UI_LIBRARY_VALUES, ar as INTEGRATIONS_VALUES, bi as PYTHON_TESTING_VALUES, bt as ELIXIR_CLUSTERING_VALUES, c as API_VALUES, ca as RUST_REALTIME_VALUES, ci as PYTHON_DATA_VALUES, cr as JAVA_API_VALUES, d as AUTH_VALUES, di as PYTHON_MEDIA_VALUES, dn as FEATURE_FLAGS_VALUES, dr as JAVA_LANGUAGE_VALUES, ea as RUST_CLI_VALUES, fi as PYTHON_MESSAGE_QUEUE_VALUES, fn as FILE_STORAGE_VALUES, fo as WEB_DEPLOY_VALUES, fr as JAVA_LIBRARIES_VALUES, gi as PYTHON_QUALITY_VALUES, gr as JAVA_WEB_FRAMEWORK_VALUES, gt as ELIXIR_API_VALUES, hi as PYTHON_PACKAGE_MANAGER_VALUES, hn as FRONTEND_VALUES, hr as JAVA_TESTING_LIBRARIES_VALUES, ht as EFFECT_VALUES, i as AI_VALUES, ia as RUST_LOGGING_VALUES, ii as PYTHON_AUTH_VALUES, jn as GO_ORM_VALUES, jt as ELIXIR_ORM_VALUES, ka as SERVER_DEPLOY_VALUES, kn as GO_MIGRATIONS_VALUES, kr as KOTLIN_MOBILE_VALUES, kt as ELIXIR_LIBRARIES_VALUES, l as APP_PLATFORM_ADDON_VALUES, la as RUST_TEMPLATING_VALUES, li as PYTHON_GRAPHQL_VALUES, lr as JAVA_AUTH_VALUES, mi as PYTHON_ORM_VALUES, mn as FORMS_VALUES, mr as JAVA_ORM_VALUES, na as RUST_FRONTEND_VALUES, ni as PYTHON_AI_VALUES, o as ANIMATION_VALUES, oa as RUST_OBSERVABILITY_VALUES, oi as PYTHON_CLI_VALUES, oo as VALIDATION_VALUES, pi as PYTHON_OBSERVABILITY_VALUES, pn as FILE_UPLOAD_VALUES, pr as JAVA_LOGGING_VALUES, pt as ECOMMERCE_VALUES, q as DOTNET_TESTING_VALUES, ra as RUST_LIBRARIES_VALUES, ri as PYTHON_API_VALUES, rr as I18N_VALUES, sa as RUST_ORM_VALUES, si as PYTHON_CLOUD_SDK_VALUES, so as VECTOR_DB_VALUES, t as ADDONS_VALUES, ta as RUST_ERROR_HANDLING_VALUES, ti as PAYMENTS_VALUES, to as TESTING_VALUES, ua as RUST_WEB_FRAMEWORK_VALUES, ui as PYTHON_HTTP_CLIENT_VALUES, ur as JAVA_BUILD_TOOL_VALUES, vi as PYTHON_SERVER_VALUES, vt as ELIXIR_AUTH_VALUES, wn as GO_CLI_VALUES, wt as ELIXIR_HTTP_SERVER_VALUES, xi as PYTHON_VALIDATION_VALUES, xn as GO_API_VALUES, xt as ELIXIR_DEPLOY_VALUES, y as BACKEND_VALUES, yi as PYTHON_TASK_QUEUE_VALUES, yt as ELIXIR_CACHING_VALUES, z as DOTNET_CACHING_VALUES, zr as MOBILE_STORAGE_VALUES } from "./schemas-CtieNRfz.mjs";
2
2
 
3
3
  //#region src/stack-compatibility-rules.ts
4
4
  const WEB_FRAMEWORKS = [
@@ -534,6 +534,8 @@ const LEGACY_TYPESCRIPT_BACKEND_SINGLE_CATEGORIES = {
534
534
  rateLimit: "rateLimit",
535
535
  fileStorage: "fileStorage",
536
536
  featureFlags: "featureFlags",
537
+ integrations: "integrations",
538
+ ecommerce: "ecommerce",
537
539
  payments: "payments",
538
540
  realtime: "realtime",
539
541
  ai: "ai",
@@ -559,6 +561,8 @@ const LEGACY_TYPESCRIPT_FRONTEND_SINGLE_CATEGORIES = {
559
561
  };
560
562
  const LEGACY_DATABASE_SINGLE_CATEGORIES = { dbSetup: "dbSetup" };
561
563
  const LEGACY_MOBILE_SINGLE_CATEGORIES = {
564
+ auth: "auth",
565
+ payments: "payments",
562
566
  navigation: "mobileNavigation",
563
567
  ui: "mobileUI",
564
568
  storage: "mobileStorage",
@@ -595,8 +599,10 @@ const CODE_QUALITY_ADDONS = new Set([
595
599
  "oxlint",
596
600
  "ultracite",
597
601
  "lefthook",
598
- "husky"
602
+ "husky",
603
+ "gitleaks"
599
604
  ]);
605
+ const TYPESCRIPT_CODE_QUALITY_ADDONS = new Set(["knip"]);
600
606
  const DOCUMENTATION_ADDONS = new Set(["starlight", "fumadocs"]);
601
607
  const FRONTEND_APP_PLATFORM_ADDONS = new Set(APP_PLATFORM_ADDON_VALUES);
602
608
  const FRONTEND_DATA_FETCHING_ADDONS = new Set([
@@ -616,6 +622,7 @@ const WORKSPACE_TOOLING_ADDONS = new Set([
616
622
  "nx",
617
623
  "docker-compose",
618
624
  "devcontainer",
625
+ "kong",
619
626
  "github-actions",
620
627
  "ruler",
621
628
  "mcp",
@@ -649,6 +656,7 @@ const LEGACY_ARRAY_CATEGORIES = new Set([
649
656
  "javaLibraries",
650
657
  "javaTestingLibraries",
651
658
  "mobileLibraries",
659
+ "kotlinMobileLibraries",
652
660
  "dotnetLibraries",
653
661
  "dotnetTesting",
654
662
  "dotnetObservability",
@@ -659,6 +667,10 @@ const LEGACY_ARRAY_CATEGORIES = new Set([
659
667
  "elixirLibraries"
660
668
  ]);
661
669
  function getAddonStackPartBinding(toolId) {
670
+ if (TYPESCRIPT_CODE_QUALITY_ADDONS.has(toolId)) return {
671
+ role: "codeQuality",
672
+ ecosystem: "typescript"
673
+ };
662
674
  if (CODE_QUALITY_ADDONS.has(toolId)) return {
663
675
  role: "codeQuality",
664
676
  ecosystem: "universal"
@@ -702,6 +714,12 @@ const OWNER_ROLES_BY_SCOPED_ROLE = {
702
714
  ...Object.fromEntries(Object.keys(LEGACY_TYPESCRIPT_FRONTEND_SINGLE_CATEGORIES).map((role) => [role, ["frontend"]])),
703
715
  ...Object.fromEntries([...Object.keys(LEGACY_MOBILE_SINGLE_CATEGORIES), ...Object.keys(LEGACY_MOBILE_ARRAY_CATEGORIES)].map((role) => [role, ["mobile"]])),
704
716
  deploy: ["frontend", "backend"],
717
+ auth: [
718
+ "frontend",
719
+ "backend",
720
+ "mobile"
721
+ ],
722
+ payments: ["backend", "mobile"],
705
723
  dbSetup: ["database"],
706
724
  migrations: ["backend"],
707
725
  ui: ["frontend", "mobile"],
@@ -905,6 +923,7 @@ const GRAPH_PROJECTION_DEFAULT_LEGACY_CATEGORIES = [
905
923
  ...Object.values(LEGACY_DATABASE_SINGLE_CATEGORIES),
906
924
  ...Object.values(LEGACY_MOBILE_SINGLE_CATEGORIES),
907
925
  ...Object.values(LEGACY_MOBILE_ARRAY_CATEGORIES),
926
+ "kotlinMobileLibraries",
908
927
  ...Object.values(LEGACY_EXTRA_CATEGORIES_BY_ECOSYSTEM).flatMap((categories) => Object.values(categories)),
909
928
  ...Object.values(LEGACY_SHARED_BACKEND_SINGLE_CATEGORIES_BY_ECOSYSTEM).flatMap((categories) => Object.values(categories))
910
929
  ];
@@ -946,6 +965,10 @@ const STACK_TOOL_DEFINITIONS = [
946
965
  allowMultiple: true,
947
966
  ownerless: true
948
967
  }),
968
+ ...defineTools(ADDONS_VALUES.filter((value) => TYPESCRIPT_CODE_QUALITY_ADDONS.has(value)), "codeQuality", "typescript", void 0, {
969
+ allowMultiple: true,
970
+ ownerless: true
971
+ }),
949
972
  ...defineTools(ADDONS_VALUES.filter((value) => DOCUMENTATION_ADDONS.has(value)), "documentation", "universal", void 0, {
950
973
  allowMultiple: true,
951
974
  ownerless: true
@@ -973,6 +996,8 @@ const STACK_TOOL_DEFINITIONS = [
973
996
  ...defineTools(RATE_LIMIT_VALUES, "rateLimit", "typescript", "rateLimit"),
974
997
  ...defineTools(FILE_STORAGE_VALUES, "fileStorage", "typescript", "fileStorage"),
975
998
  ...defineTools(FEATURE_FLAGS_VALUES, "featureFlags", "typescript", "featureFlags"),
999
+ ...defineTools(INTEGRATIONS_VALUES, "integrations", "typescript", "integrations"),
1000
+ ...defineTools(ECOMMERCE_VALUES, "ecommerce", "typescript", "ecommerce"),
976
1001
  ...defineTools(PAYMENTS_VALUES, "payments", "typescript", "payments"),
977
1002
  ...defineTools(REALTIME_VALUES, "realtime", "typescript", "realtime"),
978
1003
  ...defineTools(AI_VALUES, "ai", "typescript", "ai"),
@@ -981,6 +1006,7 @@ const STACK_TOOL_DEFINITIONS = [
981
1006
  ...defineTools(EFFECT_VALUES, "effect", "typescript", "effect"),
982
1007
  ...defineTools(TESTING_VALUES, "testing", "typescript", "testing"),
983
1008
  ...defineTools(AUTH_VALUES, "auth", "react-native", "auth"),
1009
+ ...defineTools(["revenuecat"], "payments", "react-native", "payments"),
984
1010
  ...defineTools(MOBILE_NAVIGATION_VALUES, "navigation", "react-native", "mobileNavigation"),
985
1011
  ...defineTools(MOBILE_UI_VALUES, "ui", "react-native", "mobileUI"),
986
1012
  ...defineTools(MOBILE_STORAGE_VALUES, "storage", "react-native", "mobileStorage"),
@@ -991,6 +1017,11 @@ const STACK_TOOL_DEFINITIONS = [
991
1017
  ...defineTools(MOBILE_LIBRARIES_VALUES, "libraries", "react-native", "mobileLibraries", { allowMultiple: true }),
992
1018
  ...defineTools(RUST_WEB_FRAMEWORK_VALUES, "backend", "rust", "rustWebFramework"),
993
1019
  ...defineTools(RUST_FRONTEND_VALUES, "frontend", "rust", "rustFrontend"),
1020
+ ...defineTools(DOTNET_FRONTEND_VALUES, "frontend", "dotnet", "dotnetFrontend"),
1021
+ ...defineTools(KOTLIN_MOBILE_VALUES, "mobile", "kotlin", "kotlinMobile"),
1022
+ ...defineTools(KOTLIN_MOBILE_LIBRARIES_VALUES, "libraries", "kotlin", "kotlinMobileLibraries", { allowMultiple: true }),
1023
+ ...defineTools(SWIFT_MOBILE_VALUES, "mobile", "swift", "swiftMobile"),
1024
+ ...defineTools(DART_MOBILE_VALUES, "mobile", "dart", "dartMobile"),
994
1025
  ...defineTools(RUST_ORM_VALUES, "orm", "rust", "rustOrm"),
995
1026
  ...defineTools(RUST_API_VALUES, "api", "rust", "rustApi"),
996
1027
  ...defineTools(RUST_AUTH_VALUES, "auth", "rust", "rustAuth"),
@@ -1321,6 +1352,13 @@ function createTypeScriptBackendCompatibilityIssue(part, context) {
1321
1352
  message: "Dodo Payments are not yet supported for React + Vite projects."
1322
1353
  });
1323
1354
  }
1355
+ if (part.role === "payments" && part.toolId === "xendit" && (context.ownerToolId === "none" || context.ownerToolId === "convex")) return createStackGraphIssue({
1356
+ code: "INCOMPATIBLE_OWNER_TOOL",
1357
+ partId: part.id,
1358
+ role: part.role,
1359
+ toolId: part.toolId,
1360
+ message: "Xendit Payment Sessions require a server backend."
1361
+ });
1324
1362
  if (part.role === "email" && part.toolId !== "none" && context.ownerToolId === "convex") return createStackGraphIssue({
1325
1363
  code: "INCOMPATIBLE_OWNER_TOOL",
1326
1364
  partId: part.id,
@@ -1335,6 +1373,31 @@ function createTypeScriptBackendCompatibilityIssue(part, context) {
1335
1373
  toolId: part.toolId,
1336
1374
  message: "Rate limiting helpers are not generated with Convex backend"
1337
1375
  });
1376
+ if (part.role === "integrations" && part.toolId === "nango") {
1377
+ if (context.ownerToolId === "none") return createStackGraphIssue({
1378
+ code: "INCOMPATIBLE_OWNER_TOOL",
1379
+ partId: part.id,
1380
+ role: part.role,
1381
+ toolId: part.toolId,
1382
+ message: "Nango integrations require a generated backend."
1383
+ });
1384
+ if (context.ownerToolId === "convex") return createStackGraphIssue({
1385
+ code: "INCOMPATIBLE_OWNER_TOOL",
1386
+ partId: part.id,
1387
+ role: part.role,
1388
+ toolId: part.toolId,
1389
+ message: "Nango integrations are not available with the Convex backend."
1390
+ });
1391
+ const runtimeTool = context.siblingToolIdsByRole?.runtime;
1392
+ const deployTools = context.selectedToolIdsByRoleList?.deploy ?? [];
1393
+ if (runtimeTool === "workers" || context.ownerToolId === "self" && deployTools.includes("cloudflare")) return createStackGraphIssue({
1394
+ code: "INCOMPATIBLE_GRAPH_SELECTION",
1395
+ partId: part.id,
1396
+ role: part.role,
1397
+ toolId: part.toolId,
1398
+ message: "Nango's Node SDK is not available on Cloudflare Workers."
1399
+ });
1400
+ }
1338
1401
  if (part.role === "cms" && part.toolId === "payload") {
1339
1402
  if (context.primaryToolIdsByRole?.frontend !== "next") return createStackGraphIssue({
1340
1403
  code: "INCOMPATIBLE_GRAPH_SELECTION",
@@ -1692,8 +1755,8 @@ function createAddonCompatibilityIssue(part, context) {
1692
1755
  toolId: part.toolId,
1693
1756
  message: "Choose either Turborepo or Nx, not both"
1694
1757
  });
1695
- if (part.toolId === "docker-compose" || part.toolId === "devcontainer") {
1696
- const title = part.toolId === "devcontainer" ? "DevContainer" : "Docker Compose";
1758
+ if (part.toolId === "docker-compose" || part.toolId === "devcontainer" || part.toolId === "kong") {
1759
+ const title = part.toolId === "devcontainer" ? "DevContainer" : part.toolId === "kong" ? "Kong Gateway" : "Docker Compose";
1697
1760
  const databaseTool = context.primaryToolIdsByRole?.database;
1698
1761
  const primaryEcosystem = backendEcosystem ?? frontendEcosystem ?? context.settings?.ecosystem;
1699
1762
  const hasCompatibleEcosystem = [
@@ -1715,6 +1778,27 @@ function createAddonCompatibilityIssue(part, context) {
1715
1778
  toolId: part.toolId,
1716
1779
  message: `${title} is not compatible with Cloudflare Workers runtime.`
1717
1780
  });
1781
+ if (backendEcosystem && !DOCKER_COMPOSE_COMPATIBLE_ECOSYSTEMS.has(backendEcosystem)) return createStackGraphIssue({
1782
+ code: "INCOMPATIBLE_GRAPH_SELECTION",
1783
+ partId: part.id,
1784
+ role: part.role,
1785
+ toolId: part.toolId,
1786
+ message: `${title} does not yet provide a container template for ${backendEcosystem} backends.`
1787
+ });
1788
+ if (part.toolId === "kong" && primaryEcosystem === "typescript" && (!backendTool || backendTool === "none")) return createStackGraphIssue({
1789
+ code: "INCOMPATIBLE_GRAPH_SELECTION",
1790
+ partId: part.id,
1791
+ role: part.role,
1792
+ toolId: part.toolId,
1793
+ message: "Kong Gateway requires a TypeScript backend service."
1794
+ });
1795
+ if (part.toolId === "kong" && primaryEcosystem !== "typescript" && primaryEcosystem !== "java" && (!backendTool || backendTool === "none")) return createStackGraphIssue({
1796
+ code: "INCOMPATIBLE_GRAPH_SELECTION",
1797
+ partId: part.id,
1798
+ role: part.role,
1799
+ toolId: part.toolId,
1800
+ message: `Kong Gateway requires a ${primaryEcosystem ?? "supported"} HTTP server.`
1801
+ });
1718
1802
  if (!hasCompatibleEcosystem) return createStackGraphIssue({
1719
1803
  code: "INCOMPATIBLE_GRAPH_SELECTION",
1720
1804
  partId: part.id,
@@ -1729,12 +1813,45 @@ function createAddonCompatibilityIssue(part, context) {
1729
1813
  toolId: part.toolId,
1730
1814
  message: `${title} currently supports Next.js, TanStack Router, React Router, React Vite, Solid, or Astro.`
1731
1815
  });
1732
- if (backendEcosystem === "typescript" && backendTool === "self" && frontendTool !== "next") return createStackGraphIssue({
1816
+ if (backendEcosystem === "typescript" && backendTool === "self" && frontendTool !== "next" && frontendTool !== "vinext") return createStackGraphIssue({
1817
+ code: "INCOMPATIBLE_GRAPH_SELECTION",
1818
+ partId: part.id,
1819
+ role: part.role,
1820
+ toolId: part.toolId,
1821
+ message: `${title} self-backend support currently requires Next.js or Vinext.`
1822
+ });
1823
+ if (part.toolId === "kong" && primaryEcosystem === "rust" && (apiTool === "tonic" || apiTool === "jsonrpsee")) return createStackGraphIssue({
1824
+ code: "INCOMPATIBLE_GRAPH_SELECTION",
1825
+ partId: part.id,
1826
+ role: part.role,
1827
+ toolId: part.toolId,
1828
+ message: "Kong Gateway currently requires an HTTP Rust API."
1829
+ });
1830
+ if (part.toolId === "kong" && primaryEcosystem === "rust" && backendTool === "loco") return createStackGraphIssue({
1831
+ code: "INCOMPATIBLE_GRAPH_SELECTION",
1832
+ partId: part.id,
1833
+ role: part.role,
1834
+ toolId: part.toolId,
1835
+ message: "Kong Gateway does not yet support Loco's container configuration."
1836
+ });
1837
+ if (part.toolId === "kong" && primaryEcosystem === "go" && apiTool !== void 0 && [
1838
+ "connect-go",
1839
+ "grpc-gateway",
1840
+ "oapi-codegen",
1841
+ "grpc-go"
1842
+ ].includes(apiTool)) return createStackGraphIssue({
1843
+ code: "INCOMPATIBLE_GRAPH_SELECTION",
1844
+ partId: part.id,
1845
+ role: part.role,
1846
+ toolId: part.toolId,
1847
+ message: "Kong Gateway currently requires the primary Go HTTP server API."
1848
+ });
1849
+ if (part.toolId === "kong" && primaryEcosystem === "java" && apiTool === "grpc") return createStackGraphIssue({
1733
1850
  code: "INCOMPATIBLE_GRAPH_SELECTION",
1734
1851
  partId: part.id,
1735
1852
  role: part.role,
1736
1853
  toolId: part.toolId,
1737
- message: `${title} self-backend support currently requires Next.js.`
1854
+ message: "Kong Gateway currently requires the primary Java HTTP API."
1738
1855
  });
1739
1856
  if (frontendEcosystem === "rust" && frontendTool && frontendTool !== "none") return createStackGraphIssue({
1740
1857
  code: "INCOMPATIBLE_GRAPH_SELECTION",
@@ -1750,12 +1867,12 @@ function createAddonCompatibilityIssue(part, context) {
1750
1867
  toolId: part.toolId,
1751
1868
  message: `${title} for Java currently requires Spring Boot.`
1752
1869
  });
1753
- if (primaryEcosystem === "python" && databaseTool && databaseTool !== "none" && databaseTool !== "sqlite" && databaseTool !== "postgres") return createStackGraphIssue({
1870
+ if (primaryEcosystem === "python" && databaseTool && databaseTool !== "none" && databaseTool !== "sqlite" && databaseTool !== "postgres" && databaseTool !== "mongodb") return createStackGraphIssue({
1754
1871
  code: "INCOMPATIBLE_GRAPH_SELECTION",
1755
1872
  partId: part.id,
1756
1873
  role: part.role,
1757
1874
  toolId: part.toolId,
1758
- message: `${title} for Python ORM projects currently supports SQLite defaults or Postgres.`
1875
+ message: `${title} for Python ORM projects currently supports SQLite, Postgres, or MongoDB.`
1759
1876
  });
1760
1877
  }
1761
1878
  if (part.toolId === "backend-utils") {
@@ -2114,40 +2231,55 @@ function parseRolePath(rolePath) {
2114
2231
  const rawRole = segments.length === 1 ? segments[0] : segments[segments.length - 1];
2115
2232
  const rawOwnerRole = segments.length > 1 ? segments[0] : void 0;
2116
2233
  const role = StackPartRoleSchema.parse(rawRole);
2117
- const ownerRole = rawOwnerRole ? StackPartRoleSchema.parse(rawOwnerRole) : void 0;
2118
- if (ownerRole && !PRIMARY_ROLES.has(ownerRole)) throw new Error(`Stack part owner role '${ownerRole}' must be a primary role.`);
2234
+ if (!rawOwnerRole) return { role };
2235
+ const parsedOwnerRole = StackPartRoleSchema.safeParse(rawOwnerRole);
2236
+ if (parsedOwnerRole.success && PRIMARY_ROLES.has(parsedOwnerRole.data)) return {
2237
+ role,
2238
+ ownerRole: parsedOwnerRole.data
2239
+ };
2119
2240
  return {
2120
2241
  role,
2121
- ownerRole
2242
+ ownerPartId: sanitizePartId(rawOwnerRole)
2122
2243
  };
2123
2244
  }
2124
2245
  function parseStackPartSpecs(specs, source = "selected") {
2125
2246
  const unresolved = specs.map((spec) => {
2126
2247
  const [rolePath, ecosystem, toolId, customId] = spec.split(":");
2127
2248
  if (!rolePath || !ecosystem || !toolId || spec.split(":").length > 4) throw new Error(`Invalid --part '${spec}'. Use role:ecosystem:tool or owner.role:ecosystem:tool.`);
2128
- const { role, ownerRole } = parseRolePath(rolePath);
2249
+ const { role, ownerRole, ownerPartId } = parseRolePath(rolePath);
2129
2250
  return {
2130
2251
  role,
2131
2252
  ownerRole,
2253
+ ownerPartId,
2132
2254
  ecosystem,
2133
2255
  toolId,
2134
2256
  customId
2135
2257
  };
2136
2258
  });
2137
- const primaryParts = unresolved.filter((part) => !part.ownerRole).map((part) => createStackPart({
2259
+ const unresolvedPrimaryParts = unresolved.filter((part) => !part.ownerRole && !part.ownerPartId);
2260
+ const primaryRoleCounts = /* @__PURE__ */ new Map();
2261
+ for (const part of unresolvedPrimaryParts) primaryRoleCounts.set(part.role, (primaryRoleCounts.get(part.role) ?? 0) + 1);
2262
+ const repeatedTargetRoot = {
2263
+ frontend: "apps",
2264
+ backend: "services",
2265
+ mobile: "apps",
2266
+ database: "data"
2267
+ };
2268
+ const primaryParts = unresolvedPrimaryParts.map((part) => createStackPart({
2138
2269
  role: part.role,
2139
2270
  ecosystem: part.ecosystem,
2140
2271
  toolId: part.toolId,
2141
2272
  source,
2142
- id: part.customId
2273
+ id: part.customId,
2274
+ targetPath: (primaryRoleCounts.get(part.role) ?? 0) > 1 && PRIMARY_ROLES.has(part.role) ? `${repeatedTargetRoot[part.role]}/${sanitizePartId(part.customId ?? `${part.ecosystem}-${part.toolId}`).replaceAll(":", "-")}` : void 0
2143
2275
  }));
2144
2276
  const primaryByRole = new Map(primaryParts.map((part) => [part.role, part]));
2145
2277
  const primaryByRoleAndEcosystem = new Map(primaryParts.map((part) => [`${part.role}:${part.ecosystem}`, part]));
2146
- const scopedParts = unresolved.filter((part) => part.ownerRole !== void 0).map((part) => createStackPart({
2278
+ const scopedParts = unresolved.filter((part) => part.ownerRole !== void 0 || part.ownerPartId !== void 0).map((part) => createStackPart({
2147
2279
  role: part.role,
2148
2280
  ecosystem: part.ecosystem,
2149
2281
  toolId: part.toolId,
2150
- ownerPartId: primaryByRoleAndEcosystem.get(`${part.ownerRole}:${part.ecosystem}`)?.id ?? primaryByRole.get(part.ownerRole)?.id,
2282
+ ownerPartId: part.ownerPartId ? primaryParts.find((candidate) => candidate.id === part.ownerPartId)?.id ?? part.ownerPartId : part.ownerRole ? primaryByRoleAndEcosystem.get(`${part.ownerRole}:${part.ecosystem}`)?.id ?? primaryByRole.get(part.ownerRole)?.id : void 0,
2151
2283
  source,
2152
2284
  id: part.customId
2153
2285
  }));
@@ -2155,7 +2287,12 @@ function parseStackPartSpecs(specs, source = "selected") {
2155
2287
  }
2156
2288
  function formatStackPartSpec(part, parts = []) {
2157
2289
  const owner = part.ownerPartId ? parts.find((candidate) => candidate.id === part.ownerPartId) : void 0;
2158
- return `${owner ? `${owner.role}.${part.role}` : part.role}:${part.ecosystem}:${part.toolId}`;
2290
+ const sameRoleOwners = owner ? parts.filter((candidate) => candidate.role === owner.role && candidate.ecosystem === owner.ecosystem && !candidate.ownerPartId && candidate.source !== "provided") : [];
2291
+ const ownerSelector = owner && sameRoleOwners.length > 1 ? owner.id : owner?.role;
2292
+ const rolePath = ownerSelector ? `${ownerSelector}.${part.role}` : part.role;
2293
+ const canonicalId = sanitizePartId(`${part.role}:${part.ecosystem}:${part.toolId}`);
2294
+ const customId = !part.ownerPartId && part.id !== canonicalId ? `:${part.id}` : "";
2295
+ return `${rolePath}:${part.ecosystem}:${part.toolId}${customId}`;
2159
2296
  }
2160
2297
  function materializeProvidedStackParts(parts) {
2161
2298
  const next = [...parts];
@@ -2287,6 +2424,11 @@ function legacyProjectConfigToStackParts(config, source = "legacy") {
2287
2424
  const frontendPart = addLegacyPart(parts, "frontend", "typescript", webFrontend, source);
2288
2425
  if (frontendPart?.toolId === "astro" && config.astroIntegration && config.astroIntegration !== "none") frontendPart.settings = { astroIntegration: config.astroIntegration };
2289
2426
  const mobilePart = addLegacyPart(parts, "mobile", "react-native", nativeFrontend, source);
2427
+ addLegacyPart(parts, "frontend", "dotnet", config.dotnetFrontend, source);
2428
+ const kotlinMobilePart = addLegacyPart(parts, "mobile", "kotlin", config.kotlinMobile, source);
2429
+ addLegacyPart(parts, "mobile", "swift", config.swiftMobile, source);
2430
+ addLegacyPart(parts, "mobile", "dart", config.dartMobile, source);
2431
+ if (kotlinMobilePart) for (const library of config.kotlinMobileLibraries ?? []) addLegacyPart(parts, "libraries", "kotlin", library, source, kotlinMobilePart.id);
2290
2432
  let backendPart;
2291
2433
  if ((config.ecosystem === void 0 || config.ecosystem === "typescript") && config.backend && config.backend !== "none") backendPart = addLegacyPart(parts, "backend", "typescript", config.backend, source);
2292
2434
  if (config.ecosystem === "rust" && config.rustFrontend && config.rustFrontend !== "none") addLegacyPart(parts, "frontend", "rust", config.rustFrontend, source);
@@ -2348,10 +2490,10 @@ function legacyProjectConfigToStackParts(config, source = "legacy") {
2348
2490
  }
2349
2491
  function ecosystemForLegacy(parts) {
2350
2492
  const frontend = getPrimaryPart(parts, "frontend");
2351
- if (frontend?.ecosystem && frontend.ecosystem !== "universal") return frontend.ecosystem;
2493
+ if (frontend?.ecosystem && frontend.ecosystem !== "universal" && frontend.ecosystem !== "kotlin" && frontend.ecosystem !== "swift" && frontend.ecosystem !== "dart") return frontend.ecosystem;
2352
2494
  if (getPrimaryPart(parts, "mobile")) return "react-native";
2353
2495
  const backend = getPrimaryPart(parts, "backend");
2354
- if (backend?.ecosystem && backend.ecosystem !== "universal") return backend.ecosystem;
2496
+ if (backend?.ecosystem && backend.ecosystem !== "universal" && backend.ecosystem !== "kotlin" && backend.ecosystem !== "swift" && backend.ecosystem !== "dart") return backend.ecosystem;
2355
2497
  return "typescript";
2356
2498
  }
2357
2499
  function stackPartsToLegacyProjectConfigPartial(parts) {
@@ -2379,7 +2521,7 @@ function stackPartsToLegacyProjectConfigPartial(parts) {
2379
2521
  const astroIntegration = part.settings?.astroIntegration;
2380
2522
  if (typeof astroIntegration === "string") config.astroIntegration = astroIntegration;
2381
2523
  } else if (part.role === "frontend" && part.ecosystem === "rust") config.rustFrontend = part.toolId;
2382
- else if (part.role === "mobile") config.frontend = [...config.frontend ?? [], part.toolId];
2524
+ else if (part.role === "mobile" && part.ecosystem === "react-native") config.frontend = [...config.frontend ?? [], part.toolId];
2383
2525
  else {
2384
2526
  const legacyArrayCategory$1 = getLegacyArrayCategoryForPart(part);
2385
2527
  if (legacyArrayCategory$1) {
@@ -2427,7 +2569,10 @@ function getLegacyCategoryForPart(part, parts) {
2427
2569
  const legacyCategory = LEGACY_TYPESCRIPT_BACKEND_SINGLE_CATEGORIES[part.role] ?? LEGACY_TYPESCRIPT_BACKEND_INFRA_CATEGORIES[part.role];
2428
2570
  if (legacyCategory) return legacyCategory;
2429
2571
  }
2430
- if (owner?.role === "mobile" && part.ecosystem === "react-native" && part.role === "auth") return "auth";
2572
+ if (owner?.role === "mobile" && part.ecosystem === "react-native") {
2573
+ if (part.role === "auth") return "auth";
2574
+ if (part.role === "payments") return "payments";
2575
+ }
2431
2576
  if (owner?.role === "database" && part.ecosystem === "universal") {
2432
2577
  const legacyCategory = LEGACY_DATABASE_SINGLE_CATEGORIES[part.role];
2433
2578
  if (legacyCategory) return legacyCategory;
@@ -2488,7 +2633,7 @@ function stackGraphToLegacyProjectConfigForEcosystem(config, ecosystem) {
2488
2633
  if (part.source === "provided" || part.ownerPartId !== frontend?.id || frontendScopedPartRoles.has(part.role)) continue;
2489
2634
  projectLegacyCategoryFromPart(projected, part, ecosystem, parts);
2490
2635
  }
2491
- const mobileScopedPartRoles = new Set(["auth"]);
2636
+ const mobileScopedPartRoles = new Set(["auth", "payments"]);
2492
2637
  for (const part of parts) {
2493
2638
  if (part.source === "provided" || part.ownerPartId !== mobile?.id || mobileScopedPartRoles.has(part.role)) continue;
2494
2639
  projectLegacyCategoryFromPart(projected, part, ecosystem, parts);
@@ -2506,11 +2651,43 @@ function stackGraphToLegacyProjectConfigForEcosystem(config, ecosystem) {
2506
2651
  function validateStackParts(parts) {
2507
2652
  const issues = [];
2508
2653
  const partsById = new Map(parts.map((part) => [part.id, part]));
2509
- for (const role of PRIMARY_ROLES) if (parts.filter((part) => part.role === role && !part.ownerPartId).length > 1) issues.push({
2510
- code: "DUPLICATE_PRIMARY_ROLE",
2511
- role,
2512
- message: `Only one primary '${role}' stack part is supported in v1.`
2654
+ const seenPartIds = /* @__PURE__ */ new Set();
2655
+ const selectedPrimaryParts = parts.filter((part) => !part.ownerPartId && part.source !== "provided" && PRIMARY_ROLES.has(part.role));
2656
+ const unsupportedRepeatedPrimaryGroups = [
2657
+ {
2658
+ label: "TypeScript web frontend",
2659
+ parts: selectedPrimaryParts.filter((part) => part.role === "frontend" && part.ecosystem === "typescript")
2660
+ },
2661
+ {
2662
+ label: "TypeScript backend",
2663
+ parts: selectedPrimaryParts.filter((part) => part.role === "backend" && part.ecosystem === "typescript")
2664
+ },
2665
+ {
2666
+ label: "React Native mobile app",
2667
+ parts: selectedPrimaryParts.filter((part) => part.role === "mobile" && part.ecosystem === "react-native")
2668
+ },
2669
+ {
2670
+ label: "database",
2671
+ parts: selectedPrimaryParts.filter((part) => part.role === "database")
2672
+ }
2673
+ ];
2674
+ for (const group of unsupportedRepeatedPrimaryGroups) for (const part of group.parts.slice(1)) issues.push({
2675
+ code: "UNSUPPORTED_REPEATED_PRIMARY",
2676
+ partId: part.id,
2677
+ role: part.role,
2678
+ toolId: part.toolId,
2679
+ message: `Only one ${group.label} is currently supported. Named repeated backend services are supported for Rust, Python, Go, Java/Kotlin, .NET, and Elixir.`
2513
2680
  });
2681
+ for (const part of parts) {
2682
+ if (seenPartIds.has(part.id)) issues.push({
2683
+ code: "DUPLICATE_PART_ID",
2684
+ partId: part.id,
2685
+ role: part.role,
2686
+ toolId: part.toolId,
2687
+ message: `Stack part ID '${part.id}' is repeated. Give repeated primary services unique IDs with role:ecosystem:tool:id.`
2688
+ });
2689
+ seenPartIds.add(part.id);
2690
+ }
2514
2691
  for (const part of parts) {
2515
2692
  const definition = findDefinition(part);
2516
2693
  if (!definition) issues.push({
@@ -2542,6 +2719,7 @@ function validateStackParts(parts) {
2542
2719
  }
2543
2720
  const byScope = /* @__PURE__ */ new Map();
2544
2721
  for (const part of parts) {
2722
+ if (!part.ownerPartId && PRIMARY_ROLES.has(part.role)) continue;
2545
2723
  const key = `${part.ownerPartId ?? "root"}:${part.role}`;
2546
2724
  byScope.set(key, [...byScope.get(key) ?? [], part]);
2547
2725
  }
@@ -2574,4 +2752,4 @@ function validateStackParts(parts) {
2574
2752
 
2575
2753
  //#endregion
2576
2754
  export { isBackendUtilsCompatibleBackend as C, requiresChatSdkVercelAIForExamples as E, hasTauriCompatibleFrontend as S, isExampleChatSdkAllowed as T, UI_LIBRARY_COMPATIBILITY as _, getAddonStackPartBinding as a, hasPWACompatibleFrontend as b, getStackPartOptions as c, materializeProvidedStackParts as d, parseStackPartSpecs as f, BACKEND_UTILS_COMPATIBLE_BACKENDS as g, validateStackParts as h, formatStackPartSpec as i, getStackToolDefinitions as l, stackPartsToLegacyProjectConfigPartial as m, STACK_TOOL_DEFINITIONS as n, getRoleTargetPath as o, stackGraphToLegacyProjectConfigForEcosystem as p, createStackPart as r, getStackPartCompatibilityIssueForPart as s, ELIXIR_UNSUPPORTED_GRAPH_TOOLS as t, legacyProjectConfigToStackParts as u, getUnsupportedWebDeployFrontend as v, isExampleAIAllowed as w, hasTanStackAICompatibleFrontend as x, hasDockerComposeCompatibleFrontend as y };
2577
- //# sourceMappingURL=stack-graph-DiLi3WuL.mjs.map
2755
+ //# sourceMappingURL=stack-graph-CXTiPofQ.mjs.map