render-create 0.1.0 → 0.2.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/commands/init.js +115 -43
- package/dist/types.d.ts +10 -0
- package/package.json +3 -2
- package/templates/fastapi/main-simple.py +29 -0
- package/templates/fastify/index-simple.ts +39 -0
- package/templates/presets.json +24 -11
package/dist/commands/init.js
CHANGED
|
@@ -421,17 +421,24 @@ async function scaffoldFrontend(projectDir, _componentId, component, projectName
|
|
|
421
421
|
/**
|
|
422
422
|
* Scaffold an API component
|
|
423
423
|
*/
|
|
424
|
-
async function scaffoldApi(projectDir, _componentId, component, projectName, skipInstall) {
|
|
424
|
+
async function scaffoldApi(projectDir, _componentId, component, projectName, skipInstall, hasDatabase) {
|
|
425
425
|
const subdir = join(projectDir, component.subdir);
|
|
426
426
|
ensureDir(subdir);
|
|
427
427
|
console.log(chalk.blue(`\nScaffolding API: ${component.name}...\n`));
|
|
428
|
+
// Choose files based on database selection
|
|
429
|
+
const scaffoldFiles = hasDatabase && component.scaffoldFilesWithDb
|
|
430
|
+
? component.scaffoldFilesWithDb
|
|
431
|
+
: component.scaffoldFiles;
|
|
428
432
|
if (component.runtime === "python") {
|
|
429
433
|
// Python API
|
|
430
|
-
const pythonDeps =
|
|
434
|
+
const pythonDeps = [
|
|
435
|
+
...(component.pythonDependencies ?? []),
|
|
436
|
+
...(hasDatabase ? (component.pythonDependenciesWithDb ?? []) : []),
|
|
437
|
+
];
|
|
431
438
|
writeFileSync(join(subdir, "requirements.txt"), `${pythonDeps.join("\n")}\n`);
|
|
432
439
|
console.log(chalk.green(` Created requirements.txt`));
|
|
433
|
-
if (
|
|
434
|
-
copyPostCreateFiles(subdir,
|
|
440
|
+
if (scaffoldFiles) {
|
|
441
|
+
copyPostCreateFiles(subdir, scaffoldFiles, projectName);
|
|
435
442
|
}
|
|
436
443
|
if (!skipInstall) {
|
|
437
444
|
installPythonDependencies(subdir);
|
|
@@ -439,23 +446,33 @@ async function scaffoldApi(projectDir, _componentId, component, projectName, ski
|
|
|
439
446
|
}
|
|
440
447
|
else {
|
|
441
448
|
// Node API
|
|
449
|
+
const scripts = {
|
|
450
|
+
...(component.scripts ?? {}),
|
|
451
|
+
...(hasDatabase ? (component.scriptsWithDb ?? {}) : {}),
|
|
452
|
+
};
|
|
442
453
|
const packageJson = {
|
|
443
454
|
name: `${projectName}-${component.subdir}`,
|
|
444
455
|
version: "0.1.0",
|
|
445
456
|
private: true,
|
|
446
457
|
type: "module",
|
|
447
|
-
scripts
|
|
458
|
+
scripts,
|
|
448
459
|
dependencies: {},
|
|
449
460
|
devDependencies: {},
|
|
450
461
|
};
|
|
451
462
|
writeFileSync(join(subdir, "package.json"), `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
452
463
|
console.log(chalk.green(` Created package.json`));
|
|
453
|
-
if (
|
|
454
|
-
copyPostCreateFiles(subdir,
|
|
464
|
+
if (scaffoldFiles) {
|
|
465
|
+
copyPostCreateFiles(subdir, scaffoldFiles, projectName);
|
|
455
466
|
}
|
|
456
467
|
if (!skipInstall) {
|
|
457
|
-
const deps =
|
|
458
|
-
|
|
468
|
+
const deps = [
|
|
469
|
+
...(component.dependencies ?? []),
|
|
470
|
+
...(hasDatabase ? (component.dependenciesWithDb ?? []) : []),
|
|
471
|
+
];
|
|
472
|
+
const devDeps = [
|
|
473
|
+
...(component.devDependencies ?? []),
|
|
474
|
+
...(hasDatabase ? (component.devDependenciesWithDb ?? []) : []),
|
|
475
|
+
];
|
|
459
476
|
if (deps.length > 0) {
|
|
460
477
|
console.log(chalk.gray(` npm install ${deps.join(" ")}`));
|
|
461
478
|
execSync(`npm install ${deps.join(" ")}`, { cwd: subdir, stdio: "inherit" });
|
|
@@ -671,6 +688,7 @@ function hasWorkflowSelected(selection, components) {
|
|
|
671
688
|
function collectRules(selection, components) {
|
|
672
689
|
const rules = new Set(["general"]);
|
|
673
690
|
const hasWorkflows = hasWorkflowSelected(selection, components);
|
|
691
|
+
const hasDatabase = !!selection.database;
|
|
674
692
|
if (selection.frontend) {
|
|
675
693
|
const comp = components.frontends[selection.frontend];
|
|
676
694
|
for (const rule of comp?.rules ?? []) {
|
|
@@ -682,6 +700,12 @@ function collectRules(selection, components) {
|
|
|
682
700
|
for (const rule of comp?.rules ?? []) {
|
|
683
701
|
rules.add(rule);
|
|
684
702
|
}
|
|
703
|
+
// Add database rules (ORM) when database is selected
|
|
704
|
+
if (hasDatabase && comp?.rulesWithDb) {
|
|
705
|
+
for (const rule of comp.rulesWithDb) {
|
|
706
|
+
rules.add(rule);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
685
709
|
// Add workflows rule to APIs when workflows are selected
|
|
686
710
|
if (hasWorkflows) {
|
|
687
711
|
rules.add("workflows");
|
|
@@ -753,11 +777,15 @@ ${structureLines.join("\n")}
|
|
|
753
777
|
|
|
754
778
|
1. Set up environment variables (copy \`.env.example\` to \`.env\` in each service)
|
|
755
779
|
2. Install dependencies in each service directory
|
|
756
|
-
3.
|
|
780
|
+
3. Push to GitHub and deploy via the Render Dashboard
|
|
757
781
|
|
|
758
782
|
## Deploy to Render
|
|
759
783
|
|
|
760
|
-
This project includes a \`render.yaml\` Blueprint for easy deployment
|
|
784
|
+
This project includes a \`render.yaml\` Blueprint for easy deployment:
|
|
785
|
+
|
|
786
|
+
1. Push this repo to GitHub
|
|
787
|
+
2. Go to [dashboard.render.com/blueprints](https://dashboard.render.com/select-repo?type=blueprint)
|
|
788
|
+
3. Connect your repo and deploy
|
|
761
789
|
`;
|
|
762
790
|
writeFileSync(join(projectDir, "README.md"), readmeContent);
|
|
763
791
|
// Create root .gitignore
|
|
@@ -797,6 +825,7 @@ Thumbs.db
|
|
|
797
825
|
}
|
|
798
826
|
// Scaffold APIs
|
|
799
827
|
const hasWorkflows = hasWorkflowSelected(selection, components);
|
|
828
|
+
const hasDatabase = !!selection.database;
|
|
800
829
|
for (const apiId of selection.apis) {
|
|
801
830
|
const comp = components.apis[apiId];
|
|
802
831
|
if (comp) {
|
|
@@ -812,7 +841,7 @@ Thumbs.db
|
|
|
812
841
|
: comp.pythonDependencies,
|
|
813
842
|
}
|
|
814
843
|
: comp;
|
|
815
|
-
await scaffoldApi(projectDir, apiId, apiComp, selection.projectName, skipInstall);
|
|
844
|
+
await scaffoldApi(projectDir, apiId, apiComp, selection.projectName, skipInstall, hasDatabase);
|
|
816
845
|
}
|
|
817
846
|
}
|
|
818
847
|
// Scaffold workers
|
|
@@ -911,7 +940,8 @@ RENDER_API_KEY=
|
|
|
911
940
|
console.log(chalk.white("\nNext steps:\n"));
|
|
912
941
|
console.log(chalk.cyan(` cd ${selection.projectName}`));
|
|
913
942
|
console.log(chalk.cyan(` # Start each service in its directory`));
|
|
914
|
-
console.log(chalk.cyan(`
|
|
943
|
+
console.log(chalk.cyan(` git init && git add . && git commit -m "Initial commit"`));
|
|
944
|
+
console.log(chalk.cyan(` # Push to GitHub, then deploy at dashboard.render.com/blueprints`));
|
|
915
945
|
console.log();
|
|
916
946
|
}
|
|
917
947
|
/**
|
|
@@ -953,24 +983,13 @@ export async function init(nameArg, options) {
|
|
|
953
983
|
message: "Select a stack preset:",
|
|
954
984
|
choices: presetChoices,
|
|
955
985
|
});
|
|
956
|
-
questions.push({
|
|
957
|
-
type: "checkbox",
|
|
958
|
-
name: "extras",
|
|
959
|
-
message: "Include extras:",
|
|
960
|
-
choices: [
|
|
961
|
-
{ name: ".env.example template", value: "env", checked: true },
|
|
962
|
-
{ name: "docker-compose.yml", value: "docker", checked: false },
|
|
963
|
-
],
|
|
964
|
-
});
|
|
965
986
|
}
|
|
966
987
|
const answers = await inquirer.prompt(questions);
|
|
967
988
|
projectName = projectName ?? answers.projectName;
|
|
968
989
|
selectedPresetId = options.preset ?? answers.preset;
|
|
969
|
-
selectedExtras = answers.extras ?? (options.yes ? ["env"] : []);
|
|
970
990
|
}
|
|
971
991
|
else {
|
|
972
992
|
selectedPresetId = options.preset;
|
|
973
|
-
selectedExtras = options.yes ? ["env"] : [];
|
|
974
993
|
}
|
|
975
994
|
// Validate preset
|
|
976
995
|
if (selectedPresetId && selectedPresetId !== "custom") {
|
|
@@ -980,6 +999,24 @@ export async function init(nameArg, options) {
|
|
|
980
999
|
console.log(chalk.yellow(`Available presets: ${Object.keys(presetsConfig.presets).join(", ")}`));
|
|
981
1000
|
process.exit(1);
|
|
982
1001
|
}
|
|
1002
|
+
// Ask for extras for non-custom presets
|
|
1003
|
+
if (!options.yes) {
|
|
1004
|
+
const extrasAnswer = await inquirer.prompt([
|
|
1005
|
+
{
|
|
1006
|
+
type: "checkbox",
|
|
1007
|
+
name: "extras",
|
|
1008
|
+
message: "Include extras (Space to select, Enter to confirm):",
|
|
1009
|
+
choices: [
|
|
1010
|
+
{ name: ".env.example template", value: "env", checked: true },
|
|
1011
|
+
{ name: "docker-compose.yml", value: "docker", checked: false },
|
|
1012
|
+
],
|
|
1013
|
+
},
|
|
1014
|
+
]);
|
|
1015
|
+
selectedExtras = extrasAnswer.extras;
|
|
1016
|
+
}
|
|
1017
|
+
else {
|
|
1018
|
+
selectedExtras = ["env"];
|
|
1019
|
+
}
|
|
983
1020
|
}
|
|
984
1021
|
// Handle custom/composable preset
|
|
985
1022
|
if (selectedPresetId === "custom") {
|
|
@@ -1054,20 +1091,8 @@ export async function init(nameArg, options) {
|
|
|
1054
1091
|
frontendDeployType = "static";
|
|
1055
1092
|
}
|
|
1056
1093
|
}
|
|
1057
|
-
// Step 3:
|
|
1058
|
-
const
|
|
1059
|
-
{
|
|
1060
|
-
type: "checkbox",
|
|
1061
|
-
name: "apis",
|
|
1062
|
-
message: "Select API backends (optional, press Enter to skip):",
|
|
1063
|
-
choices: apiChoices,
|
|
1064
|
-
},
|
|
1065
|
-
{
|
|
1066
|
-
type: "checkbox",
|
|
1067
|
-
name: "workers",
|
|
1068
|
-
message: "Select background workers (optional, press Enter to skip):",
|
|
1069
|
-
choices: workerChoices,
|
|
1070
|
-
},
|
|
1094
|
+
// Step 3: Database and cache
|
|
1095
|
+
const { database, cache } = await inquirer.prompt([
|
|
1071
1096
|
{
|
|
1072
1097
|
type: "list",
|
|
1073
1098
|
name: "database",
|
|
@@ -1080,6 +1105,53 @@ export async function init(nameArg, options) {
|
|
|
1080
1105
|
message: "Add cache?",
|
|
1081
1106
|
choices: cacheChoices,
|
|
1082
1107
|
},
|
|
1108
|
+
]);
|
|
1109
|
+
// Step 4: API backends (two-step)
|
|
1110
|
+
const { wantApi } = await inquirer.prompt([
|
|
1111
|
+
{
|
|
1112
|
+
type: "confirm",
|
|
1113
|
+
name: "wantApi",
|
|
1114
|
+
message: "Add API backend?",
|
|
1115
|
+
default: true,
|
|
1116
|
+
},
|
|
1117
|
+
]);
|
|
1118
|
+
let selectedApis = [];
|
|
1119
|
+
if (wantApi) {
|
|
1120
|
+
const { apis } = await inquirer.prompt([
|
|
1121
|
+
{
|
|
1122
|
+
type: "checkbox",
|
|
1123
|
+
name: "apis",
|
|
1124
|
+
message: "Select API backends:",
|
|
1125
|
+
choices: apiChoices,
|
|
1126
|
+
validate: (input) => input.length > 0 || "Please select at least one API",
|
|
1127
|
+
},
|
|
1128
|
+
]);
|
|
1129
|
+
selectedApis = apis;
|
|
1130
|
+
}
|
|
1131
|
+
// Step 5: Background workers (two-step)
|
|
1132
|
+
const { wantWorker } = await inquirer.prompt([
|
|
1133
|
+
{
|
|
1134
|
+
type: "confirm",
|
|
1135
|
+
name: "wantWorker",
|
|
1136
|
+
message: "Add background worker?",
|
|
1137
|
+
default: true,
|
|
1138
|
+
},
|
|
1139
|
+
]);
|
|
1140
|
+
let selectedWorkers = [];
|
|
1141
|
+
if (wantWorker) {
|
|
1142
|
+
const { workers } = await inquirer.prompt([
|
|
1143
|
+
{
|
|
1144
|
+
type: "checkbox",
|
|
1145
|
+
name: "workers",
|
|
1146
|
+
message: "Select background workers:",
|
|
1147
|
+
choices: workerChoices,
|
|
1148
|
+
validate: (input) => input.length > 0 || "Please select at least one worker",
|
|
1149
|
+
},
|
|
1150
|
+
]);
|
|
1151
|
+
selectedWorkers = workers;
|
|
1152
|
+
}
|
|
1153
|
+
// Step 6: Extras
|
|
1154
|
+
const { extras } = await inquirer.prompt([
|
|
1083
1155
|
{
|
|
1084
1156
|
type: "checkbox",
|
|
1085
1157
|
name: "extras",
|
|
@@ -1094,11 +1166,11 @@ export async function init(nameArg, options) {
|
|
|
1094
1166
|
projectName,
|
|
1095
1167
|
frontend: frontend === "none" ? null : frontend,
|
|
1096
1168
|
frontendDeployType,
|
|
1097
|
-
apis:
|
|
1098
|
-
workers:
|
|
1099
|
-
database:
|
|
1100
|
-
cache:
|
|
1101
|
-
extras
|
|
1169
|
+
apis: selectedApis,
|
|
1170
|
+
workers: selectedWorkers,
|
|
1171
|
+
database: database === "none" ? null : database,
|
|
1172
|
+
cache: cache === "none" ? null : cache,
|
|
1173
|
+
extras,
|
|
1102
1174
|
};
|
|
1103
1175
|
// Scaffold the composable project
|
|
1104
1176
|
await scaffoldComposableProject(selection, components, options.skipInstall ?? false);
|
package/dist/types.d.ts
CHANGED
|
@@ -155,6 +155,16 @@ export interface ApiComponent extends BaseComponent {
|
|
|
155
155
|
/** For Python APIs */
|
|
156
156
|
pythonDependencies?: string[];
|
|
157
157
|
scaffoldFiles: Record<string, string>;
|
|
158
|
+
/** Additional files when database is selected */
|
|
159
|
+
scaffoldFilesWithDb?: Record<string, string>;
|
|
160
|
+
/** Additional dependencies when database is selected */
|
|
161
|
+
dependenciesWithDb?: string[];
|
|
162
|
+
devDependenciesWithDb?: string[];
|
|
163
|
+
pythonDependenciesWithDb?: string[];
|
|
164
|
+
/** Additional scripts when database is selected */
|
|
165
|
+
scriptsWithDb?: Record<string, string>;
|
|
166
|
+
/** Additional rules when database is selected */
|
|
167
|
+
rulesWithDb?: string[];
|
|
158
168
|
blueprint: {
|
|
159
169
|
type: "web";
|
|
160
170
|
runtime: "node" | "python";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "render-create",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI to scaffold and deploy applications on Render with best practices, Cursor rules, and Infrastructure as Code",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"postversion": "git push && git push --tags",
|
|
31
31
|
"release:patch": "npm version patch",
|
|
32
32
|
"release:minor": "npm version minor",
|
|
33
|
-
"release:major": "npm version major"
|
|
33
|
+
"release:major": "npm version major",
|
|
34
|
+
"publish:npm": "npm publish --access public"
|
|
34
35
|
},
|
|
35
36
|
"keywords": [
|
|
36
37
|
"render",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from fastapi import FastAPI
|
|
3
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
4
|
+
|
|
5
|
+
app = FastAPI(title="API")
|
|
6
|
+
|
|
7
|
+
# CORS
|
|
8
|
+
app.add_middleware(
|
|
9
|
+
CORSMiddleware,
|
|
10
|
+
allow_origins=["*"],
|
|
11
|
+
allow_credentials=True,
|
|
12
|
+
allow_methods=["*"],
|
|
13
|
+
allow_headers=["*"],
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.get("/health")
|
|
18
|
+
async def health():
|
|
19
|
+
"""Health check endpoint."""
|
|
20
|
+
return {"status": "ok"}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@app.get("/api/hello")
|
|
24
|
+
async def hello():
|
|
25
|
+
"""Hello endpoint."""
|
|
26
|
+
return {
|
|
27
|
+
"message": "Hello from FastAPI!",
|
|
28
|
+
"timestamp": datetime.now().isoformat(),
|
|
29
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import Fastify from "fastify";
|
|
2
|
+
import cors from "@fastify/cors";
|
|
3
|
+
|
|
4
|
+
const fastify = Fastify({
|
|
5
|
+
logger: true,
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// Register CORS
|
|
9
|
+
await fastify.register(cors, {
|
|
10
|
+
origin: process.env.CORS_ORIGIN || "*",
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// Health check endpoint
|
|
14
|
+
fastify.get("/health", async () => {
|
|
15
|
+
return { status: "ok" };
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// API routes
|
|
19
|
+
fastify.get("/api/hello", async () => {
|
|
20
|
+
return {
|
|
21
|
+
message: "Hello from Fastify!",
|
|
22
|
+
timestamp: new Date().toISOString(),
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Start server
|
|
27
|
+
const start = async () => {
|
|
28
|
+
try {
|
|
29
|
+
const host = process.env.HOST || "0.0.0.0";
|
|
30
|
+
const port = parseInt(process.env.PORT || "3000", 10);
|
|
31
|
+
await fastify.listen({ port, host });
|
|
32
|
+
console.log(`Server running at http://${host}:${port}`);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
fastify.log.error(err);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
start();
|
package/templates/presets.json
CHANGED
|
@@ -74,29 +74,37 @@
|
|
|
74
74
|
"apis": {
|
|
75
75
|
"fastify": {
|
|
76
76
|
"name": "Fastify (Node.js)",
|
|
77
|
-
"description": "
|
|
77
|
+
"description": "Fast Node.js API framework",
|
|
78
78
|
"subdir": "node-api",
|
|
79
79
|
"runtime": "node",
|
|
80
|
-
"rules": ["typescript", "fastify"
|
|
80
|
+
"rules": ["typescript", "fastify"],
|
|
81
81
|
"configs": ["biome", "tsconfig", "gitignore-node"],
|
|
82
|
-
"dependencies": ["fastify", "@fastify/cors", "@fastify/env", "
|
|
83
|
-
"devDependencies": ["typescript", "@types/node", "tsx", "
|
|
82
|
+
"dependencies": ["fastify", "@fastify/cors", "@fastify/env", "zod"],
|
|
83
|
+
"devDependencies": ["typescript", "@types/node", "tsx", "@biomejs/biome"],
|
|
84
84
|
"scripts": {
|
|
85
85
|
"dev": "tsx watch src/index.ts",
|
|
86
86
|
"build": "tsc",
|
|
87
87
|
"start": "node dist/index.js",
|
|
88
88
|
"lint": "biome check .",
|
|
89
|
-
"format": "biome check --write ."
|
|
90
|
-
"db:generate": "drizzle-kit generate",
|
|
91
|
-
"db:migrate": "drizzle-kit migrate",
|
|
92
|
-
"db:studio": "drizzle-kit studio"
|
|
89
|
+
"format": "biome check --write ."
|
|
93
90
|
},
|
|
94
91
|
"scaffoldFiles": {
|
|
92
|
+
"src/index.ts": "fastify/index-simple.ts"
|
|
93
|
+
},
|
|
94
|
+
"scaffoldFilesWithDb": {
|
|
95
95
|
"src/index.ts": "fastify/index.ts",
|
|
96
96
|
"src/db/index.ts": "drizzle/db-index.ts",
|
|
97
97
|
"src/db/schema.ts": "drizzle/schema.ts",
|
|
98
98
|
"drizzle.config.ts": "drizzle/drizzle.config.ts"
|
|
99
99
|
},
|
|
100
|
+
"dependenciesWithDb": ["drizzle-orm", "postgres"],
|
|
101
|
+
"devDependenciesWithDb": ["drizzle-kit"],
|
|
102
|
+
"scriptsWithDb": {
|
|
103
|
+
"db:generate": "drizzle-kit generate",
|
|
104
|
+
"db:migrate": "drizzle-kit migrate",
|
|
105
|
+
"db:studio": "drizzle-kit studio"
|
|
106
|
+
},
|
|
107
|
+
"rulesWithDb": ["drizzle"],
|
|
100
108
|
"blueprint": {
|
|
101
109
|
"type": "web",
|
|
102
110
|
"runtime": "node",
|
|
@@ -112,19 +120,24 @@
|
|
|
112
120
|
},
|
|
113
121
|
"fastapi": {
|
|
114
122
|
"name": "FastAPI (Python)",
|
|
115
|
-
"description": "
|
|
123
|
+
"description": "Fast Python API framework",
|
|
116
124
|
"subdir": "python-api",
|
|
117
125
|
"runtime": "python",
|
|
118
|
-
"rules": ["python"
|
|
126
|
+
"rules": ["python"],
|
|
119
127
|
"configs": ["ruff", "gitignore-python"],
|
|
120
|
-
"pythonDependencies": ["fastapi", "uvicorn[standard]", "
|
|
128
|
+
"pythonDependencies": ["fastapi", "uvicorn[standard]", "pydantic", "python-dotenv"],
|
|
121
129
|
"scaffoldFiles": {
|
|
130
|
+
"main.py": "fastapi/main-simple.py"
|
|
131
|
+
},
|
|
132
|
+
"scaffoldFilesWithDb": {
|
|
122
133
|
"main.py": "fastapi/main.py",
|
|
123
134
|
"app/__init__.py": "fastapi/app/__init__.py",
|
|
124
135
|
"app/config.py": "fastapi/app/config.py",
|
|
125
136
|
"app/database.py": "fastapi/app/database.py",
|
|
126
137
|
"app/models.py": "fastapi/app/models.py"
|
|
127
138
|
},
|
|
139
|
+
"pythonDependenciesWithDb": ["sqlalchemy", "psycopg2-binary", "pydantic-settings", "alembic"],
|
|
140
|
+
"rulesWithDb": ["sqlalchemy"],
|
|
128
141
|
"blueprint": {
|
|
129
142
|
"type": "web",
|
|
130
143
|
"runtime": "python",
|