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.
Files changed (66) hide show
  1. package/README.md +49 -4
  2. package/dist/index.js +122 -67
  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,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} ${gray}|${reset}
5953
- ${gray}|${reset} \uD83D\uDE80 ${blue}Best Backend Code${reset} ${gray}|${reset}
5954
- ${gray}|${reset} ${gray}|${reset}
5955
- ${gray}|${reset} ${gray}Bootstrap production-ready backends with Bun & TypeScript${reset} ${gray}|${reset}
5956
- ${gray}|${reset} ${gray}[ Bun ] ---------- [ TypeScript ] ---------- [ Docker ]${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
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 (or . for current directory)",
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 (value === "." || value.startsWith("./") || value.startsWith("../") || value.startsWith("~/")) {
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
- if (!/^[a-z0-9-_/]+$/i.test(value))
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 • Drizzle ORM"
6018
+ hint: "Dockerized • Native postgres driver"
6005
6019
  },
6006
6020
  {
6007
6021
  value: "mysql" /* mysql */,
6008
6022
  label: "MySQL",
6009
- 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)"
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(`The following files/folders already exist: ${conflicts.join(", ")}
9059
- ` + "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')");
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
- 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
+ }
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 hasMongodb = packages.includes("mongodb" /* mongodb */);
10194
- const hasRedis = packages.includes("redis" /* redis */);
10195
- 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) {
10196
10236
  return;
10197
10237
  }
10198
10238
  let composeContent = `version: '3.8'
10199
10239
 
10200
10240
  services:
10201
10241
  `;
10202
- composeContent += ` app:
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
- const dependencies = [];
10212
- if (hasPostgres)
10213
- dependencies.push("postgres");
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
- dependencies.forEach((dep) => {
10224
- 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:
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
- render_title("Generating Docker configuration");
16825
- await generate_dockerfile(installerOptions);
16826
- 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
+ }
16827
16882
  if (!cliResults.flags.noInstall) {
16828
16883
  render_title("Installing dependencies");
16829
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
+ }