deploy-bbc 1.2.3 → 1.3.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/README.md +49 -4
- package/dist/index.js +132 -72
- package/dist/templates/base/.env.example +1 -1
- package/dist/templates/base/package.json +2 -1
- package/dist/templates/base/src/config/index.ts +1 -1
- package/dist/templates/base/src/controllers/user/create-user.controller.ts +84 -0
- package/dist/templates/base/src/controllers/user/delete-user.controller.ts +60 -0
- package/dist/templates/base/src/controllers/user/get-user.controller.ts +74 -0
- package/dist/templates/base/src/controllers/user/get-users.controller.ts +41 -0
- package/dist/templates/base/src/controllers/user/update-user.controller.ts +111 -0
- package/dist/templates/base/src/models/user.model.ts +83 -0
- package/dist/templates/base/src/routes/index.ts +5 -0
- package/dist/templates/base/src/routes/user.route.ts +17 -0
- package/dist/templates/base/src/types/common/api-response.types.ts +30 -0
- package/dist/templates/base/src/types/index.ts +5 -2
- package/dist/templates/base/src/types/models/user.types.ts +26 -0
- package/dist/templates/base-bun-native/.env.example +1 -1
- package/dist/templates/base-bun-native/package.json +2 -1
- package/dist/templates/base-bun-native/src/config/index.ts +1 -1
- package/dist/templates/base-bun-native/src/controllers/user/create-user.controller.ts +76 -0
- package/dist/templates/base-bun-native/src/controllers/user/delete-user.controller.ts +53 -0
- package/dist/templates/base-bun-native/src/controllers/user/get-user.controller.ts +67 -0
- package/dist/templates/base-bun-native/src/controllers/user/get-users.controller.ts +40 -0
- package/dist/templates/base-bun-native/src/controllers/user/update-user.controller.ts +101 -0
- package/dist/templates/base-bun-native/src/index.ts +3 -3
- package/dist/templates/base-bun-native/src/models/user.model.ts +83 -0
- package/dist/templates/base-bun-native/src/routes/index.ts +10 -6
- package/dist/templates/base-bun-native/src/routes/user.route.ts +50 -0
- package/dist/templates/base-bun-native/src/types/common/api-response.types.ts +30 -0
- package/dist/templates/base-bun-native/src/types/index.ts +5 -2
- package/dist/templates/base-bun-native/src/types/models/user.types.ts +26 -0
- package/dist/templates/base-express/.env.example +1 -1
- package/dist/templates/base-express/package.json +2 -1
- package/dist/templates/base-express/src/config/index.ts +1 -1
- package/dist/templates/base-express/src/controllers/user/create-user.controller.ts +75 -0
- package/dist/templates/base-express/src/controllers/user/delete-user.controller.ts +56 -0
- package/dist/templates/base-express/src/controllers/user/get-user.controller.ts +70 -0
- package/dist/templates/base-express/src/controllers/user/get-users.controller.ts +41 -0
- package/dist/templates/base-express/src/controllers/user/update-user.controller.ts +102 -0
- package/dist/templates/base-express/src/models/user.model.ts +83 -0
- package/dist/templates/base-express/src/routes/index.ts +5 -0
- package/dist/templates/base-express/src/routes/user.route.ts +17 -0
- package/dist/templates/base-express/src/types/common/api-response.types.ts +30 -0
- package/dist/templates/base-express/src/types/index.ts +5 -2
- package/dist/templates/base-express/src/types/models/user.types.ts +26 -0
- package/dist/templates/extras/database/mongodb/src/db/index.ts +70 -0
- package/dist/templates/extras/database/mongodb/src/db/models/user.model.ts +87 -0
- package/dist/templates/extras/database/mysql/src/db/index.ts +106 -0
- package/dist/templates/extras/database/postgres/src/db/index.ts +96 -0
- package/dist/templates/extras/database/redis/src/db/redis.ts +215 -0
- package/dist/templates/extras/database/sqlite/src/db/index.ts +185 -0
- package/dist/templates/templates/base/.dockerignore +45 -0
- package/dist/templates/templates/base/src/models/user.model.ts +1 -1
- package/dist/templates/templates/base-bun-native/.dockerignore +45 -0
- package/dist/templates/templates/base-bun-native/src/models/user.model.ts +1 -1
- package/dist/templates/templates/base-express/.dockerignore +45 -0
- package/dist/templates/templates/base-express/src/models/user.model.ts +1 -1
- package/dist/templates/templates/extras/database/mongodb/src/db/index.ts +70 -0
- package/dist/templates/templates/extras/database/mongodb/src/db/models/user.model.ts +87 -0
- package/dist/templates/templates/extras/database/mysql/src/db/index.ts +106 -0
- package/dist/templates/templates/extras/database/postgres/src/db/index.ts +96 -0
- package/dist/templates/templates/extras/database/redis/src/db/redis.ts +215 -0
- package/dist/templates/templates/extras/database/sqlite/src/db/index.ts +185 -0
- package/package.json +1 -1
- package/dist/templates/extras/database/mysql/drizzle.config.ts +0 -0
- package/dist/templates/templates/extras/database/mysql/drizzle.config.ts +0 -0
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ It ships with production-ready defaults, optional integrations, Docker support,
|
|
|
39
39
|
- 🚀 **Production-ready templates** with best practices
|
|
40
40
|
- 🔌 **30+ integrations** (databases, auth, AI, cloud, infra)
|
|
41
41
|
- 🛡️ **Fully type-safe** with strict TypeScript
|
|
42
|
-
- 🐳 **
|
|
42
|
+
- 🐳 **Optional Docker support** for databases and/or backend
|
|
43
43
|
- 💎 **Strong developer experience** with testing and docs
|
|
44
44
|
- ⚙️ **Zero-config defaults** that work out of the box
|
|
45
45
|
|
|
@@ -78,8 +78,9 @@ bunx deploy-bbc my-backend
|
|
|
78
78
|
<img height="40" src="https://cdn.brandfetch.io/idwlYcQpHB/theme/dark/symbol.svg?c=1bxid64Mup7aczewSAYMX&t=1668515608635" alt="Redis" />
|
|
79
79
|
</p>
|
|
80
80
|
|
|
81
|
-
- **PostgreSQL** with
|
|
82
|
-
- **MySQL** with
|
|
81
|
+
- **PostgreSQL** with native postgres driver
|
|
82
|
+
- **MySQL** with mysql2 driver (Bun-optimized)
|
|
83
|
+
- **SQLite** with bun:sqlite (built-in, zero dependencies)
|
|
83
84
|
- **MongoDB** with Mongoose
|
|
84
85
|
- **Redis** for caching and queues
|
|
85
86
|
|
|
@@ -179,11 +180,55 @@ src/
|
|
|
179
180
|
|
|
180
181
|
## Docker Support
|
|
181
182
|
|
|
183
|
+
The CLI provides flexible Docker configuration options:
|
|
184
|
+
|
|
185
|
+
### Options
|
|
186
|
+
|
|
187
|
+
During setup, you'll be asked:
|
|
188
|
+
|
|
189
|
+
1. **Dockerize databases?** - Generates docker-compose services for:
|
|
190
|
+
- PostgreSQL
|
|
191
|
+
- MySQL
|
|
192
|
+
- MongoDB
|
|
193
|
+
- Redis
|
|
194
|
+
|
|
195
|
+
2. **Dockerize the backend?** - Creates:
|
|
196
|
+
- Multi-stage Dockerfile optimized for Bun
|
|
197
|
+
- App service in docker-compose.yml
|
|
198
|
+
|
|
199
|
+
### Usage
|
|
200
|
+
|
|
201
|
+
If you selected to dockerize your databases:
|
|
202
|
+
|
|
182
203
|
```bash
|
|
204
|
+
# Start only databases
|
|
205
|
+
docker-compose up postgres redis -d
|
|
206
|
+
|
|
207
|
+
# Run your app locally
|
|
208
|
+
bun run dev
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
If you dockerized both databases and backend:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Start everything
|
|
183
215
|
docker-compose up
|
|
216
|
+
|
|
217
|
+
# Or in detached mode
|
|
218
|
+
docker-compose up -d
|
|
184
219
|
```
|
|
185
220
|
|
|
186
|
-
|
|
221
|
+
### SQLite with Docker
|
|
222
|
+
|
|
223
|
+
When using SQLite with a dockerized backend, your database file is automatically mounted as a volume to persist data between container restarts.
|
|
224
|
+
|
|
225
|
+
### CLI Flags
|
|
226
|
+
|
|
227
|
+
You can also use CLI flags for non-interactive setup:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
npx deploy-bbc my-api --dockerizeDb --dockerizeBackend
|
|
231
|
+
```
|
|
187
232
|
|
|
188
233
|
---
|
|
189
234
|
|
package/dist/index.js
CHANGED
|
@@ -5934,39 +5934,58 @@ var defaultOptions = {
|
|
|
5934
5934
|
CI: false
|
|
5935
5935
|
};
|
|
5936
5936
|
var run_cli = async () => {
|
|
5937
|
-
const program2 = new Command().name("deploy-bbc").description("Bootstrap a production-ready backend with Bun").argument("[dir]", "The name of the application").option("--noGit", "Skip git initialization", defaultOptions.noGit).option("--noInstall", "Skip dependency installation", defaultOptions.noInstall).option("--default", "Use default options", defaultOptions.default).option("--CI", "Run in CI mode (non-interactive)", defaultOptions.CI).option("--hono", "Use Hono framework (default)").option("--express", "Use Express framework").option("--bun-native", "Use Bun native HTTP server").option("--postgres", "Include PostgreSQL").option("--mysql", "Include MySQL").option("--mongodb", "Include MongoDB").option("--redis", "Include Redis").option("--jwt", "Include JWT authentication").option("--oauth", "Include OAuth 2.0").option("--session", "Include session-based auth").option("--openai", "Include OpenAI SDK").option("--anthropic", "Include Anthropic Claude SDK").option("--gemini", "Include Google Gemini SDK").option("--vercelAI", "Include Vercel AI SDK").option("--aws", "Include AWS SDK").option("--gcp", "Include Google Cloud SDK").option("--azure", "Include Azure SDK").option("--cloudflareR2", "Include Cloudflare R2").option("--resend", "Include Resend email service").option("--sendgrid", "Include SendGrid").option("--nodemailer", "Include NodeMailer").option("--socketio", "Include Socket.io").option("--sse", "Include Server-Sent Events").option("--bullmq", "Include BullMQ").option("--inngest", "Include Inngest").option("--upstashRateLimit", "Include Upstash Rate Limit").option("--customRateLimit", "Include custom rate limiting").option("--sentry", "Include Sentry").option("--logtail", "Include LogTail").option("--swagger", "Include Swagger/OpenAPI").option("--scalar", "Include Scalar API docs").option("--vitest", "Include Vitest testing").option("--zod", "Include Zod validation").option("--yup", "Include Yup validation").parse(process.argv);
|
|
5937
|
+
const program2 = new Command().name("deploy-bbc").description("Bootstrap a production-ready backend with Bun").argument("[dir]", "The name of the application").option("--noGit", "Skip git initialization", defaultOptions.noGit).option("--noInstall", "Skip dependency installation", defaultOptions.noInstall).option("--default", "Use default options", defaultOptions.default).option("--CI", "Run in CI mode (non-interactive)", defaultOptions.CI).option("--hono", "Use Hono framework (default)").option("--express", "Use Express framework").option("--bun-native", "Use Bun native HTTP server").option("--postgres", "Include PostgreSQL").option("--mysql", "Include MySQL").option("--sqlite", "Include SQLite").option("--mongodb", "Include MongoDB").option("--redis", "Include Redis").option("--jwt", "Include JWT authentication").option("--oauth", "Include OAuth 2.0").option("--session", "Include session-based auth").option("--openai", "Include OpenAI SDK").option("--anthropic", "Include Anthropic Claude SDK").option("--gemini", "Include Google Gemini SDK").option("--vercelAI", "Include Vercel AI SDK").option("--aws", "Include AWS SDK").option("--gcp", "Include Google Cloud SDK").option("--azure", "Include Azure SDK").option("--cloudflareR2", "Include Cloudflare R2").option("--resend", "Include Resend email service").option("--sendgrid", "Include SendGrid").option("--nodemailer", "Include NodeMailer").option("--socketio", "Include Socket.io").option("--sse", "Include Server-Sent Events").option("--bullmq", "Include BullMQ").option("--inngest", "Include Inngest").option("--upstashRateLimit", "Include Upstash Rate Limit").option("--customRateLimit", "Include custom rate limiting").option("--sentry", "Include Sentry").option("--logtail", "Include LogTail").option("--swagger", "Include Swagger/OpenAPI").option("--scalar", "Include Scalar API docs").option("--vitest", "Include Vitest testing").option("--zod", "Include Zod validation").option("--yup", "Include Yup validation").option("--dockerizeDb", "Dockerize databases (PostgreSQL, MySQL, Redis, MongoDB)").option("--dockerizeBackend", "Dockerize the backend application").parse(process.argv);
|
|
5938
5938
|
const cliProvidedName = program2.args[0];
|
|
5939
5939
|
const cliOptions = program2.opts();
|
|
5940
5940
|
if (cliOptions.CI) {
|
|
5941
5941
|
return build_from_flags(cliProvidedName, cliOptions);
|
|
5942
5942
|
}
|
|
5943
|
+
const blue = "\x1B[38;5;75m";
|
|
5944
|
+
const gray = "\x1B[90m";
|
|
5945
|
+
const reset = "\x1B[0m";
|
|
5943
5946
|
const intro = `
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5947
|
+
${gray}____________________________________________________________________${reset}
|
|
5948
|
+
${gray}/ \\${reset}
|
|
5949
|
+
${gray}|${reset} ${blue}█▀▀▄ █▀▀ █▀▀█ █ █▀▀█ █ █ █▀▀▄ █▀▀▄ █▀▀${reset} ${gray}|${reset}
|
|
5950
|
+
${gray}|${reset} ${blue}█ █ █▀▀ █ █ █ █ █ █▄▄█ █▀▀▄ █▀▀▄ █${reset} ${gray}|${reset}
|
|
5951
|
+
${gray}|${reset} ${blue}█▄▄▀ ▀▀▀ █▀▀▀ ▀▀▀ ▀▀▀▀ ▄▄▄█ █▄▄▀ █▄▄▀ ▀▀▀${reset} ${gray}|${reset}
|
|
5952
|
+
${gray}|${reset} ${gray}|${reset}
|
|
5953
|
+
${gray}|${reset} \uD83D\uDE80 ${blue}Best Backend Code${reset} ${gray}|${reset}
|
|
5954
|
+
${gray}|${reset} ${gray}|${reset}
|
|
5955
|
+
${gray}|${reset} ${gray}Backend so good, it hurts${reset} ${gray}|${reset}
|
|
5956
|
+
${gray}|${reset} ${gray}[ Bun ] ---------- [ TypeScript ] ---------- [ Docker ]${reset} ${gray}|${reset}
|
|
5957
|
+
${gray}\\____________________________________________________________________/${reset}
|
|
5953
5958
|
`;
|
|
5954
|
-
console.log(
|
|
5959
|
+
console.log(intro);
|
|
5955
5960
|
Ie(source_default.bgCyan(source_default.black(" deploy-bbc ")));
|
|
5956
5961
|
const project = await Ce({
|
|
5957
5962
|
...add_cli_header("\uD83D\uDCE6 CORE"),
|
|
5958
5963
|
projectName: () => he({
|
|
5959
5964
|
message: "What will your project be called?",
|
|
5960
|
-
placeholder: "my-awesome-api (
|
|
5965
|
+
placeholder: "my-awesome-api (use '.' for current dir if empty)",
|
|
5961
5966
|
defaultValue: cliProvidedName || "my-backend",
|
|
5962
5967
|
validate: (value) => {
|
|
5963
5968
|
if (!value)
|
|
5964
5969
|
return "Please enter a project name";
|
|
5965
|
-
if (
|
|
5966
|
-
return;
|
|
5970
|
+
if (!/^[a-z0-9-_/.]+$/i.test(value)) {
|
|
5971
|
+
return "Only letters, numbers, dashes, underscores, and slashes allowed";
|
|
5972
|
+
}
|
|
5973
|
+
if (value === ".") {
|
|
5974
|
+
const fs = __require("fs");
|
|
5975
|
+
const path = __require("path");
|
|
5976
|
+
const cwd = process.cwd();
|
|
5977
|
+
const conflictingPaths = ["src", "package.json"];
|
|
5978
|
+
const conflicts = [];
|
|
5979
|
+
for (const pathToCheck of conflictingPaths) {
|
|
5980
|
+
if (fs.existsSync(path.join(cwd, pathToCheck))) {
|
|
5981
|
+
conflicts.push(pathToCheck);
|
|
5982
|
+
}
|
|
5983
|
+
}
|
|
5984
|
+
if (conflicts.length > 0) {
|
|
5985
|
+
return `Current directory already contains: ${conflicts.join(", ")}. Please use a new directory name or run from an empty directory.`;
|
|
5986
|
+
}
|
|
5967
5987
|
}
|
|
5968
|
-
|
|
5969
|
-
return "Only letters, numbers, dashes, underscores, and slashes";
|
|
5988
|
+
return;
|
|
5970
5989
|
}
|
|
5971
5990
|
}),
|
|
5972
5991
|
framework: () => ve({
|
|
@@ -5996,12 +6015,17 @@ var run_cli = async () => {
|
|
|
5996
6015
|
{
|
|
5997
6016
|
value: "postgres" /* postgres */,
|
|
5998
6017
|
label: "PostgreSQL",
|
|
5999
|
-
hint: "Dockerized •
|
|
6018
|
+
hint: "Dockerized • Native postgres driver"
|
|
6000
6019
|
},
|
|
6001
6020
|
{
|
|
6002
6021
|
value: "mysql" /* mysql */,
|
|
6003
6022
|
label: "MySQL",
|
|
6004
|
-
hint: "Dockerized •
|
|
6023
|
+
hint: "Dockerized • mysql2 driver"
|
|
6024
|
+
},
|
|
6025
|
+
{
|
|
6026
|
+
value: "sqlite" /* sqlite */,
|
|
6027
|
+
label: "SQLite",
|
|
6028
|
+
hint: "File-based • bun:sqlite (built-in)"
|
|
6005
6029
|
},
|
|
6006
6030
|
{
|
|
6007
6031
|
value: "mongodb" /* mongodb */,
|
|
@@ -6166,6 +6190,20 @@ var run_cli = async () => {
|
|
|
6166
6190
|
],
|
|
6167
6191
|
initialValue: "zod" /* zod */
|
|
6168
6192
|
}),
|
|
6193
|
+
...add_cli_header("\uD83D\uDC33 DOCKER"),
|
|
6194
|
+
dockerizeDb: ({ results }) => {
|
|
6195
|
+
const hasDatabases = results.databases && results.databases.length > 0;
|
|
6196
|
+
if (!hasDatabases)
|
|
6197
|
+
return Promise.resolve(false);
|
|
6198
|
+
return ye({
|
|
6199
|
+
message: "Dockerize databases? (PostgreSQL, MySQL, Redis, MongoDB)",
|
|
6200
|
+
initialValue: true
|
|
6201
|
+
});
|
|
6202
|
+
},
|
|
6203
|
+
dockerizeBackend: () => ye({
|
|
6204
|
+
message: "Dockerize the backend application?",
|
|
6205
|
+
initialValue: true
|
|
6206
|
+
}),
|
|
6169
6207
|
installDeps: () => ye({
|
|
6170
6208
|
message: "Install dependencies?",
|
|
6171
6209
|
initialValue: !cliOptions.noInstall
|
|
@@ -6200,7 +6238,9 @@ var run_cli = async () => {
|
|
|
6200
6238
|
flags: {
|
|
6201
6239
|
...defaultOptions,
|
|
6202
6240
|
noInstall: !project.installDeps,
|
|
6203
|
-
noGit: !project.initGit
|
|
6241
|
+
noGit: !project.initGit,
|
|
6242
|
+
dockerizeDb: project.dockerizeDb,
|
|
6243
|
+
dockerizeBackend: project.dockerizeBackend
|
|
6204
6244
|
}
|
|
6205
6245
|
};
|
|
6206
6246
|
};
|
|
@@ -6224,6 +6264,8 @@ function build_from_flags(appName, flags) {
|
|
|
6224
6264
|
packages.push("postgres" /* postgres */);
|
|
6225
6265
|
if (flags.mysql)
|
|
6226
6266
|
packages.push("mysql" /* mysql */);
|
|
6267
|
+
if (flags.sqlite)
|
|
6268
|
+
packages.push("sqlite" /* sqlite */);
|
|
6227
6269
|
if (flags.mongodb)
|
|
6228
6270
|
packages.push("mongodb" /* mongodb */);
|
|
6229
6271
|
if (flags.redis)
|
|
@@ -9050,8 +9092,14 @@ async function scaffold_project(options) {
|
|
|
9050
9092
|
}
|
|
9051
9093
|
if (conflicts.length > 0) {
|
|
9052
9094
|
spinner.fail("Cannot scaffold in current directory");
|
|
9053
|
-
throw new Error(`
|
|
9054
|
-
|
|
9095
|
+
throw new Error(`Current directory already contains: ${conflicts.join(", ")}
|
|
9096
|
+
|
|
9097
|
+
` + `To fix this:
|
|
9098
|
+
` + ` 1. Create a new directory: mkdir my-project && cd my-project
|
|
9099
|
+
` + ` 2. Or run from a parent directory and specify a new project name
|
|
9100
|
+
` + ` 3. Or use an empty directory
|
|
9101
|
+
|
|
9102
|
+
` + "Example: npx deploy-bbc (then enter a new project name like 'my-api')");
|
|
9055
9103
|
}
|
|
9056
9104
|
}
|
|
9057
9105
|
await import_fs_extra.default.ensureDir(projectDir);
|
|
@@ -9120,9 +9168,6 @@ var DEPENDENCY_VERSION_MAP = {
|
|
|
9120
9168
|
mysql2: "^3.9.0",
|
|
9121
9169
|
mongoose: "^8.1.0",
|
|
9122
9170
|
redis: "^4.6.12",
|
|
9123
|
-
"drizzle-orm": "^0.29.3",
|
|
9124
|
-
"drizzle-kit": "^0.20.10",
|
|
9125
|
-
kysely: "^0.27.2",
|
|
9126
9171
|
jsonwebtoken: "^9.0.2",
|
|
9127
9172
|
"@types/jsonwebtoken": "^9.0.5",
|
|
9128
9173
|
bcryptjs: "^2.4.3",
|
|
@@ -9180,6 +9225,9 @@ async function database_installer(options) {
|
|
|
9180
9225
|
case "mysql" /* mysql */:
|
|
9181
9226
|
await install_mysql(projectDir);
|
|
9182
9227
|
break;
|
|
9228
|
+
case "sqlite" /* sqlite */:
|
|
9229
|
+
await install_sqlite(projectDir);
|
|
9230
|
+
break;
|
|
9183
9231
|
case "mongodb" /* mongodb */:
|
|
9184
9232
|
await install_mongodb(projectDir);
|
|
9185
9233
|
break;
|
|
@@ -9193,33 +9241,40 @@ async function install_postgres(projectDir) {
|
|
|
9193
9241
|
const templateDir = path4.resolve(__dirname3, "templates/extras/database/postgres");
|
|
9194
9242
|
await copy_template_files(templateDir, projectDir);
|
|
9195
9243
|
await add_package_dependency(projectDir, {
|
|
9196
|
-
postgres: DEPENDENCY_VERSION_MAP["postgres"]
|
|
9197
|
-
"drizzle-orm": DEPENDENCY_VERSION_MAP["drizzle-orm"]
|
|
9198
|
-
});
|
|
9199
|
-
await add_package_dependency(projectDir, {}, {
|
|
9200
|
-
"drizzle-kit": DEPENDENCY_VERSION_MAP["drizzle-kit"]
|
|
9244
|
+
postgres: DEPENDENCY_VERSION_MAP["postgres"]
|
|
9201
9245
|
});
|
|
9202
9246
|
await append_env_example(projectDir, `
|
|
9203
9247
|
# PostgreSQL Configuration
|
|
9204
9248
|
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
|
|
9205
9249
|
`);
|
|
9206
|
-
await add_db_scripts(projectDir, "postgres");
|
|
9207
9250
|
}
|
|
9208
9251
|
async function install_mysql(projectDir) {
|
|
9209
9252
|
const templateDir = path4.resolve(__dirname3, "templates/extras/database/mysql");
|
|
9210
9253
|
await copy_template_files(templateDir, projectDir);
|
|
9211
9254
|
await add_package_dependency(projectDir, {
|
|
9212
|
-
mysql2: DEPENDENCY_VERSION_MAP["mysql2"]
|
|
9213
|
-
"drizzle-orm": DEPENDENCY_VERSION_MAP["drizzle-orm"]
|
|
9214
|
-
});
|
|
9215
|
-
await add_package_dependency(projectDir, {}, {
|
|
9216
|
-
"drizzle-kit": DEPENDENCY_VERSION_MAP["drizzle-kit"]
|
|
9255
|
+
mysql2: DEPENDENCY_VERSION_MAP["mysql2"]
|
|
9217
9256
|
});
|
|
9218
9257
|
await append_env_example(projectDir, `
|
|
9219
9258
|
# MySQL Configuration
|
|
9220
9259
|
DATABASE_URL=mysql://user:password@localhost:3306/dbname
|
|
9221
9260
|
`);
|
|
9222
|
-
|
|
9261
|
+
}
|
|
9262
|
+
async function install_sqlite(projectDir) {
|
|
9263
|
+
const templateDir = path4.resolve(__dirname3, "templates/extras/database/sqlite");
|
|
9264
|
+
await copy_template_files(templateDir, projectDir);
|
|
9265
|
+
await append_env_example(projectDir, `
|
|
9266
|
+
# SQLite Configuration
|
|
9267
|
+
DATABASE_PATH=./data/app.db
|
|
9268
|
+
`);
|
|
9269
|
+
await import_fs_extra3.default.ensureDir(path4.join(projectDir, "data"));
|
|
9270
|
+
const gitignorePath = path4.join(projectDir, ".gitignore");
|
|
9271
|
+
const gitignoreContent = await import_fs_extra3.default.readFile(gitignorePath, "utf-8");
|
|
9272
|
+
if (!gitignoreContent.includes("data/")) {
|
|
9273
|
+
await import_fs_extra3.default.appendFile(gitignorePath, `
|
|
9274
|
+
# SQLite database
|
|
9275
|
+
data/
|
|
9276
|
+
`);
|
|
9277
|
+
}
|
|
9223
9278
|
}
|
|
9224
9279
|
async function install_mongodb(projectDir) {
|
|
9225
9280
|
const templateDir = path4.resolve(__dirname3, "templates/extras/database/mongodb");
|
|
@@ -9271,17 +9326,6 @@ async function append_env_example(projectDir, content) {
|
|
|
9271
9326
|
const envPath = path4.join(projectDir, ".env.example");
|
|
9272
9327
|
await import_fs_extra3.default.appendFile(envPath, content);
|
|
9273
9328
|
}
|
|
9274
|
-
async function add_db_scripts(projectDir, dbType) {
|
|
9275
|
-
const packageJsonPath = path4.join(projectDir, "package.json");
|
|
9276
|
-
const packageJson = await import_fs_extra3.default.readJson(packageJsonPath);
|
|
9277
|
-
packageJson.scripts = {
|
|
9278
|
-
...packageJson.scripts,
|
|
9279
|
-
"db:generate": "drizzle-kit generate",
|
|
9280
|
-
"db:migrate": "drizzle-kit migrate",
|
|
9281
|
-
"db:studio": "drizzle-kit studio"
|
|
9282
|
-
};
|
|
9283
|
-
await import_fs_extra3.default.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
9284
|
-
}
|
|
9285
9329
|
|
|
9286
9330
|
// src/installers/auth.ts
|
|
9287
9331
|
var import_fs_extra4 = __toESM(require_lib(), 1);
|
|
@@ -10182,19 +10226,21 @@ CMD ["bun", "run", "src/index.ts"]
|
|
|
10182
10226
|
var import_fs_extra17 = __toESM(require_lib(), 1);
|
|
10183
10227
|
import path18 from "path";
|
|
10184
10228
|
async function generate_docker_compose(options) {
|
|
10185
|
-
const { projectDir, packages, appName } = options;
|
|
10186
|
-
const hasPostgres = packages.includes("postgres" /* postgres */);
|
|
10187
|
-
const hasMysql = packages.includes("mysql" /* mysql */);
|
|
10188
|
-
const
|
|
10189
|
-
const
|
|
10190
|
-
|
|
10229
|
+
const { projectDir, packages, appName, dockerizeDb, dockerizeBackend } = options;
|
|
10230
|
+
const hasPostgres = dockerizeDb && packages.includes("postgres" /* postgres */);
|
|
10231
|
+
const hasMysql = dockerizeDb && packages.includes("mysql" /* mysql */);
|
|
10232
|
+
const hasSqlite = dockerizeDb && packages.includes("sqlite" /* sqlite */);
|
|
10233
|
+
const hasMongodb = dockerizeDb && packages.includes("mongodb" /* mongodb */);
|
|
10234
|
+
const hasRedis = dockerizeDb && packages.includes("redis" /* redis */);
|
|
10235
|
+
if (!dockerizeBackend && !hasPostgres && !hasMysql && !hasSqlite && !hasMongodb && !hasRedis) {
|
|
10191
10236
|
return;
|
|
10192
10237
|
}
|
|
10193
10238
|
let composeContent = `version: '3.8'
|
|
10194
10239
|
|
|
10195
10240
|
services:
|
|
10196
10241
|
`;
|
|
10197
|
-
|
|
10242
|
+
if (dockerizeBackend) {
|
|
10243
|
+
composeContent += ` app:
|
|
10198
10244
|
build: .
|
|
10199
10245
|
ports:
|
|
10200
10246
|
- "8000:8000"
|
|
@@ -10203,22 +10249,28 @@ services:
|
|
|
10203
10249
|
env_file:
|
|
10204
10250
|
- .env
|
|
10205
10251
|
`;
|
|
10206
|
-
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
if (hasMysql)
|
|
10210
|
-
dependencies.push("mysql");
|
|
10211
|
-
if (hasMongodb)
|
|
10212
|
-
dependencies.push("mongodb");
|
|
10213
|
-
if (hasRedis)
|
|
10214
|
-
dependencies.push("redis");
|
|
10215
|
-
if (dependencies.length > 0) {
|
|
10216
|
-
composeContent += ` depends_on:
|
|
10252
|
+
if (hasSqlite) {
|
|
10253
|
+
composeContent += ` volumes:
|
|
10254
|
+
- ./data:/app/data
|
|
10217
10255
|
`;
|
|
10218
|
-
|
|
10219
|
-
|
|
10256
|
+
}
|
|
10257
|
+
const dependencies = [];
|
|
10258
|
+
if (hasPostgres)
|
|
10259
|
+
dependencies.push("postgres");
|
|
10260
|
+
if (hasMysql)
|
|
10261
|
+
dependencies.push("mysql");
|
|
10262
|
+
if (hasMongodb)
|
|
10263
|
+
dependencies.push("mongodb");
|
|
10264
|
+
if (hasRedis)
|
|
10265
|
+
dependencies.push("redis");
|
|
10266
|
+
if (dependencies.length > 0) {
|
|
10267
|
+
composeContent += ` depends_on:
|
|
10220
10268
|
`;
|
|
10221
|
-
|
|
10269
|
+
dependencies.forEach((dep) => {
|
|
10270
|
+
composeContent += ` - ${dep}
|
|
10271
|
+
`;
|
|
10272
|
+
});
|
|
10273
|
+
}
|
|
10222
10274
|
}
|
|
10223
10275
|
if (hasPostgres) {
|
|
10224
10276
|
composeContent += `
|
|
@@ -16809,16 +16861,24 @@ async function create_project(cliResults) {
|
|
|
16809
16861
|
appName: projectName,
|
|
16810
16862
|
framework: cliResults.framework,
|
|
16811
16863
|
packages: cliResults.packages,
|
|
16812
|
-
noInstall: cliResults.flags.noInstall
|
|
16864
|
+
noInstall: cliResults.flags.noInstall,
|
|
16865
|
+
dockerizeDb: cliResults.flags.dockerizeDb || false,
|
|
16866
|
+
dockerizeBackend: cliResults.flags.dockerizeBackend || false
|
|
16813
16867
|
};
|
|
16814
16868
|
render_title("Creating project structure");
|
|
16815
16869
|
await scaffold_project(installerOptions);
|
|
16816
16870
|
render_title("Installing selected packages");
|
|
16817
16871
|
const installerMap = build_installer_map(installerOptions);
|
|
16818
16872
|
await run_installers(installerMap, installerOptions);
|
|
16819
|
-
|
|
16820
|
-
|
|
16821
|
-
|
|
16873
|
+
if (cliResults.flags.dockerizeDb || cliResults.flags.dockerizeBackend) {
|
|
16874
|
+
render_title("Generating Docker configuration");
|
|
16875
|
+
if (cliResults.flags.dockerizeBackend) {
|
|
16876
|
+
await generate_dockerfile(installerOptions);
|
|
16877
|
+
}
|
|
16878
|
+
if (cliResults.flags.dockerizeDb || cliResults.flags.dockerizeBackend) {
|
|
16879
|
+
await generate_docker_compose(installerOptions);
|
|
16880
|
+
}
|
|
16881
|
+
}
|
|
16822
16882
|
if (!cliResults.flags.noInstall) {
|
|
16823
16883
|
render_title("Installing dependencies");
|
|
16824
16884
|
await install_dependencies(projectDir);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { user_model } from "../../models/user.model.js";
|
|
4
|
+
import type { ApiResponse, ApiError } from "../../types/common/api-response.types.js";
|
|
5
|
+
import type { UserResponse } from "../../types/models/user.types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validation schema
|
|
9
|
+
*/
|
|
10
|
+
const create_user_schema = z.object({
|
|
11
|
+
email: z.string().email("Invalid email address"),
|
|
12
|
+
name: z.string().min(2, "Name must be at least 2 characters").max(100, "Name must not exceed 100 characters"),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Helper to format user response
|
|
17
|
+
*/
|
|
18
|
+
function format_user_response(user: any): UserResponse {
|
|
19
|
+
return {
|
|
20
|
+
id: user.id,
|
|
21
|
+
email: user.email,
|
|
22
|
+
name: user.name,
|
|
23
|
+
createdAt: user.createdAt.toISOString(),
|
|
24
|
+
updatedAt: user.updatedAt.toISOString(),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a new user
|
|
30
|
+
* POST /users
|
|
31
|
+
*/
|
|
32
|
+
export async function create_user(c: Context) {
|
|
33
|
+
try {
|
|
34
|
+
const body = await c.req.json();
|
|
35
|
+
|
|
36
|
+
// Validate request body
|
|
37
|
+
const validation = create_user_schema.safeParse(body);
|
|
38
|
+
if (!validation.success) {
|
|
39
|
+
return c.json<ApiError>(
|
|
40
|
+
{
|
|
41
|
+
success: false,
|
|
42
|
+
error: "Validation failed",
|
|
43
|
+
details: validation.error.errors.map((err) => ({
|
|
44
|
+
field: err.path.join("."),
|
|
45
|
+
message: err.message,
|
|
46
|
+
})),
|
|
47
|
+
},
|
|
48
|
+
400
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check if email already exists
|
|
53
|
+
const existing_user = await user_model.find_by_email(validation.data.email);
|
|
54
|
+
if (existing_user) {
|
|
55
|
+
return c.json<ApiError>(
|
|
56
|
+
{
|
|
57
|
+
success: false,
|
|
58
|
+
error: "User with this email already exists",
|
|
59
|
+
},
|
|
60
|
+
409
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Create user
|
|
65
|
+
const user = await user_model.create(validation.data);
|
|
66
|
+
|
|
67
|
+
return c.json<ApiResponse<UserResponse>>(
|
|
68
|
+
{
|
|
69
|
+
success: true,
|
|
70
|
+
data: format_user_response(user),
|
|
71
|
+
message: "User created successfully",
|
|
72
|
+
},
|
|
73
|
+
201
|
|
74
|
+
);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return c.json<ApiError>(
|
|
77
|
+
{
|
|
78
|
+
success: false,
|
|
79
|
+
error: "Failed to create user",
|
|
80
|
+
},
|
|
81
|
+
500
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { user_model } from "../../models/user.model.js";
|
|
4
|
+
import type { ApiResponse, ApiError } from "../../types/common/api-response.types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Validation schema
|
|
8
|
+
*/
|
|
9
|
+
const user_id_schema = z.string().uuid("Invalid user ID format");
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Delete user by ID
|
|
13
|
+
* DELETE /users/:id
|
|
14
|
+
*/
|
|
15
|
+
export async function delete_user(c: Context) {
|
|
16
|
+
try {
|
|
17
|
+
const id = c.req.param("id");
|
|
18
|
+
|
|
19
|
+
// Validate ID format
|
|
20
|
+
const validation = user_id_schema.safeParse(id);
|
|
21
|
+
if (!validation.success) {
|
|
22
|
+
return c.json<ApiError>(
|
|
23
|
+
{
|
|
24
|
+
success: false,
|
|
25
|
+
error: "Invalid user ID",
|
|
26
|
+
details: validation.error.errors.map((err) => ({
|
|
27
|
+
field: err.path.join("."),
|
|
28
|
+
message: err.message,
|
|
29
|
+
})),
|
|
30
|
+
},
|
|
31
|
+
400
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const deleted = await user_model.delete(id);
|
|
36
|
+
|
|
37
|
+
if (!deleted) {
|
|
38
|
+
return c.json<ApiError>(
|
|
39
|
+
{
|
|
40
|
+
success: false,
|
|
41
|
+
error: "User not found",
|
|
42
|
+
},
|
|
43
|
+
404
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return c.json<ApiResponse>({
|
|
48
|
+
success: true,
|
|
49
|
+
message: "User deleted successfully",
|
|
50
|
+
});
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return c.json<ApiError>(
|
|
53
|
+
{
|
|
54
|
+
success: false,
|
|
55
|
+
error: "Failed to delete user",
|
|
56
|
+
},
|
|
57
|
+
500
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { user_model } from "../../models/user.model.js";
|
|
4
|
+
import type { ApiResponse, ApiError } from "../../types/common/api-response.types.js";
|
|
5
|
+
import type { UserResponse } from "../../types/models/user.types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validation schema
|
|
9
|
+
*/
|
|
10
|
+
const user_id_schema = z.string().uuid("Invalid user ID format");
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Helper to format user response
|
|
14
|
+
*/
|
|
15
|
+
function format_user_response(user: any): UserResponse {
|
|
16
|
+
return {
|
|
17
|
+
id: user.id,
|
|
18
|
+
email: user.email,
|
|
19
|
+
name: user.name,
|
|
20
|
+
createdAt: user.createdAt.toISOString(),
|
|
21
|
+
updatedAt: user.updatedAt.toISOString(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get user by ID
|
|
27
|
+
* GET /users/:id
|
|
28
|
+
*/
|
|
29
|
+
export async function get_user(c: Context) {
|
|
30
|
+
try {
|
|
31
|
+
const id = c.req.param("id");
|
|
32
|
+
|
|
33
|
+
// Validate ID format
|
|
34
|
+
const validation = user_id_schema.safeParse(id);
|
|
35
|
+
if (!validation.success) {
|
|
36
|
+
return c.json<ApiError>(
|
|
37
|
+
{
|
|
38
|
+
success: false,
|
|
39
|
+
error: "Invalid user ID",
|
|
40
|
+
details: validation.error.errors.map((err) => ({
|
|
41
|
+
field: err.path.join("."),
|
|
42
|
+
message: err.message,
|
|
43
|
+
})),
|
|
44
|
+
},
|
|
45
|
+
400
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const user = await user_model.find_by_id(id);
|
|
50
|
+
|
|
51
|
+
if (!user) {
|
|
52
|
+
return c.json<ApiError>(
|
|
53
|
+
{
|
|
54
|
+
success: false,
|
|
55
|
+
error: "User not found",
|
|
56
|
+
},
|
|
57
|
+
404
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return c.json<ApiResponse<UserResponse>>({
|
|
62
|
+
success: true,
|
|
63
|
+
data: format_user_response(user),
|
|
64
|
+
});
|
|
65
|
+
} catch (error) {
|
|
66
|
+
return c.json<ApiError>(
|
|
67
|
+
{
|
|
68
|
+
success: false,
|
|
69
|
+
error: "Failed to fetch user",
|
|
70
|
+
},
|
|
71
|
+
500
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|