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.
- package/CLAUDE.md +329 -0
- package/README.md +0 -0
- package/cli/README.md +0 -0
- package/cli/package.json +43 -0
- package/cli/src/cli/index.ts +449 -0
- package/cli/src/helpers/create-project.ts +66 -0
- package/cli/src/helpers/generate-docker-compose.ts +133 -0
- package/cli/src/helpers/generate-dockerfile.ts +45 -0
- package/cli/src/helpers/init-git.ts +33 -0
- package/cli/src/helpers/install-dependencies.ts +28 -0
- package/cli/src/helpers/log-next-steps.ts +84 -0
- package/cli/src/helpers/scaffold-project.ts +62 -0
- package/cli/src/index.ts +18 -0
- package/cli/src/installers/ai.ts +123 -0
- package/cli/src/installers/auth.ts +132 -0
- package/cli/src/installers/base.ts +16 -0
- package/cli/src/installers/cloud.ts +127 -0
- package/cli/src/installers/database.ts +212 -0
- package/cli/src/installers/docs.ts +93 -0
- package/cli/src/installers/email.ts +119 -0
- package/cli/src/installers/env-variables.ts +27 -0
- package/cli/src/installers/index.ts +145 -0
- package/cli/src/installers/observability.ts +103 -0
- package/cli/src/installers/queue.ts +103 -0
- package/cli/src/installers/ratelimit.ts +98 -0
- package/cli/src/installers/realtime.ts +79 -0
- package/cli/src/installers/testing.ts +88 -0
- package/cli/src/installers/validation.ts +85 -0
- package/cli/src/templates/base/.env.example +3 -0
- package/cli/src/templates/base/README.md +31 -0
- package/cli/src/templates/base/package.json +20 -0
- package/cli/src/templates/base/src/config/index.ts +8 -0
- package/cli/src/templates/base/src/index.ts +26 -0
- package/cli/src/templates/base/src/middleware/error.ts +13 -0
- package/cli/src/templates/base/src/middleware/logger.ts +8 -0
- package/cli/src/templates/base/src/routes/index.ts +12 -0
- package/cli/src/templates/base/src/types/index.ts +2 -0
- package/cli/src/templates/base/src/utils/env.ts +5 -0
- package/cli/src/templates/base/tsconfig.json +20 -0
- package/cli/src/templates/base-bun-native/.env.example +3 -0
- package/cli/src/templates/base-bun-native/README.md +31 -0
- package/cli/src/templates/base-bun-native/package.json +19 -0
- package/cli/src/templates/base-bun-native/src/config/index.ts +8 -0
- package/cli/src/templates/base-bun-native/src/index.ts +50 -0
- package/cli/src/templates/base-bun-native/src/middleware/error.ts +20 -0
- package/cli/src/templates/base-bun-native/src/middleware/logger.ts +6 -0
- package/cli/src/templates/base-bun-native/src/routes/index.ts +21 -0
- package/cli/src/templates/base-bun-native/src/types/index.ts +2 -0
- package/cli/src/templates/base-bun-native/src/utils/env.ts +5 -0
- package/cli/src/templates/base-bun-native/tsconfig.json +20 -0
- package/cli/src/templates/base-express/.env.example +3 -0
- package/cli/src/templates/base-express/README.md +31 -0
- package/cli/src/templates/base-express/package.json +21 -0
- package/cli/src/templates/base-express/src/config/index.ts +8 -0
- package/cli/src/templates/base-express/src/index.ts +27 -0
- package/cli/src/templates/base-express/src/middleware/error.ts +15 -0
- package/cli/src/templates/base-express/src/middleware/logger.ts +12 -0
- package/cli/src/templates/base-express/src/routes/index.ts +12 -0
- package/cli/src/templates/base-express/src/types/index.ts +2 -0
- package/cli/src/templates/base-express/src/utils/env.ts +5 -0
- package/cli/src/templates/base-express/tsconfig.json +20 -0
- package/cli/src/templates/extras/ai/anthropic/src/routes/ai/claude.ts +0 -0
- package/cli/src/templates/extras/ai/anthropic/src/services/ai/anthropic.ts +0 -0
- package/cli/src/templates/extras/ai/gemini/src/services/ai/gemini.ts +0 -0
- package/cli/src/templates/extras/ai/openai/src/routes/ai/chat.ts +0 -0
- package/cli/src/templates/extras/ai/openai/src/services/ai/openai.ts +0 -0
- package/cli/src/templates/extras/ai/vercel-ai/src/routes/ai/generate.ts +0 -0
- package/cli/src/templates/extras/ai/vercel-ai/src/routes/ai/stream.ts +0 -0
- package/cli/src/templates/extras/ai/vercel-ai/src/services/ai/index.ts +0 -0
- package/cli/src/templates/extras/auth/jwt/src/middleware/auth.ts +0 -0
- package/cli/src/templates/extras/auth/jwt/src/routes/auth.ts +0 -0
- package/cli/src/templates/extras/auth/jwt/src/utils/jwt.ts +0 -0
- package/cli/src/templates/extras/auth/oauth/src/config/oauth.ts +0 -0
- package/cli/src/templates/extras/auth/oauth/src/routes/auth.ts +0 -0
- package/cli/src/templates/extras/auth/session/src/config/session.ts +0 -0
- package/cli/src/templates/extras/auth/session/src/middleware/session.ts +0 -0
- package/cli/src/templates/extras/cloud/aws/src/services/aws/s3.ts +0 -0
- package/cli/src/templates/extras/cloud/aws/src/services/aws/ses.ts +0 -0
- package/cli/src/templates/extras/cloud/azure/src/services/azure/blob.ts +0 -0
- package/cli/src/templates/extras/cloud/cloudflare-r2/src/services/cloudflare/r2.ts +0 -0
- package/cli/src/templates/extras/cloud/gcp/src/services/gcp/storage.ts +0 -0
- package/cli/src/templates/extras/database/mongodb/src/db/index.ts +0 -0
- package/cli/src/templates/extras/database/mongodb/src/db/models/user.model.ts +0 -0
- package/cli/src/templates/extras/database/mysql/drizzle.config.ts +0 -0
- package/cli/src/templates/extras/database/postgres/src/db/index.ts +0 -0
- package/cli/src/templates/extras/database/redis/src/db/redis.ts +0 -0
- package/cli/src/templates/extras/docs/scalar/src/openapi/index.ts +0 -0
- package/cli/src/templates/extras/docs/scalar/src/routes/docs.ts +0 -0
- package/cli/src/templates/extras/docs/swagger/src/openapi/index.ts +0 -0
- package/cli/src/templates/extras/docs/swagger/src/routes/docs.ts +0 -0
- package/cli/src/templates/extras/email/nodemailer/src/services/email/nodemailer.ts +0 -0
- package/cli/src/templates/extras/email/resend/src/services/email/resend.ts +0 -0
- package/cli/src/templates/extras/email/resend/src/templates/email/welcome.ts +0 -0
- package/cli/src/templates/extras/email/sendgrid/src/services/email/sendgrid.ts +0 -0
- package/cli/src/templates/extras/observability/logtail/src/config/logger.ts +0 -0
- package/cli/src/templates/extras/observability/sentry/src/config/sentry.ts +0 -0
- package/cli/src/templates/extras/observability/sentry/src/middleware/sentry.ts +0 -0
- package/cli/src/templates/extras/queue/bullmq/src/queue/index.ts +0 -0
- package/cli/src/templates/extras/queue/bullmq/src/queue/jobs/email.job.ts +0 -0
- package/cli/src/templates/extras/queue/bullmq/src/queue/processors/email.processor.ts +0 -0
- package/cli/src/templates/extras/queue/bullmq/src/routes/queue.ts +0 -0
- package/cli/src/templates/extras/queue/inngest/src/inngest/client.ts +0 -0
- package/cli/src/templates/extras/queue/inngest/src/inngest/functions/email.ts +0 -0
- package/cli/src/templates/extras/queue/inngest/src/routes/inngest.ts +0 -0
- package/cli/src/templates/extras/realtime/socketio/src/socket/handlers.ts +0 -0
- package/cli/src/templates/extras/realtime/socketio/src/socket/index.ts +0 -0
- package/cli/src/templates/extras/realtime/sse/src/routes/sse.ts +0 -0
- package/cli/src/templates/extras/testing/vitest/src/__tests__/example.test.ts +0 -0
- package/cli/src/templates/extras/testing/vitest/src/__tests__/setup.ts +0 -0
- package/cli/src/templates/extras/testing/vitest/vitest.config.ts +0 -0
- package/cli/src/templates/extras/validation/yup/src/middleware/index.ts +1 -0
- package/cli/src/templates/extras/validation/yup/src/middleware/validate.ts +83 -0
- package/cli/src/templates/extras/validation/yup/src/routes/users.ts +132 -0
- package/cli/src/templates/extras/validation/zod/src/middleware/index.ts +1 -0
- package/cli/src/templates/extras/validation/zod/src/middleware/validate.ts +80 -0
- package/cli/src/templates/extras/validation/zod/src/routes/users.ts +128 -0
- package/cli/src/types/index.ts +126 -0
- package/cli/src/utils/add-package-dependency.ts +56 -0
- package/cli/src/utils/dependency-version-map.ts +85 -0
- package/cli/src/utils/logger.ts +19 -0
- package/cli/src/utils/parse-name-and-path.ts +55 -0
- package/cli/src/utils/render-title.ts +11 -0
- package/cli/tsconfig.json +35 -0
- package/package.json +20 -0
- package/prettier.config.mjs +0 -0
- package/test-cli.sh +56 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { type InstallerOptions, AvailablePackages } from "../types/index.js";
|
|
5
|
+
import { add_package_dependency } from "../utils/add-package-dependency.js";
|
|
6
|
+
import { DEPENDENCY_VERSION_MAP } from "../utils/dependency-version-map.js";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Queue installer - handles BullMQ and Inngest.
|
|
13
|
+
*
|
|
14
|
+
* @param options - Installer options with selected packages
|
|
15
|
+
*/
|
|
16
|
+
export async function queue_installer(
|
|
17
|
+
options: InstallerOptions
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
const { projectDir, packages } = options;
|
|
20
|
+
|
|
21
|
+
for (const pkg of packages) {
|
|
22
|
+
switch (pkg) {
|
|
23
|
+
case AvailablePackages.bullmq:
|
|
24
|
+
await install_bullmq(projectDir);
|
|
25
|
+
break;
|
|
26
|
+
case AvailablePackages.inngest:
|
|
27
|
+
await install_inngest(projectDir);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function install_bullmq(projectDir: string): Promise<void> {
|
|
34
|
+
const templateDir = path.resolve(
|
|
35
|
+
__dirname,
|
|
36
|
+
"../templates/extras/queue/bullmq"
|
|
37
|
+
);
|
|
38
|
+
await copy_template_files(templateDir, projectDir);
|
|
39
|
+
|
|
40
|
+
await add_package_dependency(projectDir, {
|
|
41
|
+
bullmq: DEPENDENCY_VERSION_MAP["bullmq"],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await append_env_example(
|
|
45
|
+
projectDir,
|
|
46
|
+
"\n# BullMQ Configuration\nREDIS_HOST=localhost\nREDIS_PORT=6379\nREDIS_PASSWORD=\n"
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function install_inngest(projectDir: string): Promise<void> {
|
|
51
|
+
const templateDir = path.resolve(
|
|
52
|
+
__dirname,
|
|
53
|
+
"../templates/extras/queue/inngest"
|
|
54
|
+
);
|
|
55
|
+
await copy_template_files(templateDir, projectDir);
|
|
56
|
+
|
|
57
|
+
await add_package_dependency(projectDir, {
|
|
58
|
+
inngest: DEPENDENCY_VERSION_MAP["inngest"],
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
await append_env_example(
|
|
62
|
+
projectDir,
|
|
63
|
+
"\n# Inngest Configuration\nINNGEST_EVENT_KEY=your-inngest-event-key\nINNGEST_SIGNING_KEY=your-inngest-signing-key\n"
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function copy_template_files(
|
|
68
|
+
templateDir: string,
|
|
69
|
+
projectDir: string
|
|
70
|
+
): Promise<void> {
|
|
71
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const srcDir = path.join(templateDir, "src");
|
|
76
|
+
if (await fs.pathExists(srcDir)) {
|
|
77
|
+
const targetSrcDir = path.join(projectDir, "src");
|
|
78
|
+
await fs.copy(srcDir, targetSrcDir, {
|
|
79
|
+
overwrite: false,
|
|
80
|
+
errorOnExist: false,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const templateFiles = await fs.readdir(templateDir);
|
|
85
|
+
for (const file of templateFiles) {
|
|
86
|
+
if (file !== "src" && (file.endsWith(".ts") || file.endsWith(".json"))) {
|
|
87
|
+
const srcFile = path.join(templateDir, file);
|
|
88
|
+
const destFile = path.join(projectDir, file);
|
|
89
|
+
|
|
90
|
+
if (!(await fs.pathExists(destFile))) {
|
|
91
|
+
await fs.copy(srcFile, destFile);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function append_env_example(
|
|
98
|
+
projectDir: string,
|
|
99
|
+
content: string
|
|
100
|
+
): Promise<void> {
|
|
101
|
+
const envPath = path.join(projectDir, ".env.example");
|
|
102
|
+
await fs.appendFile(envPath, content);
|
|
103
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { type InstallerOptions, AvailablePackages } from "../types/index.js";
|
|
5
|
+
import { add_package_dependency } from "../utils/add-package-dependency.js";
|
|
6
|
+
import { DEPENDENCY_VERSION_MAP } from "../utils/dependency-version-map.js";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Rate limit installer - handles Upstash Rate Limit and custom rate limiting.
|
|
13
|
+
*
|
|
14
|
+
* @param options - Installer options with selected packages
|
|
15
|
+
*/
|
|
16
|
+
export async function ratelimit_installer(
|
|
17
|
+
options: InstallerOptions
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
const { projectDir, packages } = options;
|
|
20
|
+
|
|
21
|
+
for (const pkg of packages) {
|
|
22
|
+
switch (pkg) {
|
|
23
|
+
case AvailablePackages.upstashRateLimit:
|
|
24
|
+
await install_upstash_ratelimit(projectDir);
|
|
25
|
+
break;
|
|
26
|
+
case AvailablePackages.customRateLimit:
|
|
27
|
+
await install_custom_ratelimit(projectDir);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function install_upstash_ratelimit(projectDir: string): Promise<void> {
|
|
34
|
+
const templateDir = path.resolve(
|
|
35
|
+
__dirname,
|
|
36
|
+
"../templates/extras/ratelimit/upstash"
|
|
37
|
+
);
|
|
38
|
+
await copy_template_files(templateDir, projectDir);
|
|
39
|
+
|
|
40
|
+
await add_package_dependency(projectDir, {
|
|
41
|
+
"@upstash/ratelimit": DEPENDENCY_VERSION_MAP["@upstash/ratelimit"],
|
|
42
|
+
"@upstash/redis": DEPENDENCY_VERSION_MAP["@upstash/redis"],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await append_env_example(
|
|
46
|
+
projectDir,
|
|
47
|
+
"\n# Upstash Rate Limit Configuration\nUPSTASH_REDIS_REST_URL=your-upstash-redis-rest-url\nUPSTASH_REDIS_REST_TOKEN=your-upstash-redis-rest-token\n"
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function install_custom_ratelimit(projectDir: string): Promise<void> {
|
|
52
|
+
const templateDir = path.resolve(
|
|
53
|
+
__dirname,
|
|
54
|
+
"../templates/extras/ratelimit/custom"
|
|
55
|
+
);
|
|
56
|
+
await copy_template_files(templateDir, projectDir);
|
|
57
|
+
|
|
58
|
+
// Custom rate limit doesn't require external dependencies
|
|
59
|
+
// It uses built-in Hono middleware or custom implementation
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function copy_template_files(
|
|
63
|
+
templateDir: string,
|
|
64
|
+
projectDir: string
|
|
65
|
+
): Promise<void> {
|
|
66
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const srcDir = path.join(templateDir, "src");
|
|
71
|
+
if (await fs.pathExists(srcDir)) {
|
|
72
|
+
const targetSrcDir = path.join(projectDir, "src");
|
|
73
|
+
await fs.copy(srcDir, targetSrcDir, {
|
|
74
|
+
overwrite: false,
|
|
75
|
+
errorOnExist: false,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const templateFiles = await fs.readdir(templateDir);
|
|
80
|
+
for (const file of templateFiles) {
|
|
81
|
+
if (file !== "src" && (file.endsWith(".ts") || file.endsWith(".json"))) {
|
|
82
|
+
const srcFile = path.join(templateDir, file);
|
|
83
|
+
const destFile = path.join(projectDir, file);
|
|
84
|
+
|
|
85
|
+
if (!(await fs.pathExists(destFile))) {
|
|
86
|
+
await fs.copy(srcFile, destFile);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function append_env_example(
|
|
93
|
+
projectDir: string,
|
|
94
|
+
content: string
|
|
95
|
+
): Promise<void> {
|
|
96
|
+
const envPath = path.join(projectDir, ".env.example");
|
|
97
|
+
await fs.appendFile(envPath, content);
|
|
98
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { type InstallerOptions, AvailablePackages } from "../types/index.js";
|
|
5
|
+
import { add_package_dependency } from "../utils/add-package-dependency.js";
|
|
6
|
+
import { DEPENDENCY_VERSION_MAP } from "../utils/dependency-version-map.js";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Realtime installer - handles Socket.IO and Server-Sent Events (SSE).
|
|
13
|
+
*
|
|
14
|
+
* @param options - Installer options with selected packages
|
|
15
|
+
*/
|
|
16
|
+
export async function realtime_installer(
|
|
17
|
+
options: InstallerOptions
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
const { projectDir, packages } = options;
|
|
20
|
+
|
|
21
|
+
for (const pkg of packages) {
|
|
22
|
+
switch (pkg) {
|
|
23
|
+
case AvailablePackages.socketio:
|
|
24
|
+
await install_socketio(projectDir);
|
|
25
|
+
break;
|
|
26
|
+
case AvailablePackages.sse:
|
|
27
|
+
await install_sse(projectDir);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function install_socketio(projectDir: string): Promise<void> {
|
|
34
|
+
const templateDir = path.resolve(
|
|
35
|
+
__dirname,
|
|
36
|
+
"../templates/extras/realtime/socketio"
|
|
37
|
+
);
|
|
38
|
+
await copy_template_files(templateDir, projectDir);
|
|
39
|
+
|
|
40
|
+
await add_package_dependency(projectDir, {
|
|
41
|
+
"socket.io": DEPENDENCY_VERSION_MAP["socket.io"],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await add_package_dependency(
|
|
45
|
+
projectDir,
|
|
46
|
+
{},
|
|
47
|
+
{
|
|
48
|
+
"@types/socket.io": DEPENDENCY_VERSION_MAP["@types/socket.io"],
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function install_sse(projectDir: string): Promise<void> {
|
|
54
|
+
const templateDir = path.resolve(
|
|
55
|
+
__dirname,
|
|
56
|
+
"../templates/extras/realtime/sse"
|
|
57
|
+
);
|
|
58
|
+
await copy_template_files(templateDir, projectDir);
|
|
59
|
+
|
|
60
|
+
// SSE has no external dependencies, it's a native web standard
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function copy_template_files(
|
|
64
|
+
templateDir: string,
|
|
65
|
+
projectDir: string
|
|
66
|
+
): Promise<void> {
|
|
67
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const srcDir = path.join(templateDir, "src");
|
|
72
|
+
if (await fs.pathExists(srcDir)) {
|
|
73
|
+
const targetSrcDir = path.join(projectDir, "src");
|
|
74
|
+
await fs.copy(srcDir, targetSrcDir, {
|
|
75
|
+
overwrite: false,
|
|
76
|
+
errorOnExist: false,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { type InstallerOptions, AvailablePackages } from "../types/index.js";
|
|
5
|
+
import { add_package_dependency } from "../utils/add-package-dependency.js";
|
|
6
|
+
import { DEPENDENCY_VERSION_MAP } from "../utils/dependency-version-map.js";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Testing installer - handles Vitest testing framework.
|
|
13
|
+
*
|
|
14
|
+
* @param options - Installer options with selected packages
|
|
15
|
+
*/
|
|
16
|
+
export async function testing_installer(
|
|
17
|
+
options: InstallerOptions
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
const { projectDir, packages } = options;
|
|
20
|
+
|
|
21
|
+
for (const pkg of packages) {
|
|
22
|
+
switch (pkg) {
|
|
23
|
+
case AvailablePackages.vitest:
|
|
24
|
+
await install_vitest(projectDir);
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function install_vitest(projectDir: string): Promise<void> {
|
|
31
|
+
const templateDir = path.resolve(
|
|
32
|
+
__dirname,
|
|
33
|
+
"../templates/extras/testing/vitest"
|
|
34
|
+
);
|
|
35
|
+
await copy_template_files(templateDir, projectDir);
|
|
36
|
+
|
|
37
|
+
await add_package_dependency(projectDir, {
|
|
38
|
+
vitest: DEPENDENCY_VERSION_MAP["vitest"],
|
|
39
|
+
"@vitest/ui": DEPENDENCY_VERSION_MAP["@vitest/ui"],
|
|
40
|
+
supertest: DEPENDENCY_VERSION_MAP["supertest"],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await add_package_dependency(
|
|
44
|
+
projectDir,
|
|
45
|
+
{},
|
|
46
|
+
{
|
|
47
|
+
"@types/supertest": DEPENDENCY_VERSION_MAP["@types/supertest"],
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function copy_template_files(
|
|
53
|
+
templateDir: string,
|
|
54
|
+
projectDir: string
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const srcDir = path.join(templateDir, "src");
|
|
61
|
+
if (await fs.pathExists(srcDir)) {
|
|
62
|
+
const targetSrcDir = path.join(projectDir, "src");
|
|
63
|
+
await fs.copy(srcDir, targetSrcDir, {
|
|
64
|
+
overwrite: false,
|
|
65
|
+
errorOnExist: false,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const templateFiles = await fs.readdir(templateDir);
|
|
70
|
+
for (const file of templateFiles) {
|
|
71
|
+
if (file !== "src" && (file.endsWith(".ts") || file.endsWith(".json"))) {
|
|
72
|
+
const srcFile = path.join(templateDir, file);
|
|
73
|
+
const destFile = path.join(projectDir, file);
|
|
74
|
+
|
|
75
|
+
if (!(await fs.pathExists(destFile))) {
|
|
76
|
+
await fs.copy(srcFile, destFile);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function append_env_example(
|
|
83
|
+
projectDir: string,
|
|
84
|
+
content: string
|
|
85
|
+
): Promise<void> {
|
|
86
|
+
const envPath = path.join(projectDir, ".env.example");
|
|
87
|
+
await fs.appendFile(envPath, content);
|
|
88
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { type InstallerOptions, AvailablePackages } from "../types/index.js";
|
|
5
|
+
import { add_package_dependency } from "../utils/add-package-dependency.js";
|
|
6
|
+
import { DEPENDENCY_VERSION_MAP } from "../utils/dependency-version-map.js";
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Validation installer - handles Zod and Yup validation libraries.
|
|
13
|
+
*
|
|
14
|
+
* @param options - Installer options with selected packages
|
|
15
|
+
*/
|
|
16
|
+
export async function validation_installer(
|
|
17
|
+
options: InstallerOptions
|
|
18
|
+
): Promise<void> {
|
|
19
|
+
const { projectDir, packages } = options;
|
|
20
|
+
|
|
21
|
+
for (const pkg of packages) {
|
|
22
|
+
switch (pkg) {
|
|
23
|
+
case AvailablePackages.zod:
|
|
24
|
+
await install_zod(projectDir);
|
|
25
|
+
break;
|
|
26
|
+
case AvailablePackages.yup:
|
|
27
|
+
await install_yup(projectDir);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function install_zod(projectDir: string): Promise<void> {
|
|
34
|
+
const templateDir = path.resolve(
|
|
35
|
+
__dirname,
|
|
36
|
+
"../templates/extras/validation/zod"
|
|
37
|
+
);
|
|
38
|
+
await copy_template_files(templateDir, projectDir);
|
|
39
|
+
|
|
40
|
+
await add_package_dependency(projectDir, {
|
|
41
|
+
zod: DEPENDENCY_VERSION_MAP["zod"],
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function install_yup(projectDir: string): Promise<void> {
|
|
46
|
+
const templateDir = path.resolve(
|
|
47
|
+
__dirname,
|
|
48
|
+
"../templates/extras/validation/yup"
|
|
49
|
+
);
|
|
50
|
+
await copy_template_files(templateDir, projectDir);
|
|
51
|
+
|
|
52
|
+
await add_package_dependency(projectDir, {
|
|
53
|
+
yup: DEPENDENCY_VERSION_MAP["yup"],
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function copy_template_files(
|
|
58
|
+
templateDir: string,
|
|
59
|
+
projectDir: string
|
|
60
|
+
): Promise<void> {
|
|
61
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const srcDir = path.join(templateDir, "src");
|
|
66
|
+
if (await fs.pathExists(srcDir)) {
|
|
67
|
+
const targetSrcDir = path.join(projectDir, "src");
|
|
68
|
+
await fs.copy(srcDir, targetSrcDir, {
|
|
69
|
+
overwrite: false,
|
|
70
|
+
errorOnExist: false,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const templateFiles = await fs.readdir(templateDir);
|
|
75
|
+
for (const file of templateFiles) {
|
|
76
|
+
if (file !== "src" && (file.endsWith(".ts") || file.endsWith(".json"))) {
|
|
77
|
+
const srcFile = path.join(templateDir, file);
|
|
78
|
+
const destFile = path.join(projectDir, file);
|
|
79
|
+
|
|
80
|
+
if (!(await fs.pathExists(destFile))) {
|
|
81
|
+
await fs.copy(srcFile, destFile);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# My Backend App
|
|
2
|
+
|
|
3
|
+
Production-ready Bun backend with TypeScript and Hono.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies
|
|
9
|
+
bun install
|
|
10
|
+
|
|
11
|
+
# Copy environment variables
|
|
12
|
+
cp .env.example .env
|
|
13
|
+
|
|
14
|
+
# Run development server
|
|
15
|
+
bun run dev
|
|
16
|
+
|
|
17
|
+
# Build for production
|
|
18
|
+
bun run build
|
|
19
|
+
|
|
20
|
+
# Run production server
|
|
21
|
+
bun run start
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## API Endpoints
|
|
25
|
+
|
|
26
|
+
- `GET /` - Welcome message
|
|
27
|
+
- `GET /health` - Health check
|
|
28
|
+
|
|
29
|
+
## Documentation
|
|
30
|
+
|
|
31
|
+
Visit `/docs` for API documentation (if Swagger/Scalar is installed).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-backend-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Production-ready Bun backend with TypeScript",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "bun --watch src/index.ts",
|
|
8
|
+
"start": "bun src/index.ts",
|
|
9
|
+
"build": "bun build src/index.ts --outdir dist --target bun",
|
|
10
|
+
"type-check": "tsc --noEmit"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"hono": "^4.0.0",
|
|
14
|
+
"dotenv": "^16.3.1"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/bun": "latest",
|
|
18
|
+
"typescript": "^5.3.3"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { logger as loggerMiddleware } from "./middleware/logger.js";
|
|
3
|
+
import { errorHandler } from "./middleware/error.js";
|
|
4
|
+
import routes from "./routes/index.js";
|
|
5
|
+
import { config } from "./config/index.js";
|
|
6
|
+
|
|
7
|
+
const app = new Hono();
|
|
8
|
+
|
|
9
|
+
// Middleware
|
|
10
|
+
app.use("*", loggerMiddleware);
|
|
11
|
+
app.onError(errorHandler);
|
|
12
|
+
|
|
13
|
+
// Routes
|
|
14
|
+
app.route("/", routes);
|
|
15
|
+
|
|
16
|
+
// Health check
|
|
17
|
+
app.get("/health", (c) => {
|
|
18
|
+
return c.json({ status: "ok", timestamp: new Date().toISOString() });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
console.log(`🚀 Server running on http://localhost:${config.port}`);
|
|
22
|
+
|
|
23
|
+
export default {
|
|
24
|
+
port: config.port,
|
|
25
|
+
fetch: app.fetch,
|
|
26
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ErrorHandler } from "hono";
|
|
2
|
+
|
|
3
|
+
export const errorHandler: ErrorHandler = (err, c) => {
|
|
4
|
+
console.error(`Error: ${err.message}`, err);
|
|
5
|
+
|
|
6
|
+
return c.json(
|
|
7
|
+
{
|
|
8
|
+
error: err.message || "Internal Server Error",
|
|
9
|
+
status: err.status || 500,
|
|
10
|
+
},
|
|
11
|
+
err.status || 500
|
|
12
|
+
);
|
|
13
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from "hono";
|
|
2
|
+
|
|
3
|
+
export const logger: MiddlewareHandler = async (c, next) => {
|
|
4
|
+
const start = Date.now();
|
|
5
|
+
await next();
|
|
6
|
+
const ms = Date.now() - start;
|
|
7
|
+
console.log(`${c.req.method} ${c.req.url} - ${c.res.status} (${ms}ms)`);
|
|
8
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ESNext"],
|
|
7
|
+
"types": ["bun-types"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"outDir": "./dist",
|
|
16
|
+
"rootDir": "./src"
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# My Backend App
|
|
2
|
+
|
|
3
|
+
Production-ready Bun backend with TypeScript and Hono.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies
|
|
9
|
+
bun install
|
|
10
|
+
|
|
11
|
+
# Copy environment variables
|
|
12
|
+
cp .env.example .env
|
|
13
|
+
|
|
14
|
+
# Run development server
|
|
15
|
+
bun run dev
|
|
16
|
+
|
|
17
|
+
# Build for production
|
|
18
|
+
bun run build
|
|
19
|
+
|
|
20
|
+
# Run production server
|
|
21
|
+
bun run start
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## API Endpoints
|
|
25
|
+
|
|
26
|
+
- `GET /` - Welcome message
|
|
27
|
+
- `GET /health` - Health check
|
|
28
|
+
|
|
29
|
+
## Documentation
|
|
30
|
+
|
|
31
|
+
Visit `/docs` for API documentation (if Swagger/Scalar is installed).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-backend-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Production-ready backend with Bun native HTTP server",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "bun --watch src/index.ts",
|
|
8
|
+
"start": "bun src/index.ts",
|
|
9
|
+
"build": "bun build src/index.ts --outdir dist --target bun",
|
|
10
|
+
"type-check": "tsc --noEmit"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"dotenv": "^16.3.1"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/bun": "latest",
|
|
17
|
+
"typescript": "^5.3.3"
|
|
18
|
+
}
|
|
19
|
+
}
|