@better-fullstack/types 1.6.3 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{defaults-C-sFuvss.d.mts → defaults-DYWPNKDb.d.mts} +2 -2
- package/dist/defaults-DYWPNKDb.d.mts.map +1 -0
- package/dist/{defaults-aGwVXJh5.mjs → defaults-DnrxiPa9.mjs} +1 -1
- package/dist/{defaults-aGwVXJh5.mjs.map → defaults-DnrxiPa9.mjs.map} +1 -1
- package/dist/defaults.d.mts +3 -3
- package/dist/defaults.mjs +1 -1
- package/dist/index.d.mts +5 -176
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -2811
- package/dist/index.mjs.map +1 -1
- package/dist/json-schema.mjs +1 -1
- package/dist/{schemas-BsdLtIDm.d.mts → schemas-9siFEKYg.d.mts} +1 -1
- package/dist/{schemas-BsdLtIDm.d.mts.map → schemas-9siFEKYg.d.mts.map} +1 -1
- package/dist/{schemas-CDxaaiIP.mjs → schemas-DDTcRKek.mjs} +1 -1
- package/dist/{schemas-CDxaaiIP.mjs.map → schemas-DDTcRKek.mjs.map} +1 -1
- package/dist/schemas.d.mts +1 -1
- package/dist/schemas.mjs +1 -1
- package/dist/stack-translation-CUd4T2bV.mjs +3798 -0
- package/dist/stack-translation-CUd4T2bV.mjs.map +1 -0
- package/dist/stack-translation-Ct4UaQX9.d.mts +301 -0
- package/dist/stack-translation-Ct4UaQX9.d.mts.map +1 -0
- package/dist/stack-translation.d.mts +5 -0
- package/dist/stack-translation.mjs +4 -0
- package/dist/{types-rP2wE60D.d.mts → types-Do72vki5.d.mts} +2 -2
- package/dist/{types-rP2wE60D.d.mts.map → types-Do72vki5.d.mts.map} +1 -1
- package/dist/types.d.mts +2 -2
- package/package.json +6 -2
- package/dist/defaults-C-sFuvss.d.mts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,2815 +1,8 @@
|
|
|
1
|
-
import { $ as FrontendSchema, $n as VALIDATION_VALUES, $t as PythonQualitySchema, A as DATABASE_SETUP_VALUES, An as SHADCN_BASE_VALUES, At as LoggingSchema, B as EcosystemSchema, Bn as ShadcnBaseSchema, Bt as PYTHON_ORM_VALUES, C as CLIInputSchema, Cn as RustLibrariesSchema, Ct as JavaBuildToolSchema, D as CSS_FRAMEWORK_VALUES, Dn as SEARCH_VALUES, Dt as JavaWebFrameworkSchema, E as CSSFrameworkSchema, En as RustWebFrameworkSchema, Et as JavaTestingLibrariesSchema, F as DirectoryConflictSchema, Fn as SHADCN_STYLE_VALUES, Ft as PACKAGE_MANAGER_VALUES, G as FILE_STORAGE_VALUES, Gn as ShadcnStyleSchema, Gt as PackageManagerSchema, H as EmailSchema, Hn as ShadcnFontSchema, Ht as PYTHON_TASK_QUEUE_VALUES, I as ECOSYSTEM_VALUES, In as STATE_MANAGEMENT_VALUES, It as PAYMENTS_VALUES, J as FRONTEND_VALUES, Jn as TESTING_VALUES, Jt as ProjectNameSchema, K as FILE_UPLOAD_VALUES, Kn as StateManagementSchema, Kt as PaymentsSchema, L as EFFECT_VALUES, Ln as SearchSchema, Lt as PYTHON_AI_VALUES, M as DIRECTORY_CONFLICT_VALUES, Mn as SHADCN_FONT_VALUES, Mt as ORMSchema, N as DatabaseSchema, Nn as SHADCN_ICON_LIBRARY_VALUES, Nt as ORM_VALUES, O as CachingSchema, On as SERVER_DEPLOY_VALUES, Ot as JobQueueSchema, P as DatabaseSetupSchema, Pn as SHADCN_RADIUS_VALUES, Pt as ObservabilitySchema, Q as FormsSchema, Qn as UI_LIBRARY_VALUES, Qt as PythonOrmSchema, R as EMAIL_VALUES, Rn as ServerDeploySchema, Rt as PYTHON_AUTH_VALUES, S as CACHING_VALUES, Sn as RustFrontendSchema, St as JavaAuthSchema, T as CMS_VALUES, Tn as RustOrmSchema, Tt as JavaOrmSchema, U as ExamplesSchema, Un as ShadcnIconLibrarySchema, Ut as PYTHON_VALIDATION_VALUES, V as EffectSchema, Vn as ShadcnColorThemeSchema, Vt as PYTHON_QUALITY_VALUES, W as FEATURE_FLAGS_VALUES, Wn as ShadcnRadiusSchema, Wt as PYTHON_WEB_FRAMEWORK_VALUES, X as FileStorageSchema, Xn as TestingSchema, Xt as PythonAuthSchema, Y as FeatureFlagsSchema, Yn as TemplateSchema, Yt as PythonAiSchema, Z as FileUploadSchema, Zn as UILibrarySchema, Zt as PythonGraphqlSchema, _ as AuthSchema, _n as RustApiSchema, _t as JAVA_LIBRARIES_VALUES, a as ANALYTICS_VALUES, an as RUST_API_VALUES, at as GO_WEB_FRAMEWORK_VALUES, b as BetterTStackConfigFileSchema, bn as RustCliSchema, bt as JAVA_WEB_FRAMEWORK_VALUES, c as API_VALUES, cn as RUST_CLI_VALUES, ct as GoCliSchema, d as AddInputSchema, dn as RUST_LIBRARIES_VALUES, dt as GoWebFrameworkSchema, en as PythonTaskQueueSchema, er as VERSION_CHANNEL_VALUES, et as GO_API_VALUES, f as AddonsSchema, fn as RUST_LOGGING_VALUES, ft as I18N_VALUES, g as AstroIntegrationSchema, gn as RuntimeSchema, gt as JAVA_BUILD_TOOL_VALUES, h as AnimationSchema, hn as RealtimeSchema, ht as JAVA_AUTH_VALUES, i as AI_VALUES, in as RUNTIME_VALUES, ir as WebDeploySchema, it as GO_ORM_VALUES, j as DATABASE_VALUES, jn as SHADCN_COLOR_THEME_VALUES, jt as OBSERVABILITY_VALUES, k as CreateInputSchema, kn as SHADCN_BASE_COLOR_VALUES, kt as LOGGING_VALUES, l as ASTRO_INTEGRATION_VALUES, ln as RUST_ERROR_HANDLING_VALUES, lt as GoLoggingSchema, m as AnalyticsSchema, mn as RUST_WEB_FRAMEWORK_VALUES, mt as InitResultSchema, n as AISchema, nn as PythonWebFrameworkSchema, nr as VersionChannelSchema, nt as GO_CLI_VALUES, o as ANIMATION_VALUES, on as RUST_AUTH_VALUES, ot as GoApiSchema, p as AiDocsSchema, pn as RUST_ORM_VALUES, pt as I18nSchema, q as FORMS_VALUES, qn as TEMPLATE_VALUES, qt as ProjectConfigSchema, r as AI_DOCS_VALUES, rn as REALTIME_VALUES, rr as WEB_DEPLOY_VALUES, rt as GO_LOGGING_VALUES, s as APISchema, sn as RUST_CACHING_VALUES, st as GoAuthSchema, t as ADDONS_VALUES, tn as PythonValidationSchema, tr as ValidationSchema, tt as GO_AUTH_VALUES, u as AUTH_VALUES, un as RUST_FRONTEND_VALUES, ut as GoOrmSchema, v as BACKEND_VALUES, vn as RustAuthSchema, vt as JAVA_ORM_VALUES, w as CMSSchema, wn as RustLoggingSchema, wt as JavaLibrariesSchema, x as BetterTStackConfigSchema, xn as RustErrorHandlingSchema, xt as JOB_QUEUE_VALUES, y as BackendSchema, yn as RustCachingSchema, yt as JAVA_TESTING_LIBRARIES_VALUES, z as EXAMPLES_VALUES, zn as ShadcnBaseColorSchema, zt as PYTHON_GRAPHQL_VALUES } from "./schemas-
|
|
1
|
+
import { $ as FrontendSchema, $n as VALIDATION_VALUES, $t as PythonQualitySchema, A as DATABASE_SETUP_VALUES, An as SHADCN_BASE_VALUES, At as LoggingSchema, B as EcosystemSchema, Bn as ShadcnBaseSchema, Bt as PYTHON_ORM_VALUES, C as CLIInputSchema, Cn as RustLibrariesSchema, Ct as JavaBuildToolSchema, D as CSS_FRAMEWORK_VALUES, Dn as SEARCH_VALUES, Dt as JavaWebFrameworkSchema, E as CSSFrameworkSchema, En as RustWebFrameworkSchema, Et as JavaTestingLibrariesSchema, F as DirectoryConflictSchema, Fn as SHADCN_STYLE_VALUES, Ft as PACKAGE_MANAGER_VALUES, G as FILE_STORAGE_VALUES, Gn as ShadcnStyleSchema, Gt as PackageManagerSchema, H as EmailSchema, Hn as ShadcnFontSchema, Ht as PYTHON_TASK_QUEUE_VALUES, I as ECOSYSTEM_VALUES, In as STATE_MANAGEMENT_VALUES, It as PAYMENTS_VALUES, J as FRONTEND_VALUES, Jn as TESTING_VALUES, Jt as ProjectNameSchema, K as FILE_UPLOAD_VALUES, Kn as StateManagementSchema, Kt as PaymentsSchema, L as EFFECT_VALUES, Ln as SearchSchema, Lt as PYTHON_AI_VALUES, M as DIRECTORY_CONFLICT_VALUES, Mn as SHADCN_FONT_VALUES, Mt as ORMSchema, N as DatabaseSchema, Nn as SHADCN_ICON_LIBRARY_VALUES, Nt as ORM_VALUES, O as CachingSchema, On as SERVER_DEPLOY_VALUES, Ot as JobQueueSchema, P as DatabaseSetupSchema, Pn as SHADCN_RADIUS_VALUES, Pt as ObservabilitySchema, Q as FormsSchema, Qn as UI_LIBRARY_VALUES, Qt as PythonOrmSchema, R as EMAIL_VALUES, Rn as ServerDeploySchema, Rt as PYTHON_AUTH_VALUES, S as CACHING_VALUES, Sn as RustFrontendSchema, St as JavaAuthSchema, T as CMS_VALUES, Tn as RustOrmSchema, Tt as JavaOrmSchema, U as ExamplesSchema, Un as ShadcnIconLibrarySchema, Ut as PYTHON_VALIDATION_VALUES, V as EffectSchema, Vn as ShadcnColorThemeSchema, Vt as PYTHON_QUALITY_VALUES, W as FEATURE_FLAGS_VALUES, Wn as ShadcnRadiusSchema, Wt as PYTHON_WEB_FRAMEWORK_VALUES, X as FileStorageSchema, Xn as TestingSchema, Xt as PythonAuthSchema, Y as FeatureFlagsSchema, Yn as TemplateSchema, Yt as PythonAiSchema, Z as FileUploadSchema, Zn as UILibrarySchema, Zt as PythonGraphqlSchema, _ as AuthSchema, _n as RustApiSchema, _t as JAVA_LIBRARIES_VALUES, a as ANALYTICS_VALUES, an as RUST_API_VALUES, at as GO_WEB_FRAMEWORK_VALUES, b as BetterTStackConfigFileSchema, bn as RustCliSchema, bt as JAVA_WEB_FRAMEWORK_VALUES, c as API_VALUES, cn as RUST_CLI_VALUES, ct as GoCliSchema, d as AddInputSchema, dn as RUST_LIBRARIES_VALUES, dt as GoWebFrameworkSchema, en as PythonTaskQueueSchema, er as VERSION_CHANNEL_VALUES, et as GO_API_VALUES, f as AddonsSchema, fn as RUST_LOGGING_VALUES, ft as I18N_VALUES, g as AstroIntegrationSchema, gn as RuntimeSchema, gt as JAVA_BUILD_TOOL_VALUES, h as AnimationSchema, hn as RealtimeSchema, ht as JAVA_AUTH_VALUES, i as AI_VALUES, in as RUNTIME_VALUES, ir as WebDeploySchema, it as GO_ORM_VALUES, j as DATABASE_VALUES, jn as SHADCN_COLOR_THEME_VALUES, jt as OBSERVABILITY_VALUES, k as CreateInputSchema, kn as SHADCN_BASE_COLOR_VALUES, kt as LOGGING_VALUES, l as ASTRO_INTEGRATION_VALUES, ln as RUST_ERROR_HANDLING_VALUES, lt as GoLoggingSchema, m as AnalyticsSchema, mn as RUST_WEB_FRAMEWORK_VALUES, mt as InitResultSchema, n as AISchema, nn as PythonWebFrameworkSchema, nr as VersionChannelSchema, nt as GO_CLI_VALUES, o as ANIMATION_VALUES, on as RUST_AUTH_VALUES, ot as GoApiSchema, p as AiDocsSchema, pn as RUST_ORM_VALUES, pt as I18nSchema, q as FORMS_VALUES, qn as TEMPLATE_VALUES, qt as ProjectConfigSchema, r as AI_DOCS_VALUES, rn as REALTIME_VALUES, rr as WEB_DEPLOY_VALUES, rt as GO_LOGGING_VALUES, s as APISchema, sn as RUST_CACHING_VALUES, st as GoAuthSchema, t as ADDONS_VALUES, tn as PythonValidationSchema, tr as ValidationSchema, tt as GO_AUTH_VALUES, u as AUTH_VALUES, un as RUST_FRONTEND_VALUES, ut as GoOrmSchema, v as BACKEND_VALUES, vn as RustAuthSchema, vt as JAVA_ORM_VALUES, w as CMSSchema, wn as RustLoggingSchema, wt as JavaLibrariesSchema, x as BetterTStackConfigSchema, xn as RustErrorHandlingSchema, xt as JOB_QUEUE_VALUES, y as BackendSchema, yn as RustCachingSchema, yt as JAVA_TESTING_LIBRARIES_VALUES, z as EXAMPLES_VALUES, zn as ShadcnBaseColorSchema, zt as PYTHON_GRAPHQL_VALUES } from "./schemas-DDTcRKek.mjs";
|
|
2
2
|
import "./types.mjs";
|
|
3
|
-
import { t as
|
|
3
|
+
import { $ as getCapabilityDefinitions, A as evaluateCompatibility, B as hasPWACompatibleFrontend, C as getCategoryCliValues, D as normalizeOptionId, E as isMultiSelectCategory, F as getCompatibleCSSFrameworks, G as isFrontendAllowedWithBackend, H as hasWebStyling, I as getCompatibleFormLibraries, J as requiresChatSdkVercelAI, K as isOptionCompatible, L as getCompatibleUILibraries, M as getApiFrontendCompatibilityIssue, N as getCategoryDisplayName, O as allowedApisForFrontends, P as getCompatibleAddons, Q as validateProjectName, R as getDisabledReason, S as OPTION_CATEGORY_METADATA, T as getOptionMetadata, U as isExampleAIAllowed, V as hasTauriCompatibleFrontend, W as isExampleChatSdkAllowed, X as splitFrontends, Y as requiresChatSdkVercelAIForSelection, Z as validateAddonCompatibility, _ as parseStackSelectionFromUrlRecord, a as STACK_SELECTION_URL_KEYS, b as stackSelectionToProjectConfig, c as cloneDefaultStackSelection, d as isArrayStackSelectionKey, et as getCapabilityDisabledReason, f as isCliDefaultStackSelection, g as parseStackSelectionFromSearch, h as normalizeStackSelectionValue, i as STACK_SELECTION_OPTION_CATEGORY_BY_KEY, j as getAIFrontendCompatibilityIssue, k as analyzeStackCompatibility, l as createStackSelectionSearchParams, m as normalizeStackSelection, n as NON_OPTION_STACK_SELECTION_KEYS, nt as normalizeCapabilitySelection, o as VIRTUAL_NONE_MULTI_SELECT_STACK_SELECTION_KEYS, p as isStackSelectionDefault, q as isWebFrontend, r as STACK_SELECTION_KEYS, s as cliInputToProjectConfigPartial, t as DEFAULT_STACK_SELECTION, tt as getSupportedCapabilityOptions, u as generateStackSelectionCommand, v as processCliArrayOption, w as getCategoryOptionIds, x as usesVirtualNoneStackSelection, y as stackSelectionToCliComparableConfig, z as hasDockerComposeCompatibleFrontend } from "./stack-translation-CUd4T2bV.mjs";
|
|
4
|
+
import { t as createCliDefaultProjectConfigBase } from "./defaults-DnrxiPa9.mjs";
|
|
4
5
|
|
|
5
|
-
//#region src/capabilities.ts
|
|
6
|
-
const CAPABILITY_DEFINITIONS = { auth: [
|
|
7
|
-
{
|
|
8
|
-
id: "better-auth",
|
|
9
|
-
label: "Better-Auth",
|
|
10
|
-
description: "The most comprehensive authentication framework for TypeScript",
|
|
11
|
-
promptHint: "comprehensive auth framework for TypeScript",
|
|
12
|
-
icon: "/icon/better-auth.svg",
|
|
13
|
-
color: "from-green-400 to-green-600",
|
|
14
|
-
default: true
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
id: "go-better-auth",
|
|
18
|
-
label: "GoBetterAuth",
|
|
19
|
-
description: "Embedded auth routes for Go applications",
|
|
20
|
-
promptHint: "embedded auth routes for Go applications",
|
|
21
|
-
icon: "https://cdn.simpleicons.org/go/00ADD8",
|
|
22
|
-
color: "from-cyan-400 to-sky-600"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: "clerk",
|
|
26
|
-
label: "Clerk",
|
|
27
|
-
description: "More than authentication, Complete User Management",
|
|
28
|
-
promptHint: "More than auth, Complete User Management",
|
|
29
|
-
icon: "https://cdn.simpleicons.org/clerk/6C47FF",
|
|
30
|
-
color: "from-blue-400 to-blue-600"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
id: "nextauth",
|
|
34
|
-
label: "Auth.js (NextAuth)",
|
|
35
|
-
description: "Open source authentication for Next.js",
|
|
36
|
-
promptHint: "Authentication for Next.js (formerly NextAuth.js)",
|
|
37
|
-
icon: "/icon/nextauth.png",
|
|
38
|
-
color: "from-orange-400 to-orange-600"
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
id: "stack-auth",
|
|
42
|
-
label: "Stack Auth",
|
|
43
|
-
description: "Open-source Auth0/Clerk alternative with user management",
|
|
44
|
-
promptHint: "Open-source Auth0/Clerk alternative",
|
|
45
|
-
icon: "/icon/stack-auth.svg",
|
|
46
|
-
color: "from-purple-400 to-purple-600"
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
id: "supabase-auth",
|
|
50
|
-
label: "Supabase Auth",
|
|
51
|
-
description: "Open-source Auth with Supabase platform integration",
|
|
52
|
-
promptHint: "Auth with Supabase platform integration",
|
|
53
|
-
icon: "https://cdn.simpleicons.org/supabase/3FCF8E",
|
|
54
|
-
color: "from-emerald-400 to-emerald-600"
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
id: "auth0",
|
|
58
|
-
label: "Auth0",
|
|
59
|
-
description: "Flexible identity platform for authentication and authorization",
|
|
60
|
-
promptHint: "Flexible identity platform for authentication",
|
|
61
|
-
icon: "https://cdn.simpleicons.org/auth0/EB5424",
|
|
62
|
-
color: "from-orange-400 to-orange-600"
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
id: "none",
|
|
66
|
-
label: "No Auth",
|
|
67
|
-
description: "Skip authentication",
|
|
68
|
-
promptHint: "No authentication",
|
|
69
|
-
icon: "",
|
|
70
|
-
color: "from-red-400 to-red-600"
|
|
71
|
-
}
|
|
72
|
-
] };
|
|
73
|
-
const NATIVE_FRONTENDS = new Set([
|
|
74
|
-
"native-bare",
|
|
75
|
-
"native-uniwind",
|
|
76
|
-
"native-unistyles"
|
|
77
|
-
]);
|
|
78
|
-
const CONVEX_BETTER_AUTH_WEB = new Set([
|
|
79
|
-
"react-vite",
|
|
80
|
-
"tanstack-router",
|
|
81
|
-
"tanstack-start",
|
|
82
|
-
"next"
|
|
83
|
-
]);
|
|
84
|
-
const CONVEX_CLERK_WEB = new Set([
|
|
85
|
-
"react-router",
|
|
86
|
-
"react-vite",
|
|
87
|
-
"tanstack-router",
|
|
88
|
-
"tanstack-start",
|
|
89
|
-
"next"
|
|
90
|
-
]);
|
|
91
|
-
function capitalizeFirst(value) {
|
|
92
|
-
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
93
|
-
}
|
|
94
|
-
function dedupe(values) {
|
|
95
|
-
return [...new Set(values)];
|
|
96
|
-
}
|
|
97
|
-
function getFrontendSets(context) {
|
|
98
|
-
if (context.frontend) {
|
|
99
|
-
const webFrontend = context.frontend.filter((frontend) => !NATIVE_FRONTENDS.has(frontend));
|
|
100
|
-
const nativeFrontend = context.frontend.filter((frontend) => NATIVE_FRONTENDS.has(frontend));
|
|
101
|
-
return {
|
|
102
|
-
webFrontend: dedupe(webFrontend),
|
|
103
|
-
nativeFrontend: dedupe(nativeFrontend)
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
return {
|
|
107
|
-
webFrontend: dedupe(context.webFrontend ?? []),
|
|
108
|
-
nativeFrontend: dedupe(context.nativeFrontend ?? [])
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
function isSelfBackend(backend) {
|
|
112
|
-
return backend === "self" || backend?.startsWith("self-") === true;
|
|
113
|
-
}
|
|
114
|
-
function getNextOnlyAuthLabel(optionId) {
|
|
115
|
-
switch (optionId) {
|
|
116
|
-
case "nextauth": return "Auth.js (NextAuth)";
|
|
117
|
-
case "stack-auth": return "Stack Auth";
|
|
118
|
-
case "supabase-auth": return "Supabase Auth";
|
|
119
|
-
case "auth0": return "Auth0";
|
|
120
|
-
default: {
|
|
121
|
-
const _exhaustive = optionId;
|
|
122
|
-
return String(_exhaustive);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
function getAuthDisabledReason(context, optionId) {
|
|
127
|
-
if (optionId === "none") return null;
|
|
128
|
-
const ecosystem = context.ecosystem ?? "typescript";
|
|
129
|
-
const backend = context.backend;
|
|
130
|
-
const { webFrontend, nativeFrontend } = getFrontendSets(context);
|
|
131
|
-
const hasNextJs = webFrontend.includes("next");
|
|
132
|
-
const hasTanStackStart = webFrontend.includes("tanstack-start");
|
|
133
|
-
const hasNativeFrontend = nativeFrontend.some((frontend) => frontend !== "none");
|
|
134
|
-
if (optionId === "go-better-auth") return ecosystem === "go" ? null : "GoBetterAuth is available only for Go stacks";
|
|
135
|
-
if (ecosystem === "go") return "Go stacks currently support GoBetterAuth only";
|
|
136
|
-
if (ecosystem !== "typescript") return `${capitalizeFirst(ecosystem)} stacks do not support auth integrations yet`;
|
|
137
|
-
if (backend === "none") return "No backend selected";
|
|
138
|
-
if (optionId === "better-auth") {
|
|
139
|
-
if (backend === "convex") {
|
|
140
|
-
if (!(webFrontend.some((frontend) => CONVEX_BETTER_AUTH_WEB.has(frontend)) || nativeFrontend.some((frontend) => NATIVE_FRONTENDS.has(frontend)))) return "Better-Auth with Convex requires React + Vite, TanStack Router, TanStack Start, Next.js, or React Native";
|
|
141
|
-
}
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
if (optionId === "clerk") {
|
|
145
|
-
if (backend === "convex") {
|
|
146
|
-
if (!(webFrontend.some((frontend) => CONVEX_CLERK_WEB.has(frontend)) || nativeFrontend.some((frontend) => NATIVE_FRONTENDS.has(frontend)))) return "Clerk with Convex requires React Router, React + Vite, TanStack Router, TanStack Start, Next.js, or React Native";
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
if (isSelfBackend(backend)) {
|
|
150
|
-
if ((hasNextJs || hasTanStackStart) && hasNativeFrontend) return "In Better-Fullstack, Clerk with self backend is currently supported only for web-only Next.js or TanStack Start projects (no native companion app)";
|
|
151
|
-
if (hasNextJs || hasTanStackStart) return null;
|
|
152
|
-
if (backend === "self-astro" || webFrontend.includes("astro")) return "In Better-Fullstack, Clerk is not yet supported for Astro fullstack projects";
|
|
153
|
-
if (backend === "self-nuxt" || webFrontend.includes("nuxt")) return "In Better-Fullstack, Clerk is not yet supported for Nuxt fullstack projects";
|
|
154
|
-
if (backend === "self-svelte" || webFrontend.includes("svelte")) return "In Better-Fullstack, Clerk is not yet supported for SvelteKit fullstack projects";
|
|
155
|
-
if (backend === "self-solid-start" || webFrontend.includes("solid-start")) return "In Better-Fullstack, Clerk is not yet supported for SolidStart fullstack projects";
|
|
156
|
-
return "In Better-Fullstack, Clerk is currently supported with Convex, Next.js fullstack, or TanStack Start fullstack";
|
|
157
|
-
}
|
|
158
|
-
return "In Better-Fullstack, Clerk is currently supported with Convex, Next.js fullstack, or TanStack Start fullstack";
|
|
159
|
-
}
|
|
160
|
-
const nextOnlyLabel = getNextOnlyAuthLabel(optionId);
|
|
161
|
-
if (backend !== "self" && backend !== "self-next") return `In Better-Fullstack, ${nextOnlyLabel} is currently supported only with the 'self' backend (fullstack Next.js)`;
|
|
162
|
-
if (!hasNextJs) return `In Better-Fullstack, ${nextOnlyLabel} currently requires the Next.js frontend`;
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
165
|
-
function getCapabilityDefinitions(capability) {
|
|
166
|
-
return CAPABILITY_DEFINITIONS[capability];
|
|
167
|
-
}
|
|
168
|
-
function getCapabilityDisabledReason(capability, context, optionId) {
|
|
169
|
-
if (capability === "auth") return getAuthDisabledReason(context, optionId);
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
function getSupportedCapabilityOptions(capability, context) {
|
|
173
|
-
return getCapabilityDefinitions(capability).filter((definition) => getCapabilityDisabledReason(capability, context, definition.id) === null);
|
|
174
|
-
}
|
|
175
|
-
function normalizeCapabilitySelection(capability, context, optionId) {
|
|
176
|
-
const fallbackValue = "none";
|
|
177
|
-
if (!optionId || optionId === fallbackValue) return {
|
|
178
|
-
value: optionId ?? fallbackValue,
|
|
179
|
-
normalized: false,
|
|
180
|
-
reason: null,
|
|
181
|
-
message: null
|
|
182
|
-
};
|
|
183
|
-
const reason = getCapabilityDisabledReason(capability, context, optionId);
|
|
184
|
-
if (!reason) return {
|
|
185
|
-
value: optionId,
|
|
186
|
-
normalized: false,
|
|
187
|
-
reason: null,
|
|
188
|
-
message: null
|
|
189
|
-
};
|
|
190
|
-
return {
|
|
191
|
-
value: fallbackValue,
|
|
192
|
-
normalized: true,
|
|
193
|
-
reason,
|
|
194
|
-
message: `${capitalizeFirst(capability)} set to 'None' (${reason})`
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
//#endregion
|
|
199
|
-
//#region src/compatibility.ts
|
|
200
|
-
const CATEGORY_ORDER = [
|
|
201
|
-
...[
|
|
202
|
-
"webFrontend",
|
|
203
|
-
"nativeFrontend",
|
|
204
|
-
"astroIntegration",
|
|
205
|
-
"cssFramework",
|
|
206
|
-
"uiLibrary",
|
|
207
|
-
"backend",
|
|
208
|
-
"backendLibraries",
|
|
209
|
-
"runtime",
|
|
210
|
-
"api",
|
|
211
|
-
"database",
|
|
212
|
-
"orm",
|
|
213
|
-
"dbSetup",
|
|
214
|
-
"webDeploy",
|
|
215
|
-
"serverDeploy",
|
|
216
|
-
"auth",
|
|
217
|
-
"payments",
|
|
218
|
-
"email",
|
|
219
|
-
"fileUpload",
|
|
220
|
-
"logging",
|
|
221
|
-
"observability",
|
|
222
|
-
"featureFlags",
|
|
223
|
-
"analytics",
|
|
224
|
-
"ai",
|
|
225
|
-
"stateManagement",
|
|
226
|
-
"forms",
|
|
227
|
-
"validation",
|
|
228
|
-
"testing",
|
|
229
|
-
"realtime",
|
|
230
|
-
"jobQueue",
|
|
231
|
-
"caching",
|
|
232
|
-
"i18n",
|
|
233
|
-
"search",
|
|
234
|
-
"fileStorage",
|
|
235
|
-
"animation",
|
|
236
|
-
"cms",
|
|
237
|
-
"codeQuality",
|
|
238
|
-
"documentation",
|
|
239
|
-
"appPlatforms",
|
|
240
|
-
"packageManager",
|
|
241
|
-
"versionChannel",
|
|
242
|
-
"examples",
|
|
243
|
-
"aiDocs",
|
|
244
|
-
"git",
|
|
245
|
-
"install"
|
|
246
|
-
],
|
|
247
|
-
"rustWebFramework",
|
|
248
|
-
"rustFrontend",
|
|
249
|
-
"rustOrm",
|
|
250
|
-
"rustApi",
|
|
251
|
-
"rustCli",
|
|
252
|
-
"rustLibraries",
|
|
253
|
-
"pythonWebFramework",
|
|
254
|
-
"pythonOrm",
|
|
255
|
-
"pythonValidation",
|
|
256
|
-
"pythonAi",
|
|
257
|
-
"pythonAuth",
|
|
258
|
-
"pythonTaskQueue",
|
|
259
|
-
"pythonGraphql",
|
|
260
|
-
"pythonQuality",
|
|
261
|
-
"goWebFramework",
|
|
262
|
-
"goOrm",
|
|
263
|
-
"goApi",
|
|
264
|
-
"goCli",
|
|
265
|
-
"goLogging",
|
|
266
|
-
"goAuth",
|
|
267
|
-
"javaWebFramework",
|
|
268
|
-
"javaBuildTool",
|
|
269
|
-
"javaOrm",
|
|
270
|
-
"javaAuth",
|
|
271
|
-
"javaLibraries",
|
|
272
|
-
"javaTestingLibraries"
|
|
273
|
-
];
|
|
274
|
-
const DEFAULT_RUNTIME = "bun";
|
|
275
|
-
function validateProjectName(name) {
|
|
276
|
-
const INVALID_CHARS = [
|
|
277
|
-
"<",
|
|
278
|
-
">",
|
|
279
|
-
":",
|
|
280
|
-
"\"",
|
|
281
|
-
"|",
|
|
282
|
-
"?",
|
|
283
|
-
"*",
|
|
284
|
-
"/",
|
|
285
|
-
"\\"
|
|
286
|
-
];
|
|
287
|
-
const MAX_LENGTH = 255;
|
|
288
|
-
if (name === ".") return void 0;
|
|
289
|
-
if (!name) return "Project name cannot be empty";
|
|
290
|
-
if (name.length > MAX_LENGTH) return `Project name must be less than ${MAX_LENGTH} characters`;
|
|
291
|
-
if (INVALID_CHARS.some((char) => name.includes(char))) return "Project name contains invalid characters";
|
|
292
|
-
if (name.startsWith(".") || name.startsWith("-")) return "Project name cannot start with a dot or dash";
|
|
293
|
-
if (name.toLowerCase() === "node_modules" || name.toLowerCase() === "favicon.ico") return "Project name is reserved";
|
|
294
|
-
}
|
|
295
|
-
const hasPWACompatibleFrontend = (webFrontend) => webFrontend.some((f) => [
|
|
296
|
-
"tanstack-router",
|
|
297
|
-
"react-router",
|
|
298
|
-
"react-vite",
|
|
299
|
-
"solid",
|
|
300
|
-
"next",
|
|
301
|
-
"astro"
|
|
302
|
-
].includes(f));
|
|
303
|
-
const hasTauriCompatibleFrontend = (webFrontend) => webFrontend.some((f) => [
|
|
304
|
-
"tanstack-router",
|
|
305
|
-
"react-router",
|
|
306
|
-
"react-vite",
|
|
307
|
-
"nuxt",
|
|
308
|
-
"svelte",
|
|
309
|
-
"solid",
|
|
310
|
-
"next",
|
|
311
|
-
"astro"
|
|
312
|
-
].includes(f));
|
|
313
|
-
const hasDockerComposeCompatibleFrontend = (webFrontend) => webFrontend.some((f) => [
|
|
314
|
-
"tanstack-router",
|
|
315
|
-
"react-router",
|
|
316
|
-
"react-vite",
|
|
317
|
-
"solid",
|
|
318
|
-
"next",
|
|
319
|
-
"astro"
|
|
320
|
-
].includes(f));
|
|
321
|
-
const isChatSdkExampleSupported = (stack) => {
|
|
322
|
-
if (stack.ecosystem !== "typescript") return false;
|
|
323
|
-
if (stack.backend === "self-next" || stack.backend === "self-tanstack-start") return true;
|
|
324
|
-
if (stack.backend === "self-nuxt") return true;
|
|
325
|
-
if (stack.backend === "hono") return stack.runtime === "node";
|
|
326
|
-
return false;
|
|
327
|
-
};
|
|
328
|
-
const requiresChatSdkVercelAI = (stack) => {
|
|
329
|
-
return stack.examples.includes("chat-sdk") && (stack.backend === "self-nuxt" || stack.backend === "hono" && stack.runtime === "node");
|
|
330
|
-
};
|
|
331
|
-
const getCategoryDisplayName = (categoryKey) => {
|
|
332
|
-
const rustCategoryNames = {
|
|
333
|
-
rustWebFramework: "Rust Web Framework",
|
|
334
|
-
rustFrontend: "Rust Frontend (WASM)",
|
|
335
|
-
rustOrm: "Rust ORM / Database",
|
|
336
|
-
rustApi: "Rust API Layer",
|
|
337
|
-
rustCli: "Rust CLI Tools",
|
|
338
|
-
rustLibraries: "Rust Core Libraries",
|
|
339
|
-
rustLogging: "Rust Logging",
|
|
340
|
-
rustErrorHandling: "Rust Error Handling",
|
|
341
|
-
rustCaching: "Rust Caching",
|
|
342
|
-
rustAuth: "Rust Auth"
|
|
343
|
-
};
|
|
344
|
-
const pythonCategoryNames = {
|
|
345
|
-
pythonWebFramework: "Python Web Framework",
|
|
346
|
-
pythonOrm: "Python ORM / Database",
|
|
347
|
-
pythonValidation: "Python Validation",
|
|
348
|
-
pythonAi: "Python AI / ML",
|
|
349
|
-
pythonAuth: "Python Auth",
|
|
350
|
-
pythonTaskQueue: "Python Task Queue",
|
|
351
|
-
pythonGraphql: "Python GraphQL",
|
|
352
|
-
pythonQuality: "Python Code Quality"
|
|
353
|
-
};
|
|
354
|
-
const goCategoryNames = {
|
|
355
|
-
goWebFramework: "Go Web Framework",
|
|
356
|
-
goOrm: "Go ORM / Database",
|
|
357
|
-
goApi: "Go API Layer",
|
|
358
|
-
goCli: "Go CLI Tools",
|
|
359
|
-
goLogging: "Go Logging",
|
|
360
|
-
goAuth: "Go Auth"
|
|
361
|
-
};
|
|
362
|
-
const javaCategoryNames = {
|
|
363
|
-
javaWebFramework: "Java Web Framework",
|
|
364
|
-
javaBuildTool: "Java Build Tool",
|
|
365
|
-
javaOrm: "Java ORM / Database",
|
|
366
|
-
javaAuth: "Java Auth",
|
|
367
|
-
javaLibraries: "Java Libraries",
|
|
368
|
-
javaTestingLibraries: "Java Testing Libraries"
|
|
369
|
-
};
|
|
370
|
-
if (rustCategoryNames[categoryKey]) return rustCategoryNames[categoryKey];
|
|
371
|
-
if (pythonCategoryNames[categoryKey]) return pythonCategoryNames[categoryKey];
|
|
372
|
-
if (goCategoryNames[categoryKey]) return goCategoryNames[categoryKey];
|
|
373
|
-
if (javaCategoryNames[categoryKey]) return javaCategoryNames[categoryKey];
|
|
374
|
-
const tsCategoryNames = { i18n: "Internationalization (i18n)" };
|
|
375
|
-
if (tsCategoryNames[categoryKey]) return tsCategoryNames[categoryKey];
|
|
376
|
-
const result = categoryKey.replace(/([A-Z])/g, " $1");
|
|
377
|
-
return result.charAt(0).toUpperCase() + result.slice(1);
|
|
378
|
-
};
|
|
379
|
-
/**
|
|
380
|
-
* Analyzes the stack and auto-adjusts incompatible selections.
|
|
381
|
-
* This follows the CLI approach: when you make a selection, dependent items adjust automatically.
|
|
382
|
-
* The flow is: frontend -> backend -> runtime -> database -> orm -> api -> auth -> etc.
|
|
383
|
-
*/
|
|
384
|
-
const analyzeStackCompatibility = (stack) => {
|
|
385
|
-
if (stack.yolo === "true") return {
|
|
386
|
-
adjustedStack: null,
|
|
387
|
-
notes: {},
|
|
388
|
-
changes: []
|
|
389
|
-
};
|
|
390
|
-
const nextStack = { ...stack };
|
|
391
|
-
let changed = false;
|
|
392
|
-
const notes = {};
|
|
393
|
-
const changes = [];
|
|
394
|
-
for (const cat of CATEGORY_ORDER) notes[cat] = {
|
|
395
|
-
notes: [],
|
|
396
|
-
hasIssue: false
|
|
397
|
-
};
|
|
398
|
-
if (nextStack.backend === "convex") {
|
|
399
|
-
for (const [key, value] of Object.entries({
|
|
400
|
-
runtime: "none",
|
|
401
|
-
database: "none",
|
|
402
|
-
orm: "none",
|
|
403
|
-
api: "none",
|
|
404
|
-
dbSetup: "none",
|
|
405
|
-
serverDeploy: "none",
|
|
406
|
-
search: "none",
|
|
407
|
-
fileStorage: "none"
|
|
408
|
-
})) {
|
|
409
|
-
const catKey = key;
|
|
410
|
-
if (nextStack[catKey] !== value) {
|
|
411
|
-
nextStack[catKey] = value;
|
|
412
|
-
changed = true;
|
|
413
|
-
changes.push({
|
|
414
|
-
category: "backend",
|
|
415
|
-
message: `${getCategoryDisplayName(catKey)} set to '${value}' (Convex provides this)`
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
if (nextStack.webFrontend.includes("solid")) {
|
|
420
|
-
nextStack.webFrontend = nextStack.webFrontend.filter((f) => f !== "solid");
|
|
421
|
-
if (nextStack.webFrontend.length === 0) nextStack.webFrontend = ["none"];
|
|
422
|
-
changed = true;
|
|
423
|
-
changes.push({
|
|
424
|
-
category: "backend",
|
|
425
|
-
message: "Removed Solid (incompatible with Convex)"
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
if (nextStack.webFrontend.includes("solid-start")) {
|
|
429
|
-
nextStack.webFrontend = nextStack.webFrontend.filter((f) => f !== "solid-start");
|
|
430
|
-
if (nextStack.webFrontend.length === 0) nextStack.webFrontend = ["none"];
|
|
431
|
-
changed = true;
|
|
432
|
-
changes.push({
|
|
433
|
-
category: "backend",
|
|
434
|
-
message: "Removed SolidStart (incompatible with Convex)"
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
if (nextStack.webFrontend.includes("astro")) {
|
|
438
|
-
nextStack.webFrontend = nextStack.webFrontend.filter((f) => f !== "astro");
|
|
439
|
-
if (nextStack.webFrontend.length === 0) nextStack.webFrontend = ["none"];
|
|
440
|
-
nextStack.astroIntegration = "none";
|
|
441
|
-
changed = true;
|
|
442
|
-
changes.push({
|
|
443
|
-
category: "backend",
|
|
444
|
-
message: "Removed Astro (incompatible with Convex)"
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
if (nextStack.examples.includes("ai")) {
|
|
448
|
-
if (nextStack.webFrontend.some((f) => [
|
|
449
|
-
"solid",
|
|
450
|
-
"svelte",
|
|
451
|
-
"nuxt"
|
|
452
|
-
].includes(f))) {
|
|
453
|
-
nextStack.examples = nextStack.examples.filter((e) => e !== "ai");
|
|
454
|
-
if (nextStack.examples.length === 0) nextStack.examples = ["none"];
|
|
455
|
-
changed = true;
|
|
456
|
-
changes.push({
|
|
457
|
-
category: "examples",
|
|
458
|
-
message: "AI example removed (Convex AI only supports React-based frontends including React + Vite)"
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
if (nextStack.backend === "none") {
|
|
464
|
-
const noneOverrides = {
|
|
465
|
-
runtime: "none",
|
|
466
|
-
database: "none",
|
|
467
|
-
orm: "none",
|
|
468
|
-
api: "none",
|
|
469
|
-
dbSetup: "none",
|
|
470
|
-
serverDeploy: "none",
|
|
471
|
-
payments: "none",
|
|
472
|
-
search: "none",
|
|
473
|
-
fileStorage: "none"
|
|
474
|
-
};
|
|
475
|
-
if (nextStack.ecosystem !== "go") noneOverrides.auth = "none";
|
|
476
|
-
for (const [key, value] of Object.entries(noneOverrides)) {
|
|
477
|
-
const catKey = key;
|
|
478
|
-
if (nextStack[catKey] !== value) {
|
|
479
|
-
nextStack[catKey] = value;
|
|
480
|
-
changed = true;
|
|
481
|
-
changes.push({
|
|
482
|
-
category: "backend",
|
|
483
|
-
message: `${getCategoryDisplayName(catKey)} set to '${value}' (no backend)`
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
if (nextStack.examples.length > 0 && !(nextStack.examples.length === 1 && nextStack.examples[0] === "none")) {
|
|
488
|
-
nextStack.examples = ["none"];
|
|
489
|
-
changed = true;
|
|
490
|
-
changes.push({
|
|
491
|
-
category: "backend",
|
|
492
|
-
message: "Examples cleared (no backend)"
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
if (nextStack.backend === "self-next" || nextStack.backend === "self-tanstack-start" || nextStack.backend === "self-astro" || nextStack.backend === "self-nuxt" || nextStack.backend === "self-svelte" || nextStack.backend === "self-solid-start") {
|
|
497
|
-
if (nextStack.runtime !== "none") {
|
|
498
|
-
nextStack.runtime = "none";
|
|
499
|
-
changed = true;
|
|
500
|
-
changes.push({
|
|
501
|
-
category: "backend",
|
|
502
|
-
message: "Runtime set to 'None' (fullstack uses frontend's API routes)"
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
if (nextStack.serverDeploy !== "none") {
|
|
506
|
-
nextStack.serverDeploy = "none";
|
|
507
|
-
changed = true;
|
|
508
|
-
changes.push({
|
|
509
|
-
category: "backend",
|
|
510
|
-
message: "Server deploy set to 'None' (fullstack uses frontend deployment)"
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
if (nextStack.backend === "self-next" && !nextStack.webFrontend.includes("next")) {
|
|
514
|
-
nextStack.webFrontend = ["next"];
|
|
515
|
-
changed = true;
|
|
516
|
-
changes.push({
|
|
517
|
-
category: "backend",
|
|
518
|
-
message: "Frontend set to 'Next.js' (required for Next.js fullstack)"
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
if (nextStack.backend === "self-tanstack-start" && !nextStack.webFrontend.includes("tanstack-start")) {
|
|
522
|
-
nextStack.webFrontend = ["tanstack-start"];
|
|
523
|
-
changed = true;
|
|
524
|
-
changes.push({
|
|
525
|
-
category: "backend",
|
|
526
|
-
message: "Frontend set to 'TanStack Start' (required for TanStack Start fullstack)"
|
|
527
|
-
});
|
|
528
|
-
}
|
|
529
|
-
if (nextStack.backend === "self-astro" && !nextStack.webFrontend.includes("astro")) {
|
|
530
|
-
nextStack.webFrontend = ["astro"];
|
|
531
|
-
if (nextStack.astroIntegration === "none") nextStack.astroIntegration = "react";
|
|
532
|
-
changed = true;
|
|
533
|
-
changes.push({
|
|
534
|
-
category: "backend",
|
|
535
|
-
message: "Frontend set to 'Astro' (required for Astro fullstack)"
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
if (nextStack.backend === "self-nuxt" && !nextStack.webFrontend.includes("nuxt")) {
|
|
539
|
-
nextStack.webFrontend = ["nuxt"];
|
|
540
|
-
changed = true;
|
|
541
|
-
changes.push({
|
|
542
|
-
category: "backend",
|
|
543
|
-
message: "Frontend set to 'Nuxt' (required for Nuxt fullstack)"
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
if (nextStack.backend === "self-svelte" && !nextStack.webFrontend.includes("svelte")) {
|
|
547
|
-
nextStack.webFrontend = ["svelte"];
|
|
548
|
-
changed = true;
|
|
549
|
-
changes.push({
|
|
550
|
-
category: "backend",
|
|
551
|
-
message: "Frontend set to 'SvelteKit' (required for SvelteKit fullstack)"
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
if (nextStack.backend === "self-solid-start" && !nextStack.webFrontend.includes("solid-start")) {
|
|
555
|
-
nextStack.webFrontend = ["solid-start"];
|
|
556
|
-
changed = true;
|
|
557
|
-
changes.push({
|
|
558
|
-
category: "backend",
|
|
559
|
-
message: "Frontend set to 'SolidStart' (required for SolidStart fullstack)"
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
if (nextStack.runtime === "workers" && nextStack.backend !== "hono") {
|
|
564
|
-
nextStack.backend = "hono";
|
|
565
|
-
changed = true;
|
|
566
|
-
changes.push({
|
|
567
|
-
category: "runtime",
|
|
568
|
-
message: "Backend set to 'Hono' (required for Workers)"
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
if (nextStack.runtime === "workers" && nextStack.serverDeploy === "none") {
|
|
572
|
-
nextStack.serverDeploy = "cloudflare";
|
|
573
|
-
changed = true;
|
|
574
|
-
changes.push({
|
|
575
|
-
category: "runtime",
|
|
576
|
-
message: "Server deploy set to 'Cloudflare' (required for Workers)"
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
if (nextStack.runtime === "workers" && nextStack.database === "mongodb") {
|
|
580
|
-
nextStack.database = "sqlite";
|
|
581
|
-
nextStack.orm = "drizzle";
|
|
582
|
-
nextStack.dbSetup = "d1";
|
|
583
|
-
changed = true;
|
|
584
|
-
changes.push({
|
|
585
|
-
category: "runtime",
|
|
586
|
-
message: "Database changed to SQLite with D1 (Better-Fullstack doesn't support MongoDB with Workers)"
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
if (nextStack.runtime === "none" && nextStack.backend !== "convex" && nextStack.backend !== "none" && nextStack.backend !== "self-next" && nextStack.backend !== "self-tanstack-start" && nextStack.backend !== "self-astro" && nextStack.backend !== "self-nuxt" && nextStack.backend !== "self-svelte" && nextStack.backend !== "self-solid-start") {
|
|
590
|
-
nextStack.runtime = DEFAULT_RUNTIME;
|
|
591
|
-
changed = true;
|
|
592
|
-
changes.push({
|
|
593
|
-
category: "runtime",
|
|
594
|
-
message: `Runtime set to '${DEFAULT_RUNTIME}' (required for this backend)`
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
if (nextStack.backend !== "convex" && nextStack.backend !== "none") {
|
|
598
|
-
if (nextStack.database === "none") {
|
|
599
|
-
if (nextStack.orm !== "none") {
|
|
600
|
-
nextStack.orm = "none";
|
|
601
|
-
changed = true;
|
|
602
|
-
changes.push({
|
|
603
|
-
category: "database",
|
|
604
|
-
message: "ORM set to 'None' (no database selected)"
|
|
605
|
-
});
|
|
606
|
-
}
|
|
607
|
-
if (nextStack.dbSetup !== "none") {
|
|
608
|
-
nextStack.dbSetup = "none";
|
|
609
|
-
changed = true;
|
|
610
|
-
changes.push({
|
|
611
|
-
category: "database",
|
|
612
|
-
message: "DB Setup set to 'None' (no database selected)"
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
if (nextStack.database === "mongodb") {
|
|
617
|
-
if (nextStack.orm !== "prisma" && nextStack.orm !== "mongoose") {
|
|
618
|
-
nextStack.orm = "prisma";
|
|
619
|
-
changed = true;
|
|
620
|
-
changes.push({
|
|
621
|
-
category: "database",
|
|
622
|
-
message: "ORM set to 'Prisma' (required for MongoDB)"
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
if (nextStack.dbSetup !== "mongodb-atlas" && nextStack.dbSetup !== "none" && nextStack.dbSetup !== "docker") {
|
|
626
|
-
nextStack.dbSetup = "none";
|
|
627
|
-
changed = true;
|
|
628
|
-
changes.push({
|
|
629
|
-
category: "database",
|
|
630
|
-
message: "DB Setup set to 'None' (incompatible with MongoDB)"
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
if ([
|
|
635
|
-
"sqlite",
|
|
636
|
-
"postgres",
|
|
637
|
-
"mysql"
|
|
638
|
-
].includes(nextStack.database)) {
|
|
639
|
-
if (nextStack.orm === "none") {
|
|
640
|
-
nextStack.orm = "drizzle";
|
|
641
|
-
changed = true;
|
|
642
|
-
changes.push({
|
|
643
|
-
category: "database",
|
|
644
|
-
message: "ORM set to 'Drizzle' (required for database)"
|
|
645
|
-
});
|
|
646
|
-
}
|
|
647
|
-
if (nextStack.orm === "mongoose") {
|
|
648
|
-
nextStack.orm = "drizzle";
|
|
649
|
-
changed = true;
|
|
650
|
-
changes.push({
|
|
651
|
-
category: "database",
|
|
652
|
-
message: "ORM set to 'Drizzle' (Mongoose only works with MongoDB)"
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
if (nextStack.orm !== "none" && nextStack.database === "none") if (nextStack.orm === "mongoose") {
|
|
657
|
-
nextStack.database = "mongodb";
|
|
658
|
-
changed = true;
|
|
659
|
-
changes.push({
|
|
660
|
-
category: "orm",
|
|
661
|
-
message: "Database set to 'MongoDB' (required for Mongoose)"
|
|
662
|
-
});
|
|
663
|
-
} else {
|
|
664
|
-
nextStack.database = "sqlite";
|
|
665
|
-
changed = true;
|
|
666
|
-
changes.push({
|
|
667
|
-
category: "orm",
|
|
668
|
-
message: "Database set to 'SQLite' (required for ORM)"
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
if (nextStack.dbSetup === "turso" && nextStack.database !== "sqlite") {
|
|
672
|
-
nextStack.database = "sqlite";
|
|
673
|
-
changed = true;
|
|
674
|
-
changes.push({
|
|
675
|
-
category: "dbSetup",
|
|
676
|
-
message: "Database set to 'SQLite' (required for Turso)"
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
if (nextStack.dbSetup === "d1") {
|
|
680
|
-
if (nextStack.database !== "sqlite") {
|
|
681
|
-
nextStack.database = "sqlite";
|
|
682
|
-
changed = true;
|
|
683
|
-
changes.push({
|
|
684
|
-
category: "dbSetup",
|
|
685
|
-
message: "Database set to 'SQLite' (required for D1)"
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
|
-
if (nextStack.runtime !== "workers") {
|
|
689
|
-
nextStack.runtime = "workers";
|
|
690
|
-
nextStack.backend = "hono";
|
|
691
|
-
changed = true;
|
|
692
|
-
changes.push({
|
|
693
|
-
category: "dbSetup",
|
|
694
|
-
message: "Runtime set to 'Workers' with 'Hono' (required for D1)"
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
if (nextStack.dbSetup === "neon" && nextStack.database !== "postgres") {
|
|
699
|
-
nextStack.database = "postgres";
|
|
700
|
-
changed = true;
|
|
701
|
-
changes.push({
|
|
702
|
-
category: "dbSetup",
|
|
703
|
-
message: "Database set to 'PostgreSQL' (required for Neon)"
|
|
704
|
-
});
|
|
705
|
-
}
|
|
706
|
-
if (nextStack.dbSetup === "supabase" && nextStack.database !== "postgres") {
|
|
707
|
-
nextStack.database = "postgres";
|
|
708
|
-
changed = true;
|
|
709
|
-
changes.push({
|
|
710
|
-
category: "dbSetup",
|
|
711
|
-
message: "Database set to 'PostgreSQL' (required for Supabase)"
|
|
712
|
-
});
|
|
713
|
-
}
|
|
714
|
-
if (nextStack.dbSetup === "prisma-postgres" && nextStack.database !== "postgres") {
|
|
715
|
-
nextStack.database = "postgres";
|
|
716
|
-
changed = true;
|
|
717
|
-
changes.push({
|
|
718
|
-
category: "dbSetup",
|
|
719
|
-
message: "Database set to 'PostgreSQL' (required for Prisma Postgres)"
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
|
-
if (nextStack.dbSetup === "mongodb-atlas" && nextStack.database !== "mongodb") {
|
|
723
|
-
nextStack.database = "mongodb";
|
|
724
|
-
if (nextStack.orm !== "prisma" && nextStack.orm !== "mongoose") nextStack.orm = "prisma";
|
|
725
|
-
changed = true;
|
|
726
|
-
changes.push({
|
|
727
|
-
category: "dbSetup",
|
|
728
|
-
message: "Database set to 'MongoDB' (required for MongoDB Atlas)"
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
if (nextStack.dbSetup === "planetscale" && nextStack.database !== "postgres" && nextStack.database !== "mysql") {
|
|
732
|
-
nextStack.database = "postgres";
|
|
733
|
-
changed = true;
|
|
734
|
-
changes.push({
|
|
735
|
-
category: "dbSetup",
|
|
736
|
-
message: "Database set to 'PostgreSQL' (required for PlanetScale)"
|
|
737
|
-
});
|
|
738
|
-
}
|
|
739
|
-
if (nextStack.dbSetup === "docker") {
|
|
740
|
-
if (nextStack.database === "sqlite") {
|
|
741
|
-
nextStack.dbSetup = "none";
|
|
742
|
-
changed = true;
|
|
743
|
-
changes.push({
|
|
744
|
-
category: "dbSetup",
|
|
745
|
-
message: "DB Setup set to 'None' (SQLite doesn't need Docker)"
|
|
746
|
-
});
|
|
747
|
-
}
|
|
748
|
-
if (nextStack.runtime === "workers") {
|
|
749
|
-
nextStack.dbSetup = "d1";
|
|
750
|
-
changed = true;
|
|
751
|
-
changes.push({
|
|
752
|
-
category: "dbSetup",
|
|
753
|
-
message: "DB Setup set to 'D1' (Better-Fullstack doesn't support Docker setup with Workers)"
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
if (nextStack.backend !== "convex" && nextStack.backend !== "none") {
|
|
759
|
-
if (nextStack.webFrontend.some((f) => [
|
|
760
|
-
"nuxt",
|
|
761
|
-
"svelte",
|
|
762
|
-
"solid",
|
|
763
|
-
"solid-start"
|
|
764
|
-
].includes(f)) && nextStack.api === "trpc") {
|
|
765
|
-
nextStack.api = "orpc";
|
|
766
|
-
changed = true;
|
|
767
|
-
changes.push({
|
|
768
|
-
category: "api",
|
|
769
|
-
message: "API set to 'oRPC' (required for this frontend)"
|
|
770
|
-
});
|
|
771
|
-
}
|
|
772
|
-
if (nextStack.webFrontend.includes("astro") && nextStack.astroIntegration !== "react" && nextStack.api === "trpc") {
|
|
773
|
-
nextStack.api = "orpc";
|
|
774
|
-
changed = true;
|
|
775
|
-
changes.push({
|
|
776
|
-
category: "api",
|
|
777
|
-
message: "API set to 'oRPC' (tRPC requires React integration with Astro)"
|
|
778
|
-
});
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
if (!nextStack.webFrontend.includes("astro") && nextStack.astroIntegration !== "none") {
|
|
782
|
-
nextStack.astroIntegration = "none";
|
|
783
|
-
changed = true;
|
|
784
|
-
changes.push({
|
|
785
|
-
category: "astroIntegration",
|
|
786
|
-
message: "Astro integration reset (Astro not selected)"
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
if (nextStack.webFrontend.includes("astro") && nextStack.astroIntegration === "none") {
|
|
790
|
-
if (nextStack.api === "trpc") {
|
|
791
|
-
nextStack.astroIntegration = "react";
|
|
792
|
-
changed = true;
|
|
793
|
-
changes.push({
|
|
794
|
-
category: "astroIntegration",
|
|
795
|
-
message: "Astro integration set to 'React' (required for tRPC)"
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
if (nextStack.auth === "better-auth" && nextStack.database === "redis") {
|
|
800
|
-
nextStack.auth = "none";
|
|
801
|
-
changed = true;
|
|
802
|
-
changes.push({
|
|
803
|
-
category: "auth",
|
|
804
|
-
message: "Auth set to 'None' (Better Auth requires a SQL database, not Redis)"
|
|
805
|
-
});
|
|
806
|
-
}
|
|
807
|
-
if (nextStack.auth === "better-auth" && [
|
|
808
|
-
"typeorm",
|
|
809
|
-
"sequelize",
|
|
810
|
-
"mikroorm"
|
|
811
|
-
].includes(nextStack.orm)) {
|
|
812
|
-
nextStack.auth = "none";
|
|
813
|
-
changed = true;
|
|
814
|
-
changes.push({
|
|
815
|
-
category: "auth",
|
|
816
|
-
message: `Auth set to 'None' (${nextStack.orm} has no Better Auth adapter)`
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
|
-
const normalizedAuth = normalizeCapabilitySelection("auth", {
|
|
820
|
-
ecosystem: nextStack.ecosystem,
|
|
821
|
-
backend: nextStack.backend,
|
|
822
|
-
webFrontend: nextStack.webFrontend,
|
|
823
|
-
nativeFrontend: nextStack.nativeFrontend
|
|
824
|
-
}, nextStack.auth);
|
|
825
|
-
if (normalizedAuth.normalized && nextStack.auth !== normalizedAuth.value) {
|
|
826
|
-
nextStack.auth = normalizedAuth.value;
|
|
827
|
-
changed = true;
|
|
828
|
-
changes.push({
|
|
829
|
-
category: "auth",
|
|
830
|
-
message: normalizedAuth.message ?? "Auth set to 'None'"
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
if (nextStack.payments === "dodo" && nextStack.webFrontend.includes("react-vite")) {
|
|
834
|
-
nextStack.payments = "none";
|
|
835
|
-
changed = true;
|
|
836
|
-
changes.push({
|
|
837
|
-
category: "payments",
|
|
838
|
-
message: "Payments set to 'None' (Dodo Payments support is not available for React + Vite yet)"
|
|
839
|
-
});
|
|
840
|
-
}
|
|
841
|
-
if (nextStack.payments === "polar") {
|
|
842
|
-
if (nextStack.auth !== "better-auth") {
|
|
843
|
-
nextStack.payments = "none";
|
|
844
|
-
changed = true;
|
|
845
|
-
changes.push({
|
|
846
|
-
category: "payments",
|
|
847
|
-
message: "Payments set to 'None' (Polar requires Better Auth)"
|
|
848
|
-
});
|
|
849
|
-
}
|
|
850
|
-
if (!nextStack.webFrontend.some((f) => f !== "none")) {
|
|
851
|
-
nextStack.payments = "none";
|
|
852
|
-
changed = true;
|
|
853
|
-
changes.push({
|
|
854
|
-
category: "payments",
|
|
855
|
-
message: "Payments set to 'None' (Polar requires web frontend)"
|
|
856
|
-
});
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
if (nextStack.email !== "none") {
|
|
860
|
-
if (nextStack.backend === "convex") {
|
|
861
|
-
nextStack.email = "none";
|
|
862
|
-
changed = true;
|
|
863
|
-
changes.push({
|
|
864
|
-
category: "email",
|
|
865
|
-
message: "Email set to 'None' (incompatible with Convex)"
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
if (nextStack.backend === "none") {
|
|
869
|
-
nextStack.email = "none";
|
|
870
|
-
changed = true;
|
|
871
|
-
changes.push({
|
|
872
|
-
category: "email",
|
|
873
|
-
message: "Email set to 'None' (requires backend)"
|
|
874
|
-
});
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
if (!nextStack.webFrontend.some((f) => f !== "none")) {
|
|
878
|
-
if (nextStack.cssFramework !== "none") {
|
|
879
|
-
nextStack.cssFramework = "none";
|
|
880
|
-
changed = true;
|
|
881
|
-
changes.push({
|
|
882
|
-
category: "cssFramework",
|
|
883
|
-
message: "CSS framework set to 'None' (no web frontend)"
|
|
884
|
-
});
|
|
885
|
-
}
|
|
886
|
-
if (nextStack.uiLibrary !== "none") {
|
|
887
|
-
nextStack.uiLibrary = "none";
|
|
888
|
-
changed = true;
|
|
889
|
-
changes.push({
|
|
890
|
-
category: "uiLibrary",
|
|
891
|
-
message: "UI library set to 'None' (no web frontend)"
|
|
892
|
-
});
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
if ([
|
|
896
|
-
"shadcn-ui",
|
|
897
|
-
"daisyui",
|
|
898
|
-
"nextui"
|
|
899
|
-
].includes(nextStack.uiLibrary) && nextStack.cssFramework !== "tailwind") {
|
|
900
|
-
nextStack.cssFramework = "tailwind";
|
|
901
|
-
changed = true;
|
|
902
|
-
changes.push({
|
|
903
|
-
category: "cssFramework",
|
|
904
|
-
message: `CSS framework set to 'Tailwind' (required by ${nextStack.uiLibrary})`
|
|
905
|
-
});
|
|
906
|
-
}
|
|
907
|
-
const reactOnlyLibraries = [
|
|
908
|
-
"shadcn-ui",
|
|
909
|
-
"radix-ui",
|
|
910
|
-
"chakra-ui",
|
|
911
|
-
"nextui"
|
|
912
|
-
];
|
|
913
|
-
const reactFrontends = [
|
|
914
|
-
"tanstack-router",
|
|
915
|
-
"react-router",
|
|
916
|
-
"react-vite",
|
|
917
|
-
"tanstack-start",
|
|
918
|
-
"next"
|
|
919
|
-
];
|
|
920
|
-
if (reactOnlyLibraries.includes(nextStack.uiLibrary)) {
|
|
921
|
-
const hasReactFrontend = nextStack.webFrontend.some((f) => reactFrontends.includes(f));
|
|
922
|
-
const hasAstroReact = nextStack.webFrontend.includes("astro") && nextStack.astroIntegration === "react";
|
|
923
|
-
if (!hasReactFrontend && !hasAstroReact && nextStack.webFrontend.some((f) => f !== "none")) {
|
|
924
|
-
nextStack.uiLibrary = "daisyui";
|
|
925
|
-
changed = true;
|
|
926
|
-
changes.push({
|
|
927
|
-
category: "uiLibrary",
|
|
928
|
-
message: "UI library changed to 'daisyUI' (React-only library incompatible with this frontend)"
|
|
929
|
-
});
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
if (nextStack.uiLibrary === "headless-ui") {
|
|
933
|
-
const hasReactFrontend = nextStack.webFrontend.some((f) => reactFrontends.includes(f));
|
|
934
|
-
const hasVueFrontend = nextStack.webFrontend.includes("nuxt");
|
|
935
|
-
const hasAstroReactOrVue = nextStack.webFrontend.includes("astro") && ["react", "vue"].includes(nextStack.astroIntegration);
|
|
936
|
-
if (!hasReactFrontend && !hasVueFrontend && !hasAstroReactOrVue) {
|
|
937
|
-
nextStack.uiLibrary = "daisyui";
|
|
938
|
-
changed = true;
|
|
939
|
-
changes.push({
|
|
940
|
-
category: "uiLibrary",
|
|
941
|
-
message: "UI library changed to 'daisyUI' (Headless UI requires React or Vue)"
|
|
942
|
-
});
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
if (nextStack.uiLibrary === "park-ui") {
|
|
946
|
-
const hasReactFrontend = nextStack.webFrontend.some((f) => reactFrontends.includes(f));
|
|
947
|
-
const hasVueFrontend = nextStack.webFrontend.includes("nuxt");
|
|
948
|
-
const hasSolidFrontend = nextStack.webFrontend.includes("solid");
|
|
949
|
-
const hasAstroCompatible = nextStack.webFrontend.includes("astro") && [
|
|
950
|
-
"react",
|
|
951
|
-
"vue",
|
|
952
|
-
"solid"
|
|
953
|
-
].includes(nextStack.astroIntegration);
|
|
954
|
-
if (!hasReactFrontend && !hasVueFrontend && !hasSolidFrontend && !hasAstroCompatible && nextStack.webFrontend.some((f) => f !== "none")) {
|
|
955
|
-
nextStack.uiLibrary = "daisyui";
|
|
956
|
-
changed = true;
|
|
957
|
-
changes.push({
|
|
958
|
-
category: "uiLibrary",
|
|
959
|
-
message: "UI library changed to 'daisyUI' (Park UI requires React, Vue, or Solid)"
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
const pwaCompat = hasPWACompatibleFrontend(nextStack.webFrontend);
|
|
964
|
-
const tauriCompat = hasTauriCompatibleFrontend(nextStack.webFrontend);
|
|
965
|
-
if (!pwaCompat && nextStack.appPlatforms.includes("pwa")) {
|
|
966
|
-
nextStack.appPlatforms = nextStack.appPlatforms.filter((a) => a !== "pwa");
|
|
967
|
-
changed = true;
|
|
968
|
-
changes.push({
|
|
969
|
-
category: "appPlatforms",
|
|
970
|
-
message: "PWA removed (requires compatible frontend)"
|
|
971
|
-
});
|
|
972
|
-
}
|
|
973
|
-
if (!tauriCompat && nextStack.appPlatforms.includes("tauri")) {
|
|
974
|
-
nextStack.appPlatforms = nextStack.appPlatforms.filter((a) => a !== "tauri");
|
|
975
|
-
changed = true;
|
|
976
|
-
changes.push({
|
|
977
|
-
category: "appPlatforms",
|
|
978
|
-
message: "Tauri removed (requires compatible frontend)"
|
|
979
|
-
});
|
|
980
|
-
}
|
|
981
|
-
if (nextStack.examples.includes("ai")) {
|
|
982
|
-
if (nextStack.webFrontend.includes("solid") || nextStack.webFrontend.includes("solid-start")) {
|
|
983
|
-
nextStack.examples = nextStack.examples.filter((e) => e !== "ai");
|
|
984
|
-
if (nextStack.examples.length === 0) nextStack.examples = ["none"];
|
|
985
|
-
changed = true;
|
|
986
|
-
changes.push({
|
|
987
|
-
category: "examples",
|
|
988
|
-
message: "AI removed (not compatible with Solid frontend)"
|
|
989
|
-
});
|
|
990
|
-
}
|
|
991
|
-
if (nextStack.backend === "convex") {
|
|
992
|
-
if (nextStack.webFrontend.some((f) => ["svelte", "nuxt"].includes(f))) {
|
|
993
|
-
nextStack.examples = nextStack.examples.filter((e) => e !== "ai");
|
|
994
|
-
if (nextStack.examples.length === 0) nextStack.examples = ["none"];
|
|
995
|
-
changed = true;
|
|
996
|
-
changes.push({
|
|
997
|
-
category: "examples",
|
|
998
|
-
message: "AI removed (Convex AI only supports React-based frontends including React + Vite)"
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
if (nextStack.examples.includes("chat-sdk")) {
|
|
1004
|
-
const hasReactVite = nextStack.webFrontend.includes("react-vite");
|
|
1005
|
-
if (hasReactVite || !isChatSdkExampleSupported(nextStack)) {
|
|
1006
|
-
nextStack.examples = nextStack.examples.filter((e) => e !== "chat-sdk");
|
|
1007
|
-
if (nextStack.examples.length === 0) nextStack.examples = ["none"];
|
|
1008
|
-
changed = true;
|
|
1009
|
-
let reason = "unsupported stack";
|
|
1010
|
-
if (hasReactVite) reason = "React + Vite support is not available yet";
|
|
1011
|
-
else if (nextStack.ecosystem !== "typescript") reason = "TypeScript ecosystem only";
|
|
1012
|
-
else if (nextStack.backend === "convex") reason = "Convex backend not supported in v1";
|
|
1013
|
-
else if (nextStack.backend === "none") reason = "requires a backend";
|
|
1014
|
-
else if (nextStack.backend === "hono" && nextStack.runtime !== "node") reason = "Hono profile requires Node runtime";
|
|
1015
|
-
else if (nextStack.backend.startsWith("self-")) reason = "self backend only supports Next.js, TanStack Start, or Nuxt in v1";
|
|
1016
|
-
changes.push({
|
|
1017
|
-
category: "examples",
|
|
1018
|
-
message: `Chat SDK removed (${reason})`
|
|
1019
|
-
});
|
|
1020
|
-
} else if (requiresChatSdkVercelAI(nextStack) && nextStack.aiSdk !== "vercel-ai") {
|
|
1021
|
-
nextStack.aiSdk = "vercel-ai";
|
|
1022
|
-
changed = true;
|
|
1023
|
-
changes.push({
|
|
1024
|
-
category: "ai",
|
|
1025
|
-
message: "AI SDK set to 'Vercel AI SDK' (required by Chat SDK Nuxt/Hono profile in v1)"
|
|
1026
|
-
});
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
if (nextStack.webFrontend.includes("fresh")) {
|
|
1030
|
-
if (nextStack.forms === "tanstack-form") {
|
|
1031
|
-
nextStack.forms = "none";
|
|
1032
|
-
changed = true;
|
|
1033
|
-
changes.push({
|
|
1034
|
-
category: "forms",
|
|
1035
|
-
message: "Forms set to 'None' (TanStack Form has no Preact adapter)"
|
|
1036
|
-
});
|
|
1037
|
-
}
|
|
1038
|
-
if ([
|
|
1039
|
-
"nanostores",
|
|
1040
|
-
"xstate",
|
|
1041
|
-
"tanstack-store"
|
|
1042
|
-
].includes(nextStack.stateManagement)) {
|
|
1043
|
-
const oldValue = nextStack.stateManagement;
|
|
1044
|
-
nextStack.stateManagement = "none";
|
|
1045
|
-
changed = true;
|
|
1046
|
-
changes.push({
|
|
1047
|
-
category: "stateManagement",
|
|
1048
|
-
message: `State management set to 'None' (${oldValue} requires React bindings)`
|
|
1049
|
-
});
|
|
1050
|
-
}
|
|
1051
|
-
if (nextStack.animation === "lottie") {
|
|
1052
|
-
nextStack.animation = "none";
|
|
1053
|
-
changed = true;
|
|
1054
|
-
changes.push({
|
|
1055
|
-
category: "animation",
|
|
1056
|
-
message: "Animation set to 'None' (Lottie requires lottie-react)"
|
|
1057
|
-
});
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
if (nextStack.ecosystem === "java") {
|
|
1061
|
-
if (nextStack.javaBuildTool === "none") {
|
|
1062
|
-
if (nextStack.javaWebFramework !== "none") {
|
|
1063
|
-
nextStack.javaWebFramework = "none";
|
|
1064
|
-
changed = true;
|
|
1065
|
-
changes.push({
|
|
1066
|
-
category: "javaBuildTool",
|
|
1067
|
-
message: "Java web framework set to 'None' (source-only Java does not use a framework)"
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1070
|
-
if (nextStack.javaTestingLibraries.some((library) => library !== "none")) {
|
|
1071
|
-
nextStack.javaTestingLibraries = [];
|
|
1072
|
-
changed = true;
|
|
1073
|
-
changes.push({
|
|
1074
|
-
category: "javaBuildTool",
|
|
1075
|
-
message: "Java testing libraries cleared (a build tool is required for test dependencies)"
|
|
1076
|
-
});
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
if (nextStack.javaWebFramework !== "spring-boot" || nextStack.javaBuildTool === "none") {
|
|
1080
|
-
if (nextStack.javaOrm !== "none") {
|
|
1081
|
-
nextStack.javaOrm = "none";
|
|
1082
|
-
changed = true;
|
|
1083
|
-
changes.push({
|
|
1084
|
-
category: "javaWebFramework",
|
|
1085
|
-
message: "Java ORM set to 'None' (current scaffold only supports it with Spring Boot)"
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
if (nextStack.javaAuth !== "none") {
|
|
1089
|
-
nextStack.javaAuth = "none";
|
|
1090
|
-
changed = true;
|
|
1091
|
-
changes.push({
|
|
1092
|
-
category: "javaWebFramework",
|
|
1093
|
-
message: "Java auth set to 'None' (current scaffold only supports it with Spring Boot)"
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
if (nextStack.javaLibraries.some((library) => library !== "none")) {
|
|
1097
|
-
nextStack.javaLibraries = [];
|
|
1098
|
-
changed = true;
|
|
1099
|
-
changes.push({
|
|
1100
|
-
category: "javaWebFramework",
|
|
1101
|
-
message: "Java libraries cleared (Spring libraries require Spring Boot)"
|
|
1102
|
-
});
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
if (nextStack.javaWebFramework === "spring-boot" && nextStack.javaBuildTool !== "none") {
|
|
1106
|
-
if (nextStack.javaOrm !== "spring-data-jpa") {
|
|
1107
|
-
const filteredLibraries = nextStack.javaLibraries.filter((library) => library !== "flyway" && library !== "liquibase");
|
|
1108
|
-
if (filteredLibraries.length !== nextStack.javaLibraries.length) {
|
|
1109
|
-
nextStack.javaLibraries = filteredLibraries;
|
|
1110
|
-
changed = true;
|
|
1111
|
-
changes.push({
|
|
1112
|
-
category: "javaOrm",
|
|
1113
|
-
message: "Java migration libraries cleared (Flyway and Liquibase require Spring Data JPA)"
|
|
1114
|
-
});
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
if (nextStack.javaLibraries.includes("flyway") && nextStack.javaLibraries.includes("liquibase")) {
|
|
1118
|
-
nextStack.javaLibraries = nextStack.javaLibraries.filter((library) => library !== "liquibase");
|
|
1119
|
-
changed = true;
|
|
1120
|
-
changes.push({
|
|
1121
|
-
category: "javaLibraries",
|
|
1122
|
-
message: "Liquibase cleared (Flyway and Liquibase cannot be combined)"
|
|
1123
|
-
});
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
if (nextStack.webDeploy !== "none" && !nextStack.webFrontend.some((f) => f !== "none")) {
|
|
1128
|
-
nextStack.webDeploy = "none";
|
|
1129
|
-
changed = true;
|
|
1130
|
-
changes.push({
|
|
1131
|
-
category: "webDeploy",
|
|
1132
|
-
message: "Web deploy set to 'None' (no web frontend)"
|
|
1133
|
-
});
|
|
1134
|
-
}
|
|
1135
|
-
if (nextStack.serverDeploy === "cloudflare") {
|
|
1136
|
-
if (nextStack.runtime !== "workers" || nextStack.backend !== "hono") {
|
|
1137
|
-
nextStack.serverDeploy = "none";
|
|
1138
|
-
changed = true;
|
|
1139
|
-
changes.push({
|
|
1140
|
-
category: "serverDeploy",
|
|
1141
|
-
message: "Server deploy set to 'None' (Cloudflare requires Workers + Hono)"
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
if (nextStack.serverDeploy !== "none" && [
|
|
1146
|
-
"none",
|
|
1147
|
-
"convex",
|
|
1148
|
-
"self-next",
|
|
1149
|
-
"self-tanstack-start",
|
|
1150
|
-
"self-astro",
|
|
1151
|
-
"self-nuxt",
|
|
1152
|
-
"self-svelte",
|
|
1153
|
-
"self-solid-start"
|
|
1154
|
-
].includes(nextStack.backend)) {
|
|
1155
|
-
nextStack.serverDeploy = "none";
|
|
1156
|
-
changed = true;
|
|
1157
|
-
changes.push({
|
|
1158
|
-
category: "serverDeploy",
|
|
1159
|
-
message: "Server deploy set to 'None' (not needed for this backend)"
|
|
1160
|
-
});
|
|
1161
|
-
}
|
|
1162
|
-
return {
|
|
1163
|
-
adjustedStack: changed ? nextStack : null,
|
|
1164
|
-
notes,
|
|
1165
|
-
changes
|
|
1166
|
-
};
|
|
1167
|
-
};
|
|
1168
|
-
/**
|
|
1169
|
-
* Returns a reason why an option is disabled, or null if it's enabled.
|
|
1170
|
-
*
|
|
1171
|
-
* PHILOSOPHY: Only disable options that are TRULY incompatible.
|
|
1172
|
-
* - Don't create circular dependencies
|
|
1173
|
-
* - Allow users to select options that will trigger auto-adjustments
|
|
1174
|
-
* - Follow CLI behavior: filter options based on UPSTREAM selections only
|
|
1175
|
-
*/
|
|
1176
|
-
const getDisabledReason = (currentStack, category, optionId) => {
|
|
1177
|
-
if (currentStack.backend === "convex") {
|
|
1178
|
-
if (category === "runtime" && optionId !== "none") return "Convex provides its own runtime";
|
|
1179
|
-
if (category === "database" && optionId !== "none") return "Convex provides its own database";
|
|
1180
|
-
if (category === "orm" && optionId !== "none") return "Convex has built-in data access";
|
|
1181
|
-
if (category === "api" && optionId !== "none") return "Convex provides its own API layer";
|
|
1182
|
-
if (category === "dbSetup" && optionId !== "none") return "Convex handles database setup";
|
|
1183
|
-
if (category === "serverDeploy" && optionId !== "none") return "Convex has its own deployment";
|
|
1184
|
-
if (category === "search" && optionId !== "none") return "Search requires a standalone backend";
|
|
1185
|
-
if (category === "fileStorage" && optionId !== "none") return "File storage requires a standalone backend";
|
|
1186
|
-
if (category === "webFrontend" && optionId === "solid") return "In Better-Fullstack, the Convex backend is currently not available with Solid";
|
|
1187
|
-
if (category === "webFrontend" && optionId === "astro") return "In Better-Fullstack, the Convex backend is currently not available with Astro";
|
|
1188
|
-
if (category === "examples" && optionId === "ai") {
|
|
1189
|
-
if (currentStack.webFrontend.some((f) => [
|
|
1190
|
-
"solid",
|
|
1191
|
-
"svelte",
|
|
1192
|
-
"nuxt"
|
|
1193
|
-
].includes(f))) return `Convex AI example only supports React-based frontends including React + Vite (not ${currentStack.webFrontend.find((f) => [
|
|
1194
|
-
"solid",
|
|
1195
|
-
"svelte",
|
|
1196
|
-
"nuxt"
|
|
1197
|
-
].includes(f))})`;
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
if (currentStack.backend === "none") {
|
|
1201
|
-
if (category === "runtime" && optionId !== "none") return "No backend selected";
|
|
1202
|
-
if (category === "database" && optionId !== "none") return "No backend selected";
|
|
1203
|
-
if (category === "orm" && optionId !== "none") return "No backend selected";
|
|
1204
|
-
if (category === "api" && optionId !== "none") return "No backend selected";
|
|
1205
|
-
if (category === "dbSetup" && optionId !== "none") return "No backend selected";
|
|
1206
|
-
if (category === "serverDeploy" && optionId !== "none") return "No backend selected";
|
|
1207
|
-
if (category === "payments" && optionId !== "none") return "No backend selected";
|
|
1208
|
-
if (category === "search" && optionId !== "none") return "No backend selected";
|
|
1209
|
-
if (category === "fileStorage" && optionId !== "none") return "No backend selected";
|
|
1210
|
-
if (category === "examples" && optionId !== "none") return "No backend selected";
|
|
1211
|
-
}
|
|
1212
|
-
if (currentStack.backend === "self-next") {
|
|
1213
|
-
if (category === "runtime" && optionId !== "none") return "Next.js fullstack uses built-in API routes";
|
|
1214
|
-
if (category === "webFrontend" && optionId !== "next" && optionId !== "none") return "Next.js fullstack requires Next.js frontend";
|
|
1215
|
-
if (category === "serverDeploy" && optionId !== "none") return "Fullstack uses frontend deployment";
|
|
1216
|
-
}
|
|
1217
|
-
if (currentStack.backend === "self-tanstack-start") {
|
|
1218
|
-
if (category === "runtime" && optionId !== "none") return "TanStack Start fullstack uses built-in API routes";
|
|
1219
|
-
if (category === "webFrontend" && optionId !== "tanstack-start" && optionId !== "none") return "TanStack Start fullstack requires TanStack Start frontend";
|
|
1220
|
-
if (category === "serverDeploy" && optionId !== "none") return "Fullstack uses frontend deployment";
|
|
1221
|
-
}
|
|
1222
|
-
if (currentStack.backend === "self-astro") {
|
|
1223
|
-
if (category === "runtime" && optionId !== "none") return "Astro fullstack uses built-in API routes";
|
|
1224
|
-
if (category === "webFrontend" && optionId !== "astro" && optionId !== "none") return "Astro fullstack requires Astro frontend";
|
|
1225
|
-
if (category === "serverDeploy" && optionId !== "none") return "Fullstack uses frontend deployment";
|
|
1226
|
-
}
|
|
1227
|
-
if (currentStack.backend === "self-nuxt") {
|
|
1228
|
-
if (category === "runtime" && optionId !== "none") return "Nuxt fullstack uses built-in API routes";
|
|
1229
|
-
if (category === "webFrontend" && optionId !== "nuxt" && optionId !== "none") return "Nuxt fullstack requires Nuxt frontend";
|
|
1230
|
-
if (category === "serverDeploy" && optionId !== "none") return "Fullstack uses frontend deployment";
|
|
1231
|
-
}
|
|
1232
|
-
if (currentStack.backend === "self-svelte") {
|
|
1233
|
-
if (category === "runtime" && optionId !== "none") return "SvelteKit fullstack uses built-in API routes";
|
|
1234
|
-
if (category === "webFrontend" && optionId !== "svelte" && optionId !== "none") return "SvelteKit fullstack requires SvelteKit frontend";
|
|
1235
|
-
if (category === "serverDeploy" && optionId !== "none") return "Fullstack uses frontend deployment";
|
|
1236
|
-
}
|
|
1237
|
-
if (currentStack.backend === "self-solid-start") {
|
|
1238
|
-
if (category === "runtime" && optionId !== "none") return "SolidStart fullstack uses built-in API routes";
|
|
1239
|
-
if (category === "webFrontend" && optionId !== "solid-start" && optionId !== "none") return "SolidStart fullstack requires SolidStart frontend";
|
|
1240
|
-
if (category === "serverDeploy" && optionId !== "none") return "Fullstack uses frontend deployment";
|
|
1241
|
-
}
|
|
1242
|
-
if (category === "backend") {
|
|
1243
|
-
if (optionId === "self-next" && !currentStack.webFrontend.includes("next")) return "Requires Next.js frontend";
|
|
1244
|
-
if (optionId === "self-tanstack-start" && !currentStack.webFrontend.includes("tanstack-start")) return "Requires TanStack Start frontend";
|
|
1245
|
-
if (optionId === "self-astro" && !currentStack.webFrontend.includes("astro")) return "Requires Astro frontend";
|
|
1246
|
-
if (optionId === "self-nuxt" && !currentStack.webFrontend.includes("nuxt")) return "Requires Nuxt frontend";
|
|
1247
|
-
if (optionId === "self-svelte" && !currentStack.webFrontend.includes("svelte")) return "Requires SvelteKit frontend";
|
|
1248
|
-
if (optionId === "self-solid-start" && !currentStack.webFrontend.includes("solid-start")) return "Requires SolidStart frontend";
|
|
1249
|
-
if (optionId === "convex" && currentStack.webFrontend.includes("solid")) return "In Better-Fullstack, Convex is currently not available with Solid";
|
|
1250
|
-
if (optionId === "convex" && currentStack.webFrontend.includes("solid-start")) return "In Better-Fullstack, Convex is currently not available with SolidStart";
|
|
1251
|
-
if (optionId === "convex" && currentStack.webFrontend.includes("astro")) return "In Better-Fullstack, Convex is currently not available with Astro";
|
|
1252
|
-
if (currentStack.runtime === "workers" && optionId !== "hono" && optionId !== "none") return "In Better-Fullstack, Workers runtime is currently supported only with Hono";
|
|
1253
|
-
}
|
|
1254
|
-
if (category === "runtime") {
|
|
1255
|
-
if (optionId === "workers" && currentStack.backend !== "hono") return "In Better-Fullstack, Workers runtime currently requires the Hono backend";
|
|
1256
|
-
if (optionId === "none") {
|
|
1257
|
-
if (![
|
|
1258
|
-
"convex",
|
|
1259
|
-
"none",
|
|
1260
|
-
"self-next",
|
|
1261
|
-
"self-tanstack-start",
|
|
1262
|
-
"self-astro",
|
|
1263
|
-
"self-nuxt",
|
|
1264
|
-
"self-svelte",
|
|
1265
|
-
"self-solid-start"
|
|
1266
|
-
].includes(currentStack.backend)) return "Runtime 'None' only for Convex or fullstack backends";
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
if (category === "database") {
|
|
1270
|
-
if (optionId === "mongodb" && currentStack.runtime === "workers") return "In Better-Fullstack, MongoDB is currently not available with Workers runtime";
|
|
1271
|
-
}
|
|
1272
|
-
if (category === "orm") {
|
|
1273
|
-
if (optionId === "mongoose") {
|
|
1274
|
-
if (currentStack.runtime === "workers") return "Mongoose requires MongoDB, and Better-Fullstack currently doesn't support MongoDB with Workers runtime";
|
|
1275
|
-
if (currentStack.database !== "none" && currentStack.database !== "mongodb") return "Mongoose only works with MongoDB";
|
|
1276
|
-
}
|
|
1277
|
-
if (optionId === "drizzle" && currentStack.database === "mongodb") return "Drizzle does not support MongoDB";
|
|
1278
|
-
if (optionId === "none" && currentStack.database !== "none") return "Database requires an ORM";
|
|
1279
|
-
}
|
|
1280
|
-
if (category === "dbSetup" && optionId !== "none") {
|
|
1281
|
-
if (currentStack.database === "none") return "Select a database first";
|
|
1282
|
-
if (optionId === "turso" && currentStack.database !== "sqlite") return "Turso requires SQLite";
|
|
1283
|
-
if (optionId === "d1") {
|
|
1284
|
-
if (currentStack.database !== "sqlite") return "D1 requires SQLite";
|
|
1285
|
-
if (currentStack.runtime !== "workers") return "D1 requires Workers runtime";
|
|
1286
|
-
}
|
|
1287
|
-
if (optionId === "neon" && currentStack.database !== "postgres") return "Neon requires PostgreSQL";
|
|
1288
|
-
if (optionId === "supabase" && currentStack.database !== "postgres") return "Supabase requires PostgreSQL";
|
|
1289
|
-
if (optionId === "prisma-postgres" && currentStack.database !== "postgres") return "Prisma Postgres requires PostgreSQL";
|
|
1290
|
-
if (optionId === "mongodb-atlas" && currentStack.database !== "mongodb") return "MongoDB Atlas requires MongoDB";
|
|
1291
|
-
if (optionId === "planetscale" && currentStack.database !== "postgres" && currentStack.database !== "mysql") return "PlanetScale requires PostgreSQL or MySQL";
|
|
1292
|
-
if (optionId === "docker") {
|
|
1293
|
-
if (currentStack.database === "sqlite") return "SQLite doesn't need Docker";
|
|
1294
|
-
if (currentStack.runtime === "workers") return "Docker is incompatible with Workers";
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
if (category === "api" && optionId === "trpc") {
|
|
1298
|
-
if (currentStack.webFrontend.some((f) => [
|
|
1299
|
-
"nuxt",
|
|
1300
|
-
"svelte",
|
|
1301
|
-
"solid",
|
|
1302
|
-
"solid-start"
|
|
1303
|
-
].includes(f))) return `${currentStack.webFrontend.find((f) => [
|
|
1304
|
-
"nuxt",
|
|
1305
|
-
"svelte",
|
|
1306
|
-
"solid",
|
|
1307
|
-
"solid-start"
|
|
1308
|
-
].includes(f))} requires oRPC, not tRPC`;
|
|
1309
|
-
if (currentStack.webFrontend.includes("astro") && currentStack.astroIntegration !== "react" && currentStack.astroIntegration !== "none") return `Astro with ${currentStack.astroIntegration} integration requires oRPC, not tRPC`;
|
|
1310
|
-
}
|
|
1311
|
-
if (category === "astroIntegration") {
|
|
1312
|
-
if (!currentStack.webFrontend.includes("astro") && optionId !== "none") return "Astro integration requires Astro frontend";
|
|
1313
|
-
if (currentStack.api === "trpc" && optionId !== "react" && optionId !== "none") return "tRPC requires React integration with Astro";
|
|
1314
|
-
}
|
|
1315
|
-
if (category === "auth") {
|
|
1316
|
-
if (optionId === "better-auth" && currentStack.database === "redis") return "Better Auth requires a SQL database (not Redis)";
|
|
1317
|
-
if (optionId === "better-auth" && [
|
|
1318
|
-
"typeorm",
|
|
1319
|
-
"sequelize",
|
|
1320
|
-
"mikroorm"
|
|
1321
|
-
].includes(currentStack.orm)) return `Better Auth has no ${currentStack.orm} adapter`;
|
|
1322
|
-
return getCapabilityDisabledReason("auth", {
|
|
1323
|
-
ecosystem: currentStack.ecosystem,
|
|
1324
|
-
backend: currentStack.backend,
|
|
1325
|
-
webFrontend: currentStack.webFrontend,
|
|
1326
|
-
nativeFrontend: currentStack.nativeFrontend
|
|
1327
|
-
}, optionId);
|
|
1328
|
-
}
|
|
1329
|
-
if (category === "payments" && optionId === "polar") {
|
|
1330
|
-
if (currentStack.auth !== "better-auth") return "Polar requires Better Auth";
|
|
1331
|
-
if (!currentStack.webFrontend.some((f) => f !== "none")) return "Polar requires a web frontend";
|
|
1332
|
-
}
|
|
1333
|
-
if (category === "payments" && optionId !== "none" && currentStack.webFrontend.includes("react-vite") && optionId === "dodo") return "Dodo Payments are not yet supported for React + Vite projects";
|
|
1334
|
-
if (category === "cms" && optionId === "payload") {
|
|
1335
|
-
if (!currentStack.webFrontend.includes("next")) return "Payload CMS v3 requires Next.js";
|
|
1336
|
-
}
|
|
1337
|
-
if (category === "email" && optionId !== "none") {
|
|
1338
|
-
if (currentStack.backend === "convex") return "Email integration is not available with Convex backend";
|
|
1339
|
-
if (currentStack.backend === "none") return "Email integration requires a backend";
|
|
1340
|
-
}
|
|
1341
|
-
if (category === "ai" && requiresChatSdkVercelAI(currentStack) && optionId !== "vercel-ai") return "Chat SDK example (Nuxt/Hono profile) requires Vercel AI SDK in v1";
|
|
1342
|
-
if (category === "ai" && optionId === "tanstack-ai") {
|
|
1343
|
-
const compatibleFrontends = [
|
|
1344
|
-
"tanstack-router",
|
|
1345
|
-
"react-router",
|
|
1346
|
-
"react-vite",
|
|
1347
|
-
"tanstack-start",
|
|
1348
|
-
"next",
|
|
1349
|
-
"redwood",
|
|
1350
|
-
"solid",
|
|
1351
|
-
"solid-start"
|
|
1352
|
-
];
|
|
1353
|
-
if (!currentStack.webFrontend.some((f) => compatibleFrontends.includes(f))) return "TanStack AI requires React or Solid frontend (no Vue/Svelte/Angular adapter yet)";
|
|
1354
|
-
}
|
|
1355
|
-
if (category === "appPlatforms") {
|
|
1356
|
-
if (optionId === "pwa" && !hasPWACompatibleFrontend(currentStack.webFrontend)) return "PWA requires TanStack Router, React Router, Solid, Next.js, or Astro";
|
|
1357
|
-
if (optionId === "tauri" && !hasTauriCompatibleFrontend(currentStack.webFrontend)) return "Tauri requires TanStack Router, React Router, Nuxt, Svelte, Solid, Next.js, or Astro";
|
|
1358
|
-
if (optionId === "docker-compose") {
|
|
1359
|
-
if (currentStack.backend === "convex") return "Docker Compose is not compatible with Convex backend (managed service)";
|
|
1360
|
-
if (currentStack.runtime === "workers") return "Docker Compose is not compatible with Cloudflare Workers runtime";
|
|
1361
|
-
if (currentStack.ecosystem === "typescript" && !hasDockerComposeCompatibleFrontend(currentStack.webFrontend)) return "Docker Compose currently supports Next.js, TanStack Router, React Router, React Vite, Solid, or Astro";
|
|
1362
|
-
if (currentStack.ecosystem === "typescript" && currentStack.backend === "self" && !currentStack.webFrontend.includes("next")) return "Docker Compose self-backend support currently requires Next.js";
|
|
1363
|
-
if (currentStack.ecosystem === "rust" && currentStack.rustFrontend !== "none") return "Docker Compose for Rust currently supports server-only projects";
|
|
1364
|
-
if (currentStack.ecosystem === "java" && currentStack.javaWebFramework !== "spring-boot") return "Docker Compose for Java currently requires Spring Boot";
|
|
1365
|
-
if (currentStack.ecosystem === "python" && currentStack.database !== "none" && currentStack.database !== "sqlite" && currentStack.database !== "postgres") return "Docker Compose for Python ORM projects currently supports SQLite defaults or Postgres";
|
|
1366
|
-
}
|
|
1367
|
-
if (optionId === "tanstack-query" && currentStack.api !== "none") return "TanStack Query is already included via your API layer";
|
|
1368
|
-
if ([
|
|
1369
|
-
"tanstack-query",
|
|
1370
|
-
"tanstack-table",
|
|
1371
|
-
"tanstack-virtual",
|
|
1372
|
-
"tanstack-db",
|
|
1373
|
-
"tanstack-pacer"
|
|
1374
|
-
].includes(optionId) && currentStack.webFrontend.length === 1 && currentStack.webFrontend[0] === "astro" && (!currentStack.astroIntegration || currentStack.astroIntegration === "none")) return "TanStack libraries with Astro require a UI framework integration (React, Vue, Svelte, or Solid)";
|
|
1375
|
-
}
|
|
1376
|
-
if (category === "examples") {
|
|
1377
|
-
if (optionId === "ai") {
|
|
1378
|
-
if (currentStack.webFrontend.includes("solid") || currentStack.webFrontend.includes("solid-start")) return "AI example not compatible with Solid frontend";
|
|
1379
|
-
if (currentStack.backend === "convex") {
|
|
1380
|
-
if (currentStack.webFrontend.some((f) => ["svelte", "nuxt"].includes(f))) return `Convex AI example only supports React-based frontends including React + Vite (not ${currentStack.webFrontend.find((f) => ["svelte", "nuxt"].includes(f))})`;
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
if (optionId === "chat-sdk") {
|
|
1384
|
-
if (currentStack.webFrontend.includes("react-vite")) return "Chat SDK example is not yet supported for React + Vite projects";
|
|
1385
|
-
if (currentStack.ecosystem !== "typescript") return "Chat SDK example is currently available only for TypeScript stacks";
|
|
1386
|
-
if (currentStack.backend === "convex") return "Chat SDK example is not supported with Convex backend in v1";
|
|
1387
|
-
if (currentStack.backend === "self-astro" || currentStack.backend === "self-svelte" || currentStack.backend === "self-solid-start") return "Chat SDK self backend profile supports Next.js, TanStack Start, or Nuxt in v1";
|
|
1388
|
-
if (currentStack.backend === "self-next" || currentStack.backend === "self-tanstack-start") return null;
|
|
1389
|
-
if (currentStack.backend === "self-nuxt") return null;
|
|
1390
|
-
if (currentStack.backend === "hono") {
|
|
1391
|
-
if (currentStack.runtime !== "node") return "Chat SDK Hono profile requires Node runtime in v1";
|
|
1392
|
-
return null;
|
|
1393
|
-
}
|
|
1394
|
-
if (currentStack.backend.startsWith("self-")) return "Chat SDK self backend profile supports Next.js, TanStack Start, or Nuxt in v1";
|
|
1395
|
-
if (currentStack.backend !== "none") return "Chat SDK example is only supported for self (Next/TanStack Start/Nuxt) or Hono+Node in v1";
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
const isFresh = currentStack.webFrontend.includes("fresh");
|
|
1399
|
-
if (category === "forms" && optionId === "tanstack-form" && isFresh) return "TanStack Form has no Preact adapter (Fresh uses Preact)";
|
|
1400
|
-
if (category === "stateManagement" && isFresh) {
|
|
1401
|
-
if (optionId === "nanostores") return "Nanostores requires @nanostores/react (no Preact support)";
|
|
1402
|
-
if (optionId === "xstate") return "XState requires @xstate/react (no Preact support)";
|
|
1403
|
-
if (optionId === "tanstack-store") return "TanStack Store requires @tanstack/react-store (no Preact support)";
|
|
1404
|
-
}
|
|
1405
|
-
if (category === "animation" && optionId === "lottie" && isFresh) return "Lottie uses lottie-react which requires React (not Preact)";
|
|
1406
|
-
if (category === "cssFramework") {
|
|
1407
|
-
if (!currentStack.webFrontend.some((f) => f !== "none")) {
|
|
1408
|
-
if (optionId !== "none") return "CSS framework requires a web frontend";
|
|
1409
|
-
}
|
|
1410
|
-
if ([
|
|
1411
|
-
"shadcn-ui",
|
|
1412
|
-
"daisyui",
|
|
1413
|
-
"nextui"
|
|
1414
|
-
].includes(currentStack.uiLibrary) && optionId !== "tailwind") return `${currentStack.uiLibrary === "shadcn-ui" ? "shadcn/ui" : currentStack.uiLibrary === "daisyui" ? "daisyUI" : "NextUI"} requires Tailwind CSS`;
|
|
1415
|
-
}
|
|
1416
|
-
if (category === "uiLibrary") {
|
|
1417
|
-
if (!currentStack.webFrontend.some((f) => f !== "none")) {
|
|
1418
|
-
if (optionId !== "none") return "UI library requires a web frontend";
|
|
1419
|
-
}
|
|
1420
|
-
const reactOnlyLibraries = [
|
|
1421
|
-
"shadcn-ui",
|
|
1422
|
-
"radix-ui",
|
|
1423
|
-
"chakra-ui",
|
|
1424
|
-
"nextui"
|
|
1425
|
-
];
|
|
1426
|
-
const reactFrontends = [
|
|
1427
|
-
"tanstack-router",
|
|
1428
|
-
"react-router",
|
|
1429
|
-
"react-vite",
|
|
1430
|
-
"tanstack-start",
|
|
1431
|
-
"next"
|
|
1432
|
-
];
|
|
1433
|
-
if (reactOnlyLibraries.includes(optionId)) {
|
|
1434
|
-
const hasReactFrontend = currentStack.webFrontend.some((f) => reactFrontends.includes(f));
|
|
1435
|
-
const hasAstroReact = currentStack.webFrontend.includes("astro") && currentStack.astroIntegration === "react";
|
|
1436
|
-
if (!hasReactFrontend && !hasAstroReact) return `${optionId === "shadcn-ui" ? "shadcn/ui" : optionId === "radix-ui" ? "Radix UI" : optionId === "chakra-ui" ? "Chakra UI" : "NextUI"} requires a React-based frontend`;
|
|
1437
|
-
}
|
|
1438
|
-
if (optionId === "headless-ui") {
|
|
1439
|
-
const hasReactFrontend = currentStack.webFrontend.some((f) => reactFrontends.includes(f));
|
|
1440
|
-
const hasVueFrontend = currentStack.webFrontend.includes("nuxt");
|
|
1441
|
-
const hasAstroReactOrVue = currentStack.webFrontend.includes("astro") && ["react", "vue"].includes(currentStack.astroIntegration);
|
|
1442
|
-
if (!hasReactFrontend && !hasVueFrontend && !hasAstroReactOrVue) return "Headless UI requires React or Vue frontend";
|
|
1443
|
-
}
|
|
1444
|
-
if (optionId === "park-ui") {
|
|
1445
|
-
const hasReactFrontend = currentStack.webFrontend.some((f) => reactFrontends.includes(f));
|
|
1446
|
-
const hasVueFrontend = currentStack.webFrontend.includes("nuxt");
|
|
1447
|
-
const hasSolidFrontend = currentStack.webFrontend.includes("solid") || currentStack.webFrontend.includes("solid-start");
|
|
1448
|
-
const hasAstroCompatible = currentStack.webFrontend.includes("astro") && [
|
|
1449
|
-
"react",
|
|
1450
|
-
"vue",
|
|
1451
|
-
"solid"
|
|
1452
|
-
].includes(currentStack.astroIntegration);
|
|
1453
|
-
if (!hasReactFrontend && !hasVueFrontend && !hasSolidFrontend && !hasAstroCompatible) return "Park UI requires React, Vue, or Solid frontend";
|
|
1454
|
-
if (currentStack.cssFramework === "none") return "Park UI requires a CSS framework";
|
|
1455
|
-
}
|
|
1456
|
-
if ([
|
|
1457
|
-
"shadcn-ui",
|
|
1458
|
-
"daisyui",
|
|
1459
|
-
"nextui"
|
|
1460
|
-
].includes(optionId)) {
|
|
1461
|
-
if (currentStack.cssFramework !== "tailwind") return `${optionId === "shadcn-ui" ? "shadcn/ui" : optionId === "daisyui" ? "daisyUI" : "NextUI"} requires Tailwind CSS`;
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
if (category === "webDeploy" && optionId !== "none") {
|
|
1465
|
-
if (!currentStack.webFrontend.some((f) => f !== "none")) return "Web deployment requires a web frontend";
|
|
1466
|
-
if (optionId === "vercel") {
|
|
1467
|
-
if (currentStack.webFrontend.some((f) => ["redwood", "fresh"].includes(f))) return "Vercel deployment is not available for Redwood/Fresh (they have their own deploy systems)";
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
if (category === "serverDeploy") {
|
|
1471
|
-
if (optionId === "cloudflare") {
|
|
1472
|
-
if (currentStack.runtime !== "workers") return "In Better-Fullstack, Cloudflare server deploy currently requires Workers runtime";
|
|
1473
|
-
if (currentStack.backend !== "hono") return "In Better-Fullstack, Cloudflare server deploy is currently supported only with Hono";
|
|
1474
|
-
}
|
|
1475
|
-
if (optionId === "vercel") {
|
|
1476
|
-
if (["nestjs", "adonisjs"].includes(currentStack.backend)) return "Vercel serverless functions are incompatible with persistent-process backends like NestJS/AdonisJS. Use Fly.io or Railway instead.";
|
|
1477
|
-
if (currentStack.backend === "encore") return "Encore manages its own deployment infrastructure";
|
|
1478
|
-
}
|
|
1479
|
-
if (optionId !== "none") {
|
|
1480
|
-
if ([
|
|
1481
|
-
"none",
|
|
1482
|
-
"convex",
|
|
1483
|
-
"self-next",
|
|
1484
|
-
"self-tanstack-start",
|
|
1485
|
-
"self-astro",
|
|
1486
|
-
"self-nuxt",
|
|
1487
|
-
"self-svelte",
|
|
1488
|
-
"self-solid-start"
|
|
1489
|
-
].includes(currentStack.backend)) return "Server deployment not needed for this backend";
|
|
1490
|
-
}
|
|
1491
|
-
if (optionId === "none" && currentStack.runtime === "workers") return "Workers requires server deployment";
|
|
1492
|
-
}
|
|
1493
|
-
if (category === "i18n") {
|
|
1494
|
-
if (optionId === "next-intl") {
|
|
1495
|
-
if (!currentStack.webFrontend.includes("next")) return "next-intl requires Next.js";
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
if (category === "javaWebFramework") {
|
|
1499
|
-
if (optionId === "spring-boot" && currentStack.javaBuildTool === "none") return "Spring Boot requires Maven or Gradle";
|
|
1500
|
-
}
|
|
1501
|
-
if (category === "javaBuildTool") {
|
|
1502
|
-
if (optionId === "none") {
|
|
1503
|
-
if (currentStack.javaWebFramework === "spring-boot") return "Spring Boot requires Maven or Gradle";
|
|
1504
|
-
if (currentStack.javaOrm !== "none") return "Java ORM support requires Maven or Gradle";
|
|
1505
|
-
if (currentStack.javaAuth !== "none") return "Java auth support requires Maven or Gradle";
|
|
1506
|
-
if (currentStack.javaLibraries.some((library) => library !== "none")) return "Java libraries require Maven or Gradle";
|
|
1507
|
-
if (currentStack.javaTestingLibraries.some((library) => library !== "none")) return "Java testing libraries require Maven or Gradle";
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
if (category === "javaOrm") {
|
|
1511
|
-
if (optionId !== "none" && currentStack.javaWebFramework !== "spring-boot") return "Java ORM support currently requires Spring Boot";
|
|
1512
|
-
if (optionId !== "none" && currentStack.javaBuildTool === "none") return "Java ORM support requires Maven or Gradle";
|
|
1513
|
-
}
|
|
1514
|
-
if (category === "javaAuth") {
|
|
1515
|
-
if (optionId !== "none" && currentStack.javaWebFramework !== "spring-boot") return "Java auth support currently requires Spring Boot";
|
|
1516
|
-
if (optionId !== "none" && currentStack.javaBuildTool === "none") return "Java auth support requires Maven or Gradle";
|
|
1517
|
-
}
|
|
1518
|
-
if (category === "javaLibraries") {
|
|
1519
|
-
if (optionId !== "none" && currentStack.javaWebFramework !== "spring-boot") return "Spring libraries currently require Spring Boot in the Java scaffold";
|
|
1520
|
-
if (optionId !== "none" && currentStack.javaBuildTool === "none") return "Java libraries require Maven or Gradle";
|
|
1521
|
-
if (optionId === "flyway" && currentStack.javaOrm !== "spring-data-jpa") return "Flyway currently requires Spring Data JPA in the Java scaffold";
|
|
1522
|
-
if (optionId === "liquibase" && currentStack.javaOrm !== "spring-data-jpa") return "Liquibase currently requires Spring Data JPA in the Java scaffold";
|
|
1523
|
-
if (optionId === "flyway" && currentStack.javaLibraries.includes("liquibase")) return "Flyway cannot be combined with Liquibase in the current Java scaffold";
|
|
1524
|
-
if (optionId === "liquibase" && currentStack.javaLibraries.includes("flyway")) return "Liquibase cannot be combined with Flyway in the current Java scaffold";
|
|
1525
|
-
}
|
|
1526
|
-
if (category === "javaTestingLibraries") {
|
|
1527
|
-
if (optionId !== "none" && currentStack.javaBuildTool === "none") return "Java testing libraries require Maven or Gradle";
|
|
1528
|
-
}
|
|
1529
|
-
return null;
|
|
1530
|
-
};
|
|
1531
|
-
const isOptionCompatible = (currentStack, category, optionId) => {
|
|
1532
|
-
if (currentStack.yolo === "true") return true;
|
|
1533
|
-
return getDisabledReason(currentStack, category, optionId) === null;
|
|
1534
|
-
};
|
|
1535
|
-
const WEB_FRAMEWORKS = [
|
|
1536
|
-
"tanstack-router",
|
|
1537
|
-
"react-router",
|
|
1538
|
-
"react-vite",
|
|
1539
|
-
"tanstack-start",
|
|
1540
|
-
"next",
|
|
1541
|
-
"nuxt",
|
|
1542
|
-
"svelte",
|
|
1543
|
-
"solid",
|
|
1544
|
-
"solid-start",
|
|
1545
|
-
"astro",
|
|
1546
|
-
"qwik",
|
|
1547
|
-
"angular",
|
|
1548
|
-
"redwood",
|
|
1549
|
-
"fresh",
|
|
1550
|
-
"none"
|
|
1551
|
-
];
|
|
1552
|
-
const UI_LIBRARY_COMPATIBILITY = {
|
|
1553
|
-
"shadcn-ui": {
|
|
1554
|
-
frontends: [
|
|
1555
|
-
"tanstack-router",
|
|
1556
|
-
"react-router",
|
|
1557
|
-
"react-vite",
|
|
1558
|
-
"tanstack-start",
|
|
1559
|
-
"next",
|
|
1560
|
-
"astro"
|
|
1561
|
-
],
|
|
1562
|
-
cssFrameworks: ["tailwind"]
|
|
1563
|
-
},
|
|
1564
|
-
daisyui: {
|
|
1565
|
-
frontends: [
|
|
1566
|
-
"tanstack-router",
|
|
1567
|
-
"react-router",
|
|
1568
|
-
"react-vite",
|
|
1569
|
-
"tanstack-start",
|
|
1570
|
-
"next",
|
|
1571
|
-
"nuxt",
|
|
1572
|
-
"svelte",
|
|
1573
|
-
"solid",
|
|
1574
|
-
"solid-start",
|
|
1575
|
-
"astro",
|
|
1576
|
-
"qwik",
|
|
1577
|
-
"angular",
|
|
1578
|
-
"redwood",
|
|
1579
|
-
"fresh"
|
|
1580
|
-
],
|
|
1581
|
-
cssFrameworks: ["tailwind"]
|
|
1582
|
-
},
|
|
1583
|
-
"radix-ui": {
|
|
1584
|
-
frontends: [
|
|
1585
|
-
"tanstack-router",
|
|
1586
|
-
"react-router",
|
|
1587
|
-
"react-vite",
|
|
1588
|
-
"tanstack-start",
|
|
1589
|
-
"next",
|
|
1590
|
-
"astro"
|
|
1591
|
-
],
|
|
1592
|
-
cssFrameworks: [
|
|
1593
|
-
"tailwind",
|
|
1594
|
-
"scss",
|
|
1595
|
-
"less",
|
|
1596
|
-
"postcss-only",
|
|
1597
|
-
"none"
|
|
1598
|
-
]
|
|
1599
|
-
},
|
|
1600
|
-
"headless-ui": {
|
|
1601
|
-
frontends: [
|
|
1602
|
-
"tanstack-router",
|
|
1603
|
-
"react-router",
|
|
1604
|
-
"react-vite",
|
|
1605
|
-
"tanstack-start",
|
|
1606
|
-
"next",
|
|
1607
|
-
"nuxt",
|
|
1608
|
-
"astro"
|
|
1609
|
-
],
|
|
1610
|
-
cssFrameworks: [
|
|
1611
|
-
"tailwind",
|
|
1612
|
-
"scss",
|
|
1613
|
-
"less",
|
|
1614
|
-
"postcss-only",
|
|
1615
|
-
"none"
|
|
1616
|
-
]
|
|
1617
|
-
},
|
|
1618
|
-
"park-ui": {
|
|
1619
|
-
frontends: [
|
|
1620
|
-
"tanstack-router",
|
|
1621
|
-
"react-router",
|
|
1622
|
-
"react-vite",
|
|
1623
|
-
"tanstack-start",
|
|
1624
|
-
"next",
|
|
1625
|
-
"nuxt",
|
|
1626
|
-
"solid",
|
|
1627
|
-
"solid-start",
|
|
1628
|
-
"astro"
|
|
1629
|
-
],
|
|
1630
|
-
cssFrameworks: [
|
|
1631
|
-
"tailwind",
|
|
1632
|
-
"scss",
|
|
1633
|
-
"less",
|
|
1634
|
-
"postcss-only"
|
|
1635
|
-
]
|
|
1636
|
-
},
|
|
1637
|
-
"chakra-ui": {
|
|
1638
|
-
frontends: [
|
|
1639
|
-
"tanstack-router",
|
|
1640
|
-
"react-router",
|
|
1641
|
-
"react-vite",
|
|
1642
|
-
"tanstack-start",
|
|
1643
|
-
"next",
|
|
1644
|
-
"astro"
|
|
1645
|
-
],
|
|
1646
|
-
cssFrameworks: [
|
|
1647
|
-
"tailwind",
|
|
1648
|
-
"scss",
|
|
1649
|
-
"less",
|
|
1650
|
-
"postcss-only",
|
|
1651
|
-
"none"
|
|
1652
|
-
]
|
|
1653
|
-
},
|
|
1654
|
-
nextui: {
|
|
1655
|
-
frontends: [
|
|
1656
|
-
"tanstack-router",
|
|
1657
|
-
"react-router",
|
|
1658
|
-
"react-vite",
|
|
1659
|
-
"tanstack-start",
|
|
1660
|
-
"next",
|
|
1661
|
-
"astro"
|
|
1662
|
-
],
|
|
1663
|
-
cssFrameworks: ["tailwind"]
|
|
1664
|
-
},
|
|
1665
|
-
mantine: {
|
|
1666
|
-
frontends: [
|
|
1667
|
-
"tanstack-router",
|
|
1668
|
-
"react-router",
|
|
1669
|
-
"react-vite",
|
|
1670
|
-
"tanstack-start",
|
|
1671
|
-
"next",
|
|
1672
|
-
"astro"
|
|
1673
|
-
],
|
|
1674
|
-
cssFrameworks: [
|
|
1675
|
-
"tailwind",
|
|
1676
|
-
"scss",
|
|
1677
|
-
"less",
|
|
1678
|
-
"postcss-only",
|
|
1679
|
-
"none"
|
|
1680
|
-
]
|
|
1681
|
-
},
|
|
1682
|
-
"base-ui": {
|
|
1683
|
-
frontends: [
|
|
1684
|
-
"tanstack-router",
|
|
1685
|
-
"react-router",
|
|
1686
|
-
"react-vite",
|
|
1687
|
-
"tanstack-start",
|
|
1688
|
-
"next",
|
|
1689
|
-
"astro"
|
|
1690
|
-
],
|
|
1691
|
-
cssFrameworks: [
|
|
1692
|
-
"tailwind",
|
|
1693
|
-
"scss",
|
|
1694
|
-
"less",
|
|
1695
|
-
"postcss-only",
|
|
1696
|
-
"none"
|
|
1697
|
-
]
|
|
1698
|
-
},
|
|
1699
|
-
"ark-ui": {
|
|
1700
|
-
frontends: [
|
|
1701
|
-
"tanstack-router",
|
|
1702
|
-
"react-router",
|
|
1703
|
-
"tanstack-start",
|
|
1704
|
-
"next",
|
|
1705
|
-
"nuxt",
|
|
1706
|
-
"svelte",
|
|
1707
|
-
"solid",
|
|
1708
|
-
"solid-start",
|
|
1709
|
-
"astro"
|
|
1710
|
-
],
|
|
1711
|
-
cssFrameworks: [
|
|
1712
|
-
"tailwind",
|
|
1713
|
-
"scss",
|
|
1714
|
-
"less",
|
|
1715
|
-
"postcss-only",
|
|
1716
|
-
"none"
|
|
1717
|
-
]
|
|
1718
|
-
},
|
|
1719
|
-
"react-aria": {
|
|
1720
|
-
frontends: [
|
|
1721
|
-
"tanstack-router",
|
|
1722
|
-
"react-router",
|
|
1723
|
-
"react-vite",
|
|
1724
|
-
"tanstack-start",
|
|
1725
|
-
"next",
|
|
1726
|
-
"astro"
|
|
1727
|
-
],
|
|
1728
|
-
cssFrameworks: [
|
|
1729
|
-
"tailwind",
|
|
1730
|
-
"scss",
|
|
1731
|
-
"less",
|
|
1732
|
-
"postcss-only",
|
|
1733
|
-
"none"
|
|
1734
|
-
]
|
|
1735
|
-
},
|
|
1736
|
-
none: {
|
|
1737
|
-
frontends: WEB_FRAMEWORKS,
|
|
1738
|
-
cssFrameworks: [
|
|
1739
|
-
"tailwind",
|
|
1740
|
-
"scss",
|
|
1741
|
-
"less",
|
|
1742
|
-
"postcss-only",
|
|
1743
|
-
"none"
|
|
1744
|
-
]
|
|
1745
|
-
}
|
|
1746
|
-
};
|
|
1747
|
-
const ADDON_COMPATIBILITY = {
|
|
1748
|
-
pwa: [
|
|
1749
|
-
"tanstack-router",
|
|
1750
|
-
"react-router",
|
|
1751
|
-
"react-vite",
|
|
1752
|
-
"solid",
|
|
1753
|
-
"next",
|
|
1754
|
-
"astro",
|
|
1755
|
-
"qwik",
|
|
1756
|
-
"angular",
|
|
1757
|
-
"redwood",
|
|
1758
|
-
"fresh"
|
|
1759
|
-
],
|
|
1760
|
-
tauri: [
|
|
1761
|
-
"tanstack-router",
|
|
1762
|
-
"react-router",
|
|
1763
|
-
"react-vite",
|
|
1764
|
-
"nuxt",
|
|
1765
|
-
"svelte",
|
|
1766
|
-
"solid",
|
|
1767
|
-
"next",
|
|
1768
|
-
"astro",
|
|
1769
|
-
"qwik",
|
|
1770
|
-
"angular",
|
|
1771
|
-
"redwood",
|
|
1772
|
-
"fresh"
|
|
1773
|
-
],
|
|
1774
|
-
biome: [],
|
|
1775
|
-
husky: [],
|
|
1776
|
-
lefthook: [],
|
|
1777
|
-
turborepo: [],
|
|
1778
|
-
starlight: [],
|
|
1779
|
-
ultracite: [],
|
|
1780
|
-
ruler: [],
|
|
1781
|
-
mcp: [],
|
|
1782
|
-
skills: [],
|
|
1783
|
-
oxlint: [],
|
|
1784
|
-
fumadocs: [],
|
|
1785
|
-
opentui: [],
|
|
1786
|
-
wxt: [],
|
|
1787
|
-
msw: [],
|
|
1788
|
-
storybook: [
|
|
1789
|
-
"tanstack-router",
|
|
1790
|
-
"react-router",
|
|
1791
|
-
"react-vite",
|
|
1792
|
-
"next",
|
|
1793
|
-
"nuxt",
|
|
1794
|
-
"svelte",
|
|
1795
|
-
"solid"
|
|
1796
|
-
],
|
|
1797
|
-
"tanstack-query": [
|
|
1798
|
-
"tanstack-router",
|
|
1799
|
-
"react-router",
|
|
1800
|
-
"react-vite",
|
|
1801
|
-
"tanstack-start",
|
|
1802
|
-
"next",
|
|
1803
|
-
"nuxt",
|
|
1804
|
-
"svelte",
|
|
1805
|
-
"solid",
|
|
1806
|
-
"solid-start",
|
|
1807
|
-
"angular",
|
|
1808
|
-
"astro",
|
|
1809
|
-
"redwood"
|
|
1810
|
-
],
|
|
1811
|
-
"tanstack-table": [
|
|
1812
|
-
"tanstack-router",
|
|
1813
|
-
"react-router",
|
|
1814
|
-
"react-vite",
|
|
1815
|
-
"tanstack-start",
|
|
1816
|
-
"next",
|
|
1817
|
-
"nuxt",
|
|
1818
|
-
"svelte",
|
|
1819
|
-
"solid",
|
|
1820
|
-
"solid-start",
|
|
1821
|
-
"angular",
|
|
1822
|
-
"astro",
|
|
1823
|
-
"redwood"
|
|
1824
|
-
],
|
|
1825
|
-
"tanstack-virtual": [
|
|
1826
|
-
"tanstack-router",
|
|
1827
|
-
"react-router",
|
|
1828
|
-
"react-vite",
|
|
1829
|
-
"tanstack-start",
|
|
1830
|
-
"next",
|
|
1831
|
-
"nuxt",
|
|
1832
|
-
"svelte",
|
|
1833
|
-
"solid",
|
|
1834
|
-
"solid-start",
|
|
1835
|
-
"angular",
|
|
1836
|
-
"astro",
|
|
1837
|
-
"redwood"
|
|
1838
|
-
],
|
|
1839
|
-
"tanstack-db": [
|
|
1840
|
-
"tanstack-router",
|
|
1841
|
-
"react-router",
|
|
1842
|
-
"react-vite",
|
|
1843
|
-
"tanstack-start",
|
|
1844
|
-
"next",
|
|
1845
|
-
"nuxt",
|
|
1846
|
-
"svelte",
|
|
1847
|
-
"solid",
|
|
1848
|
-
"solid-start",
|
|
1849
|
-
"astro",
|
|
1850
|
-
"redwood"
|
|
1851
|
-
],
|
|
1852
|
-
"tanstack-pacer": [
|
|
1853
|
-
"tanstack-router",
|
|
1854
|
-
"react-router",
|
|
1855
|
-
"react-vite",
|
|
1856
|
-
"tanstack-start",
|
|
1857
|
-
"next",
|
|
1858
|
-
"nuxt",
|
|
1859
|
-
"svelte",
|
|
1860
|
-
"solid",
|
|
1861
|
-
"solid-start",
|
|
1862
|
-
"angular",
|
|
1863
|
-
"astro",
|
|
1864
|
-
"redwood"
|
|
1865
|
-
],
|
|
1866
|
-
"docker-compose": [],
|
|
1867
|
-
none: []
|
|
1868
|
-
};
|
|
1869
|
-
function isWebFrontend(value) {
|
|
1870
|
-
return WEB_FRAMEWORKS.includes(value);
|
|
1871
|
-
}
|
|
1872
|
-
function splitFrontends(values = []) {
|
|
1873
|
-
return {
|
|
1874
|
-
web: values.filter((f) => isWebFrontend(f)),
|
|
1875
|
-
native: values.filter((f) => f === "native-bare" || f === "native-uniwind" || f === "native-unistyles")
|
|
1876
|
-
};
|
|
1877
|
-
}
|
|
1878
|
-
function allowedApisForFrontends(frontends = [], astroIntegration) {
|
|
1879
|
-
const includesNuxt = frontends.includes("nuxt");
|
|
1880
|
-
const includesSvelte = frontends.includes("svelte");
|
|
1881
|
-
const includesSolid = frontends.includes("solid");
|
|
1882
|
-
const includesAstro = frontends.includes("astro");
|
|
1883
|
-
const includesQwik = frontends.includes("qwik");
|
|
1884
|
-
const includesAngular = frontends.includes("angular");
|
|
1885
|
-
const includesRedwood = frontends.includes("redwood");
|
|
1886
|
-
const includesFresh = frontends.includes("fresh");
|
|
1887
|
-
const base = [
|
|
1888
|
-
"trpc",
|
|
1889
|
-
"orpc",
|
|
1890
|
-
"ts-rest",
|
|
1891
|
-
"garph",
|
|
1892
|
-
"graphql-yoga",
|
|
1893
|
-
"none"
|
|
1894
|
-
];
|
|
1895
|
-
if (includesQwik || includesAngular || includesRedwood || includesFresh) return ["graphql-yoga", "none"];
|
|
1896
|
-
const includesSolidStartApi = frontends.includes("solid-start");
|
|
1897
|
-
if (includesNuxt || includesSvelte || includesSolid || includesSolidStartApi) return [
|
|
1898
|
-
"orpc",
|
|
1899
|
-
"graphql-yoga",
|
|
1900
|
-
"none"
|
|
1901
|
-
];
|
|
1902
|
-
if (includesAstro && astroIntegration && astroIntegration !== "react") return [
|
|
1903
|
-
"orpc",
|
|
1904
|
-
"graphql-yoga",
|
|
1905
|
-
"none"
|
|
1906
|
-
];
|
|
1907
|
-
return base;
|
|
1908
|
-
}
|
|
1909
|
-
function isFrontendAllowedWithBackend(frontend, backend, auth) {
|
|
1910
|
-
if (backend === "convex" && frontend === "solid") return false;
|
|
1911
|
-
if (backend === "convex" && frontend === "solid-start") return false;
|
|
1912
|
-
if (backend === "convex" && frontend === "astro") return false;
|
|
1913
|
-
if (backend === "convex" && frontend === "qwik") return false;
|
|
1914
|
-
if (backend === "convex" && frontend === "angular") return false;
|
|
1915
|
-
if (backend === "convex" && frontend === "redwood") return false;
|
|
1916
|
-
if (backend === "convex" && frontend === "fresh") return false;
|
|
1917
|
-
if (frontend === "qwik" && backend && backend !== "none") return false;
|
|
1918
|
-
if (frontend === "angular" && backend === "self") return false;
|
|
1919
|
-
if (frontend === "redwood" && backend && backend !== "none") return false;
|
|
1920
|
-
if (frontend === "fresh" && backend && backend !== "none") return false;
|
|
1921
|
-
if (auth && auth !== "none") return getCapabilityDisabledReason("auth", {
|
|
1922
|
-
ecosystem: "typescript",
|
|
1923
|
-
backend,
|
|
1924
|
-
webFrontend: [frontend]
|
|
1925
|
-
}, auth) === null;
|
|
1926
|
-
return true;
|
|
1927
|
-
}
|
|
1928
|
-
function isExampleAIAllowed(backend, frontends = []) {
|
|
1929
|
-
const includesSolid = frontends.includes("solid");
|
|
1930
|
-
const includesSolidStart = frontends.includes("solid-start");
|
|
1931
|
-
if (includesSolid || includesSolidStart) return false;
|
|
1932
|
-
if (backend === "convex") {
|
|
1933
|
-
const includesNuxt = frontends.includes("nuxt");
|
|
1934
|
-
const includesSvelte = frontends.includes("svelte");
|
|
1935
|
-
if (includesNuxt || includesSvelte) return false;
|
|
1936
|
-
}
|
|
1937
|
-
return true;
|
|
1938
|
-
}
|
|
1939
|
-
function hasExampleChatSdkSelfFrontend(frontends = []) {
|
|
1940
|
-
return frontends.some((f) => [
|
|
1941
|
-
"next",
|
|
1942
|
-
"tanstack-start",
|
|
1943
|
-
"nuxt"
|
|
1944
|
-
].includes(f));
|
|
1945
|
-
}
|
|
1946
|
-
function isExampleChatSdkAllowed(backend, frontends = [], runtime) {
|
|
1947
|
-
if (frontends.includes("react-vite")) return false;
|
|
1948
|
-
if (!backend || backend === "none" || backend === "convex") return false;
|
|
1949
|
-
if (backend === "self") return hasExampleChatSdkSelfFrontend(frontends);
|
|
1950
|
-
if (backend === "self-next" || backend === "self-tanstack-start" || backend === "self-nuxt") return true;
|
|
1951
|
-
if (backend === "self-astro" || backend === "self-svelte" || backend === "self-solid-start") return false;
|
|
1952
|
-
if (backend === "hono") return runtime === "node";
|
|
1953
|
-
return false;
|
|
1954
|
-
}
|
|
1955
|
-
function requiresChatSdkVercelAIForSelection(backend, frontends = [], runtime) {
|
|
1956
|
-
if (backend === "self" && frontends.includes("nuxt")) return true;
|
|
1957
|
-
if (backend === "self-nuxt") return true;
|
|
1958
|
-
if (backend === "hono" && runtime === "node") return true;
|
|
1959
|
-
return false;
|
|
1960
|
-
}
|
|
1961
|
-
function validateAddonCompatibility(addon, frontend, _auth) {
|
|
1962
|
-
const compatibleFrontends = ADDON_COMPATIBILITY[addon];
|
|
1963
|
-
if (compatibleFrontends.length > 0) {
|
|
1964
|
-
if (!frontend.some((f) => compatibleFrontends.includes(f))) return {
|
|
1965
|
-
isCompatible: false,
|
|
1966
|
-
reason: `${addon} addon requires one of these frontends: ${compatibleFrontends.join(", ")}`
|
|
1967
|
-
};
|
|
1968
|
-
}
|
|
1969
|
-
return { isCompatible: true };
|
|
1970
|
-
}
|
|
1971
|
-
function getCompatibleAddons(allAddons, frontend, existingAddons = [], auth) {
|
|
1972
|
-
return allAddons.filter((addon) => {
|
|
1973
|
-
if (existingAddons.includes(addon)) return false;
|
|
1974
|
-
if (addon === "none") return false;
|
|
1975
|
-
const { isCompatible } = validateAddonCompatibility(addon, frontend, auth);
|
|
1976
|
-
return isCompatible;
|
|
1977
|
-
});
|
|
1978
|
-
}
|
|
1979
|
-
function getCompatibleUILibraries(frontends = [], astroIntegration) {
|
|
1980
|
-
const { web } = splitFrontends(frontends);
|
|
1981
|
-
if (web.length === 0) return ["none"];
|
|
1982
|
-
const webFrontend = web[0];
|
|
1983
|
-
return Object.keys(UI_LIBRARY_COMPATIBILITY).filter((lib) => {
|
|
1984
|
-
if (lib === "none") return true;
|
|
1985
|
-
const compatibility = UI_LIBRARY_COMPATIBILITY[lib];
|
|
1986
|
-
if (webFrontend === "astro") {
|
|
1987
|
-
if (astroIntegration === "react") return compatibility.frontends.some((f) => [
|
|
1988
|
-
"tanstack-router",
|
|
1989
|
-
"react-router",
|
|
1990
|
-
"react-vite",
|
|
1991
|
-
"tanstack-start",
|
|
1992
|
-
"next",
|
|
1993
|
-
"astro"
|
|
1994
|
-
].includes(f));
|
|
1995
|
-
return compatibility.frontends.some((f) => [
|
|
1996
|
-
"nuxt",
|
|
1997
|
-
"svelte",
|
|
1998
|
-
"solid",
|
|
1999
|
-
"qwik",
|
|
2000
|
-
"angular"
|
|
2001
|
-
].includes(f));
|
|
2002
|
-
}
|
|
2003
|
-
return compatibility.frontends.includes(webFrontend);
|
|
2004
|
-
});
|
|
2005
|
-
}
|
|
2006
|
-
function getCompatibleCSSFrameworks(uiLibrary) {
|
|
2007
|
-
if (!uiLibrary || uiLibrary === "none") return [
|
|
2008
|
-
"tailwind",
|
|
2009
|
-
"scss",
|
|
2010
|
-
"less",
|
|
2011
|
-
"postcss-only",
|
|
2012
|
-
"none"
|
|
2013
|
-
];
|
|
2014
|
-
return UI_LIBRARY_COMPATIBILITY[uiLibrary].cssFrameworks;
|
|
2015
|
-
}
|
|
2016
|
-
function hasWebStyling(frontends = []) {
|
|
2017
|
-
const { web } = splitFrontends(frontends);
|
|
2018
|
-
return web.length > 0;
|
|
2019
|
-
}
|
|
2020
|
-
function getCompatibleFormLibraries(frontends = []) {
|
|
2021
|
-
const hasSolid = frontends.includes("solid");
|
|
2022
|
-
const hasSolidStart = frontends.includes("solid-start");
|
|
2023
|
-
const hasQwik = frontends.includes("qwik");
|
|
2024
|
-
const hasFresh = frontends.includes("fresh");
|
|
2025
|
-
const all = [
|
|
2026
|
-
"tanstack-form",
|
|
2027
|
-
"react-hook-form",
|
|
2028
|
-
"formik",
|
|
2029
|
-
"final-form",
|
|
2030
|
-
"conform",
|
|
2031
|
-
"modular-forms",
|
|
2032
|
-
"none"
|
|
2033
|
-
];
|
|
2034
|
-
if (hasFresh) return all.filter((f) => f !== "tanstack-form" && f !== "react-hook-form" && f !== "formik");
|
|
2035
|
-
if (hasSolid || hasSolidStart || hasQwik) return all.filter((f) => f !== "react-hook-form" && f !== "formik" && f !== "final-form");
|
|
2036
|
-
return all;
|
|
2037
|
-
}
|
|
2038
|
-
function evaluateCompatibility(input) {
|
|
2039
|
-
const issues = [];
|
|
2040
|
-
const scalarChecks = [
|
|
2041
|
-
["runtime", input.runtime],
|
|
2042
|
-
["backend", input.backend],
|
|
2043
|
-
["database", input.database],
|
|
2044
|
-
["orm", input.orm],
|
|
2045
|
-
["dbSetup", input.dbSetup],
|
|
2046
|
-
["api", input.api],
|
|
2047
|
-
["auth", input.auth],
|
|
2048
|
-
["payments", input.payments],
|
|
2049
|
-
["email", input.email],
|
|
2050
|
-
["cssFramework", input.cssFramework],
|
|
2051
|
-
["uiLibrary", input.uiLibrary],
|
|
2052
|
-
["webDeploy", input.webDeploy],
|
|
2053
|
-
["serverDeploy", input.serverDeploy],
|
|
2054
|
-
["forms", input.forms],
|
|
2055
|
-
["stateManagement", input.stateManagement],
|
|
2056
|
-
["animation", input.animation],
|
|
2057
|
-
["ai", input.aiSdk],
|
|
2058
|
-
["javaWebFramework", input.javaWebFramework],
|
|
2059
|
-
["javaBuildTool", input.javaBuildTool],
|
|
2060
|
-
["javaOrm", input.javaOrm],
|
|
2061
|
-
["javaAuth", input.javaAuth]
|
|
2062
|
-
];
|
|
2063
|
-
for (const [category, optionId] of scalarChecks) {
|
|
2064
|
-
const reason = getDisabledReason(input, category, optionId);
|
|
2065
|
-
if (reason) issues.push({
|
|
2066
|
-
code: `INCOMPATIBLE_${category.toUpperCase()}`,
|
|
2067
|
-
message: reason,
|
|
2068
|
-
category,
|
|
2069
|
-
optionId
|
|
2070
|
-
});
|
|
2071
|
-
}
|
|
2072
|
-
for (const frontend of input.webFrontend) {
|
|
2073
|
-
const reason = getDisabledReason(input, "webFrontend", frontend);
|
|
2074
|
-
if (reason) issues.push({
|
|
2075
|
-
code: "INCOMPATIBLE_FRONTEND",
|
|
2076
|
-
message: reason,
|
|
2077
|
-
category: "webFrontend",
|
|
2078
|
-
optionId: frontend
|
|
2079
|
-
});
|
|
2080
|
-
}
|
|
2081
|
-
for (const addon of [
|
|
2082
|
-
...input.codeQuality,
|
|
2083
|
-
...input.documentation,
|
|
2084
|
-
...input.appPlatforms
|
|
2085
|
-
]) {
|
|
2086
|
-
const reason = getDisabledReason(input, "appPlatforms", addon);
|
|
2087
|
-
if (reason) issues.push({
|
|
2088
|
-
code: "INCOMPATIBLE_ADDON",
|
|
2089
|
-
message: reason,
|
|
2090
|
-
category: "appPlatforms",
|
|
2091
|
-
optionId: addon
|
|
2092
|
-
});
|
|
2093
|
-
}
|
|
2094
|
-
for (const addon of input.examples) {
|
|
2095
|
-
const reason = getDisabledReason(input, "examples", addon);
|
|
2096
|
-
if (reason) issues.push({
|
|
2097
|
-
code: "INCOMPATIBLE_ADDON",
|
|
2098
|
-
message: reason,
|
|
2099
|
-
category: "examples",
|
|
2100
|
-
optionId: addon
|
|
2101
|
-
});
|
|
2102
|
-
}
|
|
2103
|
-
for (const javaLibrary of input.javaLibraries) {
|
|
2104
|
-
const reason = getDisabledReason(input, "javaLibraries", javaLibrary);
|
|
2105
|
-
if (reason) issues.push({
|
|
2106
|
-
code: "INCOMPATIBLE_JAVA_LIBRARY",
|
|
2107
|
-
message: reason,
|
|
2108
|
-
category: "javaLibraries",
|
|
2109
|
-
optionId: javaLibrary
|
|
2110
|
-
});
|
|
2111
|
-
}
|
|
2112
|
-
for (const testingLibrary of input.javaTestingLibraries) {
|
|
2113
|
-
const reason = getDisabledReason(input, "javaTestingLibraries", testingLibrary);
|
|
2114
|
-
if (reason) issues.push({
|
|
2115
|
-
code: "INCOMPATIBLE_JAVA_TESTING_LIBRARY",
|
|
2116
|
-
message: reason,
|
|
2117
|
-
category: "javaTestingLibraries",
|
|
2118
|
-
optionId: testingLibrary
|
|
2119
|
-
});
|
|
2120
|
-
}
|
|
2121
|
-
return { issues };
|
|
2122
|
-
}
|
|
2123
|
-
|
|
2124
|
-
//#endregion
|
|
2125
|
-
//#region src/option-metadata.ts
|
|
2126
|
-
const WEB_FRONTEND_VALUES = [
|
|
2127
|
-
"tanstack-router",
|
|
2128
|
-
"react-router",
|
|
2129
|
-
"react-vite",
|
|
2130
|
-
"tanstack-start",
|
|
2131
|
-
"next",
|
|
2132
|
-
"nuxt",
|
|
2133
|
-
"svelte",
|
|
2134
|
-
"solid",
|
|
2135
|
-
"solid-start",
|
|
2136
|
-
"astro",
|
|
2137
|
-
"qwik",
|
|
2138
|
-
"angular",
|
|
2139
|
-
"redwood",
|
|
2140
|
-
"fresh",
|
|
2141
|
-
"none"
|
|
2142
|
-
];
|
|
2143
|
-
const NATIVE_FRONTEND_VALUES = [
|
|
2144
|
-
"native-bare",
|
|
2145
|
-
"native-uniwind",
|
|
2146
|
-
"native-unistyles",
|
|
2147
|
-
"none"
|
|
2148
|
-
];
|
|
2149
|
-
const BACKEND_BUILDER_VALUES = [
|
|
2150
|
-
"hono",
|
|
2151
|
-
"express",
|
|
2152
|
-
"fastify",
|
|
2153
|
-
"elysia",
|
|
2154
|
-
"fets",
|
|
2155
|
-
"nestjs",
|
|
2156
|
-
"adonisjs",
|
|
2157
|
-
"nitro",
|
|
2158
|
-
"encore",
|
|
2159
|
-
"convex",
|
|
2160
|
-
"self-next",
|
|
2161
|
-
"self-tanstack-start",
|
|
2162
|
-
"self-astro",
|
|
2163
|
-
"self-nuxt",
|
|
2164
|
-
"self-svelte",
|
|
2165
|
-
"self-solid-start",
|
|
2166
|
-
"none"
|
|
2167
|
-
];
|
|
2168
|
-
const CODE_QUALITY_VALUES = [
|
|
2169
|
-
"biome",
|
|
2170
|
-
"oxlint",
|
|
2171
|
-
"ultracite",
|
|
2172
|
-
"lefthook",
|
|
2173
|
-
"husky",
|
|
2174
|
-
"ruler"
|
|
2175
|
-
];
|
|
2176
|
-
const DOCUMENTATION_VALUES = ["starlight", "fumadocs"];
|
|
2177
|
-
const APP_PLATFORM_VALUES = [
|
|
2178
|
-
"turborepo",
|
|
2179
|
-
"pwa",
|
|
2180
|
-
"tauri",
|
|
2181
|
-
"wxt",
|
|
2182
|
-
"opentui",
|
|
2183
|
-
"mcp",
|
|
2184
|
-
"skills",
|
|
2185
|
-
"msw",
|
|
2186
|
-
"storybook",
|
|
2187
|
-
"tanstack-query",
|
|
2188
|
-
"tanstack-table",
|
|
2189
|
-
"tanstack-virtual",
|
|
2190
|
-
"tanstack-db",
|
|
2191
|
-
"tanstack-pacer",
|
|
2192
|
-
"docker-compose"
|
|
2193
|
-
];
|
|
2194
|
-
const EXAMPLE_VALUES = ["ai", "chat-sdk"];
|
|
2195
|
-
const BOOLEAN_OPTION_VALUES = ["true", "false"];
|
|
2196
|
-
const MULTI_SELECT_CATEGORIES = new Set([
|
|
2197
|
-
"webFrontend",
|
|
2198
|
-
"nativeFrontend",
|
|
2199
|
-
"codeQuality",
|
|
2200
|
-
"documentation",
|
|
2201
|
-
"appPlatforms",
|
|
2202
|
-
"examples",
|
|
2203
|
-
"aiDocs",
|
|
2204
|
-
"rustLibraries",
|
|
2205
|
-
"pythonAi",
|
|
2206
|
-
"javaLibraries",
|
|
2207
|
-
"javaTestingLibraries"
|
|
2208
|
-
]);
|
|
2209
|
-
const CATEGORY_VALUE_IDS = {
|
|
2210
|
-
api: API_VALUES,
|
|
2211
|
-
webFrontend: WEB_FRONTEND_VALUES,
|
|
2212
|
-
nativeFrontend: NATIVE_FRONTEND_VALUES,
|
|
2213
|
-
astroIntegration: ASTRO_INTEGRATION_VALUES,
|
|
2214
|
-
runtime: RUNTIME_VALUES,
|
|
2215
|
-
backend: BACKEND_BUILDER_VALUES,
|
|
2216
|
-
database: DATABASE_VALUES,
|
|
2217
|
-
orm: ORM_VALUES,
|
|
2218
|
-
dbSetup: DATABASE_SETUP_VALUES,
|
|
2219
|
-
webDeploy: WEB_DEPLOY_VALUES,
|
|
2220
|
-
serverDeploy: SERVER_DEPLOY_VALUES,
|
|
2221
|
-
auth: AUTH_VALUES,
|
|
2222
|
-
payments: PAYMENTS_VALUES,
|
|
2223
|
-
email: EMAIL_VALUES,
|
|
2224
|
-
fileUpload: FILE_UPLOAD_VALUES,
|
|
2225
|
-
logging: LOGGING_VALUES,
|
|
2226
|
-
observability: OBSERVABILITY_VALUES,
|
|
2227
|
-
backendLibraries: EFFECT_VALUES,
|
|
2228
|
-
stateManagement: STATE_MANAGEMENT_VALUES,
|
|
2229
|
-
forms: FORMS_VALUES,
|
|
2230
|
-
validation: VALIDATION_VALUES,
|
|
2231
|
-
testing: TESTING_VALUES,
|
|
2232
|
-
realtime: REALTIME_VALUES,
|
|
2233
|
-
jobQueue: JOB_QUEUE_VALUES,
|
|
2234
|
-
caching: CACHING_VALUES,
|
|
2235
|
-
i18n: I18N_VALUES,
|
|
2236
|
-
search: SEARCH_VALUES,
|
|
2237
|
-
fileStorage: FILE_STORAGE_VALUES,
|
|
2238
|
-
animation: ANIMATION_VALUES,
|
|
2239
|
-
cssFramework: CSS_FRAMEWORK_VALUES,
|
|
2240
|
-
uiLibrary: UI_LIBRARY_VALUES,
|
|
2241
|
-
cms: CMS_VALUES,
|
|
2242
|
-
featureFlags: FEATURE_FLAGS_VALUES,
|
|
2243
|
-
analytics: ANALYTICS_VALUES,
|
|
2244
|
-
codeQuality: CODE_QUALITY_VALUES,
|
|
2245
|
-
documentation: DOCUMENTATION_VALUES,
|
|
2246
|
-
appPlatforms: APP_PLATFORM_VALUES,
|
|
2247
|
-
packageManager: PACKAGE_MANAGER_VALUES,
|
|
2248
|
-
versionChannel: VERSION_CHANNEL_VALUES,
|
|
2249
|
-
examples: EXAMPLE_VALUES,
|
|
2250
|
-
ai: AI_VALUES,
|
|
2251
|
-
aiDocs: AI_DOCS_VALUES,
|
|
2252
|
-
git: BOOLEAN_OPTION_VALUES,
|
|
2253
|
-
install: BOOLEAN_OPTION_VALUES,
|
|
2254
|
-
effect: EFFECT_VALUES,
|
|
2255
|
-
shadcnBase: SHADCN_BASE_VALUES,
|
|
2256
|
-
shadcnStyle: SHADCN_STYLE_VALUES,
|
|
2257
|
-
shadcnIconLibrary: SHADCN_ICON_LIBRARY_VALUES,
|
|
2258
|
-
shadcnColorTheme: SHADCN_COLOR_THEME_VALUES,
|
|
2259
|
-
shadcnBaseColor: SHADCN_BASE_COLOR_VALUES,
|
|
2260
|
-
shadcnFont: SHADCN_FONT_VALUES,
|
|
2261
|
-
shadcnRadius: SHADCN_RADIUS_VALUES,
|
|
2262
|
-
rustWebFramework: RUST_WEB_FRAMEWORK_VALUES,
|
|
2263
|
-
rustFrontend: RUST_FRONTEND_VALUES,
|
|
2264
|
-
rustOrm: RUST_ORM_VALUES,
|
|
2265
|
-
rustApi: RUST_API_VALUES,
|
|
2266
|
-
rustCli: RUST_CLI_VALUES,
|
|
2267
|
-
rustLibraries: RUST_LIBRARIES_VALUES,
|
|
2268
|
-
rustLogging: RUST_LOGGING_VALUES,
|
|
2269
|
-
rustErrorHandling: RUST_ERROR_HANDLING_VALUES,
|
|
2270
|
-
rustCaching: RUST_CACHING_VALUES,
|
|
2271
|
-
rustAuth: RUST_AUTH_VALUES,
|
|
2272
|
-
pythonWebFramework: PYTHON_WEB_FRAMEWORK_VALUES,
|
|
2273
|
-
pythonOrm: PYTHON_ORM_VALUES,
|
|
2274
|
-
pythonValidation: PYTHON_VALIDATION_VALUES,
|
|
2275
|
-
pythonAi: PYTHON_AI_VALUES,
|
|
2276
|
-
pythonAuth: PYTHON_AUTH_VALUES,
|
|
2277
|
-
pythonTaskQueue: PYTHON_TASK_QUEUE_VALUES,
|
|
2278
|
-
pythonGraphql: PYTHON_GRAPHQL_VALUES,
|
|
2279
|
-
pythonQuality: PYTHON_QUALITY_VALUES,
|
|
2280
|
-
goWebFramework: GO_WEB_FRAMEWORK_VALUES,
|
|
2281
|
-
goOrm: GO_ORM_VALUES,
|
|
2282
|
-
goApi: GO_API_VALUES,
|
|
2283
|
-
goCli: GO_CLI_VALUES,
|
|
2284
|
-
goLogging: GO_LOGGING_VALUES,
|
|
2285
|
-
goAuth: GO_AUTH_VALUES,
|
|
2286
|
-
javaWebFramework: JAVA_WEB_FRAMEWORK_VALUES,
|
|
2287
|
-
javaBuildTool: JAVA_BUILD_TOOL_VALUES,
|
|
2288
|
-
javaOrm: JAVA_ORM_VALUES,
|
|
2289
|
-
javaAuth: JAVA_AUTH_VALUES,
|
|
2290
|
-
javaLibraries: JAVA_LIBRARIES_VALUES,
|
|
2291
|
-
javaTestingLibraries: JAVA_TESTING_LIBRARIES_VALUES
|
|
2292
|
-
};
|
|
2293
|
-
const EXACT_LABEL_OVERRIDES = {
|
|
2294
|
-
api: {
|
|
2295
|
-
trpc: "tRPC",
|
|
2296
|
-
orpc: "oRPC",
|
|
2297
|
-
"graphql-yoga": "GraphQL Yoga"
|
|
2298
|
-
},
|
|
2299
|
-
webFrontend: {
|
|
2300
|
-
next: "Next.js",
|
|
2301
|
-
"react-vite": "React + Vite",
|
|
2302
|
-
svelte: "SvelteKit",
|
|
2303
|
-
redwood: "RedwoodJS"
|
|
2304
|
-
},
|
|
2305
|
-
nativeFrontend: {
|
|
2306
|
-
"native-bare": "Expo + Bare",
|
|
2307
|
-
"native-uniwind": "Expo + Uniwind",
|
|
2308
|
-
"native-unistyles": "Expo + Unistyles"
|
|
2309
|
-
},
|
|
2310
|
-
runtime: {
|
|
2311
|
-
node: "Node.js",
|
|
2312
|
-
workers: "Cloudflare Workers"
|
|
2313
|
-
},
|
|
2314
|
-
backend: {
|
|
2315
|
-
fets: "feTS",
|
|
2316
|
-
nestjs: "NestJS",
|
|
2317
|
-
encore: "Encore.ts",
|
|
2318
|
-
"self-next": "Fullstack Next.js",
|
|
2319
|
-
"self-tanstack-start": "Fullstack TanStack Start",
|
|
2320
|
-
"self-astro": "Fullstack Astro",
|
|
2321
|
-
"self-nuxt": "Fullstack Nuxt",
|
|
2322
|
-
"self-svelte": "Fullstack SvelteKit",
|
|
2323
|
-
"self-solid-start": "Fullstack SolidStart"
|
|
2324
|
-
},
|
|
2325
|
-
database: {
|
|
2326
|
-
sqlite: "SQLite",
|
|
2327
|
-
postgres: "PostgreSQL",
|
|
2328
|
-
mongodb: "MongoDB",
|
|
2329
|
-
edgedb: "EdgeDB"
|
|
2330
|
-
},
|
|
2331
|
-
orm: {
|
|
2332
|
-
typeorm: "TypeORM",
|
|
2333
|
-
mikroorm: "MikroORM"
|
|
2334
|
-
},
|
|
2335
|
-
dbSetup: {
|
|
2336
|
-
d1: "Cloudflare D1",
|
|
2337
|
-
neon: "Neon Postgres",
|
|
2338
|
-
"prisma-postgres": "Prisma PostgreSQL",
|
|
2339
|
-
"mongodb-atlas": "MongoDB Atlas",
|
|
2340
|
-
planetscale: "PlanetScale"
|
|
2341
|
-
},
|
|
2342
|
-
webDeploy: {
|
|
2343
|
-
cloudflare: "Cloudflare",
|
|
2344
|
-
fly: "Fly.io",
|
|
2345
|
-
sst: "SST",
|
|
2346
|
-
vercel: "Vercel"
|
|
2347
|
-
},
|
|
2348
|
-
serverDeploy: {
|
|
2349
|
-
cloudflare: "Cloudflare",
|
|
2350
|
-
fly: "Fly.io",
|
|
2351
|
-
sst: "SST",
|
|
2352
|
-
vercel: "Vercel"
|
|
2353
|
-
},
|
|
2354
|
-
cms: { tinacms: "TinaCMS" },
|
|
2355
|
-
auth: {},
|
|
2356
|
-
payments: {
|
|
2357
|
-
"lemon-squeezy": "Lemon Squeezy",
|
|
2358
|
-
dodo: "Dodo Payments"
|
|
2359
|
-
},
|
|
2360
|
-
email: {
|
|
2361
|
-
"react-email": "React Email",
|
|
2362
|
-
sendgrid: "SendGrid",
|
|
2363
|
-
"aws-ses": "AWS SES"
|
|
2364
|
-
},
|
|
2365
|
-
fileUpload: {
|
|
2366
|
-
uploadthing: "UploadThing",
|
|
2367
|
-
filepond: "FilePond",
|
|
2368
|
-
uppy: "Uppy"
|
|
2369
|
-
},
|
|
2370
|
-
observability: { opentelemetry: "OpenTelemetry" },
|
|
2371
|
-
backendLibraries: {
|
|
2372
|
-
effect: "Effect (Core)",
|
|
2373
|
-
"effect-full": "Effect Full"
|
|
2374
|
-
},
|
|
2375
|
-
stateManagement: {
|
|
2376
|
-
"redux-toolkit": "Redux Toolkit",
|
|
2377
|
-
xstate: "XState"
|
|
2378
|
-
},
|
|
2379
|
-
forms: {
|
|
2380
|
-
"react-hook-form": "React Hook Form",
|
|
2381
|
-
"tanstack-form": "TanStack Form",
|
|
2382
|
-
"final-form": "Final Form",
|
|
2383
|
-
"modular-forms": "Modular Forms"
|
|
2384
|
-
},
|
|
2385
|
-
validation: {
|
|
2386
|
-
zod: "Zod",
|
|
2387
|
-
arktype: "ArkType",
|
|
2388
|
-
typebox: "TypeBox",
|
|
2389
|
-
"effect-schema": "@effect/schema"
|
|
2390
|
-
},
|
|
2391
|
-
testing: { "vitest-playwright": "Vitest + Playwright" },
|
|
2392
|
-
realtime: {
|
|
2393
|
-
"socket-io": "Socket.IO",
|
|
2394
|
-
yjs: "Y.js"
|
|
2395
|
-
},
|
|
2396
|
-
jobQueue: {
|
|
2397
|
-
bullmq: "BullMQ",
|
|
2398
|
-
"trigger-dev": "Trigger.dev"
|
|
2399
|
-
},
|
|
2400
|
-
i18n: {
|
|
2401
|
-
i18next: "i18next",
|
|
2402
|
-
"next-intl": "next-intl"
|
|
2403
|
-
},
|
|
2404
|
-
search: {
|
|
2405
|
-
meilisearch: "Meilisearch",
|
|
2406
|
-
typesense: "Typesense",
|
|
2407
|
-
elasticsearch: "Elasticsearch",
|
|
2408
|
-
algolia: "Algolia"
|
|
2409
|
-
},
|
|
2410
|
-
cssFramework: {
|
|
2411
|
-
tailwind: "Tailwind CSS",
|
|
2412
|
-
scss: "SCSS",
|
|
2413
|
-
"postcss-only": "PostCSS Only"
|
|
2414
|
-
},
|
|
2415
|
-
uiLibrary: {
|
|
2416
|
-
"shadcn-ui": "shadcn/ui",
|
|
2417
|
-
daisyui: "daisyUI",
|
|
2418
|
-
"radix-ui": "Radix UI",
|
|
2419
|
-
"headless-ui": "Headless UI",
|
|
2420
|
-
"park-ui": "Park UI",
|
|
2421
|
-
"chakra-ui": "Chakra UI",
|
|
2422
|
-
nextui: "NextUI",
|
|
2423
|
-
"base-ui": "Base UI",
|
|
2424
|
-
"ark-ui": "Ark UI",
|
|
2425
|
-
"react-aria": "React Aria"
|
|
2426
|
-
},
|
|
2427
|
-
featureFlags: {
|
|
2428
|
-
growthbook: "GrowthBook",
|
|
2429
|
-
posthog: "PostHog"
|
|
2430
|
-
},
|
|
2431
|
-
analytics: {
|
|
2432
|
-
plausible: "Plausible",
|
|
2433
|
-
umami: "Umami"
|
|
2434
|
-
},
|
|
2435
|
-
codeQuality: {
|
|
2436
|
-
biome: "Biome",
|
|
2437
|
-
oxlint: "Oxlint",
|
|
2438
|
-
ultracite: "Ultracite",
|
|
2439
|
-
lefthook: "Lefthook",
|
|
2440
|
-
husky: "Husky",
|
|
2441
|
-
ruler: "Ruler"
|
|
2442
|
-
},
|
|
2443
|
-
documentation: {
|
|
2444
|
-
starlight: "Starlight",
|
|
2445
|
-
fumadocs: "Fumadocs"
|
|
2446
|
-
},
|
|
2447
|
-
appPlatforms: {
|
|
2448
|
-
pwa: "PWA",
|
|
2449
|
-
wxt: "WXT",
|
|
2450
|
-
opentui: "OpenTUI",
|
|
2451
|
-
mcp: "MCP",
|
|
2452
|
-
msw: "MSW",
|
|
2453
|
-
"tanstack-query": "TanStack Query",
|
|
2454
|
-
"tanstack-table": "TanStack Table",
|
|
2455
|
-
"tanstack-virtual": "TanStack Virtual",
|
|
2456
|
-
"tanstack-db": "TanStack DB",
|
|
2457
|
-
"tanstack-pacer": "TanStack Pacer",
|
|
2458
|
-
"docker-compose": "Docker Compose"
|
|
2459
|
-
},
|
|
2460
|
-
versionChannel: {
|
|
2461
|
-
stable: "Stable",
|
|
2462
|
-
latest: "Latest",
|
|
2463
|
-
beta: "Beta"
|
|
2464
|
-
},
|
|
2465
|
-
examples: {
|
|
2466
|
-
ai: "AI Example",
|
|
2467
|
-
"chat-sdk": "Chat SDK Bots"
|
|
2468
|
-
},
|
|
2469
|
-
ai: {
|
|
2470
|
-
"vercel-ai": "Vercel AI SDK",
|
|
2471
|
-
voltagent: "VoltAgent",
|
|
2472
|
-
langgraph: "LangGraph.js",
|
|
2473
|
-
"openai-agents": "OpenAI Agents SDK",
|
|
2474
|
-
"google-adk": "Google ADK",
|
|
2475
|
-
modelfusion: "ModelFusion",
|
|
2476
|
-
langchain: "LangChain",
|
|
2477
|
-
llamaindex: "LlamaIndex",
|
|
2478
|
-
"tanstack-ai": "TanStack AI",
|
|
2479
|
-
"ai-cli": "AI CLI"
|
|
2480
|
-
},
|
|
2481
|
-
aiDocs: {
|
|
2482
|
-
"claude-md": "CLAUDE.md",
|
|
2483
|
-
"agents-md": "Agents.md",
|
|
2484
|
-
cursorrules: ".cursorrules"
|
|
2485
|
-
},
|
|
2486
|
-
git: {
|
|
2487
|
-
true: "Git",
|
|
2488
|
-
false: "No Git"
|
|
2489
|
-
},
|
|
2490
|
-
install: {
|
|
2491
|
-
true: "Install Dependencies",
|
|
2492
|
-
false: "Skip Install"
|
|
2493
|
-
},
|
|
2494
|
-
effect: {
|
|
2495
|
-
effect: "Effect (Core)",
|
|
2496
|
-
"effect-full": "Effect Full"
|
|
2497
|
-
},
|
|
2498
|
-
shadcnBase: {
|
|
2499
|
-
radix: "Radix UI",
|
|
2500
|
-
base: "Base UI"
|
|
2501
|
-
},
|
|
2502
|
-
shadcnStyle: {
|
|
2503
|
-
vega: "Vega",
|
|
2504
|
-
nova: "Nova",
|
|
2505
|
-
maia: "Maia",
|
|
2506
|
-
lyra: "Lyra",
|
|
2507
|
-
mira: "Mira"
|
|
2508
|
-
},
|
|
2509
|
-
shadcnIconLibrary: {
|
|
2510
|
-
lucide: "Lucide",
|
|
2511
|
-
tabler: "Tabler Icons",
|
|
2512
|
-
hugeicons: "HugeIcons",
|
|
2513
|
-
phosphor: "Phosphor Icons",
|
|
2514
|
-
remixicon: "Remix Icon"
|
|
2515
|
-
},
|
|
2516
|
-
shadcnColorTheme: { neutral: "Neutral" },
|
|
2517
|
-
shadcnBaseColor: { neutral: "Neutral" },
|
|
2518
|
-
shadcnFont: {
|
|
2519
|
-
inter: "Inter",
|
|
2520
|
-
geist: "Geist",
|
|
2521
|
-
figtree: "Figtree",
|
|
2522
|
-
"noto-sans": "Noto Sans",
|
|
2523
|
-
"nunito-sans": "Nunito Sans",
|
|
2524
|
-
roboto: "Roboto",
|
|
2525
|
-
raleway: "Raleway",
|
|
2526
|
-
"dm-sans": "DM Sans",
|
|
2527
|
-
"public-sans": "Public Sans",
|
|
2528
|
-
outfit: "Outfit",
|
|
2529
|
-
"jetbrains-mono": "JetBrains Mono",
|
|
2530
|
-
"geist-mono": "Geist Mono"
|
|
2531
|
-
},
|
|
2532
|
-
shadcnRadius: { default: "Default" },
|
|
2533
|
-
rustWebFramework: {
|
|
2534
|
-
axum: "Axum",
|
|
2535
|
-
"actix-web": "Actix-web",
|
|
2536
|
-
rocket: "Rocket"
|
|
2537
|
-
},
|
|
2538
|
-
rustFrontend: {
|
|
2539
|
-
leptos: "Leptos",
|
|
2540
|
-
dioxus: "Dioxus"
|
|
2541
|
-
},
|
|
2542
|
-
rustOrm: {
|
|
2543
|
-
"sea-orm": "SeaORM",
|
|
2544
|
-
sqlx: "SQLx",
|
|
2545
|
-
diesel: "Diesel"
|
|
2546
|
-
},
|
|
2547
|
-
rustApi: {
|
|
2548
|
-
"async-graphql": "async-graphql",
|
|
2549
|
-
tonic: "Tonic"
|
|
2550
|
-
},
|
|
2551
|
-
rustCli: {
|
|
2552
|
-
clap: "Clap",
|
|
2553
|
-
ratatui: "Ratatui"
|
|
2554
|
-
},
|
|
2555
|
-
rustLibraries: {
|
|
2556
|
-
serde: "Serde",
|
|
2557
|
-
validator: "Validator",
|
|
2558
|
-
jsonwebtoken: "jsonwebtoken",
|
|
2559
|
-
argon2: "Argon2",
|
|
2560
|
-
"tokio-test": "Tokio Test",
|
|
2561
|
-
mockall: "Mockall"
|
|
2562
|
-
},
|
|
2563
|
-
rustLogging: {
|
|
2564
|
-
tracing: "Tracing",
|
|
2565
|
-
"env-logger": "env_logger"
|
|
2566
|
-
},
|
|
2567
|
-
rustErrorHandling: {
|
|
2568
|
-
"anyhow-thiserror": "anyhow + thiserror",
|
|
2569
|
-
eyre: "eyre + color-eyre"
|
|
2570
|
-
},
|
|
2571
|
-
rustCaching: {
|
|
2572
|
-
moka: "Moka",
|
|
2573
|
-
redis: "Redis"
|
|
2574
|
-
},
|
|
2575
|
-
rustAuth: { oauth2: "OAuth2" },
|
|
2576
|
-
pythonWebFramework: {
|
|
2577
|
-
fastapi: "FastAPI",
|
|
2578
|
-
django: "Django",
|
|
2579
|
-
flask: "Flask",
|
|
2580
|
-
litestar: "Litestar"
|
|
2581
|
-
},
|
|
2582
|
-
pythonOrm: {
|
|
2583
|
-
sqlalchemy: "SQLAlchemy",
|
|
2584
|
-
sqlmodel: "SQLModel",
|
|
2585
|
-
"tortoise-orm": "Tortoise ORM"
|
|
2586
|
-
},
|
|
2587
|
-
pythonValidation: { pydantic: "Pydantic" },
|
|
2588
|
-
pythonAi: {
|
|
2589
|
-
langchain: "LangChain",
|
|
2590
|
-
llamaindex: "LlamaIndex",
|
|
2591
|
-
"openai-sdk": "OpenAI SDK",
|
|
2592
|
-
"anthropic-sdk": "Anthropic SDK",
|
|
2593
|
-
langgraph: "LangGraph",
|
|
2594
|
-
crewai: "CrewAI"
|
|
2595
|
-
},
|
|
2596
|
-
pythonAuth: {
|
|
2597
|
-
authlib: "Authlib",
|
|
2598
|
-
jwt: "JWT (python-jose)"
|
|
2599
|
-
},
|
|
2600
|
-
pythonTaskQueue: { celery: "Celery" },
|
|
2601
|
-
pythonGraphql: { strawberry: "Strawberry" },
|
|
2602
|
-
pythonQuality: { ruff: "Ruff" },
|
|
2603
|
-
goWebFramework: {
|
|
2604
|
-
gin: "Gin",
|
|
2605
|
-
echo: "Echo",
|
|
2606
|
-
fiber: "Fiber",
|
|
2607
|
-
chi: "Chi"
|
|
2608
|
-
},
|
|
2609
|
-
goOrm: {
|
|
2610
|
-
gorm: "GORM",
|
|
2611
|
-
sqlc: "sqlc",
|
|
2612
|
-
ent: "Ent"
|
|
2613
|
-
},
|
|
2614
|
-
goApi: { "grpc-go": "gRPC-Go" },
|
|
2615
|
-
goCli: {
|
|
2616
|
-
cobra: "Cobra",
|
|
2617
|
-
bubbletea: "Bubble Tea"
|
|
2618
|
-
},
|
|
2619
|
-
goLogging: {
|
|
2620
|
-
zap: "Zap",
|
|
2621
|
-
zerolog: "Zerolog",
|
|
2622
|
-
slog: "slog"
|
|
2623
|
-
},
|
|
2624
|
-
goAuth: {
|
|
2625
|
-
casbin: "Casbin",
|
|
2626
|
-
jwt: "golang-jwt"
|
|
2627
|
-
},
|
|
2628
|
-
javaWebFramework: { "spring-boot": "Spring Boot" },
|
|
2629
|
-
javaBuildTool: { maven: "Maven" },
|
|
2630
|
-
javaOrm: { "spring-data-jpa": "Spring Data JPA" },
|
|
2631
|
-
javaAuth: { "spring-security": "Spring Security" },
|
|
2632
|
-
javaLibraries: {
|
|
2633
|
-
"spring-actuator": "Spring Boot Actuator",
|
|
2634
|
-
"spring-validation": "Spring Validation",
|
|
2635
|
-
flyway: "Flyway",
|
|
2636
|
-
liquibase: "Liquibase",
|
|
2637
|
-
"springdoc-openapi": "Springdoc OpenAPI",
|
|
2638
|
-
lombok: "Lombok",
|
|
2639
|
-
mapstruct: "MapStruct",
|
|
2640
|
-
caffeine: "Caffeine"
|
|
2641
|
-
},
|
|
2642
|
-
javaTestingLibraries: {
|
|
2643
|
-
junit5: "JUnit 5",
|
|
2644
|
-
mockito: "Mockito",
|
|
2645
|
-
testcontainers: "Testcontainers",
|
|
2646
|
-
assertj: "AssertJ",
|
|
2647
|
-
"rest-assured": "REST Assured",
|
|
2648
|
-
wiremock: "WireMock",
|
|
2649
|
-
awaitility: "Awaitility",
|
|
2650
|
-
archunit: "ArchUnit",
|
|
2651
|
-
jqwik: "jqwik"
|
|
2652
|
-
}
|
|
2653
|
-
};
|
|
2654
|
-
const OPTION_ALIASES = {
|
|
2655
|
-
webFrontend: { svelte: ["sveltekit"] },
|
|
2656
|
-
backend: { "self-svelte": ["self-sveltekit"] }
|
|
2657
|
-
};
|
|
2658
|
-
const CLI_VALUE_OVERRIDES = { backend: {
|
|
2659
|
-
"self-next": "self",
|
|
2660
|
-
"self-tanstack-start": "self",
|
|
2661
|
-
"self-astro": "self",
|
|
2662
|
-
"self-nuxt": "self",
|
|
2663
|
-
"self-svelte": "self",
|
|
2664
|
-
"self-solid-start": "self"
|
|
2665
|
-
} };
|
|
2666
|
-
const TOKEN_LABELS = {
|
|
2667
|
-
ai: "AI",
|
|
2668
|
-
api: "API",
|
|
2669
|
-
auth: "Auth",
|
|
2670
|
-
css: "CSS",
|
|
2671
|
-
db: "DB",
|
|
2672
|
-
graphql: "GraphQL",
|
|
2673
|
-
grpc: "gRPC",
|
|
2674
|
-
js: "JS",
|
|
2675
|
-
md: "MD",
|
|
2676
|
-
orm: "ORM",
|
|
2677
|
-
sdk: "SDK",
|
|
2678
|
-
ses: "SES",
|
|
2679
|
-
sql: "SQL",
|
|
2680
|
-
ui: "UI"
|
|
2681
|
-
};
|
|
2682
|
-
function toStartCaseToken(token) {
|
|
2683
|
-
const lower = token.toLowerCase();
|
|
2684
|
-
if (TOKEN_LABELS[lower]) return TOKEN_LABELS[lower];
|
|
2685
|
-
return lower.charAt(0).toUpperCase() + lower.slice(1);
|
|
2686
|
-
}
|
|
2687
|
-
function humanizeOptionId(id) {
|
|
2688
|
-
return id.split("-").filter(Boolean).map(toStartCaseToken).join(" ");
|
|
2689
|
-
}
|
|
2690
|
-
function getOptionLabel(category, id) {
|
|
2691
|
-
if (category === "auth") return getCapabilityDefinitions("auth").find((option) => option.id === id)?.label ?? humanizeOptionId(id);
|
|
2692
|
-
return EXACT_LABEL_OVERRIDES[category]?.[id] ?? humanizeOptionId(id);
|
|
2693
|
-
}
|
|
2694
|
-
function getOptionAliases(category, id) {
|
|
2695
|
-
return OPTION_ALIASES[category]?.[id] ?? [];
|
|
2696
|
-
}
|
|
2697
|
-
function getCliValue(category, id) {
|
|
2698
|
-
return CLI_VALUE_OVERRIDES[category]?.[id] ?? id;
|
|
2699
|
-
}
|
|
2700
|
-
function buildCategoryMetadata(category) {
|
|
2701
|
-
return {
|
|
2702
|
-
selectionMode: MULTI_SELECT_CATEGORIES.has(category) ? "multiple" : "single",
|
|
2703
|
-
options: CATEGORY_VALUE_IDS[category].map((id) => ({
|
|
2704
|
-
id,
|
|
2705
|
-
label: getOptionLabel(category, id),
|
|
2706
|
-
aliases: getOptionAliases(category, id),
|
|
2707
|
-
cliValue: getCliValue(category, id)
|
|
2708
|
-
}))
|
|
2709
|
-
};
|
|
2710
|
-
}
|
|
2711
|
-
const OPTION_CATEGORY_METADATA = {
|
|
2712
|
-
api: buildCategoryMetadata("api"),
|
|
2713
|
-
webFrontend: buildCategoryMetadata("webFrontend"),
|
|
2714
|
-
nativeFrontend: buildCategoryMetadata("nativeFrontend"),
|
|
2715
|
-
astroIntegration: buildCategoryMetadata("astroIntegration"),
|
|
2716
|
-
runtime: buildCategoryMetadata("runtime"),
|
|
2717
|
-
backend: buildCategoryMetadata("backend"),
|
|
2718
|
-
database: buildCategoryMetadata("database"),
|
|
2719
|
-
orm: buildCategoryMetadata("orm"),
|
|
2720
|
-
dbSetup: buildCategoryMetadata("dbSetup"),
|
|
2721
|
-
webDeploy: buildCategoryMetadata("webDeploy"),
|
|
2722
|
-
serverDeploy: buildCategoryMetadata("serverDeploy"),
|
|
2723
|
-
auth: buildCategoryMetadata("auth"),
|
|
2724
|
-
payments: buildCategoryMetadata("payments"),
|
|
2725
|
-
email: buildCategoryMetadata("email"),
|
|
2726
|
-
fileUpload: buildCategoryMetadata("fileUpload"),
|
|
2727
|
-
logging: buildCategoryMetadata("logging"),
|
|
2728
|
-
observability: buildCategoryMetadata("observability"),
|
|
2729
|
-
backendLibraries: buildCategoryMetadata("backendLibraries"),
|
|
2730
|
-
stateManagement: buildCategoryMetadata("stateManagement"),
|
|
2731
|
-
forms: buildCategoryMetadata("forms"),
|
|
2732
|
-
validation: buildCategoryMetadata("validation"),
|
|
2733
|
-
testing: buildCategoryMetadata("testing"),
|
|
2734
|
-
realtime: buildCategoryMetadata("realtime"),
|
|
2735
|
-
jobQueue: buildCategoryMetadata("jobQueue"),
|
|
2736
|
-
caching: buildCategoryMetadata("caching"),
|
|
2737
|
-
i18n: buildCategoryMetadata("i18n"),
|
|
2738
|
-
search: buildCategoryMetadata("search"),
|
|
2739
|
-
fileStorage: buildCategoryMetadata("fileStorage"),
|
|
2740
|
-
animation: buildCategoryMetadata("animation"),
|
|
2741
|
-
cssFramework: buildCategoryMetadata("cssFramework"),
|
|
2742
|
-
uiLibrary: buildCategoryMetadata("uiLibrary"),
|
|
2743
|
-
cms: buildCategoryMetadata("cms"),
|
|
2744
|
-
featureFlags: buildCategoryMetadata("featureFlags"),
|
|
2745
|
-
analytics: buildCategoryMetadata("analytics"),
|
|
2746
|
-
codeQuality: buildCategoryMetadata("codeQuality"),
|
|
2747
|
-
documentation: buildCategoryMetadata("documentation"),
|
|
2748
|
-
appPlatforms: buildCategoryMetadata("appPlatforms"),
|
|
2749
|
-
packageManager: buildCategoryMetadata("packageManager"),
|
|
2750
|
-
versionChannel: buildCategoryMetadata("versionChannel"),
|
|
2751
|
-
examples: buildCategoryMetadata("examples"),
|
|
2752
|
-
ai: buildCategoryMetadata("ai"),
|
|
2753
|
-
aiDocs: buildCategoryMetadata("aiDocs"),
|
|
2754
|
-
git: buildCategoryMetadata("git"),
|
|
2755
|
-
install: buildCategoryMetadata("install"),
|
|
2756
|
-
effect: buildCategoryMetadata("effect"),
|
|
2757
|
-
shadcnBase: buildCategoryMetadata("shadcnBase"),
|
|
2758
|
-
shadcnStyle: buildCategoryMetadata("shadcnStyle"),
|
|
2759
|
-
shadcnIconLibrary: buildCategoryMetadata("shadcnIconLibrary"),
|
|
2760
|
-
shadcnColorTheme: buildCategoryMetadata("shadcnColorTheme"),
|
|
2761
|
-
shadcnBaseColor: buildCategoryMetadata("shadcnBaseColor"),
|
|
2762
|
-
shadcnFont: buildCategoryMetadata("shadcnFont"),
|
|
2763
|
-
shadcnRadius: buildCategoryMetadata("shadcnRadius"),
|
|
2764
|
-
rustWebFramework: buildCategoryMetadata("rustWebFramework"),
|
|
2765
|
-
rustFrontend: buildCategoryMetadata("rustFrontend"),
|
|
2766
|
-
rustOrm: buildCategoryMetadata("rustOrm"),
|
|
2767
|
-
rustApi: buildCategoryMetadata("rustApi"),
|
|
2768
|
-
rustCli: buildCategoryMetadata("rustCli"),
|
|
2769
|
-
rustLibraries: buildCategoryMetadata("rustLibraries"),
|
|
2770
|
-
rustLogging: buildCategoryMetadata("rustLogging"),
|
|
2771
|
-
rustErrorHandling: buildCategoryMetadata("rustErrorHandling"),
|
|
2772
|
-
rustCaching: buildCategoryMetadata("rustCaching"),
|
|
2773
|
-
rustAuth: buildCategoryMetadata("rustAuth"),
|
|
2774
|
-
pythonWebFramework: buildCategoryMetadata("pythonWebFramework"),
|
|
2775
|
-
pythonOrm: buildCategoryMetadata("pythonOrm"),
|
|
2776
|
-
pythonValidation: buildCategoryMetadata("pythonValidation"),
|
|
2777
|
-
pythonAi: buildCategoryMetadata("pythonAi"),
|
|
2778
|
-
pythonAuth: buildCategoryMetadata("pythonAuth"),
|
|
2779
|
-
pythonTaskQueue: buildCategoryMetadata("pythonTaskQueue"),
|
|
2780
|
-
pythonGraphql: buildCategoryMetadata("pythonGraphql"),
|
|
2781
|
-
pythonQuality: buildCategoryMetadata("pythonQuality"),
|
|
2782
|
-
goWebFramework: buildCategoryMetadata("goWebFramework"),
|
|
2783
|
-
goOrm: buildCategoryMetadata("goOrm"),
|
|
2784
|
-
goApi: buildCategoryMetadata("goApi"),
|
|
2785
|
-
goCli: buildCategoryMetadata("goCli"),
|
|
2786
|
-
goLogging: buildCategoryMetadata("goLogging"),
|
|
2787
|
-
goAuth: buildCategoryMetadata("goAuth"),
|
|
2788
|
-
javaWebFramework: buildCategoryMetadata("javaWebFramework"),
|
|
2789
|
-
javaBuildTool: buildCategoryMetadata("javaBuildTool"),
|
|
2790
|
-
javaOrm: buildCategoryMetadata("javaOrm"),
|
|
2791
|
-
javaAuth: buildCategoryMetadata("javaAuth"),
|
|
2792
|
-
javaLibraries: buildCategoryMetadata("javaLibraries"),
|
|
2793
|
-
javaTestingLibraries: buildCategoryMetadata("javaTestingLibraries")
|
|
2794
|
-
};
|
|
2795
|
-
const OPTION_LOOKUP = Object.fromEntries(Object.entries(OPTION_CATEGORY_METADATA).map(([category, metadata]) => [category, new Map(metadata.options.flatMap((option) => [[option.id.toLowerCase(), option.id], ...option.aliases.map((alias) => [alias.toLowerCase(), option.id])]))]));
|
|
2796
|
-
function isMultiSelectCategory(category) {
|
|
2797
|
-
return OPTION_CATEGORY_METADATA[category].selectionMode === "multiple";
|
|
2798
|
-
}
|
|
2799
|
-
function getOptionMetadata(category, optionId) {
|
|
2800
|
-
return OPTION_CATEGORY_METADATA[category].options.find((option) => option.id === optionId);
|
|
2801
|
-
}
|
|
2802
|
-
function getCategoryOptionIds(category) {
|
|
2803
|
-
return OPTION_CATEGORY_METADATA[category].options.map((option) => option.id);
|
|
2804
|
-
}
|
|
2805
|
-
function getCategoryCliValues(category) {
|
|
2806
|
-
return [...new Set(OPTION_CATEGORY_METADATA[category].options.map((option) => option.cliValue))];
|
|
2807
|
-
}
|
|
2808
|
-
function normalizeOptionId(category, value) {
|
|
2809
|
-
return OPTION_LOOKUP[category].get(value.toLowerCase()) ?? value;
|
|
2810
|
-
}
|
|
2811
|
-
|
|
2812
|
-
//#endregion
|
|
2813
6
|
//#region src/local-dev.ts
|
|
2814
7
|
const VITE_WEB_FRONTENDS = new Set([
|
|
2815
8
|
"react-router",
|
|
@@ -2825,5 +18,5 @@ function getLocalWebDevPort(frontend) {
|
|
|
2825
18
|
}
|
|
2826
19
|
|
|
2827
20
|
//#endregion
|
|
2828
|
-
export { ADDONS_VALUES, AISchema, AI_DOCS_VALUES, AI_VALUES, ANALYTICS_VALUES, ANIMATION_VALUES, APISchema, API_VALUES, ASTRO_INTEGRATION_VALUES, AUTH_VALUES, AddInputSchema, AddonsSchema, AiDocsSchema, AnalyticsSchema, AnimationSchema, AstroIntegrationSchema, AuthSchema, BACKEND_VALUES, BackendSchema, BetterTStackConfigFileSchema, BetterTStackConfigSchema, CACHING_VALUES, CLIInputSchema, CMSSchema, CMS_VALUES, CSSFrameworkSchema, CSS_FRAMEWORK_VALUES, CachingSchema, CreateInputSchema, DATABASE_SETUP_VALUES, DATABASE_VALUES, DIRECTORY_CONFLICT_VALUES, DatabaseSchema, DatabaseSetupSchema, DirectoryConflictSchema, ECOSYSTEM_VALUES, EFFECT_VALUES, EMAIL_VALUES, EXAMPLES_VALUES, EcosystemSchema, EffectSchema, EmailSchema, ExamplesSchema, FEATURE_FLAGS_VALUES, FILE_STORAGE_VALUES, FILE_UPLOAD_VALUES, FORMS_VALUES, FRONTEND_VALUES, FeatureFlagsSchema, FileStorageSchema, FileUploadSchema, FormsSchema, FrontendSchema, GO_API_VALUES, GO_AUTH_VALUES, GO_CLI_VALUES, GO_LOGGING_VALUES, GO_ORM_VALUES, GO_WEB_FRAMEWORK_VALUES, GoApiSchema, GoAuthSchema, GoCliSchema, GoLoggingSchema, GoOrmSchema, GoWebFrameworkSchema, I18N_VALUES, I18nSchema, InitResultSchema, JAVA_AUTH_VALUES, JAVA_BUILD_TOOL_VALUES, JAVA_LIBRARIES_VALUES, JAVA_ORM_VALUES, JAVA_TESTING_LIBRARIES_VALUES, JAVA_WEB_FRAMEWORK_VALUES, JOB_QUEUE_VALUES, JavaAuthSchema, JavaBuildToolSchema, JavaLibrariesSchema, JavaOrmSchema, JavaTestingLibrariesSchema, JavaWebFrameworkSchema, JobQueueSchema, LOGGING_VALUES, LoggingSchema, OBSERVABILITY_VALUES, OPTION_CATEGORY_METADATA, ORMSchema, ORM_VALUES, ObservabilitySchema, PACKAGE_MANAGER_VALUES, PAYMENTS_VALUES, PYTHON_AI_VALUES, PYTHON_AUTH_VALUES, PYTHON_GRAPHQL_VALUES, PYTHON_ORM_VALUES, PYTHON_QUALITY_VALUES, PYTHON_TASK_QUEUE_VALUES, PYTHON_VALIDATION_VALUES, PYTHON_WEB_FRAMEWORK_VALUES, PackageManagerSchema, PaymentsSchema, ProjectConfigSchema, ProjectNameSchema, PythonAiSchema, PythonAuthSchema, PythonGraphqlSchema, PythonOrmSchema, PythonQualitySchema, PythonTaskQueueSchema, PythonValidationSchema, PythonWebFrameworkSchema, REALTIME_VALUES, RUNTIME_VALUES, RUST_API_VALUES, RUST_AUTH_VALUES, RUST_CACHING_VALUES, RUST_CLI_VALUES, RUST_ERROR_HANDLING_VALUES, RUST_FRONTEND_VALUES, RUST_LIBRARIES_VALUES, RUST_LOGGING_VALUES, RUST_ORM_VALUES, RUST_WEB_FRAMEWORK_VALUES, RealtimeSchema, RuntimeSchema, RustApiSchema, RustAuthSchema, RustCachingSchema, RustCliSchema, RustErrorHandlingSchema, RustFrontendSchema, RustLibrariesSchema, RustLoggingSchema, RustOrmSchema, RustWebFrameworkSchema, SEARCH_VALUES, SERVER_DEPLOY_VALUES, SHADCN_BASE_COLOR_VALUES, SHADCN_BASE_VALUES, SHADCN_COLOR_THEME_VALUES, SHADCN_FONT_VALUES, SHADCN_ICON_LIBRARY_VALUES, SHADCN_RADIUS_VALUES, SHADCN_STYLE_VALUES, STATE_MANAGEMENT_VALUES, SearchSchema, ServerDeploySchema, ShadcnBaseColorSchema, ShadcnBaseSchema, ShadcnColorThemeSchema, ShadcnFontSchema, ShadcnIconLibrarySchema, ShadcnRadiusSchema, ShadcnStyleSchema, StateManagementSchema, TEMPLATE_VALUES, TESTING_VALUES, TemplateSchema, TestingSchema, UILibrarySchema, UI_LIBRARY_VALUES, VALIDATION_VALUES, VERSION_CHANNEL_VALUES, ValidationSchema, VersionChannelSchema, WEB_DEPLOY_VALUES, WebDeploySchema, allowedApisForFrontends, analyzeStackCompatibility, createCliDefaultProjectConfigBase, evaluateCompatibility, getCapabilityDefinitions, getCapabilityDisabledReason, getCategoryCliValues, getCategoryDisplayName, getCategoryOptionIds, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleFormLibraries, getCompatibleUILibraries, getDisabledReason, getLocalWebDevPort, getOptionMetadata, getSupportedCapabilityOptions, hasDockerComposeCompatibleFrontend, hasPWACompatibleFrontend, hasTauriCompatibleFrontend, hasWebStyling, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isMultiSelectCategory, isOptionCompatible, isWebFrontend, normalizeCapabilitySelection, normalizeOptionId, requiresChatSdkVercelAI, requiresChatSdkVercelAIForSelection, splitFrontends, validateAddonCompatibility, validateProjectName };
|
|
21
|
+
export { ADDONS_VALUES, AISchema, AI_DOCS_VALUES, AI_VALUES, ANALYTICS_VALUES, ANIMATION_VALUES, APISchema, API_VALUES, ASTRO_INTEGRATION_VALUES, AUTH_VALUES, AddInputSchema, AddonsSchema, AiDocsSchema, AnalyticsSchema, AnimationSchema, AstroIntegrationSchema, AuthSchema, BACKEND_VALUES, BackendSchema, BetterTStackConfigFileSchema, BetterTStackConfigSchema, CACHING_VALUES, CLIInputSchema, CMSSchema, CMS_VALUES, CSSFrameworkSchema, CSS_FRAMEWORK_VALUES, CachingSchema, CreateInputSchema, DATABASE_SETUP_VALUES, DATABASE_VALUES, DEFAULT_STACK_SELECTION, DIRECTORY_CONFLICT_VALUES, DatabaseSchema, DatabaseSetupSchema, DirectoryConflictSchema, ECOSYSTEM_VALUES, EFFECT_VALUES, EMAIL_VALUES, EXAMPLES_VALUES, EcosystemSchema, EffectSchema, EmailSchema, ExamplesSchema, FEATURE_FLAGS_VALUES, FILE_STORAGE_VALUES, FILE_UPLOAD_VALUES, FORMS_VALUES, FRONTEND_VALUES, FeatureFlagsSchema, FileStorageSchema, FileUploadSchema, FormsSchema, FrontendSchema, GO_API_VALUES, GO_AUTH_VALUES, GO_CLI_VALUES, GO_LOGGING_VALUES, GO_ORM_VALUES, GO_WEB_FRAMEWORK_VALUES, GoApiSchema, GoAuthSchema, GoCliSchema, GoLoggingSchema, GoOrmSchema, GoWebFrameworkSchema, I18N_VALUES, I18nSchema, InitResultSchema, JAVA_AUTH_VALUES, JAVA_BUILD_TOOL_VALUES, JAVA_LIBRARIES_VALUES, JAVA_ORM_VALUES, JAVA_TESTING_LIBRARIES_VALUES, JAVA_WEB_FRAMEWORK_VALUES, JOB_QUEUE_VALUES, JavaAuthSchema, JavaBuildToolSchema, JavaLibrariesSchema, JavaOrmSchema, JavaTestingLibrariesSchema, JavaWebFrameworkSchema, JobQueueSchema, LOGGING_VALUES, LoggingSchema, NON_OPTION_STACK_SELECTION_KEYS, OBSERVABILITY_VALUES, OPTION_CATEGORY_METADATA, ORMSchema, ORM_VALUES, ObservabilitySchema, PACKAGE_MANAGER_VALUES, PAYMENTS_VALUES, PYTHON_AI_VALUES, PYTHON_AUTH_VALUES, PYTHON_GRAPHQL_VALUES, PYTHON_ORM_VALUES, PYTHON_QUALITY_VALUES, PYTHON_TASK_QUEUE_VALUES, PYTHON_VALIDATION_VALUES, PYTHON_WEB_FRAMEWORK_VALUES, PackageManagerSchema, PaymentsSchema, ProjectConfigSchema, ProjectNameSchema, PythonAiSchema, PythonAuthSchema, PythonGraphqlSchema, PythonOrmSchema, PythonQualitySchema, PythonTaskQueueSchema, PythonValidationSchema, PythonWebFrameworkSchema, REALTIME_VALUES, RUNTIME_VALUES, RUST_API_VALUES, RUST_AUTH_VALUES, RUST_CACHING_VALUES, RUST_CLI_VALUES, RUST_ERROR_HANDLING_VALUES, RUST_FRONTEND_VALUES, RUST_LIBRARIES_VALUES, RUST_LOGGING_VALUES, RUST_ORM_VALUES, RUST_WEB_FRAMEWORK_VALUES, RealtimeSchema, RuntimeSchema, RustApiSchema, RustAuthSchema, RustCachingSchema, RustCliSchema, RustErrorHandlingSchema, RustFrontendSchema, RustLibrariesSchema, RustLoggingSchema, RustOrmSchema, RustWebFrameworkSchema, SEARCH_VALUES, SERVER_DEPLOY_VALUES, SHADCN_BASE_COLOR_VALUES, SHADCN_BASE_VALUES, SHADCN_COLOR_THEME_VALUES, SHADCN_FONT_VALUES, SHADCN_ICON_LIBRARY_VALUES, SHADCN_RADIUS_VALUES, SHADCN_STYLE_VALUES, STACK_SELECTION_KEYS, STACK_SELECTION_OPTION_CATEGORY_BY_KEY, STACK_SELECTION_URL_KEYS, STATE_MANAGEMENT_VALUES, SearchSchema, ServerDeploySchema, ShadcnBaseColorSchema, ShadcnBaseSchema, ShadcnColorThemeSchema, ShadcnFontSchema, ShadcnIconLibrarySchema, ShadcnRadiusSchema, ShadcnStyleSchema, StateManagementSchema, TEMPLATE_VALUES, TESTING_VALUES, TemplateSchema, TestingSchema, UILibrarySchema, UI_LIBRARY_VALUES, VALIDATION_VALUES, VERSION_CHANNEL_VALUES, VIRTUAL_NONE_MULTI_SELECT_STACK_SELECTION_KEYS, ValidationSchema, VersionChannelSchema, WEB_DEPLOY_VALUES, WebDeploySchema, allowedApisForFrontends, analyzeStackCompatibility, cliInputToProjectConfigPartial, cloneDefaultStackSelection, createCliDefaultProjectConfigBase, createStackSelectionSearchParams, evaluateCompatibility, generateStackSelectionCommand, getAIFrontendCompatibilityIssue, getApiFrontendCompatibilityIssue, getCapabilityDefinitions, getCapabilityDisabledReason, getCategoryCliValues, getCategoryDisplayName, getCategoryOptionIds, getCompatibleAddons, getCompatibleCSSFrameworks, getCompatibleFormLibraries, getCompatibleUILibraries, getDisabledReason, getLocalWebDevPort, getOptionMetadata, getSupportedCapabilityOptions, hasDockerComposeCompatibleFrontend, hasPWACompatibleFrontend, hasTauriCompatibleFrontend, hasWebStyling, isArrayStackSelectionKey, isCliDefaultStackSelection, isExampleAIAllowed, isExampleChatSdkAllowed, isFrontendAllowedWithBackend, isMultiSelectCategory, isOptionCompatible, isStackSelectionDefault, isWebFrontend, normalizeCapabilitySelection, normalizeOptionId, normalizeStackSelection, normalizeStackSelectionValue, parseStackSelectionFromSearch, parseStackSelectionFromUrlRecord, processCliArrayOption, requiresChatSdkVercelAI, requiresChatSdkVercelAIForSelection, splitFrontends, stackSelectionToCliComparableConfig, stackSelectionToProjectConfig, usesVirtualNoneStackSelection, validateAddonCompatibility, validateProjectName };
|
|
2829
22
|
//# sourceMappingURL=index.mjs.map
|