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.
Files changed (66) hide show
  1. package/README.md +49 -4
  2. package/dist/index.js +132 -72
  3. package/dist/templates/base/.env.example +1 -1
  4. package/dist/templates/base/package.json +2 -1
  5. package/dist/templates/base/src/config/index.ts +1 -1
  6. package/dist/templates/base/src/controllers/user/create-user.controller.ts +84 -0
  7. package/dist/templates/base/src/controllers/user/delete-user.controller.ts +60 -0
  8. package/dist/templates/base/src/controllers/user/get-user.controller.ts +74 -0
  9. package/dist/templates/base/src/controllers/user/get-users.controller.ts +41 -0
  10. package/dist/templates/base/src/controllers/user/update-user.controller.ts +111 -0
  11. package/dist/templates/base/src/models/user.model.ts +83 -0
  12. package/dist/templates/base/src/routes/index.ts +5 -0
  13. package/dist/templates/base/src/routes/user.route.ts +17 -0
  14. package/dist/templates/base/src/types/common/api-response.types.ts +30 -0
  15. package/dist/templates/base/src/types/index.ts +5 -2
  16. package/dist/templates/base/src/types/models/user.types.ts +26 -0
  17. package/dist/templates/base-bun-native/.env.example +1 -1
  18. package/dist/templates/base-bun-native/package.json +2 -1
  19. package/dist/templates/base-bun-native/src/config/index.ts +1 -1
  20. package/dist/templates/base-bun-native/src/controllers/user/create-user.controller.ts +76 -0
  21. package/dist/templates/base-bun-native/src/controllers/user/delete-user.controller.ts +53 -0
  22. package/dist/templates/base-bun-native/src/controllers/user/get-user.controller.ts +67 -0
  23. package/dist/templates/base-bun-native/src/controllers/user/get-users.controller.ts +40 -0
  24. package/dist/templates/base-bun-native/src/controllers/user/update-user.controller.ts +101 -0
  25. package/dist/templates/base-bun-native/src/index.ts +3 -3
  26. package/dist/templates/base-bun-native/src/models/user.model.ts +83 -0
  27. package/dist/templates/base-bun-native/src/routes/index.ts +10 -6
  28. package/dist/templates/base-bun-native/src/routes/user.route.ts +50 -0
  29. package/dist/templates/base-bun-native/src/types/common/api-response.types.ts +30 -0
  30. package/dist/templates/base-bun-native/src/types/index.ts +5 -2
  31. package/dist/templates/base-bun-native/src/types/models/user.types.ts +26 -0
  32. package/dist/templates/base-express/.env.example +1 -1
  33. package/dist/templates/base-express/package.json +2 -1
  34. package/dist/templates/base-express/src/config/index.ts +1 -1
  35. package/dist/templates/base-express/src/controllers/user/create-user.controller.ts +75 -0
  36. package/dist/templates/base-express/src/controllers/user/delete-user.controller.ts +56 -0
  37. package/dist/templates/base-express/src/controllers/user/get-user.controller.ts +70 -0
  38. package/dist/templates/base-express/src/controllers/user/get-users.controller.ts +41 -0
  39. package/dist/templates/base-express/src/controllers/user/update-user.controller.ts +102 -0
  40. package/dist/templates/base-express/src/models/user.model.ts +83 -0
  41. package/dist/templates/base-express/src/routes/index.ts +5 -0
  42. package/dist/templates/base-express/src/routes/user.route.ts +17 -0
  43. package/dist/templates/base-express/src/types/common/api-response.types.ts +30 -0
  44. package/dist/templates/base-express/src/types/index.ts +5 -2
  45. package/dist/templates/base-express/src/types/models/user.types.ts +26 -0
  46. package/dist/templates/extras/database/mongodb/src/db/index.ts +70 -0
  47. package/dist/templates/extras/database/mongodb/src/db/models/user.model.ts +87 -0
  48. package/dist/templates/extras/database/mysql/src/db/index.ts +106 -0
  49. package/dist/templates/extras/database/postgres/src/db/index.ts +96 -0
  50. package/dist/templates/extras/database/redis/src/db/redis.ts +215 -0
  51. package/dist/templates/extras/database/sqlite/src/db/index.ts +185 -0
  52. package/dist/templates/templates/base/.dockerignore +45 -0
  53. package/dist/templates/templates/base/src/models/user.model.ts +1 -1
  54. package/dist/templates/templates/base-bun-native/.dockerignore +45 -0
  55. package/dist/templates/templates/base-bun-native/src/models/user.model.ts +1 -1
  56. package/dist/templates/templates/base-express/.dockerignore +45 -0
  57. package/dist/templates/templates/base-express/src/models/user.model.ts +1 -1
  58. package/dist/templates/templates/extras/database/mongodb/src/db/index.ts +70 -0
  59. package/dist/templates/templates/extras/database/mongodb/src/db/models/user.model.ts +87 -0
  60. package/dist/templates/templates/extras/database/mysql/src/db/index.ts +106 -0
  61. package/dist/templates/templates/extras/database/postgres/src/db/index.ts +96 -0
  62. package/dist/templates/templates/extras/database/redis/src/db/redis.ts +215 -0
  63. package/dist/templates/templates/extras/database/sqlite/src/db/index.ts +185 -0
  64. package/package.json +1 -1
  65. package/dist/templates/extras/database/mysql/drizzle.config.ts +0 -0
  66. 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
- - 🐳 **Dockerfile and docker-compose** included
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 Drizzle ORM
82
- - **MySQL** with Drizzle ORM
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
- Dockerfile and docker-compose are included by default.
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
- ║ \uD83D\uDE80 deploy-bbc ║
5947
- ║ (Best Backend Code) ║
5948
- ║ ║
5949
- ║ Bootstrap a production-ready backend ║
5950
- ║ with Bun, TypeScript & Docker ║
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(source_default.cyan(intro));
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 (or . for current directory)",
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 (value === "." || value.startsWith("./") || value.startsWith("../") || value.startsWith("~/")) {
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
- if (!/^[a-z0-9-_/]+$/i.test(value))
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 • Drizzle ORM"
6018
+ hint: "Dockerized • Native postgres driver"
6000
6019
  },
6001
6020
  {
6002
6021
  value: "mysql" /* mysql */,
6003
6022
  label: "MySQL",
6004
- hint: "Dockerized • Drizzle ORM"
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(`The following files/folders already exist: ${conflicts.join(", ")}
9054
- ` + "Please use an empty directory or choose a different location.");
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
- await add_db_scripts(projectDir, "mysql");
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 hasMongodb = packages.includes("mongodb" /* mongodb */);
10189
- const hasRedis = packages.includes("redis" /* redis */);
10190
- if (!hasPostgres && !hasMysql && !hasMongodb && !hasRedis) {
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
- composeContent += ` app:
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
- const dependencies = [];
10207
- if (hasPostgres)
10208
- dependencies.push("postgres");
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
- dependencies.forEach((dep) => {
10219
- composeContent += ` - ${dep}
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
- render_title("Generating Docker configuration");
16820
- await generate_dockerfile(installerOptions);
16821
- await generate_docker_compose(installerOptions);
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);
@@ -1,3 +1,3 @@
1
1
  # Server Configuration
2
- PORT=3000
2
+ PORT=8000
3
3
  NODE_ENV=development
@@ -10,8 +10,9 @@
10
10
  "type-check": "tsc --noEmit"
11
11
  },
12
12
  "dependencies": {
13
+ "dotenv": "^16.3.1",
13
14
  "hono": "^4.0.0",
14
- "dotenv": "^16.3.1"
15
+ "zod": "^3.22.4"
15
16
  },
16
17
  "devDependencies": {
17
18
  "@types/bun": "latest",
@@ -3,6 +3,6 @@ import { load_env } from "../utils/env.js";
3
3
  load_env();
4
4
 
5
5
  export const config = {
6
- port: parseInt(process.env.PORT || "3000", 10),
6
+ port: parseInt(process.env.PORT || "8000", 10),
7
7
  nodeEnv: process.env.NODE_ENV || "development",
8
8
  } as const;
@@ -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
+ }