deploy-bbc 1.2.4 → 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 +122 -67
- 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,7 +5934,7 @@ 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) {
|
|
@@ -5949,11 +5949,11 @@ ${gray}/ \\${
|
|
|
5949
5949
|
${gray}|${reset} ${blue}█▀▀▄ █▀▀ █▀▀█ █ █▀▀█ █ █ █▀▀▄ █▀▀▄ █▀▀${reset} ${gray}|${reset}
|
|
5950
5950
|
${gray}|${reset} ${blue}█ █ █▀▀ █ █ █ █ █ █▄▄█ █▀▀▄ █▀▀▄ █${reset} ${gray}|${reset}
|
|
5951
5951
|
${gray}|${reset} ${blue}█▄▄▀ ▀▀▀ █▀▀▀ ▀▀▀ ▀▀▀▀ ▄▄▄█ █▄▄▀ █▄▄▀ ▀▀▀${reset} ${gray}|${reset}
|
|
5952
|
-
${gray}|${reset}
|
|
5953
|
-
${gray}|${reset} \uD83D\uDE80 ${blue}Best Backend Code${reset}
|
|
5954
|
-
${gray}|${reset}
|
|
5955
|
-
${gray}|${reset} ${gray}
|
|
5956
|
-
${gray}|${reset} ${gray}[ Bun ] ---------- [ TypeScript ] ---------- [ Docker ]${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
5957
|
${gray}\\____________________________________________________________________/${reset}
|
|
5958
5958
|
`;
|
|
5959
5959
|
console.log(intro);
|
|
@@ -5962,16 +5962,30 @@ ${gray}\\____________________________________________________________________/${
|
|
|
5962
5962
|
...add_cli_header("\uD83D\uDCE6 CORE"),
|
|
5963
5963
|
projectName: () => he({
|
|
5964
5964
|
message: "What will your project be called?",
|
|
5965
|
-
placeholder: "my-awesome-api (
|
|
5965
|
+
placeholder: "my-awesome-api (use '.' for current dir if empty)",
|
|
5966
5966
|
defaultValue: cliProvidedName || "my-backend",
|
|
5967
5967
|
validate: (value) => {
|
|
5968
5968
|
if (!value)
|
|
5969
5969
|
return "Please enter a project name";
|
|
5970
|
-
if (
|
|
5971
|
-
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
|
+
}
|
|
5972
5987
|
}
|
|
5973
|
-
|
|
5974
|
-
return "Only letters, numbers, dashes, underscores, and slashes";
|
|
5988
|
+
return;
|
|
5975
5989
|
}
|
|
5976
5990
|
}),
|
|
5977
5991
|
framework: () => ve({
|
|
@@ -6001,12 +6015,17 @@ ${gray}\\____________________________________________________________________/${
|
|
|
6001
6015
|
{
|
|
6002
6016
|
value: "postgres" /* postgres */,
|
|
6003
6017
|
label: "PostgreSQL",
|
|
6004
|
-
hint: "Dockerized •
|
|
6018
|
+
hint: "Dockerized • Native postgres driver"
|
|
6005
6019
|
},
|
|
6006
6020
|
{
|
|
6007
6021
|
value: "mysql" /* mysql */,
|
|
6008
6022
|
label: "MySQL",
|
|
6009
|
-
hint: "Dockerized •
|
|
6023
|
+
hint: "Dockerized • mysql2 driver"
|
|
6024
|
+
},
|
|
6025
|
+
{
|
|
6026
|
+
value: "sqlite" /* sqlite */,
|
|
6027
|
+
label: "SQLite",
|
|
6028
|
+
hint: "File-based • bun:sqlite (built-in)"
|
|
6010
6029
|
},
|
|
6011
6030
|
{
|
|
6012
6031
|
value: "mongodb" /* mongodb */,
|
|
@@ -6171,6 +6190,20 @@ ${gray}\\____________________________________________________________________/${
|
|
|
6171
6190
|
],
|
|
6172
6191
|
initialValue: "zod" /* zod */
|
|
6173
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
|
+
}),
|
|
6174
6207
|
installDeps: () => ye({
|
|
6175
6208
|
message: "Install dependencies?",
|
|
6176
6209
|
initialValue: !cliOptions.noInstall
|
|
@@ -6205,7 +6238,9 @@ ${gray}\\____________________________________________________________________/${
|
|
|
6205
6238
|
flags: {
|
|
6206
6239
|
...defaultOptions,
|
|
6207
6240
|
noInstall: !project.installDeps,
|
|
6208
|
-
noGit: !project.initGit
|
|
6241
|
+
noGit: !project.initGit,
|
|
6242
|
+
dockerizeDb: project.dockerizeDb,
|
|
6243
|
+
dockerizeBackend: project.dockerizeBackend
|
|
6209
6244
|
}
|
|
6210
6245
|
};
|
|
6211
6246
|
};
|
|
@@ -6229,6 +6264,8 @@ function build_from_flags(appName, flags) {
|
|
|
6229
6264
|
packages.push("postgres" /* postgres */);
|
|
6230
6265
|
if (flags.mysql)
|
|
6231
6266
|
packages.push("mysql" /* mysql */);
|
|
6267
|
+
if (flags.sqlite)
|
|
6268
|
+
packages.push("sqlite" /* sqlite */);
|
|
6232
6269
|
if (flags.mongodb)
|
|
6233
6270
|
packages.push("mongodb" /* mongodb */);
|
|
6234
6271
|
if (flags.redis)
|
|
@@ -9055,8 +9092,14 @@ async function scaffold_project(options) {
|
|
|
9055
9092
|
}
|
|
9056
9093
|
if (conflicts.length > 0) {
|
|
9057
9094
|
spinner.fail("Cannot scaffold in current directory");
|
|
9058
|
-
throw new Error(`
|
|
9059
|
-
|
|
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')");
|
|
9060
9103
|
}
|
|
9061
9104
|
}
|
|
9062
9105
|
await import_fs_extra.default.ensureDir(projectDir);
|
|
@@ -9125,9 +9168,6 @@ var DEPENDENCY_VERSION_MAP = {
|
|
|
9125
9168
|
mysql2: "^3.9.0",
|
|
9126
9169
|
mongoose: "^8.1.0",
|
|
9127
9170
|
redis: "^4.6.12",
|
|
9128
|
-
"drizzle-orm": "^0.29.3",
|
|
9129
|
-
"drizzle-kit": "^0.20.10",
|
|
9130
|
-
kysely: "^0.27.2",
|
|
9131
9171
|
jsonwebtoken: "^9.0.2",
|
|
9132
9172
|
"@types/jsonwebtoken": "^9.0.5",
|
|
9133
9173
|
bcryptjs: "^2.4.3",
|
|
@@ -9185,6 +9225,9 @@ async function database_installer(options) {
|
|
|
9185
9225
|
case "mysql" /* mysql */:
|
|
9186
9226
|
await install_mysql(projectDir);
|
|
9187
9227
|
break;
|
|
9228
|
+
case "sqlite" /* sqlite */:
|
|
9229
|
+
await install_sqlite(projectDir);
|
|
9230
|
+
break;
|
|
9188
9231
|
case "mongodb" /* mongodb */:
|
|
9189
9232
|
await install_mongodb(projectDir);
|
|
9190
9233
|
break;
|
|
@@ -9198,33 +9241,40 @@ async function install_postgres(projectDir) {
|
|
|
9198
9241
|
const templateDir = path4.resolve(__dirname3, "templates/extras/database/postgres");
|
|
9199
9242
|
await copy_template_files(templateDir, projectDir);
|
|
9200
9243
|
await add_package_dependency(projectDir, {
|
|
9201
|
-
postgres: DEPENDENCY_VERSION_MAP["postgres"]
|
|
9202
|
-
"drizzle-orm": DEPENDENCY_VERSION_MAP["drizzle-orm"]
|
|
9203
|
-
});
|
|
9204
|
-
await add_package_dependency(projectDir, {}, {
|
|
9205
|
-
"drizzle-kit": DEPENDENCY_VERSION_MAP["drizzle-kit"]
|
|
9244
|
+
postgres: DEPENDENCY_VERSION_MAP["postgres"]
|
|
9206
9245
|
});
|
|
9207
9246
|
await append_env_example(projectDir, `
|
|
9208
9247
|
# PostgreSQL Configuration
|
|
9209
9248
|
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
|
|
9210
9249
|
`);
|
|
9211
|
-
await add_db_scripts(projectDir, "postgres");
|
|
9212
9250
|
}
|
|
9213
9251
|
async function install_mysql(projectDir) {
|
|
9214
9252
|
const templateDir = path4.resolve(__dirname3, "templates/extras/database/mysql");
|
|
9215
9253
|
await copy_template_files(templateDir, projectDir);
|
|
9216
9254
|
await add_package_dependency(projectDir, {
|
|
9217
|
-
mysql2: DEPENDENCY_VERSION_MAP["mysql2"]
|
|
9218
|
-
"drizzle-orm": DEPENDENCY_VERSION_MAP["drizzle-orm"]
|
|
9219
|
-
});
|
|
9220
|
-
await add_package_dependency(projectDir, {}, {
|
|
9221
|
-
"drizzle-kit": DEPENDENCY_VERSION_MAP["drizzle-kit"]
|
|
9255
|
+
mysql2: DEPENDENCY_VERSION_MAP["mysql2"]
|
|
9222
9256
|
});
|
|
9223
9257
|
await append_env_example(projectDir, `
|
|
9224
9258
|
# MySQL Configuration
|
|
9225
9259
|
DATABASE_URL=mysql://user:password@localhost:3306/dbname
|
|
9226
9260
|
`);
|
|
9227
|
-
|
|
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
|
+
}
|
|
9228
9278
|
}
|
|
9229
9279
|
async function install_mongodb(projectDir) {
|
|
9230
9280
|
const templateDir = path4.resolve(__dirname3, "templates/extras/database/mongodb");
|
|
@@ -9276,17 +9326,6 @@ async function append_env_example(projectDir, content) {
|
|
|
9276
9326
|
const envPath = path4.join(projectDir, ".env.example");
|
|
9277
9327
|
await import_fs_extra3.default.appendFile(envPath, content);
|
|
9278
9328
|
}
|
|
9279
|
-
async function add_db_scripts(projectDir, dbType) {
|
|
9280
|
-
const packageJsonPath = path4.join(projectDir, "package.json");
|
|
9281
|
-
const packageJson = await import_fs_extra3.default.readJson(packageJsonPath);
|
|
9282
|
-
packageJson.scripts = {
|
|
9283
|
-
...packageJson.scripts,
|
|
9284
|
-
"db:generate": "drizzle-kit generate",
|
|
9285
|
-
"db:migrate": "drizzle-kit migrate",
|
|
9286
|
-
"db:studio": "drizzle-kit studio"
|
|
9287
|
-
};
|
|
9288
|
-
await import_fs_extra3.default.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
9289
|
-
}
|
|
9290
9329
|
|
|
9291
9330
|
// src/installers/auth.ts
|
|
9292
9331
|
var import_fs_extra4 = __toESM(require_lib(), 1);
|
|
@@ -10187,19 +10226,21 @@ CMD ["bun", "run", "src/index.ts"]
|
|
|
10187
10226
|
var import_fs_extra17 = __toESM(require_lib(), 1);
|
|
10188
10227
|
import path18 from "path";
|
|
10189
10228
|
async function generate_docker_compose(options) {
|
|
10190
|
-
const { projectDir, packages, appName } = options;
|
|
10191
|
-
const hasPostgres = packages.includes("postgres" /* postgres */);
|
|
10192
|
-
const hasMysql = packages.includes("mysql" /* mysql */);
|
|
10193
|
-
const
|
|
10194
|
-
const
|
|
10195
|
-
|
|
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) {
|
|
10196
10236
|
return;
|
|
10197
10237
|
}
|
|
10198
10238
|
let composeContent = `version: '3.8'
|
|
10199
10239
|
|
|
10200
10240
|
services:
|
|
10201
10241
|
`;
|
|
10202
|
-
|
|
10242
|
+
if (dockerizeBackend) {
|
|
10243
|
+
composeContent += ` app:
|
|
10203
10244
|
build: .
|
|
10204
10245
|
ports:
|
|
10205
10246
|
- "8000:8000"
|
|
@@ -10208,22 +10249,28 @@ services:
|
|
|
10208
10249
|
env_file:
|
|
10209
10250
|
- .env
|
|
10210
10251
|
`;
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
if (hasMysql)
|
|
10215
|
-
dependencies.push("mysql");
|
|
10216
|
-
if (hasMongodb)
|
|
10217
|
-
dependencies.push("mongodb");
|
|
10218
|
-
if (hasRedis)
|
|
10219
|
-
dependencies.push("redis");
|
|
10220
|
-
if (dependencies.length > 0) {
|
|
10221
|
-
composeContent += ` depends_on:
|
|
10252
|
+
if (hasSqlite) {
|
|
10253
|
+
composeContent += ` volumes:
|
|
10254
|
+
- ./data:/app/data
|
|
10222
10255
|
`;
|
|
10223
|
-
|
|
10224
|
-
|
|
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:
|
|
10225
10268
|
`;
|
|
10226
|
-
|
|
10269
|
+
dependencies.forEach((dep) => {
|
|
10270
|
+
composeContent += ` - ${dep}
|
|
10271
|
+
`;
|
|
10272
|
+
});
|
|
10273
|
+
}
|
|
10227
10274
|
}
|
|
10228
10275
|
if (hasPostgres) {
|
|
10229
10276
|
composeContent += `
|
|
@@ -16814,16 +16861,24 @@ async function create_project(cliResults) {
|
|
|
16814
16861
|
appName: projectName,
|
|
16815
16862
|
framework: cliResults.framework,
|
|
16816
16863
|
packages: cliResults.packages,
|
|
16817
|
-
noInstall: cliResults.flags.noInstall
|
|
16864
|
+
noInstall: cliResults.flags.noInstall,
|
|
16865
|
+
dockerizeDb: cliResults.flags.dockerizeDb || false,
|
|
16866
|
+
dockerizeBackend: cliResults.flags.dockerizeBackend || false
|
|
16818
16867
|
};
|
|
16819
16868
|
render_title("Creating project structure");
|
|
16820
16869
|
await scaffold_project(installerOptions);
|
|
16821
16870
|
render_title("Installing selected packages");
|
|
16822
16871
|
const installerMap = build_installer_map(installerOptions);
|
|
16823
16872
|
await run_installers(installerMap, installerOptions);
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
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
|
+
}
|
|
16827
16882
|
if (!cliResults.flags.noInstall) {
|
|
16828
16883
|
render_title("Installing dependencies");
|
|
16829
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
|
+
}
|