create-better-fullstack 1.7.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addons-setup-BdKQJ1h6.mjs +5 -0
- package/dist/{addons-setup-DQa6TRrx.mjs → addons-setup-CGhYT2qC.mjs} +1 -1
- package/dist/{bts-config-B_rZ4_sj.mjs → bts-config-bOXo9tbL.mjs} +3 -0
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +99 -52
- package/dist/index.mjs +488 -104
- package/dist/{mcp-CuEEG8e5.mjs → mcp-BxEilSGM.mjs} +1 -1
- package/dist/mcp-entry.mjs +116 -15
- package/package.json +8 -8
- package/dist/addons-setup-CBK1Htlc.mjs +0 -5
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as __reExport } from "./chunk-CCII7kTE.mjs";
|
|
3
|
-
import { a as DEFAULT_CONFIG, c as getDefaultConfig, i as getLatestCLIVersion, l as getUserPkgManager, n as updateBtsConfig, o as DEFAULT_UI_LIBRARY_BY_FRONTEND, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-
|
|
4
|
-
import { _ as setIsFirstPrompt$1, a as canPromptInteractively, c as CLIError, d as exitWithError, f as handleError, g as runWithContextAsync, h as isSilent, l as UserCancelledError, m as isFirstPrompt, o as getPackageExecutionArgs, p as didLastPromptShowUI, s as addPackageDependency, t as setupAddons, u as exitCancelled, v as setLastPromptShownUI } from "./addons-setup-
|
|
3
|
+
import { a as DEFAULT_CONFIG, c as getDefaultConfig, i as getLatestCLIVersion, l as getUserPkgManager, n as updateBtsConfig, o as DEFAULT_UI_LIBRARY_BY_FRONTEND, r as writeBtsConfig, t as readBtsConfig } from "./bts-config-bOXo9tbL.mjs";
|
|
4
|
+
import { _ as setIsFirstPrompt$1, a as canPromptInteractively, c as CLIError, d as exitWithError, f as handleError, g as runWithContextAsync, h as isSilent, l as UserCancelledError, m as isFirstPrompt, o as getPackageExecutionArgs, p as didLastPromptShowUI, s as addPackageDependency, t as setupAddons, u as exitCancelled, v as setLastPromptShownUI } from "./addons-setup-CGhYT2qC.mjs";
|
|
5
5
|
import { cancel, confirm, intro, isCancel, log, outro, select, spinner, text } from "@clack/prompts";
|
|
6
6
|
import { createRouterClient, os } from "@orpc/server";
|
|
7
7
|
import pc from "picocolors";
|
|
@@ -430,16 +430,17 @@ const CreateCommandOptionsSchema = z.object({
|
|
|
430
430
|
pythonValidation: types_exports.PythonValidationSchema.optional().describe("Python validation (pydantic)"),
|
|
431
431
|
pythonAi: z.array(types_exports.PythonAiSchema).optional().describe("Python AI/ML frameworks"),
|
|
432
432
|
pythonAuth: types_exports.PythonAuthSchema.optional().describe("Python auth library (authlib, jwt)"),
|
|
433
|
+
pythonApi: types_exports.PythonApiSchema.optional().describe("Python API framework (django-rest-framework, django-ninja)"),
|
|
433
434
|
pythonTaskQueue: types_exports.PythonTaskQueueSchema.optional().describe("Python task queue (celery)"),
|
|
434
435
|
pythonGraphql: types_exports.PythonGraphqlSchema.optional().describe("Python GraphQL framework (strawberry)"),
|
|
435
|
-
pythonQuality: types_exports.PythonQualitySchema.optional().describe("Python code quality (ruff)"),
|
|
436
|
+
pythonQuality: types_exports.PythonQualitySchema.optional().describe("Python code quality (ruff, mypy, pyright)"),
|
|
436
437
|
goWebFramework: types_exports.GoWebFrameworkSchema.optional().describe("Go web framework (gin, echo, fiber)"),
|
|
437
438
|
goOrm: types_exports.GoOrmSchema.optional().describe("Go ORM/database (gorm, sqlc)"),
|
|
438
439
|
goApi: types_exports.GoApiSchema.optional().describe("Go API layer (grpc-go)"),
|
|
439
|
-
goCli: types_exports.GoCliSchema.optional().describe("Go CLI tools (cobra, bubbletea)"),
|
|
440
|
+
goCli: types_exports.GoCliSchema.optional().describe("Go CLI tools (cobra, bubbletea, urfave-cli)"),
|
|
440
441
|
goLogging: types_exports.GoLoggingSchema.optional().describe("Go logging (zap, zerolog, slog)"),
|
|
441
442
|
goAuth: types_exports.GoAuthSchema.optional().describe("Go auth (casbin, jwt)"),
|
|
442
|
-
javaWebFramework: types_exports.JavaWebFrameworkSchema.optional().describe("Java web framework (spring-boot, none)"),
|
|
443
|
+
javaWebFramework: types_exports.JavaWebFrameworkSchema.optional().describe("Java web framework (spring-boot, quarkus, none)"),
|
|
443
444
|
javaBuildTool: types_exports.JavaBuildToolSchema.optional().describe("Java build tool (maven, gradle, none)"),
|
|
444
445
|
javaOrm: types_exports.JavaOrmSchema.optional().describe("Java ORM/database (spring-data-jpa)"),
|
|
445
446
|
javaAuth: types_exports.JavaAuthSchema.optional().describe("Java auth (spring-security)"),
|
|
@@ -2178,6 +2179,17 @@ const CACHING_PROMPT_OPTIONS = [{
|
|
|
2178
2179
|
hint: "Skip caching layer setup"
|
|
2179
2180
|
}];
|
|
2180
2181
|
function resolveCachingPrompt(context = {}) {
|
|
2182
|
+
if (context.ecosystem && context.ecosystem !== "typescript") return context.caching !== void 0 ? {
|
|
2183
|
+
shouldPrompt: false,
|
|
2184
|
+
mode: "single",
|
|
2185
|
+
options: CACHING_PROMPT_OPTIONS,
|
|
2186
|
+
autoValue: context.caching
|
|
2187
|
+
} : {
|
|
2188
|
+
shouldPrompt: true,
|
|
2189
|
+
mode: "single",
|
|
2190
|
+
options: CACHING_PROMPT_OPTIONS,
|
|
2191
|
+
initialValue: "none"
|
|
2192
|
+
};
|
|
2181
2193
|
if (context.backend === "none" || context.backend === "convex") return {
|
|
2182
2194
|
shouldPrompt: false,
|
|
2183
2195
|
mode: "single",
|
|
@@ -2196,10 +2208,11 @@ function resolveCachingPrompt(context = {}) {
|
|
|
2196
2208
|
initialValue: "none"
|
|
2197
2209
|
};
|
|
2198
2210
|
}
|
|
2199
|
-
async function getCachingChoice(caching, backend) {
|
|
2211
|
+
async function getCachingChoice(caching, backend, ecosystem) {
|
|
2200
2212
|
const resolution = resolveCachingPrompt({
|
|
2201
2213
|
caching,
|
|
2202
|
-
backend
|
|
2214
|
+
backend,
|
|
2215
|
+
ecosystem
|
|
2203
2216
|
});
|
|
2204
2217
|
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2205
2218
|
const response = await navigableSelect({
|
|
@@ -2678,8 +2691,10 @@ const EMAIL_PROMPT_OPTIONS = [
|
|
|
2678
2691
|
hint: "No email integration"
|
|
2679
2692
|
}
|
|
2680
2693
|
];
|
|
2694
|
+
const NON_TYPESCRIPT_EMAIL_PROMPT_OPTIONS = EMAIL_PROMPT_OPTIONS.filter((option) => option.value === "resend" || option.value === "none");
|
|
2681
2695
|
function resolveEmailPrompt(context = {}) {
|
|
2682
|
-
|
|
2696
|
+
const options = context.ecosystem && context.ecosystem !== "typescript" ? NON_TYPESCRIPT_EMAIL_PROMPT_OPTIONS : EMAIL_PROMPT_OPTIONS;
|
|
2697
|
+
if ((!context.ecosystem || context.ecosystem === "typescript") && (context.backend === "none" || context.backend === "convex")) return {
|
|
2683
2698
|
shouldPrompt: false,
|
|
2684
2699
|
mode: "single",
|
|
2685
2700
|
options: [],
|
|
@@ -2688,19 +2703,20 @@ function resolveEmailPrompt(context = {}) {
|
|
|
2688
2703
|
return context.email !== void 0 ? {
|
|
2689
2704
|
shouldPrompt: false,
|
|
2690
2705
|
mode: "single",
|
|
2691
|
-
options
|
|
2706
|
+
options,
|
|
2692
2707
|
autoValue: context.email
|
|
2693
2708
|
} : {
|
|
2694
2709
|
shouldPrompt: true,
|
|
2695
2710
|
mode: "single",
|
|
2696
|
-
options
|
|
2711
|
+
options,
|
|
2697
2712
|
initialValue: DEFAULT_CONFIG.email ?? "none"
|
|
2698
2713
|
};
|
|
2699
2714
|
}
|
|
2700
|
-
async function getEmailChoice(email, backend) {
|
|
2715
|
+
async function getEmailChoice(email, backend, ecosystem) {
|
|
2701
2716
|
const resolution = resolveEmailPrompt({
|
|
2702
2717
|
email,
|
|
2703
|
-
backend
|
|
2718
|
+
backend,
|
|
2719
|
+
ecosystem
|
|
2704
2720
|
});
|
|
2705
2721
|
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
2706
2722
|
const response = await navigableSelect({
|
|
@@ -3169,6 +3185,11 @@ const GO_CLI_PROMPT_OPTIONS = [
|
|
|
3169
3185
|
label: "Bubble Tea",
|
|
3170
3186
|
hint: "Powerful TUI framework based on The Elm Architecture"
|
|
3171
3187
|
},
|
|
3188
|
+
{
|
|
3189
|
+
value: "urfave-cli",
|
|
3190
|
+
label: "urfave/cli",
|
|
3191
|
+
hint: "Declarative CLI framework with commands, flags, and shell completion"
|
|
3192
|
+
},
|
|
3172
3193
|
{
|
|
3173
3194
|
value: "none",
|
|
3174
3195
|
label: "None",
|
|
@@ -3191,6 +3212,11 @@ const GO_LOGGING_PROMPT_OPTIONS = [
|
|
|
3191
3212
|
label: "slog",
|
|
3192
3213
|
hint: "Go 1.21+ stdlib structured logging (no external dependency)"
|
|
3193
3214
|
},
|
|
3215
|
+
{
|
|
3216
|
+
value: "logrus",
|
|
3217
|
+
label: "Logrus",
|
|
3218
|
+
hint: "Classic structured logger with hooks and formatter ecosystem"
|
|
3219
|
+
},
|
|
3194
3220
|
{
|
|
3195
3221
|
value: "none",
|
|
3196
3222
|
label: "None",
|
|
@@ -3405,15 +3431,23 @@ async function getinstallChoice(install, ecosystem, javaBuildTool) {
|
|
|
3405
3431
|
|
|
3406
3432
|
//#endregion
|
|
3407
3433
|
//#region src/prompts/java-ecosystem.ts
|
|
3408
|
-
const JAVA_WEB_FRAMEWORK_PROMPT_OPTIONS = [
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3434
|
+
const JAVA_WEB_FRAMEWORK_PROMPT_OPTIONS = [
|
|
3435
|
+
{
|
|
3436
|
+
value: "spring-boot",
|
|
3437
|
+
label: "Spring Boot",
|
|
3438
|
+
hint: "Production-grade Java framework with embedded server and auto-configuration"
|
|
3439
|
+
},
|
|
3440
|
+
{
|
|
3441
|
+
value: "quarkus",
|
|
3442
|
+
label: "Quarkus",
|
|
3443
|
+
hint: "Cloud-native Java framework optimized for fast startup and lower memory use"
|
|
3444
|
+
},
|
|
3445
|
+
{
|
|
3446
|
+
value: "none",
|
|
3447
|
+
label: "None",
|
|
3448
|
+
hint: "No Java web framework"
|
|
3449
|
+
}
|
|
3450
|
+
];
|
|
3417
3451
|
const JAVA_BUILD_TOOL_PROMPT_OPTIONS = [
|
|
3418
3452
|
{
|
|
3419
3453
|
value: "maven",
|
|
@@ -3542,6 +3576,46 @@ const JAVA_LIBRARY_PROMPT_OPTIONS = [
|
|
|
3542
3576
|
label: "Caffeine",
|
|
3543
3577
|
hint: "High-performance in-memory caching through Spring Cache"
|
|
3544
3578
|
},
|
|
3579
|
+
{
|
|
3580
|
+
value: "resilience4j",
|
|
3581
|
+
label: "Resilience4j",
|
|
3582
|
+
hint: "Fault tolerance patterns for retries, circuit breakers, and rate limiting"
|
|
3583
|
+
},
|
|
3584
|
+
{
|
|
3585
|
+
value: "spring-webflux",
|
|
3586
|
+
label: "Spring WebFlux",
|
|
3587
|
+
hint: "Reactive HTTP stack for Spring applications"
|
|
3588
|
+
},
|
|
3589
|
+
{
|
|
3590
|
+
value: "spring-batch",
|
|
3591
|
+
label: "Spring Batch",
|
|
3592
|
+
hint: "Batch processing framework for ETL and scheduled jobs"
|
|
3593
|
+
},
|
|
3594
|
+
{
|
|
3595
|
+
value: "spring-kafka",
|
|
3596
|
+
label: "Spring for Apache Kafka",
|
|
3597
|
+
hint: "Kafka producer, consumer, and listener integration"
|
|
3598
|
+
},
|
|
3599
|
+
{
|
|
3600
|
+
value: "spring-mail",
|
|
3601
|
+
label: "Spring Mail",
|
|
3602
|
+
hint: "Email support through Jakarta Mail and Spring abstractions"
|
|
3603
|
+
},
|
|
3604
|
+
{
|
|
3605
|
+
value: "spring-devtools",
|
|
3606
|
+
label: "Spring Boot DevTools",
|
|
3607
|
+
hint: "Developer-time restart and local productivity support"
|
|
3608
|
+
},
|
|
3609
|
+
{
|
|
3610
|
+
value: "micrometer-prometheus",
|
|
3611
|
+
label: "Micrometer Prometheus",
|
|
3612
|
+
hint: "Prometheus metrics registry for Micrometer and Actuator"
|
|
3613
|
+
},
|
|
3614
|
+
{
|
|
3615
|
+
value: "thymeleaf",
|
|
3616
|
+
label: "Thymeleaf",
|
|
3617
|
+
hint: "Server-rendered HTML templates for Spring MVC apps"
|
|
3618
|
+
},
|
|
3545
3619
|
{
|
|
3546
3620
|
value: "none",
|
|
3547
3621
|
label: "None",
|
|
@@ -3834,8 +3908,10 @@ const OBSERVABILITY_PROMPT_OPTIONS = [
|
|
|
3834
3908
|
hint: "Skip observability/tracing setup"
|
|
3835
3909
|
}
|
|
3836
3910
|
];
|
|
3911
|
+
const NON_TYPESCRIPT_OBSERVABILITY_PROMPT_OPTIONS = OBSERVABILITY_PROMPT_OPTIONS.filter((option) => option.value === "sentry" || option.value === "none");
|
|
3837
3912
|
function resolveObservabilityPrompt(context = {}) {
|
|
3838
|
-
|
|
3913
|
+
const options = context.ecosystem && context.ecosystem !== "typescript" ? NON_TYPESCRIPT_OBSERVABILITY_PROMPT_OPTIONS : OBSERVABILITY_PROMPT_OPTIONS;
|
|
3914
|
+
if ((!context.ecosystem || context.ecosystem === "typescript") && (context.backend === "none" || context.backend === "convex")) return {
|
|
3839
3915
|
shouldPrompt: false,
|
|
3840
3916
|
mode: "single",
|
|
3841
3917
|
options: [],
|
|
@@ -3844,19 +3920,20 @@ function resolveObservabilityPrompt(context = {}) {
|
|
|
3844
3920
|
return context.observability !== void 0 ? {
|
|
3845
3921
|
shouldPrompt: false,
|
|
3846
3922
|
mode: "single",
|
|
3847
|
-
options
|
|
3923
|
+
options,
|
|
3848
3924
|
autoValue: context.observability
|
|
3849
3925
|
} : {
|
|
3850
3926
|
shouldPrompt: true,
|
|
3851
3927
|
mode: "single",
|
|
3852
|
-
options
|
|
3928
|
+
options,
|
|
3853
3929
|
initialValue: "none"
|
|
3854
3930
|
};
|
|
3855
3931
|
}
|
|
3856
|
-
async function getObservabilityChoice(observability, backend) {
|
|
3932
|
+
async function getObservabilityChoice(observability, backend, ecosystem) {
|
|
3857
3933
|
const resolution = resolveObservabilityPrompt({
|
|
3858
3934
|
observability,
|
|
3859
|
-
backend
|
|
3935
|
+
backend,
|
|
3936
|
+
ecosystem
|
|
3860
3937
|
});
|
|
3861
3938
|
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
3862
3939
|
const response = await navigableSelect({
|
|
@@ -4154,6 +4231,11 @@ const PYTHON_AI_PROMPT_OPTIONS = [
|
|
|
4154
4231
|
value: "crewai",
|
|
4155
4232
|
label: "CrewAI",
|
|
4156
4233
|
hint: "Multi-agent orchestration framework"
|
|
4234
|
+
},
|
|
4235
|
+
{
|
|
4236
|
+
value: "haystack",
|
|
4237
|
+
label: "Haystack",
|
|
4238
|
+
hint: "Composable LLM pipelines, RAG, and search applications"
|
|
4157
4239
|
}
|
|
4158
4240
|
];
|
|
4159
4241
|
const PYTHON_AUTH_PROMPT_OPTIONS = [
|
|
@@ -4173,33 +4255,89 @@ const PYTHON_AUTH_PROMPT_OPTIONS = [
|
|
|
4173
4255
|
hint: "No authentication library"
|
|
4174
4256
|
}
|
|
4175
4257
|
];
|
|
4176
|
-
const
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
},
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4258
|
+
const PYTHON_API_PROMPT_OPTIONS = [
|
|
4259
|
+
{
|
|
4260
|
+
value: "django-rest-framework",
|
|
4261
|
+
label: "Django REST Framework",
|
|
4262
|
+
hint: "Mature, widely used toolkit for building Django REST APIs"
|
|
4263
|
+
},
|
|
4264
|
+
{
|
|
4265
|
+
value: "django-ninja",
|
|
4266
|
+
label: "Django Ninja",
|
|
4267
|
+
hint: "FastAPI-style Django APIs with type hints and automatic OpenAPI docs"
|
|
4268
|
+
},
|
|
4269
|
+
{
|
|
4270
|
+
value: "none",
|
|
4271
|
+
label: "None",
|
|
4272
|
+
hint: "No additional Python API framework"
|
|
4273
|
+
}
|
|
4274
|
+
];
|
|
4275
|
+
const PYTHON_TASK_QUEUE_PROMPT_OPTIONS = [
|
|
4276
|
+
{
|
|
4277
|
+
value: "celery",
|
|
4278
|
+
label: "Celery",
|
|
4279
|
+
hint: "Distributed task queue for Python"
|
|
4280
|
+
},
|
|
4281
|
+
{
|
|
4282
|
+
value: "rq",
|
|
4283
|
+
label: "RQ",
|
|
4284
|
+
hint: "Simple Redis-backed job queue for Python"
|
|
4285
|
+
},
|
|
4286
|
+
{
|
|
4287
|
+
value: "dramatiq",
|
|
4288
|
+
label: "Dramatiq",
|
|
4289
|
+
hint: "Distributed task processing with Redis or RabbitMQ brokers"
|
|
4290
|
+
},
|
|
4291
|
+
{
|
|
4292
|
+
value: "huey",
|
|
4293
|
+
label: "Huey",
|
|
4294
|
+
hint: "Lightweight task queue with Redis-backed scheduling"
|
|
4295
|
+
},
|
|
4296
|
+
{
|
|
4297
|
+
value: "none",
|
|
4298
|
+
label: "None",
|
|
4299
|
+
hint: "No task queue"
|
|
4300
|
+
}
|
|
4301
|
+
];
|
|
4302
|
+
const PYTHON_GRAPHQL_PROMPT_OPTIONS = [
|
|
4303
|
+
{
|
|
4304
|
+
value: "strawberry",
|
|
4305
|
+
label: "Strawberry",
|
|
4306
|
+
hint: "Python GraphQL library using dataclasses and type hints"
|
|
4307
|
+
},
|
|
4308
|
+
{
|
|
4309
|
+
value: "ariadne",
|
|
4310
|
+
label: "Ariadne",
|
|
4311
|
+
hint: "Schema-first GraphQL server library for Python"
|
|
4312
|
+
},
|
|
4313
|
+
{
|
|
4314
|
+
value: "none",
|
|
4315
|
+
label: "None",
|
|
4316
|
+
hint: "No GraphQL framework"
|
|
4317
|
+
}
|
|
4318
|
+
];
|
|
4319
|
+
const PYTHON_QUALITY_PROMPT_OPTIONS = [
|
|
4320
|
+
{
|
|
4321
|
+
value: "ruff",
|
|
4322
|
+
label: "Ruff",
|
|
4323
|
+
hint: "An extremely fast Python linter and formatter"
|
|
4324
|
+
},
|
|
4325
|
+
{
|
|
4326
|
+
value: "mypy",
|
|
4327
|
+
label: "mypy",
|
|
4328
|
+
hint: "Static type checker for Python"
|
|
4329
|
+
},
|
|
4330
|
+
{
|
|
4331
|
+
value: "pyright",
|
|
4332
|
+
label: "Pyright",
|
|
4333
|
+
hint: "Fast Python type checker from Microsoft"
|
|
4334
|
+
},
|
|
4335
|
+
{
|
|
4336
|
+
value: "none",
|
|
4337
|
+
label: "None",
|
|
4338
|
+
hint: "No code quality tools"
|
|
4339
|
+
}
|
|
4340
|
+
];
|
|
4203
4341
|
function resolvePythonWebFrameworkPrompt(pythonWebFramework) {
|
|
4204
4342
|
return createStaticSinglePromptResolution(PYTHON_WEB_FRAMEWORK_PROMPT_OPTIONS, "fastapi", pythonWebFramework);
|
|
4205
4343
|
}
|
|
@@ -4272,6 +4410,20 @@ async function getPythonAuthChoice(pythonAuth) {
|
|
|
4272
4410
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4273
4411
|
return response;
|
|
4274
4412
|
}
|
|
4413
|
+
function resolvePythonApiPrompt(pythonApi) {
|
|
4414
|
+
return createStaticSinglePromptResolution(PYTHON_API_PROMPT_OPTIONS, "none", pythonApi);
|
|
4415
|
+
}
|
|
4416
|
+
async function getPythonApiChoice(pythonApi) {
|
|
4417
|
+
const resolution = resolvePythonApiPrompt(pythonApi);
|
|
4418
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4419
|
+
const response = await navigableSelect({
|
|
4420
|
+
message: "Select Python API framework",
|
|
4421
|
+
options: resolution.options,
|
|
4422
|
+
initialValue: resolution.initialValue
|
|
4423
|
+
});
|
|
4424
|
+
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4425
|
+
return response;
|
|
4426
|
+
}
|
|
4275
4427
|
function resolvePythonTaskQueuePrompt(pythonTaskQueue) {
|
|
4276
4428
|
return createStaticSinglePromptResolution(PYTHON_TASK_QUEUE_PROMPT_OPTIONS, "none", pythonTaskQueue);
|
|
4277
4429
|
}
|
|
@@ -4545,6 +4697,51 @@ const RUST_LIBRARIES_PROMPT_OPTIONS = [
|
|
|
4545
4697
|
label: "Serde",
|
|
4546
4698
|
hint: "Serialization framework for Rust"
|
|
4547
4699
|
},
|
|
4700
|
+
{
|
|
4701
|
+
value: "uuid",
|
|
4702
|
+
label: "uuid",
|
|
4703
|
+
hint: "UUID generation and parsing with Serde support"
|
|
4704
|
+
},
|
|
4705
|
+
{
|
|
4706
|
+
value: "chrono",
|
|
4707
|
+
label: "Chrono",
|
|
4708
|
+
hint: "Date and time library with Serde support"
|
|
4709
|
+
},
|
|
4710
|
+
{
|
|
4711
|
+
value: "reqwest",
|
|
4712
|
+
label: "Reqwest",
|
|
4713
|
+
hint: "Ergonomic HTTP client with JSON and Rustls TLS support"
|
|
4714
|
+
},
|
|
4715
|
+
{
|
|
4716
|
+
value: "config",
|
|
4717
|
+
label: "config",
|
|
4718
|
+
hint: "Layered configuration from files, environment, and defaults"
|
|
4719
|
+
},
|
|
4720
|
+
{
|
|
4721
|
+
value: "dashmap",
|
|
4722
|
+
label: "DashMap",
|
|
4723
|
+
hint: "Concurrent hash map for shared mutable state"
|
|
4724
|
+
},
|
|
4725
|
+
{
|
|
4726
|
+
value: "parking-lot",
|
|
4727
|
+
label: "parking_lot",
|
|
4728
|
+
hint: "Compact, fast synchronization primitives"
|
|
4729
|
+
},
|
|
4730
|
+
{
|
|
4731
|
+
value: "secrecy",
|
|
4732
|
+
label: "Secrecy",
|
|
4733
|
+
hint: "Secret value wrapper that avoids accidental exposure"
|
|
4734
|
+
},
|
|
4735
|
+
{
|
|
4736
|
+
value: "tokio-util",
|
|
4737
|
+
label: "Tokio Util",
|
|
4738
|
+
hint: "Tokio utilities for codecs, cancellation tokens, and IO helpers"
|
|
4739
|
+
},
|
|
4740
|
+
{
|
|
4741
|
+
value: "utoipa",
|
|
4742
|
+
label: "utoipa",
|
|
4743
|
+
hint: "OpenAPI documentation generation from Rust types"
|
|
4744
|
+
},
|
|
4548
4745
|
{
|
|
4549
4746
|
value: "validator",
|
|
4550
4747
|
label: "Validator",
|
|
@@ -4569,6 +4766,16 @@ const RUST_LIBRARIES_PROMPT_OPTIONS = [
|
|
|
4569
4766
|
value: "mockall",
|
|
4570
4767
|
label: "Mockall",
|
|
4571
4768
|
hint: "Powerful mocking library for Rust"
|
|
4769
|
+
},
|
|
4770
|
+
{
|
|
4771
|
+
value: "proptest",
|
|
4772
|
+
label: "Proptest",
|
|
4773
|
+
hint: "Property-based testing for Rust"
|
|
4774
|
+
},
|
|
4775
|
+
{
|
|
4776
|
+
value: "insta",
|
|
4777
|
+
label: "Insta",
|
|
4778
|
+
hint: "Snapshot testing for Rust"
|
|
4572
4779
|
}
|
|
4573
4780
|
];
|
|
4574
4781
|
const RUST_LOGGING_PROMPT_OPTIONS = [
|
|
@@ -4770,39 +4977,65 @@ async function getRustAuthChoice(rustAuth) {
|
|
|
4770
4977
|
|
|
4771
4978
|
//#endregion
|
|
4772
4979
|
//#region src/prompts/search.ts
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4980
|
+
const SEARCH_PROMPT_OPTIONS = [
|
|
4981
|
+
{
|
|
4982
|
+
value: "meilisearch",
|
|
4983
|
+
label: "Meilisearch",
|
|
4984
|
+
hint: "Lightning-fast search engine with typo tolerance"
|
|
4985
|
+
},
|
|
4986
|
+
{
|
|
4987
|
+
value: "typesense",
|
|
4988
|
+
label: "Typesense",
|
|
4989
|
+
hint: "Fast, typo-tolerant search with built-in vector search"
|
|
4990
|
+
},
|
|
4991
|
+
{
|
|
4992
|
+
value: "elasticsearch",
|
|
4993
|
+
label: "Elasticsearch",
|
|
4994
|
+
hint: "Distributed search and analytics engine with local and cloud deployments"
|
|
4995
|
+
},
|
|
4996
|
+
{
|
|
4997
|
+
value: "algolia",
|
|
4998
|
+
label: "Algolia",
|
|
4999
|
+
hint: "Hosted search API with instant results, typo tolerance, and analytics"
|
|
5000
|
+
},
|
|
5001
|
+
{
|
|
5002
|
+
value: "none",
|
|
5003
|
+
label: "None",
|
|
5004
|
+
hint: "Skip search engine setup"
|
|
5005
|
+
}
|
|
5006
|
+
];
|
|
5007
|
+
const NON_TYPESCRIPT_SEARCH_PROMPT_OPTIONS = SEARCH_PROMPT_OPTIONS.filter((option) => option.value === "meilisearch" || option.value === "none");
|
|
5008
|
+
function resolveSearchPrompt(context = {}) {
|
|
5009
|
+
const options = context.ecosystem && context.ecosystem !== "typescript" ? NON_TYPESCRIPT_SEARCH_PROMPT_OPTIONS : SEARCH_PROMPT_OPTIONS;
|
|
5010
|
+
if ((!context.ecosystem || context.ecosystem === "typescript") && (context.backend === "none" || context.backend === "convex")) return {
|
|
5011
|
+
shouldPrompt: false,
|
|
5012
|
+
mode: "single",
|
|
5013
|
+
options: [],
|
|
5014
|
+
autoValue: "none"
|
|
5015
|
+
};
|
|
5016
|
+
return context.search !== void 0 ? {
|
|
5017
|
+
shouldPrompt: false,
|
|
5018
|
+
mode: "single",
|
|
5019
|
+
options,
|
|
5020
|
+
autoValue: context.search
|
|
5021
|
+
} : {
|
|
5022
|
+
shouldPrompt: true,
|
|
5023
|
+
mode: "single",
|
|
5024
|
+
options,
|
|
5025
|
+
initialValue: "none"
|
|
5026
|
+
};
|
|
5027
|
+
}
|
|
5028
|
+
async function getSearchChoice(search, backend, ecosystem) {
|
|
5029
|
+
const resolution = resolveSearchPrompt({
|
|
5030
|
+
search,
|
|
5031
|
+
backend,
|
|
5032
|
+
ecosystem
|
|
5033
|
+
});
|
|
5034
|
+
if (!resolution.shouldPrompt) return resolution.autoValue ?? "none";
|
|
4776
5035
|
const response = await navigableSelect({
|
|
4777
5036
|
message: "Select search engine",
|
|
4778
|
-
options:
|
|
4779
|
-
|
|
4780
|
-
value: "meilisearch",
|
|
4781
|
-
label: "Meilisearch",
|
|
4782
|
-
hint: "Lightning-fast search engine with typo tolerance"
|
|
4783
|
-
},
|
|
4784
|
-
{
|
|
4785
|
-
value: "typesense",
|
|
4786
|
-
label: "Typesense",
|
|
4787
|
-
hint: "Fast, typo-tolerant search with built-in vector search"
|
|
4788
|
-
},
|
|
4789
|
-
{
|
|
4790
|
-
value: "elasticsearch",
|
|
4791
|
-
label: "Elasticsearch",
|
|
4792
|
-
hint: "Distributed search and analytics engine with local and cloud deployments"
|
|
4793
|
-
},
|
|
4794
|
-
{
|
|
4795
|
-
value: "algolia",
|
|
4796
|
-
label: "Algolia",
|
|
4797
|
-
hint: "Hosted search API with instant results, typo tolerance, and analytics"
|
|
4798
|
-
},
|
|
4799
|
-
{
|
|
4800
|
-
value: "none",
|
|
4801
|
-
label: "None",
|
|
4802
|
-
hint: "Skip search engine setup"
|
|
4803
|
-
}
|
|
4804
|
-
],
|
|
4805
|
-
initialValue: "none"
|
|
5037
|
+
options: resolution.options,
|
|
5038
|
+
initialValue: resolution.initialValue
|
|
4806
5039
|
});
|
|
4807
5040
|
if (isCancel$1(response)) return exitCancelled("Operation cancelled");
|
|
4808
5041
|
return response;
|
|
@@ -4854,6 +5087,16 @@ const STYLE_OPTIONS = [
|
|
|
4854
5087
|
value: "mira",
|
|
4855
5088
|
label: "Mira",
|
|
4856
5089
|
hint: "Dense, made for data-heavy interfaces"
|
|
5090
|
+
},
|
|
5091
|
+
{
|
|
5092
|
+
value: "luma",
|
|
5093
|
+
label: "Luma",
|
|
5094
|
+
hint: "Modern shadcn/ui v4 preset"
|
|
5095
|
+
},
|
|
5096
|
+
{
|
|
5097
|
+
value: "sera",
|
|
5098
|
+
label: "Sera",
|
|
5099
|
+
hint: "Modern shadcn/ui v4 preset"
|
|
4857
5100
|
}
|
|
4858
5101
|
];
|
|
4859
5102
|
const ICON_LIBRARY_OPTIONS = [
|
|
@@ -4881,6 +5124,16 @@ const ICON_LIBRARY_OPTIONS = [
|
|
|
4881
5124
|
value: "remixicon",
|
|
4882
5125
|
label: "Remix Icon",
|
|
4883
5126
|
hint: "Open-source neutral style icons"
|
|
5127
|
+
},
|
|
5128
|
+
{
|
|
5129
|
+
value: "heroicons",
|
|
5130
|
+
label: "Heroicons",
|
|
5131
|
+
hint: "Tailwind Labs SVG icon set"
|
|
5132
|
+
},
|
|
5133
|
+
{
|
|
5134
|
+
value: "react-icons",
|
|
5135
|
+
label: "React Icons",
|
|
5136
|
+
hint: "Popular wrapper for many icon packs"
|
|
4884
5137
|
}
|
|
4885
5138
|
];
|
|
4886
5139
|
const COLOR_THEME_OPTIONS = [
|
|
@@ -5379,6 +5632,14 @@ const UI_LIBRARY_OPTIONS = {
|
|
|
5379
5632
|
label: "Mantine",
|
|
5380
5633
|
hint: "Full-featured React component library with 120+ components"
|
|
5381
5634
|
},
|
|
5635
|
+
mui: {
|
|
5636
|
+
label: "MUI",
|
|
5637
|
+
hint: "Popular React component library implementing Material Design"
|
|
5638
|
+
},
|
|
5639
|
+
antd: {
|
|
5640
|
+
label: "Ant Design",
|
|
5641
|
+
hint: "Enterprise-class React UI component library"
|
|
5642
|
+
},
|
|
5382
5643
|
"base-ui": {
|
|
5383
5644
|
label: "Base UI",
|
|
5384
5645
|
hint: "Unstyled, accessible components from MUI team (Radix successor)"
|
|
@@ -5629,8 +5890,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
5629
5890
|
return getPaymentsChoice(flags.payments, results.auth, results.backend, results.frontend);
|
|
5630
5891
|
},
|
|
5631
5892
|
email: ({ results }) => {
|
|
5632
|
-
|
|
5633
|
-
return getEmailChoice(flags.email, results.backend);
|
|
5893
|
+
return getEmailChoice(flags.email, results.backend, results.ecosystem);
|
|
5634
5894
|
},
|
|
5635
5895
|
effect: ({ results }) => {
|
|
5636
5896
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
@@ -5701,8 +5961,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
5701
5961
|
return getLoggingChoice(flags.logging, results.backend);
|
|
5702
5962
|
},
|
|
5703
5963
|
observability: ({ results }) => {
|
|
5704
|
-
|
|
5705
|
-
return getObservabilityChoice(flags.observability, results.backend);
|
|
5964
|
+
return getObservabilityChoice(flags.observability, results.backend, results.ecosystem);
|
|
5706
5965
|
},
|
|
5707
5966
|
featureFlags: ({ results }) => {
|
|
5708
5967
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
@@ -5717,16 +5976,14 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
5717
5976
|
return getCMSChoice(flags.cms, results.backend);
|
|
5718
5977
|
},
|
|
5719
5978
|
caching: ({ results }) => {
|
|
5720
|
-
|
|
5721
|
-
return getCachingChoice(flags.caching, results.backend);
|
|
5979
|
+
return getCachingChoice(flags.caching, results.backend, results.ecosystem);
|
|
5722
5980
|
},
|
|
5723
5981
|
i18n: ({ results }) => {
|
|
5724
5982
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
5725
5983
|
return getI18nChoice(flags.i18n, results.frontend);
|
|
5726
5984
|
},
|
|
5727
5985
|
search: ({ results }) => {
|
|
5728
|
-
|
|
5729
|
-
return getSearchChoice(flags.search, results.backend);
|
|
5986
|
+
return getSearchChoice(flags.search, results.backend, results.ecosystem);
|
|
5730
5987
|
},
|
|
5731
5988
|
fileStorage: ({ results }) => {
|
|
5732
5989
|
if (results.ecosystem !== "typescript") return Promise.resolve("none");
|
|
@@ -5792,6 +6049,11 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
5792
6049
|
if (results.ecosystem !== "python") return Promise.resolve("none");
|
|
5793
6050
|
return getPythonAuthChoice(flags.pythonAuth);
|
|
5794
6051
|
},
|
|
6052
|
+
pythonApi: ({ results }) => {
|
|
6053
|
+
if (results.ecosystem !== "python") return Promise.resolve("none");
|
|
6054
|
+
if (results.pythonWebFramework !== "django") return Promise.resolve("none");
|
|
6055
|
+
return getPythonApiChoice(flags.pythonApi);
|
|
6056
|
+
},
|
|
5795
6057
|
pythonTaskQueue: ({ results }) => {
|
|
5796
6058
|
if (results.ecosystem !== "python") return Promise.resolve("none");
|
|
5797
6059
|
return getPythonTaskQueueChoice(flags.pythonTaskQueue);
|
|
@@ -5924,6 +6186,7 @@ async function gatherConfig(flags, projectName, projectDir, relativePath) {
|
|
|
5924
6186
|
pythonValidation: result.pythonValidation,
|
|
5925
6187
|
pythonAi: result.pythonAi,
|
|
5926
6188
|
pythonAuth: result.pythonAuth,
|
|
6189
|
+
pythonApi: result.pythonApi,
|
|
5927
6190
|
pythonTaskQueue: result.pythonTaskQueue,
|
|
5928
6191
|
pythonGraphql: result.pythonGraphql,
|
|
5929
6192
|
pythonQuality: result.pythonQuality,
|
|
@@ -6151,6 +6414,10 @@ function appendCommonFlags(flags, config) {
|
|
|
6151
6414
|
flags.push(config.install ? "--install" : "--no-install");
|
|
6152
6415
|
}
|
|
6153
6416
|
function appendSharedNonTypeScriptFlags(flags, config) {
|
|
6417
|
+
flags.push(`--email ${config.email}`);
|
|
6418
|
+
flags.push(`--observability ${config.observability}`);
|
|
6419
|
+
flags.push(`--caching ${config.caching}`);
|
|
6420
|
+
flags.push(`--search ${config.search}`);
|
|
6154
6421
|
flags.push(formatArrayFlag("addons", config.addons));
|
|
6155
6422
|
flags.push(formatArrayFlag("examples", config.examples));
|
|
6156
6423
|
flags.push(`--db-setup ${config.dbSetup}`);
|
|
@@ -6192,6 +6459,7 @@ function getTypeScriptFlags(config) {
|
|
|
6192
6459
|
flags.push(`--job-queue ${config.jobQueue}`);
|
|
6193
6460
|
flags.push(`--logging ${config.logging}`);
|
|
6194
6461
|
flags.push(`--observability ${config.observability}`);
|
|
6462
|
+
flags.push(`--feature-flags ${config.featureFlags}`);
|
|
6195
6463
|
flags.push(`--caching ${config.caching}`);
|
|
6196
6464
|
flags.push(`--i18n ${config.i18n}`);
|
|
6197
6465
|
flags.push(`--cms ${config.cms}`);
|
|
@@ -6230,6 +6498,7 @@ function getPythonFlags(config) {
|
|
|
6230
6498
|
flags.push(`--python-validation ${config.pythonValidation}`);
|
|
6231
6499
|
flags.push(formatArrayFlag("python-ai", config.pythonAi));
|
|
6232
6500
|
flags.push(`--python-auth ${config.pythonAuth}`);
|
|
6501
|
+
flags.push(`--python-api ${config.pythonApi}`);
|
|
6233
6502
|
flags.push(`--python-task-queue ${config.pythonTaskQueue}`);
|
|
6234
6503
|
flags.push(`--python-graphql ${config.pythonGraphql}`);
|
|
6235
6504
|
flags.push(`--python-quality ${config.pythonQuality}`);
|
|
@@ -6914,19 +7183,20 @@ function validateApiConstraints(_config, _options) {}
|
|
|
6914
7183
|
function validateJavaConstraints(config, providedFlags = /* @__PURE__ */ new Set()) {
|
|
6915
7184
|
if (config.ecosystem !== "java") return;
|
|
6916
7185
|
const hasSpringBoot = config.javaWebFramework === "spring-boot";
|
|
7186
|
+
const hasJavaWebFramework = config.javaWebFramework !== "none";
|
|
6917
7187
|
const hasNoBuildTool = config.javaBuildTool === "none";
|
|
6918
7188
|
const hasJavaLibraries = (config.javaLibraries ?? []).some((library) => library !== "none");
|
|
6919
7189
|
const hasJavaTestingLibraries = (config.javaTestingLibraries ?? []).some((library) => library !== "none");
|
|
6920
7190
|
const hasSpringOnlyFeatures = config.javaOrm !== "none" || config.javaAuth !== "none" || hasJavaLibraries;
|
|
6921
|
-
if (hasNoBuildTool &&
|
|
6922
|
-
message: "
|
|
7191
|
+
if (hasNoBuildTool && hasJavaWebFramework) incompatibilityError({
|
|
7192
|
+
message: "Java web frameworks require Maven or Gradle in the Java scaffold.",
|
|
6923
7193
|
provided: {
|
|
6924
7194
|
"java-web-framework": config.javaWebFramework ?? "none",
|
|
6925
7195
|
"java-build-tool": config.javaBuildTool ?? "none"
|
|
6926
7196
|
},
|
|
6927
|
-
suggestions: ["Use --java-build-tool maven or --java-build-tool gradle with
|
|
7197
|
+
suggestions: ["Use --java-build-tool maven or --java-build-tool gradle with Java web frameworks", "Use --java-web-framework none for a plain Java source-only scaffold"]
|
|
6928
7198
|
});
|
|
6929
|
-
if ((
|
|
7199
|
+
if ((!hasSpringBoot || hasNoBuildTool) && hasSpringOnlyFeatures) incompatibilityError({
|
|
6930
7200
|
message: "Spring-only Java features require the Spring Boot scaffold with Maven or Gradle.",
|
|
6931
7201
|
provided: {
|
|
6932
7202
|
"java-web-framework": config.javaWebFramework ?? "none",
|
|
@@ -6935,7 +7205,7 @@ function validateJavaConstraints(config, providedFlags = /* @__PURE__ */ new Set
|
|
|
6935
7205
|
"java-auth": config.javaAuth ?? "none",
|
|
6936
7206
|
"java-libraries": (config.javaLibraries ?? []).join(" ") || "none"
|
|
6937
7207
|
},
|
|
6938
|
-
suggestions: ["Use --java-web-framework spring-boot and a real build tool for Spring features", "Clear --java-orm, --java-auth, and --java-libraries when using plain Java"]
|
|
7208
|
+
suggestions: ["Use --java-web-framework spring-boot and a real build tool for Spring features", "Clear --java-orm, --java-auth, and --java-libraries when using plain Java or Quarkus"]
|
|
6939
7209
|
});
|
|
6940
7210
|
if (hasNoBuildTool && hasJavaTestingLibraries) incompatibilityError({
|
|
6941
7211
|
message: "Java testing libraries require Maven or Gradle to manage test dependencies.",
|
|
@@ -6946,6 +7216,82 @@ function validateJavaConstraints(config, providedFlags = /* @__PURE__ */ new Set
|
|
|
6946
7216
|
suggestions: ["Use --java-build-tool maven or --java-build-tool gradle to enable JUnit/Mockito/Testcontainers", "Set --java-testing-libraries none for a source-only plain Java scaffold"]
|
|
6947
7217
|
});
|
|
6948
7218
|
}
|
|
7219
|
+
function validateEmailConstraints(config) {
|
|
7220
|
+
if (!config.email || config.email === "none") return;
|
|
7221
|
+
if (config.ecosystem !== "typescript" && config.email !== "resend") incompatibilityError({
|
|
7222
|
+
message: "Only Resend email is available for non-TypeScript ecosystems.",
|
|
7223
|
+
provided: {
|
|
7224
|
+
ecosystem: config.ecosystem ?? "typescript",
|
|
7225
|
+
email: config.email
|
|
7226
|
+
},
|
|
7227
|
+
suggestions: ["Use --email resend", "Use --email none"]
|
|
7228
|
+
});
|
|
7229
|
+
if (config.ecosystem === "java" && config.email === "resend" && config.javaBuildTool === "none") incompatibilityError({
|
|
7230
|
+
message: "Resend email for Java requires Maven or Gradle to manage the SDK dependency.",
|
|
7231
|
+
provided: {
|
|
7232
|
+
"java-build-tool": "none",
|
|
7233
|
+
email: "resend"
|
|
7234
|
+
},
|
|
7235
|
+
suggestions: ["Use --java-build-tool maven", "Use --java-build-tool gradle"]
|
|
7236
|
+
});
|
|
7237
|
+
}
|
|
7238
|
+
function validateObservabilityConstraints(config) {
|
|
7239
|
+
if (!config.observability || config.observability === "none") return;
|
|
7240
|
+
if (config.ecosystem !== "typescript" && config.observability !== "sentry") incompatibilityError({
|
|
7241
|
+
message: "Only Sentry observability is available for non-TypeScript ecosystems.",
|
|
7242
|
+
provided: {
|
|
7243
|
+
ecosystem: config.ecosystem ?? "typescript",
|
|
7244
|
+
observability: config.observability
|
|
7245
|
+
},
|
|
7246
|
+
suggestions: ["Use --observability sentry", "Use --observability none"]
|
|
7247
|
+
});
|
|
7248
|
+
if (config.ecosystem === "java" && config.observability === "sentry" && config.javaBuildTool === "none") incompatibilityError({
|
|
7249
|
+
message: "Sentry observability for Java requires Maven or Gradle to manage the SDK dependency.",
|
|
7250
|
+
provided: {
|
|
7251
|
+
"java-build-tool": "none",
|
|
7252
|
+
observability: "sentry"
|
|
7253
|
+
},
|
|
7254
|
+
suggestions: ["Use --java-build-tool maven", "Use --java-build-tool gradle"]
|
|
7255
|
+
});
|
|
7256
|
+
}
|
|
7257
|
+
function validateCachingConstraints(config) {
|
|
7258
|
+
if (!config.caching || config.caching === "none") return;
|
|
7259
|
+
if (config.ecosystem !== "typescript" && config.caching !== "upstash-redis") incompatibilityError({
|
|
7260
|
+
message: "Only Upstash Redis caching is available for non-TypeScript ecosystems.",
|
|
7261
|
+
provided: {
|
|
7262
|
+
ecosystem: config.ecosystem ?? "typescript",
|
|
7263
|
+
caching: config.caching
|
|
7264
|
+
},
|
|
7265
|
+
suggestions: ["Use --caching upstash-redis", "Use --caching none"]
|
|
7266
|
+
});
|
|
7267
|
+
if (config.ecosystem === "java" && config.caching === "upstash-redis" && config.javaBuildTool === "none") incompatibilityError({
|
|
7268
|
+
message: "Upstash Redis caching for Java requires Maven or Gradle to manage the Redis client dependency.",
|
|
7269
|
+
provided: {
|
|
7270
|
+
"java-build-tool": "none",
|
|
7271
|
+
caching: "upstash-redis"
|
|
7272
|
+
},
|
|
7273
|
+
suggestions: ["Use --java-build-tool maven", "Use --java-build-tool gradle"]
|
|
7274
|
+
});
|
|
7275
|
+
}
|
|
7276
|
+
function validateSearchConstraints(config) {
|
|
7277
|
+
if (!config.search || config.search === "none") return;
|
|
7278
|
+
if (config.ecosystem !== "typescript" && config.search !== "meilisearch") incompatibilityError({
|
|
7279
|
+
message: "Only Meilisearch search is available for non-TypeScript ecosystems.",
|
|
7280
|
+
provided: {
|
|
7281
|
+
ecosystem: config.ecosystem ?? "typescript",
|
|
7282
|
+
search: config.search
|
|
7283
|
+
},
|
|
7284
|
+
suggestions: ["Use --search meilisearch", "Use --search none"]
|
|
7285
|
+
});
|
|
7286
|
+
if (config.ecosystem === "java" && config.search === "meilisearch" && config.javaBuildTool === "none") incompatibilityError({
|
|
7287
|
+
message: "Meilisearch search for Java requires Maven or Gradle to manage the SDK dependency.",
|
|
7288
|
+
provided: {
|
|
7289
|
+
"java-build-tool": "none",
|
|
7290
|
+
search: "meilisearch"
|
|
7291
|
+
},
|
|
7292
|
+
suggestions: ["Use --java-build-tool maven", "Use --java-build-tool gradle"]
|
|
7293
|
+
});
|
|
7294
|
+
}
|
|
6949
7295
|
function validateShadcnConstraints(config, providedFlags) {
|
|
6950
7296
|
const shadcnFlagMap = {
|
|
6951
7297
|
shadcnBase: "--shadcn-base",
|
|
@@ -6966,6 +7312,16 @@ function validateShadcnConstraints(config, providedFlags) {
|
|
|
6966
7312
|
suggestions: ["Add --ui-library shadcn-ui to use shadcn customization flags", "Remove the --shadcn-* flags if not using shadcn/ui"]
|
|
6967
7313
|
});
|
|
6968
7314
|
}
|
|
7315
|
+
function validatePythonApiConstraints(config) {
|
|
7316
|
+
if (config.ecosystem === "python" && config.pythonApi && config.pythonApi !== "none" && config.pythonWebFramework !== "django") incompatibilityError({
|
|
7317
|
+
message: "Python API frameworks require --python-web-framework django.",
|
|
7318
|
+
provided: {
|
|
7319
|
+
"python-web-framework": config.pythonWebFramework || "none",
|
|
7320
|
+
"python-api": config.pythonApi
|
|
7321
|
+
},
|
|
7322
|
+
suggestions: ["Use --python-web-framework django with --python-api django-rest-framework or django-ninja", "Set --python-api none for FastAPI, Flask, Litestar, or no Python web framework"]
|
|
7323
|
+
});
|
|
7324
|
+
}
|
|
6969
7325
|
function validateFullConfig(config, providedFlags, options) {
|
|
6970
7326
|
validateEcosystemAuthCompatibility(config, providedFlags);
|
|
6971
7327
|
validateDatabaseOrmAuth(config, providedFlags);
|
|
@@ -6978,6 +7334,11 @@ function validateFullConfig(config, providedFlags, options) {
|
|
|
6978
7334
|
validateBackendConstraints(config, providedFlags, options);
|
|
6979
7335
|
validateFrontendConstraints(config, providedFlags);
|
|
6980
7336
|
/* @__PURE__ */ validateApiConstraints(config, options);
|
|
7337
|
+
validatePythonApiConstraints(config);
|
|
7338
|
+
validateEmailConstraints(config);
|
|
7339
|
+
validateObservabilityConstraints(config);
|
|
7340
|
+
validateCachingConstraints(config);
|
|
7341
|
+
validateSearchConstraints(config);
|
|
6981
7342
|
validateJavaConstraints(config, providedFlags);
|
|
6982
7343
|
validateServerDeployRequiresBackend(config.serverDeploy, config.backend);
|
|
6983
7344
|
validateSelfBackendCompatibility(providedFlags, options, config);
|
|
@@ -7014,6 +7375,11 @@ function validateConfigForProgrammaticUse(config) {
|
|
|
7014
7375
|
validateDatabaseOrmAuth(config);
|
|
7015
7376
|
if (config.frontend && config.frontend.length > 0) ensureSingleWebAndNative(config.frontend);
|
|
7016
7377
|
validateApiFrontendCompatibility(config.api, config.frontend, config.astroIntegration);
|
|
7378
|
+
validatePythonApiConstraints(config);
|
|
7379
|
+
validateEmailConstraints(config);
|
|
7380
|
+
validateObservabilityConstraints(config);
|
|
7381
|
+
validateCachingConstraints(config);
|
|
7382
|
+
validateSearchConstraints(config);
|
|
7017
7383
|
validateJavaConstraints(config);
|
|
7018
7384
|
validatePaymentsCompatibility(config.payments, config.auth, config.backend, config.frontend);
|
|
7019
7385
|
if (config.addons && config.addons.length > 0) validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth, config.backend, config.runtime, config.ecosystem, config.rustFrontend, config.javaWebFramework, config.database);
|
|
@@ -8688,7 +9054,8 @@ function displayGoInstructions(config) {
|
|
|
8688
9054
|
if (goApi && goApi !== "none") output += `${pc.cyan("•")} API: ${{ "grpc-go": "gRPC-Go" }[goApi] || goApi}\n`;
|
|
8689
9055
|
if (goCli && goCli !== "none") output += `${pc.cyan("•")} CLI: ${{
|
|
8690
9056
|
cobra: "Cobra",
|
|
8691
|
-
bubbletea: "Bubble Tea"
|
|
9057
|
+
bubbletea: "Bubble Tea",
|
|
9058
|
+
"urfave-cli": "urfave/cli"
|
|
8692
9059
|
}[goCli] || goCli}\n`;
|
|
8693
9060
|
if (goLogging && goLogging !== "none") output += `${pc.cyan("•")} Logging: ${{
|
|
8694
9061
|
zap: "Zap",
|
|
@@ -8790,6 +9157,7 @@ function displayJavaInstructions(config) {
|
|
|
8790
9157
|
const { projectName, relativePath, depsInstalled, javaWebFramework, javaBuildTool, javaOrm, javaAuth, javaLibraries, javaTestingLibraries } = config;
|
|
8791
9158
|
const cdCmd = `cd ${relativePath}`;
|
|
8792
9159
|
const isSpringBoot = javaWebFramework === "spring-boot" && javaBuildTool !== "none";
|
|
9160
|
+
const isQuarkus = javaWebFramework === "quarkus" && javaBuildTool !== "none";
|
|
8793
9161
|
const rawJavaLibraries = isSpringBoot ? javaLibraries.filter((library) => library !== "none") : [];
|
|
8794
9162
|
const rawJavaLibrarySet = new Set(rawJavaLibraries);
|
|
8795
9163
|
const jpaRequiredJavaLibraries = new Set(["flyway", "liquibase"]);
|
|
@@ -8801,7 +9169,7 @@ function displayJavaInstructions(config) {
|
|
|
8801
9169
|
}
|
|
8802
9170
|
const effectiveJavaTestingLibraries = javaBuildTool === "none" ? [] : javaTestingLibraries.filter((library) => library !== "none");
|
|
8803
9171
|
const buildToolCommand = javaBuildTool === "none" ? null : javaBuildTool === "gradle" ? process.platform === "win32" ? "gradlew.bat" : "./gradlew" : process.platform === "win32" ? "mvnw.cmd" : "./mvnw";
|
|
8804
|
-
const runCommand = buildToolCommand ? isSpringBoot ? javaBuildTool === "gradle" ? `${buildToolCommand} bootRun` : `${buildToolCommand} spring-boot:run` : javaBuildTool === "gradle" ? `${buildToolCommand} run` : `${buildToolCommand} exec:java` : null;
|
|
9172
|
+
const runCommand = buildToolCommand ? isSpringBoot ? javaBuildTool === "gradle" ? `${buildToolCommand} bootRun` : `${buildToolCommand} spring-boot:run` : isQuarkus ? javaBuildTool === "gradle" ? `${buildToolCommand} quarkusDev` : `${buildToolCommand} quarkus:dev` : javaBuildTool === "gradle" ? `${buildToolCommand} run` : `${buildToolCommand} exec:java` : null;
|
|
8805
9173
|
const packageCommand = buildToolCommand ? javaBuildTool === "gradle" ? `${buildToolCommand} build` : `${buildToolCommand} package` : null;
|
|
8806
9174
|
const sourceCompileCommand = buildToolCommand ? null : `javac -d out ${getJavaMainSourcePath(projectName)}`;
|
|
8807
9175
|
const sourceRunCommand = buildToolCommand ? null : `java -cp out ${getJavaMainClass(projectName)}`;
|
|
@@ -8814,7 +9182,10 @@ function displayJavaInstructions(config) {
|
|
|
8814
9182
|
output += `${pc.cyan(`${stepCounter++}.`)} ${sourceRunCommand}\n`;
|
|
8815
9183
|
} else output += `${pc.cyan(`${stepCounter++}.`)} Add Maven or Gradle, then run the app\n`;
|
|
8816
9184
|
output += `\n${pc.bold("Your Java project includes:")}\n`;
|
|
8817
|
-
if (isSpringBoot) output += `${pc.cyan("•")} Web Framework: ${{
|
|
9185
|
+
if (isSpringBoot || isQuarkus) output += `${pc.cyan("•")} Web Framework: ${{
|
|
9186
|
+
"spring-boot": "Spring Boot",
|
|
9187
|
+
quarkus: "Quarkus"
|
|
9188
|
+
}[javaWebFramework] || javaWebFramework}\n`;
|
|
8818
9189
|
else output += `${pc.cyan("•")} Scaffold: Plain Java\n`;
|
|
8819
9190
|
if (javaBuildTool && javaBuildTool !== "none") output += `${pc.cyan("•")} Build Tool: ${{
|
|
8820
9191
|
maven: "Maven Wrapper",
|
|
@@ -8871,7 +9242,7 @@ function displayJavaInstructions(config) {
|
|
|
8871
9242
|
consola$1.box(output);
|
|
8872
9243
|
}
|
|
8873
9244
|
function displayPythonInstructions(config) {
|
|
8874
|
-
const { relativePath, depsInstalled, pythonWebFramework, pythonOrm, pythonValidation, pythonAi, pythonTaskQueue, pythonQuality } = config;
|
|
9245
|
+
const { relativePath, depsInstalled, pythonWebFramework, pythonOrm, pythonValidation, pythonAi, pythonApi, pythonTaskQueue, pythonQuality } = config;
|
|
8875
9246
|
const cdCmd = `cd ${relativePath}`;
|
|
8876
9247
|
let runCommand = "uv run uvicorn app.main:app --reload";
|
|
8877
9248
|
if (pythonWebFramework === "django") runCommand = "uv run python manage.py runserver";
|
|
@@ -8906,14 +9277,25 @@ function displayPythonInstructions(config) {
|
|
|
8906
9277
|
const aiList = pythonAi.filter((ai) => ai !== "none").map((ai) => aiNames[ai] || ai).join(", ");
|
|
8907
9278
|
output += `${pc.cyan("•")} AI: ${aiList}\n`;
|
|
8908
9279
|
}
|
|
9280
|
+
if (pythonApi && pythonApi !== "none") output += `${pc.cyan("•")} API Framework: ${{
|
|
9281
|
+
"django-rest-framework": "Django REST Framework",
|
|
9282
|
+
"django-ninja": "Django Ninja"
|
|
9283
|
+
}[pythonApi] || pythonApi}\n`;
|
|
8909
9284
|
if (pythonTaskQueue && pythonTaskQueue !== "none") output += `${pc.cyan("•")} Task Queue: ${{ celery: "Celery" }[pythonTaskQueue] || pythonTaskQueue}\n`;
|
|
8910
|
-
if (pythonQuality && pythonQuality !== "none") output += `${pc.cyan("•")} Code Quality: ${{
|
|
9285
|
+
if (pythonQuality && pythonQuality !== "none") output += `${pc.cyan("•")} Code Quality: ${{
|
|
9286
|
+
ruff: "Ruff",
|
|
9287
|
+
mypy: "mypy",
|
|
9288
|
+
pyright: "Pyright"
|
|
9289
|
+
}[pythonQuality] || pythonQuality}\n`;
|
|
8911
9290
|
output += `\n${pc.bold("Common Python commands:")}\n`;
|
|
8912
9291
|
output += `${pc.cyan("•")} Install: uv sync\n`;
|
|
8913
9292
|
output += `${pc.cyan("•")} Run: ${runCommand}\n`;
|
|
8914
9293
|
output += `${pc.cyan("•")} Test: uv run pytest\n`;
|
|
8915
|
-
|
|
8916
|
-
|
|
9294
|
+
if (pythonQuality === "ruff") {
|
|
9295
|
+
output += `${pc.cyan("•")} Format: uv run ruff format .\n`;
|
|
9296
|
+
output += `${pc.cyan("•")} Lint: uv run ruff check .\n`;
|
|
9297
|
+
} else if (pythonQuality === "mypy") output += `${pc.cyan("•")} Type check: uv run mypy src/app tests\n`;
|
|
9298
|
+
else if (pythonQuality === "pyright") output += `${pc.cyan("•")} Type check: uv run pyright\n`;
|
|
8917
9299
|
output += `\n${pc.bold("Your project will be available at:")}\n`;
|
|
8918
9300
|
output += `${pc.cyan("•")} API: http://localhost:8000\n`;
|
|
8919
9301
|
output += `\n${pc.bold("Enjoying Better Fullstack?")} Help us grow — star the repo!\n`;
|
|
@@ -9099,6 +9481,7 @@ async function createProjectHandler(input, options = {}) {
|
|
|
9099
9481
|
pythonValidation: "none",
|
|
9100
9482
|
pythonAi: [],
|
|
9101
9483
|
pythonAuth: "none",
|
|
9484
|
+
pythonApi: "none",
|
|
9102
9485
|
pythonTaskQueue: "none",
|
|
9103
9486
|
pythonGraphql: "none",
|
|
9104
9487
|
pythonQuality: "none",
|
|
@@ -9622,6 +10005,7 @@ async function createVirtual(options) {
|
|
|
9622
10005
|
pythonValidation: options.pythonValidation || "none",
|
|
9623
10006
|
pythonAi: options.pythonAi || [],
|
|
9624
10007
|
pythonAuth: options.pythonAuth || "none",
|
|
10008
|
+
pythonApi: options.pythonApi || "none",
|
|
9625
10009
|
pythonTaskQueue: options.pythonTaskQueue || "none",
|
|
9626
10010
|
pythonGraphql: options.pythonGraphql || "none",
|
|
9627
10011
|
pythonQuality: options.pythonQuality || "none",
|