deploy-bbc 0.0.1

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 (127) hide show
  1. package/CLAUDE.md +329 -0
  2. package/README.md +0 -0
  3. package/cli/README.md +0 -0
  4. package/cli/package.json +43 -0
  5. package/cli/src/cli/index.ts +449 -0
  6. package/cli/src/helpers/create-project.ts +66 -0
  7. package/cli/src/helpers/generate-docker-compose.ts +133 -0
  8. package/cli/src/helpers/generate-dockerfile.ts +45 -0
  9. package/cli/src/helpers/init-git.ts +33 -0
  10. package/cli/src/helpers/install-dependencies.ts +28 -0
  11. package/cli/src/helpers/log-next-steps.ts +84 -0
  12. package/cli/src/helpers/scaffold-project.ts +62 -0
  13. package/cli/src/index.ts +18 -0
  14. package/cli/src/installers/ai.ts +123 -0
  15. package/cli/src/installers/auth.ts +132 -0
  16. package/cli/src/installers/base.ts +16 -0
  17. package/cli/src/installers/cloud.ts +127 -0
  18. package/cli/src/installers/database.ts +212 -0
  19. package/cli/src/installers/docs.ts +93 -0
  20. package/cli/src/installers/email.ts +119 -0
  21. package/cli/src/installers/env-variables.ts +27 -0
  22. package/cli/src/installers/index.ts +145 -0
  23. package/cli/src/installers/observability.ts +103 -0
  24. package/cli/src/installers/queue.ts +103 -0
  25. package/cli/src/installers/ratelimit.ts +98 -0
  26. package/cli/src/installers/realtime.ts +79 -0
  27. package/cli/src/installers/testing.ts +88 -0
  28. package/cli/src/installers/validation.ts +85 -0
  29. package/cli/src/templates/base/.env.example +3 -0
  30. package/cli/src/templates/base/README.md +31 -0
  31. package/cli/src/templates/base/package.json +20 -0
  32. package/cli/src/templates/base/src/config/index.ts +8 -0
  33. package/cli/src/templates/base/src/index.ts +26 -0
  34. package/cli/src/templates/base/src/middleware/error.ts +13 -0
  35. package/cli/src/templates/base/src/middleware/logger.ts +8 -0
  36. package/cli/src/templates/base/src/routes/index.ts +12 -0
  37. package/cli/src/templates/base/src/types/index.ts +2 -0
  38. package/cli/src/templates/base/src/utils/env.ts +5 -0
  39. package/cli/src/templates/base/tsconfig.json +20 -0
  40. package/cli/src/templates/base-bun-native/.env.example +3 -0
  41. package/cli/src/templates/base-bun-native/README.md +31 -0
  42. package/cli/src/templates/base-bun-native/package.json +19 -0
  43. package/cli/src/templates/base-bun-native/src/config/index.ts +8 -0
  44. package/cli/src/templates/base-bun-native/src/index.ts +50 -0
  45. package/cli/src/templates/base-bun-native/src/middleware/error.ts +20 -0
  46. package/cli/src/templates/base-bun-native/src/middleware/logger.ts +6 -0
  47. package/cli/src/templates/base-bun-native/src/routes/index.ts +21 -0
  48. package/cli/src/templates/base-bun-native/src/types/index.ts +2 -0
  49. package/cli/src/templates/base-bun-native/src/utils/env.ts +5 -0
  50. package/cli/src/templates/base-bun-native/tsconfig.json +20 -0
  51. package/cli/src/templates/base-express/.env.example +3 -0
  52. package/cli/src/templates/base-express/README.md +31 -0
  53. package/cli/src/templates/base-express/package.json +21 -0
  54. package/cli/src/templates/base-express/src/config/index.ts +8 -0
  55. package/cli/src/templates/base-express/src/index.ts +27 -0
  56. package/cli/src/templates/base-express/src/middleware/error.ts +15 -0
  57. package/cli/src/templates/base-express/src/middleware/logger.ts +12 -0
  58. package/cli/src/templates/base-express/src/routes/index.ts +12 -0
  59. package/cli/src/templates/base-express/src/types/index.ts +2 -0
  60. package/cli/src/templates/base-express/src/utils/env.ts +5 -0
  61. package/cli/src/templates/base-express/tsconfig.json +20 -0
  62. package/cli/src/templates/extras/ai/anthropic/src/routes/ai/claude.ts +0 -0
  63. package/cli/src/templates/extras/ai/anthropic/src/services/ai/anthropic.ts +0 -0
  64. package/cli/src/templates/extras/ai/gemini/src/services/ai/gemini.ts +0 -0
  65. package/cli/src/templates/extras/ai/openai/src/routes/ai/chat.ts +0 -0
  66. package/cli/src/templates/extras/ai/openai/src/services/ai/openai.ts +0 -0
  67. package/cli/src/templates/extras/ai/vercel-ai/src/routes/ai/generate.ts +0 -0
  68. package/cli/src/templates/extras/ai/vercel-ai/src/routes/ai/stream.ts +0 -0
  69. package/cli/src/templates/extras/ai/vercel-ai/src/services/ai/index.ts +0 -0
  70. package/cli/src/templates/extras/auth/jwt/src/middleware/auth.ts +0 -0
  71. package/cli/src/templates/extras/auth/jwt/src/routes/auth.ts +0 -0
  72. package/cli/src/templates/extras/auth/jwt/src/utils/jwt.ts +0 -0
  73. package/cli/src/templates/extras/auth/oauth/src/config/oauth.ts +0 -0
  74. package/cli/src/templates/extras/auth/oauth/src/routes/auth.ts +0 -0
  75. package/cli/src/templates/extras/auth/session/src/config/session.ts +0 -0
  76. package/cli/src/templates/extras/auth/session/src/middleware/session.ts +0 -0
  77. package/cli/src/templates/extras/cloud/aws/src/services/aws/s3.ts +0 -0
  78. package/cli/src/templates/extras/cloud/aws/src/services/aws/ses.ts +0 -0
  79. package/cli/src/templates/extras/cloud/azure/src/services/azure/blob.ts +0 -0
  80. package/cli/src/templates/extras/cloud/cloudflare-r2/src/services/cloudflare/r2.ts +0 -0
  81. package/cli/src/templates/extras/cloud/gcp/src/services/gcp/storage.ts +0 -0
  82. package/cli/src/templates/extras/database/mongodb/src/db/index.ts +0 -0
  83. package/cli/src/templates/extras/database/mongodb/src/db/models/user.model.ts +0 -0
  84. package/cli/src/templates/extras/database/mysql/drizzle.config.ts +0 -0
  85. package/cli/src/templates/extras/database/postgres/src/db/index.ts +0 -0
  86. package/cli/src/templates/extras/database/redis/src/db/redis.ts +0 -0
  87. package/cli/src/templates/extras/docs/scalar/src/openapi/index.ts +0 -0
  88. package/cli/src/templates/extras/docs/scalar/src/routes/docs.ts +0 -0
  89. package/cli/src/templates/extras/docs/swagger/src/openapi/index.ts +0 -0
  90. package/cli/src/templates/extras/docs/swagger/src/routes/docs.ts +0 -0
  91. package/cli/src/templates/extras/email/nodemailer/src/services/email/nodemailer.ts +0 -0
  92. package/cli/src/templates/extras/email/resend/src/services/email/resend.ts +0 -0
  93. package/cli/src/templates/extras/email/resend/src/templates/email/welcome.ts +0 -0
  94. package/cli/src/templates/extras/email/sendgrid/src/services/email/sendgrid.ts +0 -0
  95. package/cli/src/templates/extras/observability/logtail/src/config/logger.ts +0 -0
  96. package/cli/src/templates/extras/observability/sentry/src/config/sentry.ts +0 -0
  97. package/cli/src/templates/extras/observability/sentry/src/middleware/sentry.ts +0 -0
  98. package/cli/src/templates/extras/queue/bullmq/src/queue/index.ts +0 -0
  99. package/cli/src/templates/extras/queue/bullmq/src/queue/jobs/email.job.ts +0 -0
  100. package/cli/src/templates/extras/queue/bullmq/src/queue/processors/email.processor.ts +0 -0
  101. package/cli/src/templates/extras/queue/bullmq/src/routes/queue.ts +0 -0
  102. package/cli/src/templates/extras/queue/inngest/src/inngest/client.ts +0 -0
  103. package/cli/src/templates/extras/queue/inngest/src/inngest/functions/email.ts +0 -0
  104. package/cli/src/templates/extras/queue/inngest/src/routes/inngest.ts +0 -0
  105. package/cli/src/templates/extras/realtime/socketio/src/socket/handlers.ts +0 -0
  106. package/cli/src/templates/extras/realtime/socketio/src/socket/index.ts +0 -0
  107. package/cli/src/templates/extras/realtime/sse/src/routes/sse.ts +0 -0
  108. package/cli/src/templates/extras/testing/vitest/src/__tests__/example.test.ts +0 -0
  109. package/cli/src/templates/extras/testing/vitest/src/__tests__/setup.ts +0 -0
  110. package/cli/src/templates/extras/testing/vitest/vitest.config.ts +0 -0
  111. package/cli/src/templates/extras/validation/yup/src/middleware/index.ts +1 -0
  112. package/cli/src/templates/extras/validation/yup/src/middleware/validate.ts +83 -0
  113. package/cli/src/templates/extras/validation/yup/src/routes/users.ts +132 -0
  114. package/cli/src/templates/extras/validation/zod/src/middleware/index.ts +1 -0
  115. package/cli/src/templates/extras/validation/zod/src/middleware/validate.ts +80 -0
  116. package/cli/src/templates/extras/validation/zod/src/routes/users.ts +128 -0
  117. package/cli/src/types/index.ts +126 -0
  118. package/cli/src/utils/add-package-dependency.ts +56 -0
  119. package/cli/src/utils/dependency-version-map.ts +85 -0
  120. package/cli/src/utils/logger.ts +19 -0
  121. package/cli/src/utils/parse-name-and-path.ts +55 -0
  122. package/cli/src/utils/render-title.ts +11 -0
  123. package/cli/tsconfig.json +35 -0
  124. package/package.json +20 -0
  125. package/prettier.config.mjs +0 -0
  126. package/test-cli.sh +56 -0
  127. package/tsconfig.json +15 -0
@@ -0,0 +1,80 @@
1
+ import { Context, Next } from "hono";
2
+ import { z, ZodSchema } from "zod";
3
+
4
+ /**
5
+ * Validation middleware for Hono using Zod schemas
6
+ * Validates request body, query parameters, or route params
7
+ */
8
+
9
+ export type ValidateTarget = "body" | "query" | "param";
10
+
11
+ interface ValidationOptions {
12
+ target: ValidateTarget;
13
+ schema: ZodSchema;
14
+ }
15
+
16
+ /**
17
+ * Create a validation middleware
18
+ * @param options - Validation configuration
19
+ * @returns Hono middleware function
20
+ */
21
+ export function validate(options: ValidationOptions) {
22
+ return async (c: Context, next: Next) => {
23
+ try {
24
+ let data: unknown;
25
+
26
+ switch (options.target) {
27
+ case "body":
28
+ data = await c.req.json();
29
+ break;
30
+ case "query":
31
+ data = c.req.query();
32
+ break;
33
+ case "param":
34
+ data = c.req.param();
35
+ break;
36
+ default:
37
+ return c.json(
38
+ { error: "Invalid validation target" },
39
+ 400
40
+ );
41
+ }
42
+
43
+ // Validate data against schema
44
+ const validated = options.schema.parse(data);
45
+
46
+ // Store validated data in context for route handlers
47
+ c.set(`validated_${options.target}`, validated);
48
+
49
+ await next();
50
+ } catch (error) {
51
+ if (error instanceof z.ZodError) {
52
+ return c.json(
53
+ {
54
+ error: "Validation failed",
55
+ details: error.errors.map((err) => ({
56
+ path: err.path.join("."),
57
+ message: err.message,
58
+ })),
59
+ },
60
+ 400
61
+ );
62
+ }
63
+
64
+ return c.json(
65
+ { error: "Invalid request data" },
66
+ 400
67
+ );
68
+ }
69
+ };
70
+ }
71
+
72
+ /**
73
+ * Helper to get validated data from context
74
+ * @param c - Hono context
75
+ * @param target - Validation target (body/query/param)
76
+ * @returns Validated data
77
+ */
78
+ export function get_validated<T>(c: Context, target: ValidateTarget): T {
79
+ return c.get(`validated_${target}`) as T;
80
+ }
@@ -0,0 +1,128 @@
1
+ import { Hono } from "hono";
2
+ import { z } from "zod";
3
+ import { validate, get_validated } from "../middleware/validate.js";
4
+
5
+ const users = new Hono();
6
+
7
+ /**
8
+ * Zod Schemas for validation
9
+ */
10
+
11
+ // Schema for creating a new user
12
+ const create_user_schema = z.object({
13
+ name: z.string().min(2, "Name must be at least 2 characters"),
14
+ email: z.string().email("Invalid email format"),
15
+ age: z.number().int().min(18, "Must be at least 18 years old").optional(),
16
+ });
17
+
18
+ // Schema for updating a user
19
+ const update_user_schema = z.object({
20
+ name: z.string().min(2).optional(),
21
+ email: z.string().email().optional(),
22
+ age: z.number().int().min(18).optional(),
23
+ });
24
+
25
+ // Schema for query parameters
26
+ const list_users_query_schema = z.object({
27
+ page: z.string().regex(/^\d+$/).transform(Number).optional(),
28
+ limit: z.string().regex(/^\d+$/).transform(Number).optional(),
29
+ search: z.string().optional(),
30
+ });
31
+
32
+ // Schema for route params
33
+ const user_id_param_schema = z.object({
34
+ id: z.string().uuid("Invalid user ID format"),
35
+ });
36
+
37
+ /**
38
+ * Routes with validation
39
+ */
40
+
41
+ // GET /users - List users with query validation
42
+ users.get(
43
+ "/",
44
+ validate({ target: "query", schema: list_users_query_schema }),
45
+ (c) => {
46
+ const query = get_validated<z.infer<typeof list_users_query_schema>>(c, "query");
47
+
48
+ return c.json({
49
+ users: [],
50
+ pagination: {
51
+ page: query.page || 1,
52
+ limit: query.limit || 10,
53
+ search: query.search,
54
+ },
55
+ });
56
+ }
57
+ );
58
+
59
+ // POST /users - Create user with body validation
60
+ users.post(
61
+ "/",
62
+ validate({ target: "body", schema: create_user_schema }),
63
+ (c) => {
64
+ const body = get_validated<z.infer<typeof create_user_schema>>(c, "body");
65
+
66
+ // Your database logic here
67
+ const new_user = {
68
+ id: crypto.randomUUID(),
69
+ ...body,
70
+ created_at: new Date().toISOString(),
71
+ };
72
+
73
+ return c.json(new_user, 201);
74
+ }
75
+ );
76
+
77
+ // GET /users/:id - Get user by ID with param validation
78
+ users.get(
79
+ "/:id",
80
+ validate({ target: "param", schema: user_id_param_schema }),
81
+ (c) => {
82
+ const params = get_validated<z.infer<typeof user_id_param_schema>>(c, "param");
83
+
84
+ // Your database logic here
85
+ const user = {
86
+ id: params.id,
87
+ name: "John Doe",
88
+ email: "john@example.com",
89
+ };
90
+
91
+ return c.json(user);
92
+ }
93
+ );
94
+
95
+ // PATCH /users/:id - Update user with param + body validation
96
+ users.patch(
97
+ "/:id",
98
+ validate({ target: "param", schema: user_id_param_schema }),
99
+ validate({ target: "body", schema: update_user_schema }),
100
+ (c) => {
101
+ const params = get_validated<z.infer<typeof user_id_param_schema>>(c, "param");
102
+ const body = get_validated<z.infer<typeof update_user_schema>>(c, "body");
103
+
104
+ // Your database logic here
105
+ const updated_user = {
106
+ id: params.id,
107
+ ...body,
108
+ updated_at: new Date().toISOString(),
109
+ };
110
+
111
+ return c.json(updated_user);
112
+ }
113
+ );
114
+
115
+ // DELETE /users/:id
116
+ users.delete(
117
+ "/:id",
118
+ validate({ target: "param", schema: user_id_param_schema }),
119
+ (c) => {
120
+ const params = get_validated<z.infer<typeof user_id_param_schema>>(c, "param");
121
+
122
+ return c.json({
123
+ message: `User ${params.id} deleted successfully`,
124
+ });
125
+ }
126
+ );
127
+
128
+ export default users;
@@ -0,0 +1,126 @@
1
+ export interface CliFlags {
2
+ noGit: boolean;
3
+ noInstall: boolean;
4
+ default: boolean;
5
+ CI: boolean;
6
+
7
+ // Database flags
8
+ postgres?: boolean;
9
+ mysql?: boolean;
10
+ mongodb?: boolean;
11
+ redis?: boolean;
12
+
13
+ // Auth flags
14
+ jwt?: boolean;
15
+ oauth?: boolean;
16
+ session?: boolean;
17
+
18
+ // AI flags
19
+ openai?: boolean;
20
+ anthropic?: boolean;
21
+ gemini?: boolean;
22
+ vercelAI?: boolean;
23
+
24
+ // Cloud flags
25
+ aws?: boolean;
26
+ gcp?: boolean;
27
+ azure?: boolean;
28
+ cloudflareR2?: boolean;
29
+
30
+ // Communication flags
31
+ resend?: boolean;
32
+ sendgrid?: boolean;
33
+ nodemailer?: boolean;
34
+ socketio?: boolean;
35
+ sse?: boolean;
36
+
37
+ // Infrastructure flags
38
+ bullmq?: boolean;
39
+ inngest?: boolean;
40
+ upstashRateLimit?: boolean;
41
+ customRateLimit?: boolean;
42
+ sentry?: boolean;
43
+ logtail?: boolean;
44
+
45
+ // DevX flags
46
+ swagger?: boolean;
47
+ scalar?: boolean;
48
+ vitest?: boolean;
49
+
50
+ // Validation flags
51
+ zod?: boolean;
52
+ yup?: boolean;
53
+ }
54
+
55
+ export type Framework = "hono" | "express" | "bun-native";
56
+
57
+ export interface CliResults {
58
+ appName: string;
59
+ framework: Framework;
60
+ packages: AvailablePackages[];
61
+ flags: CliFlags;
62
+ }
63
+
64
+ export enum AvailablePackages {
65
+ // Core
66
+ postgres = "postgres",
67
+ mysql = "mysql",
68
+ mongodb = "mongodb",
69
+ redis = "redis",
70
+ jwt = "jwt",
71
+ oauth = "oauth",
72
+ session = "session",
73
+
74
+ // AI & ML
75
+ openai = "openai",
76
+ anthropic = "anthropic",
77
+ gemini = "gemini",
78
+ vercelAI = "vercel-ai",
79
+
80
+ // Cloud & Storage
81
+ aws = "aws",
82
+ gcp = "gcp",
83
+ azure = "azure",
84
+ cloudflareR2 = "cloudflare-r2",
85
+
86
+ // Communications
87
+ resend = "resend",
88
+ sendgrid = "sendgrid",
89
+ nodemailer = "nodemailer",
90
+ socketio = "socketio",
91
+ sse = "sse",
92
+
93
+ // Infrastructure
94
+ bullmq = "bullmq",
95
+ inngest = "inngest",
96
+ upstashRateLimit = "upstash-ratelimit",
97
+ customRateLimit = "custom-ratelimit",
98
+ sentry = "sentry",
99
+ logtail = "logtail",
100
+
101
+ // Developer Experience
102
+ swagger = "swagger",
103
+ scalar = "scalar",
104
+ vitest = "vitest",
105
+
106
+ // Validation
107
+ zod = "zod",
108
+ yup = "yup",
109
+ }
110
+
111
+ export interface InstallerOptions {
112
+ projectDir: string;
113
+ packages: AvailablePackages[];
114
+ appName: string;
115
+ framework: Framework;
116
+ noInstall: boolean;
117
+ }
118
+
119
+ export type Installer = (opts: InstallerOptions) => Promise<void>;
120
+
121
+ export interface PkgInstallerMap {
122
+ [key: string]: {
123
+ inUse: boolean;
124
+ installer: Installer;
125
+ };
126
+ }
@@ -0,0 +1,56 @@
1
+ import path from "path";
2
+ import fs from "fs-extra";
3
+
4
+ /**
5
+ * Adds dependencies to a project's package.json file.
6
+ * Reads the file, merges dependencies, sorts keys alphabetically, and writes back.
7
+ *
8
+ * @param projectDir - Absolute path to the project directory
9
+ * @param dependencies - Dependencies to add to the "dependencies" section
10
+ * @param devDependencies - Optional dev dependencies to add to "devDependencies" section
11
+ */
12
+ export async function add_package_dependency(
13
+ projectDir: string,
14
+ dependencies: Record<string, string>,
15
+ devDependencies?: Record<string, string>
16
+ ): Promise<void> {
17
+ const packageJsonPath = path.join(projectDir, "package.json");
18
+
19
+ // Read existing package.json
20
+ const packageJson = await fs.readJson(packageJsonPath);
21
+
22
+ // Merge dependencies
23
+ if (dependencies && Object.keys(dependencies).length > 0) {
24
+ packageJson.dependencies = {
25
+ ...packageJson.dependencies,
26
+ ...dependencies,
27
+ };
28
+
29
+ // Sort dependencies alphabetically
30
+ packageJson.dependencies = Object.keys(packageJson.dependencies)
31
+ .sort()
32
+ .reduce((acc: Record<string, string>, key: string) => {
33
+ acc[key] = packageJson.dependencies[key];
34
+ return acc;
35
+ }, {});
36
+ }
37
+
38
+ // Merge devDependencies
39
+ if (devDependencies && Object.keys(devDependencies).length > 0) {
40
+ packageJson.devDependencies = {
41
+ ...packageJson.devDependencies,
42
+ ...devDependencies,
43
+ };
44
+
45
+ // Sort devDependencies alphabetically
46
+ packageJson.devDependencies = Object.keys(packageJson.devDependencies)
47
+ .sort()
48
+ .reduce((acc: Record<string, string>, key: string) => {
49
+ acc[key] = packageJson.devDependencies[key];
50
+ return acc;
51
+ }, {});
52
+ }
53
+
54
+ // Write back to package.json with proper formatting
55
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
56
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Central registry mapping package names to their versions.
3
+ * Single source of truth for all dependency versions used in generated projects.
4
+ */
5
+ export const DEPENDENCY_VERSION_MAP: Record<string, string> = {
6
+ // Core Framework
7
+ "hono": "^4.0.0",
8
+ "express": "^4.18.2",
9
+ "@types/express": "^4.17.21",
10
+
11
+ // Database Drivers
12
+ "postgres": "^3.4.4",
13
+ "mysql2": "^3.9.0",
14
+ "mongoose": "^8.1.0",
15
+ "redis": "^4.6.12",
16
+
17
+ // ORM & Query Builders
18
+ "drizzle-orm": "^0.29.3",
19
+ "drizzle-kit": "^0.20.10",
20
+ "kysely": "^0.27.2",
21
+
22
+ // Authentication
23
+ "jsonwebtoken": "^9.0.2",
24
+ "@types/jsonwebtoken": "^9.0.5",
25
+ "bcryptjs": "^2.4.3",
26
+ "@types/bcryptjs": "^2.4.6",
27
+ "passport": "^0.7.0",
28
+ "passport-oauth2": "^1.8.0",
29
+ "@types/passport": "^1.0.16",
30
+
31
+ // AI Providers
32
+ "openai": "^4.26.0",
33
+ "@anthropic-ai/sdk": "^0.12.0",
34
+ "@google/generative-ai": "^0.1.3",
35
+ "ai": "^3.0.0",
36
+
37
+ // Cloud Storage
38
+ "@aws-sdk/client-s3": "^3.490.0",
39
+ "@aws-sdk/s3-request-presigner": "^3.490.0",
40
+ "@google-cloud/storage": "^7.7.0",
41
+ "@azure/storage-blob": "^12.17.0",
42
+ "@cloudflare/workers-types": "^4.20240117.0",
43
+
44
+ // Email Services
45
+ "resend": "^3.0.0",
46
+ "@sendgrid/mail": "^8.1.0",
47
+ "nodemailer": "^6.9.8",
48
+ "@types/nodemailer": "^6.4.14",
49
+
50
+ // Real-time Communication
51
+ "socket.io": "^4.6.1",
52
+ "@types/socket.io": "^3.0.0",
53
+
54
+ // Queue Systems
55
+ "bullmq": "^5.1.5",
56
+ "inngest": "^3.12.0",
57
+
58
+ // Rate Limiting
59
+ "@upstash/ratelimit": "^1.0.0",
60
+ "@upstash/redis": "^1.27.1",
61
+
62
+ // Observability
63
+ "@sentry/node": "^7.99.0",
64
+ "@logtail/node": "^0.4.13",
65
+
66
+ // API Documentation
67
+ "@hono/swagger": "^0.1.0",
68
+ "@scalar/hono-api-reference": "^0.5.0",
69
+
70
+ // Testing
71
+ "vitest": "^1.2.0",
72
+ "@vitest/ui": "^1.2.0",
73
+ "supertest": "^6.3.4",
74
+ "@types/supertest": "^6.0.2",
75
+
76
+ // Utilities
77
+ "zod": "^3.22.4",
78
+ "yup": "^1.3.3",
79
+ "dotenv": "^16.3.1",
80
+ "cors": "^2.8.5",
81
+ "@types/cors": "^2.8.17",
82
+ "helmet": "^7.1.0",
83
+ "compression": "^1.7.4",
84
+ "@types/compression": "^1.7.5",
85
+ };
@@ -0,0 +1,19 @@
1
+ import chalk from "chalk";
2
+
3
+ export const logger = {
4
+ error: (...args: unknown[]) => {
5
+ console.log(chalk.red(...args));
6
+ },
7
+ warn: (...args: unknown[]) => {
8
+ console.log(chalk.yellow(...args));
9
+ },
10
+ info: (...args: unknown[]) => {
11
+ console.log(chalk.cyan(...args));
12
+ },
13
+ success: (...args: unknown[]) => {
14
+ console.log(chalk.green(...args));
15
+ },
16
+ debug: (...args: unknown[]) => {
17
+ console.log(chalk.gray(...args));
18
+ },
19
+ };
@@ -0,0 +1,55 @@
1
+ import path from "path";
2
+
3
+ export interface ParsedNameAndPath {
4
+ projectName: string;
5
+ projectDir: string;
6
+ }
7
+
8
+ /**
9
+ * Parses the app name input to extract project name and directory path.
10
+ * Handles relative paths (./my-app), absolute paths, and simple names.
11
+ *
12
+ * @param appName - The app name or path provided by the user
13
+ * @returns Object containing projectName (kebab-case) and projectDir (absolute path)
14
+ * @throws Error if the name contains invalid characters (spaces, special chars except - and _)
15
+ */
16
+ export function parse_name_and_path(appName: string): ParsedNameAndPath {
17
+ // Validate app name - no spaces or invalid characters
18
+ // Allow only alphanumeric, hyphens, underscores, slashes, and dots (for paths)
19
+ const pathRegex = /^[a-zA-Z0-9\-_/.]+$/;
20
+ if (!pathRegex.test(appName)) {
21
+ throw new Error(
22
+ `Invalid app name: "${appName}". Use only letters, numbers, hyphens, and underscores.`
23
+ );
24
+ }
25
+
26
+ let projectDir: string;
27
+ let projectName: string;
28
+
29
+ // Check if it's a path (contains / or starts with . or ~)
30
+ if (appName.includes("/") || appName.startsWith(".") || appName.startsWith("~")) {
31
+ // It's a path - resolve it to absolute
32
+ projectDir = path.resolve(process.cwd(), appName);
33
+ // Extract the last segment as the project name
34
+ projectName = path.basename(projectDir);
35
+ } else {
36
+ // It's just a name - create in current directory
37
+ projectName = appName;
38
+ projectDir = path.resolve(process.cwd(), appName);
39
+ }
40
+
41
+ // Ensure project name is kebab-case (convert underscores to hyphens)
42
+ projectName = projectName.replace(/_/g, "-").toLowerCase();
43
+
44
+ // Additional validation - ensure name doesn't start/end with hyphen
45
+ if (projectName.startsWith("-") || projectName.endsWith("-")) {
46
+ throw new Error(
47
+ `Invalid app name: "${projectName}". Name cannot start or end with a hyphen.`
48
+ );
49
+ }
50
+
51
+ return {
52
+ projectName,
53
+ projectDir,
54
+ };
55
+ }
@@ -0,0 +1,11 @@
1
+ import chalk from "chalk";
2
+
3
+ /**
4
+ * Displays a styled section header in the terminal.
5
+ * Used to visually separate different stages of the CLI execution.
6
+ *
7
+ * @param title - The title text to display
8
+ */
9
+ export function render_title(title: string): void {
10
+ console.log("\n" + chalk.bold.cyan(`▸ ${title}`));
11
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": [
6
+ "ES2022"
7
+ ],
8
+ "moduleResolution": "bundler",
9
+ "allowImportingTsExtensions": true,
10
+ "noEmit": true,
11
+ "composite": false,
12
+ "strict": true,
13
+ "downlevelIteration": true,
14
+ "skipLibCheck": true,
15
+ "jsx": "preserve",
16
+ "allowSyntheticDefaultImports": true,
17
+ "forceConsistentCasingInFileNames": true,
18
+ "allowJs": true,
19
+ "types": [
20
+ "bun-types"
21
+ ],
22
+ "esModuleInterop": true,
23
+ "resolveJsonModule": true,
24
+ "isolatedModules": true,
25
+ "outDir": "dist",
26
+ "rootDir": "src"
27
+ },
28
+ "include": [
29
+ "src/**/*"
30
+ ],
31
+ "exclude": [
32
+ "node_modules",
33
+ "dist"
34
+ ]
35
+ }
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "deploy-bbc",
3
+ "version": "0.0.1",
4
+ "description": "CLI to bootstrap production-ready backends with Bun (Best Backend Code)",
5
+ "workspaces": [
6
+ "cli"
7
+ ],
8
+ "scripts": {
9
+ "dev": "bun --watch cli/src/index.ts",
10
+ "build": "cd cli && bun run build",
11
+ "lint": "eslint . --ext .ts",
12
+ "format": "prettier --write \"**/*.{ts,json,md}\""
13
+ },
14
+ "devDependencies": {
15
+ "@types/bun": "latest",
16
+ "bun-types": "^1.3.7",
17
+ "prettier": "^3.1.1",
18
+ "typescript": "^5.3.3"
19
+ }
20
+ }
File without changes
package/test-cli.sh ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Test script for deploy-bbc CLI
4
+
5
+ echo "🧪 Testing deploy-bbc CLI..."
6
+ echo ""
7
+
8
+ # Test 1: Minimal setup
9
+ echo "Test 1: Minimal setup (postgres + jwt)"
10
+ cd /tmp
11
+ bun ~/Documents/cli/cli/src/index.ts test-minimal --CI --postgres --jwt --noInstall --noGit
12
+ echo "✅ Test 1 passed"
13
+ echo ""
14
+
15
+ # Test 2: Full stack with AI
16
+ echo "Test 2: Full stack (postgres, redis, jwt, openai, vercel-ai)"
17
+ cd /tmp
18
+ bun ~/Documents/cli/cli/src/index.ts test-fullstack --CI \
19
+ --postgres --redis \
20
+ --jwt --session \
21
+ --openai --anthropic --vercelAI \
22
+ --resend \
23
+ --bullmq \
24
+ --swagger --vitest \
25
+ --noInstall --noGit
26
+ echo "✅ Test 2 passed"
27
+ echo ""
28
+
29
+ # Test 3: MongoDB + OAuth
30
+ echo "Test 3: MongoDB + OAuth setup"
31
+ cd /tmp
32
+ bun ~/Documents/cli/cli/src/index.ts test-mongo --CI \
33
+ --mongodb \
34
+ --oauth \
35
+ --socketio \
36
+ --scalar \
37
+ --noInstall --noGit
38
+ echo "✅ Test 3 passed"
39
+ echo ""
40
+
41
+ # Test 4: Cloud services
42
+ echo "Test 4: Cloud services (AWS, GCP, Azure)"
43
+ cd /tmp
44
+ bun ~/Documents/cli/cli/src/index.ts test-cloud --CI \
45
+ --postgres \
46
+ --jwt \
47
+ --aws --gcp --azure --cloudflareR2 \
48
+ --sentry \
49
+ --noInstall --noGit
50
+ echo "✅ Test 4 passed"
51
+ echo ""
52
+
53
+ echo "✨ All tests completed successfully!"
54
+ echo ""
55
+ echo "To test interactively, run:"
56
+ echo " cd /tmp && bun ~/Documents/cli/cli/src/index.ts my-project"
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": [
6
+ "ES2022"
7
+ ],
8
+ "moduleResolution": "bundler",
9
+ "strict": true,
10
+ "skipLibCheck": true,
11
+ "types": [
12
+ "bun-types"
13
+ ]
14
+ }
15
+ }