New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

render-create

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

render-create - npm Package Compare versions

Comparing version
0.1.0
to
0.2.0
+29
templates/fastapi/main-simple.py
from datetime import datetime
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI(title="API")
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/health")
async def health():
"""Health check endpoint."""
return {"status": "ok"}
@app.get("/api/hello")
async def hello():
"""Hello endpoint."""
return {
"message": "Hello from FastAPI!",
"timestamp": datetime.now().isoformat(),
}
import Fastify from "fastify";
import cors from "@fastify/cors";
const fastify = Fastify({
logger: true,
});
// Register CORS
await fastify.register(cors, {
origin: process.env.CORS_ORIGIN || "*",
});
// Health check endpoint
fastify.get("/health", async () => {
return { status: "ok" };
});
// API routes
fastify.get("/api/hello", async () => {
return {
message: "Hello from Fastify!",
timestamp: new Date().toISOString(),
};
});
// Start server
const start = async () => {
try {
const host = process.env.HOST || "0.0.0.0";
const port = parseInt(process.env.PORT || "3000", 10);
await fastify.listen({ port, host });
console.log(`Server running at http://${host}:${port}`);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();
+115
-43

@@ -424,13 +424,20 @@ /**

*/
async function scaffoldApi(projectDir, _componentId, component, projectName, skipInstall) {
async function scaffoldApi(projectDir, _componentId, component, projectName, skipInstall, hasDatabase) {
const subdir = join(projectDir, component.subdir);
ensureDir(subdir);
console.log(chalk.blue(`\nScaffolding API: ${component.name}...\n`));
// Choose files based on database selection
const scaffoldFiles = hasDatabase && component.scaffoldFilesWithDb
? component.scaffoldFilesWithDb
: component.scaffoldFiles;
if (component.runtime === "python") {
// Python API
const pythonDeps = component.pythonDependencies ?? [];
const pythonDeps = [
...(component.pythonDependencies ?? []),
...(hasDatabase ? (component.pythonDependenciesWithDb ?? []) : []),
];
writeFileSync(join(subdir, "requirements.txt"), `${pythonDeps.join("\n")}\n`);
console.log(chalk.green(` Created requirements.txt`));
if (component.scaffoldFiles) {
copyPostCreateFiles(subdir, component.scaffoldFiles, projectName);
if (scaffoldFiles) {
copyPostCreateFiles(subdir, scaffoldFiles, projectName);
}

@@ -443,2 +450,6 @@ if (!skipInstall) {

// Node API
const scripts = {
...(component.scripts ?? {}),
...(hasDatabase ? (component.scriptsWithDb ?? {}) : {}),
};
const packageJson = {

@@ -449,3 +460,3 @@ name: `${projectName}-${component.subdir}`,

type: "module",
scripts: component.scripts ?? {},
scripts,
dependencies: {},

@@ -456,8 +467,14 @@ devDependencies: {},

console.log(chalk.green(` Created package.json`));
if (component.scaffoldFiles) {
copyPostCreateFiles(subdir, component.scaffoldFiles, projectName);
if (scaffoldFiles) {
copyPostCreateFiles(subdir, scaffoldFiles, projectName);
}
if (!skipInstall) {
const deps = component.dependencies ?? [];
const devDeps = component.devDependencies ?? [];
const deps = [
...(component.dependencies ?? []),
...(hasDatabase ? (component.dependenciesWithDb ?? []) : []),
];
const devDeps = [
...(component.devDependencies ?? []),
...(hasDatabase ? (component.devDependenciesWithDb ?? []) : []),
];
if (deps.length > 0) {

@@ -678,2 +695,3 @@ console.log(chalk.gray(` npm install ${deps.join(" ")}`));

const hasWorkflows = hasWorkflowSelected(selection, components);
const hasDatabase = !!selection.database;
if (selection.frontend) {

@@ -690,2 +708,8 @@ const comp = components.frontends[selection.frontend];

}
// Add database rules (ORM) when database is selected
if (hasDatabase && comp?.rulesWithDb) {
for (const rule of comp.rulesWithDb) {
rules.add(rule);
}
}
// Add workflows rule to APIs when workflows are selected

@@ -762,7 +786,11 @@ if (hasWorkflows) {

2. Install dependencies in each service directory
3. Run \`render blueprint launch\` to deploy to Render
3. Push to GitHub and deploy via the Render Dashboard
## Deploy to Render
This project includes a \`render.yaml\` Blueprint for easy deployment.
This project includes a \`render.yaml\` Blueprint for easy deployment:
1. Push this repo to GitHub
2. Go to [dashboard.render.com/blueprints](https://dashboard.render.com/select-repo?type=blueprint)
3. Connect your repo and deploy
`;

@@ -807,2 +835,3 @@ writeFileSync(join(projectDir, "README.md"), readmeContent);

const hasWorkflows = hasWorkflowSelected(selection, components);
const hasDatabase = !!selection.database;
for (const apiId of selection.apis) {

@@ -823,3 +852,3 @@ const comp = components.apis[apiId];

: comp;
await scaffoldApi(projectDir, apiId, apiComp, selection.projectName, skipInstall);
await scaffoldApi(projectDir, apiId, apiComp, selection.projectName, skipInstall, hasDatabase);
}

@@ -923,3 +952,4 @@ }

console.log(chalk.cyan(` # Start each service in its directory`));
console.log(chalk.cyan(` render blueprint launch # Deploy to Render`));
console.log(chalk.cyan(` git init && git add . && git commit -m "Initial commit"`));
console.log(chalk.cyan(` # Push to GitHub, then deploy at dashboard.render.com/blueprints`));
console.log();

@@ -966,11 +996,2 @@ }

});
questions.push({
type: "checkbox",
name: "extras",
message: "Include extras:",
choices: [
{ name: ".env.example template", value: "env", checked: true },
{ name: "docker-compose.yml", value: "docker", checked: false },
],
});
}

@@ -980,7 +1001,5 @@ const answers = await inquirer.prompt(questions);

selectedPresetId = options.preset ?? answers.preset;
selectedExtras = answers.extras ?? (options.yes ? ["env"] : []);
}
else {
selectedPresetId = options.preset;
selectedExtras = options.yes ? ["env"] : [];
}

@@ -995,2 +1014,20 @@ // Validate preset

}
// Ask for extras for non-custom presets
if (!options.yes) {
const extrasAnswer = await inquirer.prompt([
{
type: "checkbox",
name: "extras",
message: "Include extras (Space to select, Enter to confirm):",
choices: [
{ name: ".env.example template", value: "env", checked: true },
{ name: "docker-compose.yml", value: "docker", checked: false },
],
},
]);
selectedExtras = extrasAnswer.extras;
}
else {
selectedExtras = ["env"];
}
}

@@ -1070,17 +1107,5 @@ // Handle custom/composable preset

}
// Step 3: Rest of the prompts
const restAnswers = await inquirer.prompt([
// Step 3: Database and cache
const { database, cache } = await inquirer.prompt([
{
type: "checkbox",
name: "apis",
message: "Select API backends (optional, press Enter to skip):",
choices: apiChoices,
},
{
type: "checkbox",
name: "workers",
message: "Select background workers (optional, press Enter to skip):",
choices: workerChoices,
},
{
type: "list",

@@ -1097,3 +1122,50 @@ name: "database",

},
]);
// Step 4: API backends (two-step)
const { wantApi } = await inquirer.prompt([
{
type: "confirm",
name: "wantApi",
message: "Add API backend?",
default: true,
},
]);
let selectedApis = [];
if (wantApi) {
const { apis } = await inquirer.prompt([
{
type: "checkbox",
name: "apis",
message: "Select API backends:",
choices: apiChoices,
validate: (input) => input.length > 0 || "Please select at least one API",
},
]);
selectedApis = apis;
}
// Step 5: Background workers (two-step)
const { wantWorker } = await inquirer.prompt([
{
type: "confirm",
name: "wantWorker",
message: "Add background worker?",
default: true,
},
]);
let selectedWorkers = [];
if (wantWorker) {
const { workers } = await inquirer.prompt([
{
type: "checkbox",
name: "workers",
message: "Select background workers:",
choices: workerChoices,
validate: (input) => input.length > 0 || "Please select at least one worker",
},
]);
selectedWorkers = workers;
}
// Step 6: Extras
const { extras } = await inquirer.prompt([
{
type: "checkbox",

@@ -1112,7 +1184,7 @@ name: "extras",

frontendDeployType,
apis: restAnswers.apis,
workers: restAnswers.workers,
database: restAnswers.database === "none" ? null : restAnswers.database,
cache: restAnswers.cache === "none" ? null : restAnswers.cache,
extras: restAnswers.extras,
apis: selectedApis,
workers: selectedWorkers,
database: database === "none" ? null : database,
cache: cache === "none" ? null : cache,
extras,
};

@@ -1119,0 +1191,0 @@ // Scaffold the composable project

@@ -158,2 +158,12 @@ /**

scaffoldFiles: Record<string, string>;
/** Additional files when database is selected */
scaffoldFilesWithDb?: Record<string, string>;
/** Additional dependencies when database is selected */
dependenciesWithDb?: string[];
devDependenciesWithDb?: string[];
pythonDependenciesWithDb?: string[];
/** Additional scripts when database is selected */
scriptsWithDb?: Record<string, string>;
/** Additional rules when database is selected */
rulesWithDb?: string[];
blueprint: {

@@ -160,0 +170,0 @@ type: "web";

{
"name": "render-create",
"version": "0.1.0",
"version": "0.2.0",
"description": "CLI to scaffold and deploy applications on Render with best practices, Cursor rules, and Infrastructure as Code",

@@ -33,3 +33,4 @@ "type": "module",

"release:minor": "npm version minor",
"release:major": "npm version major"
"release:major": "npm version major",
"publish:npm": "npm publish --access public"
},

@@ -36,0 +37,0 @@ "keywords": [

@@ -77,9 +77,9 @@ {

"name": "Fastify (Node.js)",
"description": "Fastify + Drizzle + Zod",
"description": "Fast Node.js API framework",
"subdir": "node-api",
"runtime": "node",
"rules": ["typescript", "fastify", "drizzle"],
"rules": ["typescript", "fastify"],
"configs": ["biome", "tsconfig", "gitignore-node"],
"dependencies": ["fastify", "@fastify/cors", "@fastify/env", "drizzle-orm", "zod", "postgres"],
"devDependencies": ["typescript", "@types/node", "tsx", "drizzle-kit", "@biomejs/biome"],
"dependencies": ["fastify", "@fastify/cors", "@fastify/env", "zod"],
"devDependencies": ["typescript", "@types/node", "tsx", "@biomejs/biome"],
"scripts": {

@@ -90,8 +90,8 @@ "dev": "tsx watch src/index.ts",

"lint": "biome check .",
"format": "biome check --write .",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:studio": "drizzle-kit studio"
"format": "biome check --write ."
},
"scaffoldFiles": {
"src/index.ts": "fastify/index-simple.ts"
},
"scaffoldFilesWithDb": {
"src/index.ts": "fastify/index.ts",

@@ -102,2 +102,10 @@ "src/db/index.ts": "drizzle/db-index.ts",

},
"dependenciesWithDb": ["drizzle-orm", "postgres"],
"devDependenciesWithDb": ["drizzle-kit"],
"scriptsWithDb": {
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:studio": "drizzle-kit studio"
},
"rulesWithDb": ["drizzle"],
"blueprint": {

@@ -118,9 +126,12 @@ "type": "web",

"name": "FastAPI (Python)",
"description": "FastAPI + SQLAlchemy + Pydantic",
"description": "Fast Python API framework",
"subdir": "python-api",
"runtime": "python",
"rules": ["python", "sqlalchemy"],
"rules": ["python"],
"configs": ["ruff", "gitignore-python"],
"pythonDependencies": ["fastapi", "uvicorn[standard]", "sqlalchemy", "psycopg2-binary", "pydantic", "pydantic-settings", "python-dotenv", "alembic"],
"pythonDependencies": ["fastapi", "uvicorn[standard]", "pydantic", "python-dotenv"],
"scaffoldFiles": {
"main.py": "fastapi/main-simple.py"
},
"scaffoldFilesWithDb": {
"main.py": "fastapi/main.py",

@@ -132,2 +143,4 @@ "app/__init__.py": "fastapi/app/__init__.py",

},
"pythonDependenciesWithDb": ["sqlalchemy", "psycopg2-binary", "pydantic-settings", "alembic"],
"rulesWithDb": ["sqlalchemy"],
"blueprint": {

@@ -134,0 +147,0 @@ "type": "web",