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,33 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initializes a Git repository and creates an initial commit.
|
|
6
|
+
* Does not throw on failure - git is optional.
|
|
7
|
+
*
|
|
8
|
+
* @param projectDir - Absolute path to the project directory
|
|
9
|
+
*/
|
|
10
|
+
export async function init_git(projectDir: string): Promise<void> {
|
|
11
|
+
try {
|
|
12
|
+
// Initialize git repository
|
|
13
|
+
await execa("git", ["init"], { cwd: projectDir });
|
|
14
|
+
|
|
15
|
+
// Add all files
|
|
16
|
+
await execa("git", ["add", "."], { cwd: projectDir });
|
|
17
|
+
|
|
18
|
+
// Create initial commit
|
|
19
|
+
await execa(
|
|
20
|
+
"git",
|
|
21
|
+
["commit", "-m", "Initial commit from deploy-bbc"],
|
|
22
|
+
{ cwd: projectDir }
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
console.log(chalk.green("✓") + " Git repository initialized");
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// Git initialization is optional, so just warn on failure
|
|
28
|
+
console.log(
|
|
29
|
+
chalk.yellow("⚠") +
|
|
30
|
+
" Git initialization failed (this is optional and can be done manually)"
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Installs project dependencies using Bun package manager.
|
|
6
|
+
* Runs `bun install` in the project directory.
|
|
7
|
+
*
|
|
8
|
+
* @param projectDir - Absolute path to the project directory
|
|
9
|
+
* @throws Error if installation fails
|
|
10
|
+
*/
|
|
11
|
+
export async function install_dependencies(projectDir: string): Promise<void> {
|
|
12
|
+
const spinner = ora("Installing dependencies...").start();
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
await execa("bun", ["install"], {
|
|
16
|
+
cwd: projectDir,
|
|
17
|
+
stdio: "inherit",
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
spinner.succeed("Dependencies installed successfully");
|
|
21
|
+
} catch (error) {
|
|
22
|
+
spinner.fail("Failed to install dependencies");
|
|
23
|
+
console.error("\nYou can install dependencies manually by running:");
|
|
24
|
+
console.error(` cd ${projectDir}`);
|
|
25
|
+
console.error(` bun install\n`);
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { type InstallerOptions } from "../types/index.js";
|
|
3
|
+
import { type CliResults } from "../types/index.js";
|
|
4
|
+
import { AvailablePackages } from "../types/index.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Displays next steps for the user after project creation.
|
|
8
|
+
* Shows commands for navigation, Docker setup, migrations, and running the dev server.
|
|
9
|
+
*
|
|
10
|
+
* @param options - Installer options with project configuration
|
|
11
|
+
* @param cliResults - CLI results with selected packages and flags
|
|
12
|
+
*/
|
|
13
|
+
export function log_next_steps(
|
|
14
|
+
options: InstallerOptions,
|
|
15
|
+
_cliResults: CliResults
|
|
16
|
+
): void {
|
|
17
|
+
const { appName, packages } = options;
|
|
18
|
+
|
|
19
|
+
console.log("\n" + chalk.bold.green("✨ Project created successfully!"));
|
|
20
|
+
console.log("\n" + chalk.bold("Next steps:"));
|
|
21
|
+
console.log();
|
|
22
|
+
|
|
23
|
+
// Step 1: Navigate to project
|
|
24
|
+
console.log(chalk.cyan("1.") + " Navigate to your project:");
|
|
25
|
+
console.log(` ${chalk.gray("cd")} ${appName}`);
|
|
26
|
+
console.log();
|
|
27
|
+
|
|
28
|
+
// Step 2: Environment variables
|
|
29
|
+
console.log(chalk.cyan("2.") + " Set up environment variables:");
|
|
30
|
+
console.log(` ${chalk.gray("cp")} .env.example .env`);
|
|
31
|
+
console.log(` ${chalk.gray("# Edit .env with your configuration")}`);
|
|
32
|
+
console.log();
|
|
33
|
+
|
|
34
|
+
// Step 3: Docker (if database or redis selected)
|
|
35
|
+
const hasDocker =
|
|
36
|
+
packages.includes(AvailablePackages.postgres) ||
|
|
37
|
+
packages.includes(AvailablePackages.mysql) ||
|
|
38
|
+
packages.includes(AvailablePackages.mongodb) ||
|
|
39
|
+
packages.includes(AvailablePackages.redis);
|
|
40
|
+
|
|
41
|
+
if (hasDocker) {
|
|
42
|
+
console.log(chalk.cyan("3.") + " Start Docker services:");
|
|
43
|
+
console.log(` ${chalk.gray("docker-compose up -d")}`);
|
|
44
|
+
console.log();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Step 4: Database migrations (if postgres or mysql)
|
|
48
|
+
const needsMigration =
|
|
49
|
+
packages.includes(AvailablePackages.postgres) ||
|
|
50
|
+
packages.includes(AvailablePackages.mysql);
|
|
51
|
+
|
|
52
|
+
if (needsMigration) {
|
|
53
|
+
const stepNum = hasDocker ? "4" : "3";
|
|
54
|
+
console.log(chalk.cyan(`${stepNum}.`) + " Run database migrations:");
|
|
55
|
+
console.log(` ${chalk.gray("bun run db:migrate")}`);
|
|
56
|
+
console.log();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Step 5: Start development server
|
|
60
|
+
const lastStepNum = needsMigration
|
|
61
|
+
? hasDocker
|
|
62
|
+
? "5"
|
|
63
|
+
: "4"
|
|
64
|
+
: hasDocker
|
|
65
|
+
? "4"
|
|
66
|
+
: "3";
|
|
67
|
+
console.log(chalk.cyan(`${lastStepNum}.`) + " Start the development server:");
|
|
68
|
+
console.log(` ${chalk.gray("bun run dev")}`);
|
|
69
|
+
console.log();
|
|
70
|
+
|
|
71
|
+
// Additional info for docs
|
|
72
|
+
if (
|
|
73
|
+
packages.includes(AvailablePackages.swagger) ||
|
|
74
|
+
packages.includes(AvailablePackages.scalar)
|
|
75
|
+
) {
|
|
76
|
+
console.log(
|
|
77
|
+
chalk.bold("📚 API Documentation:") + " http://localhost:3000/docs"
|
|
78
|
+
);
|
|
79
|
+
console.log();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(chalk.gray("Happy coding! 🚀"));
|
|
83
|
+
console.log();
|
|
84
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { type InstallerOptions } from "../types/index.js";
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Scaffolds the base project structure by copying template files.
|
|
12
|
+
* Creates the project directory and copies all files from templates/base/
|
|
13
|
+
*
|
|
14
|
+
* @param options - Installer options containing projectDir and other config
|
|
15
|
+
* @throws Error if project directory already exists and is not empty
|
|
16
|
+
*/
|
|
17
|
+
export async function scaffold_project(
|
|
18
|
+
options: InstallerOptions
|
|
19
|
+
): Promise<void> {
|
|
20
|
+
const { projectDir, appName, framework } = options;
|
|
21
|
+
const spinner = ora("Scaffolding project...").start();
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Check if directory exists and is not empty
|
|
25
|
+
if (await fs.pathExists(projectDir)) {
|
|
26
|
+
const files = await fs.readdir(projectDir);
|
|
27
|
+
if (files.length > 0) {
|
|
28
|
+
spinner.fail(`Directory ${projectDir} already exists and is not empty`);
|
|
29
|
+
throw new Error(
|
|
30
|
+
`Cannot create project: directory "${appName}" is not empty`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Ensure project directory exists
|
|
36
|
+
await fs.ensureDir(projectDir);
|
|
37
|
+
|
|
38
|
+
// Select base template based on framework
|
|
39
|
+
const templateDirName = framework === "hono"
|
|
40
|
+
? "base"
|
|
41
|
+
: framework === "express"
|
|
42
|
+
? "base-express"
|
|
43
|
+
: "base-bun-native";
|
|
44
|
+
|
|
45
|
+
const templateDir = path.resolve(__dirname, `../templates/${templateDirName}`);
|
|
46
|
+
await fs.copy(templateDir, projectDir, {
|
|
47
|
+
overwrite: false,
|
|
48
|
+
errorOnExist: false,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Update package.json with the actual project name
|
|
52
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
53
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
54
|
+
packageJson.name = appName;
|
|
55
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
56
|
+
|
|
57
|
+
spinner.succeed("Project scaffolded successfully");
|
|
58
|
+
} catch (error) {
|
|
59
|
+
spinner.fail("Failed to scaffold project");
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
package/cli/src/index.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { run_cli } from "./cli/index.js";
|
|
4
|
+
import { create_project } from "./helpers/create-project.js";
|
|
5
|
+
import { logger } from "./utils/logger.js";
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
try {
|
|
9
|
+
const cliResults = await run_cli();
|
|
10
|
+
await create_project(cliResults);
|
|
11
|
+
} catch (error) {
|
|
12
|
+
logger.error("\n❌ An error occurred:");
|
|
13
|
+
logger.error(error);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
main();
|
|
@@ -0,0 +1,123 @@
|
|
|
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
|
+
* AI installer - handles OpenAI, Anthropic, Gemini, and Vercel AI SDK.
|
|
13
|
+
*
|
|
14
|
+
* @param options - Installer options with selected packages
|
|
15
|
+
*/
|
|
16
|
+
export async function ai_installer(options: InstallerOptions): Promise<void> {
|
|
17
|
+
const { projectDir, packages } = options;
|
|
18
|
+
|
|
19
|
+
for (const pkg of packages) {
|
|
20
|
+
switch (pkg) {
|
|
21
|
+
case AvailablePackages.openai:
|
|
22
|
+
await install_openai(projectDir);
|
|
23
|
+
break;
|
|
24
|
+
case AvailablePackages.anthropic:
|
|
25
|
+
await install_anthropic(projectDir);
|
|
26
|
+
break;
|
|
27
|
+
case AvailablePackages.gemini:
|
|
28
|
+
await install_gemini(projectDir);
|
|
29
|
+
break;
|
|
30
|
+
case AvailablePackages.vercelAI:
|
|
31
|
+
await install_vercel_ai(projectDir);
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function install_openai(projectDir: string): Promise<void> {
|
|
38
|
+
const templateDir = path.resolve(__dirname, "../templates/extras/ai/openai");
|
|
39
|
+
await copy_template_files(templateDir, projectDir);
|
|
40
|
+
|
|
41
|
+
await add_package_dependency(projectDir, {
|
|
42
|
+
openai: DEPENDENCY_VERSION_MAP["openai"],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await append_env_example(
|
|
46
|
+
projectDir,
|
|
47
|
+
"\n# OpenAI Configuration\nOPENAI_API_KEY=your-openai-api-key\n"
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function install_anthropic(projectDir: string): Promise<void> {
|
|
52
|
+
const templateDir = path.resolve(
|
|
53
|
+
__dirname,
|
|
54
|
+
"../templates/extras/ai/anthropic"
|
|
55
|
+
);
|
|
56
|
+
await copy_template_files(templateDir, projectDir);
|
|
57
|
+
|
|
58
|
+
await add_package_dependency(projectDir, {
|
|
59
|
+
"@anthropic-ai/sdk": DEPENDENCY_VERSION_MAP["@anthropic-ai/sdk"],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
await append_env_example(
|
|
63
|
+
projectDir,
|
|
64
|
+
"\n# Anthropic Configuration\nANTHROPIC_API_KEY=your-anthropic-api-key\n"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function install_gemini(projectDir: string): Promise<void> {
|
|
69
|
+
const templateDir = path.resolve(__dirname, "../templates/extras/ai/gemini");
|
|
70
|
+
await copy_template_files(templateDir, projectDir);
|
|
71
|
+
|
|
72
|
+
await add_package_dependency(projectDir, {
|
|
73
|
+
"@google/generative-ai": DEPENDENCY_VERSION_MAP["@google/generative-ai"],
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await append_env_example(
|
|
77
|
+
projectDir,
|
|
78
|
+
"\n# Google Gemini Configuration\nGEMINI_API_KEY=your-gemini-api-key\n"
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function install_vercel_ai(projectDir: string): Promise<void> {
|
|
83
|
+
const templateDir = path.resolve(
|
|
84
|
+
__dirname,
|
|
85
|
+
"../templates/extras/ai/vercel-ai"
|
|
86
|
+
);
|
|
87
|
+
await copy_template_files(templateDir, projectDir);
|
|
88
|
+
|
|
89
|
+
await add_package_dependency(projectDir, {
|
|
90
|
+
ai: DEPENDENCY_VERSION_MAP["ai"],
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
await append_env_example(
|
|
94
|
+
projectDir,
|
|
95
|
+
"\n# Vercel AI SDK Configuration\n# Add API keys for the providers you want to use with Vercel AI\n"
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function copy_template_files(
|
|
100
|
+
templateDir: string,
|
|
101
|
+
projectDir: string
|
|
102
|
+
): Promise<void> {
|
|
103
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const srcDir = path.join(templateDir, "src");
|
|
108
|
+
if (await fs.pathExists(srcDir)) {
|
|
109
|
+
const targetSrcDir = path.join(projectDir, "src");
|
|
110
|
+
await fs.copy(srcDir, targetSrcDir, {
|
|
111
|
+
overwrite: false,
|
|
112
|
+
errorOnExist: false,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function append_env_example(
|
|
118
|
+
projectDir: string,
|
|
119
|
+
content: string
|
|
120
|
+
): Promise<void> {
|
|
121
|
+
const envPath = path.join(projectDir, ".env.example");
|
|
122
|
+
await fs.appendFile(envPath, content);
|
|
123
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
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
|
+
* Auth installer - handles JWT, OAuth, and session authentication.
|
|
13
|
+
*
|
|
14
|
+
* @param options - Installer options with selected packages
|
|
15
|
+
*/
|
|
16
|
+
export async function auth_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.jwt:
|
|
24
|
+
await install_jwt(projectDir);
|
|
25
|
+
break;
|
|
26
|
+
case AvailablePackages.oauth:
|
|
27
|
+
await install_oauth(projectDir);
|
|
28
|
+
break;
|
|
29
|
+
case AvailablePackages.session:
|
|
30
|
+
await install_session(projectDir);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function install_jwt(projectDir: string): Promise<void> {
|
|
37
|
+
const templateDir = path.resolve(__dirname, "../templates/extras/auth/jwt");
|
|
38
|
+
await copy_template_files(templateDir, projectDir);
|
|
39
|
+
|
|
40
|
+
await add_package_dependency(projectDir, {
|
|
41
|
+
jsonwebtoken: DEPENDENCY_VERSION_MAP["jsonwebtoken"],
|
|
42
|
+
bcryptjs: DEPENDENCY_VERSION_MAP["bcryptjs"],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await add_package_dependency(
|
|
46
|
+
projectDir,
|
|
47
|
+
{},
|
|
48
|
+
{
|
|
49
|
+
"@types/jsonwebtoken": DEPENDENCY_VERSION_MAP["@types/jsonwebtoken"],
|
|
50
|
+
"@types/bcryptjs": DEPENDENCY_VERSION_MAP["@types/bcryptjs"],
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
await append_env_example(
|
|
55
|
+
projectDir,
|
|
56
|
+
"\n# JWT Authentication\nJWT_SECRET=your-super-secret-jwt-key-change-this\nJWT_EXPIRES_IN=7d\n"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function install_oauth(projectDir: string): Promise<void> {
|
|
61
|
+
const templateDir = path.resolve(__dirname, "../templates/extras/auth/oauth");
|
|
62
|
+
await copy_template_files(templateDir, projectDir);
|
|
63
|
+
|
|
64
|
+
await add_package_dependency(projectDir, {
|
|
65
|
+
passport: DEPENDENCY_VERSION_MAP["passport"],
|
|
66
|
+
"passport-oauth2": DEPENDENCY_VERSION_MAP["passport-oauth2"],
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
await add_package_dependency(
|
|
70
|
+
projectDir,
|
|
71
|
+
{},
|
|
72
|
+
{
|
|
73
|
+
"@types/passport": DEPENDENCY_VERSION_MAP["@types/passport"],
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
await append_env_example(
|
|
78
|
+
projectDir,
|
|
79
|
+
"\n# OAuth Configuration\nOAUTH_CLIENT_ID=your-client-id\nOAUTH_CLIENT_SECRET=your-client-secret\nOAUTH_CALLBACK_URL=http://localhost:3000/auth/callback\n"
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function install_session(projectDir: string): Promise<void> {
|
|
84
|
+
const templateDir = path.resolve(
|
|
85
|
+
__dirname,
|
|
86
|
+
"../templates/extras/auth/session"
|
|
87
|
+
);
|
|
88
|
+
await copy_template_files(templateDir, projectDir);
|
|
89
|
+
|
|
90
|
+
await append_env_example(
|
|
91
|
+
projectDir,
|
|
92
|
+
"\n# Session Configuration\nSESSION_SECRET=your-super-secret-session-key-change-this\n"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function copy_template_files(
|
|
97
|
+
templateDir: string,
|
|
98
|
+
projectDir: string
|
|
99
|
+
): Promise<void> {
|
|
100
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const srcDir = path.join(templateDir, "src");
|
|
105
|
+
if (await fs.pathExists(srcDir)) {
|
|
106
|
+
const targetSrcDir = path.join(projectDir, "src");
|
|
107
|
+
await fs.copy(srcDir, targetSrcDir, {
|
|
108
|
+
overwrite: false,
|
|
109
|
+
errorOnExist: false,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const templateFiles = await fs.readdir(templateDir);
|
|
114
|
+
for (const file of templateFiles) {
|
|
115
|
+
if (file !== "src" && (file.endsWith(".ts") || file.endsWith(".json"))) {
|
|
116
|
+
const srcFile = path.join(templateDir, file);
|
|
117
|
+
const destFile = path.join(projectDir, file);
|
|
118
|
+
|
|
119
|
+
if (!(await fs.pathExists(destFile))) {
|
|
120
|
+
await fs.copy(srcFile, destFile);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function append_env_example(
|
|
127
|
+
projectDir: string,
|
|
128
|
+
content: string
|
|
129
|
+
): Promise<void> {
|
|
130
|
+
const envPath = path.join(projectDir, ".env.example");
|
|
131
|
+
await fs.appendFile(envPath, content);
|
|
132
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type InstallerOptions } from "../types/index.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base installer - handles any base setup that's not covered by scaffold_project.
|
|
5
|
+
* Currently minimal since scaffold_project handles most base template copying.
|
|
6
|
+
*
|
|
7
|
+
* @param options - Installer options
|
|
8
|
+
*/
|
|
9
|
+
export async function base_installer(
|
|
10
|
+
_options: InstallerOptions
|
|
11
|
+
): Promise<void> {
|
|
12
|
+
// Base setup is handled by scaffold_project
|
|
13
|
+
// This installer exists for any additional base configuration
|
|
14
|
+
// that might be needed in the future
|
|
15
|
+
return Promise.resolve();
|
|
16
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
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
|
+
* Cloud installer - handles AWS, GCP, Azure, and Cloudflare R2.
|
|
13
|
+
*
|
|
14
|
+
* @param options - Installer options with selected packages
|
|
15
|
+
*/
|
|
16
|
+
export async function cloud_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.aws:
|
|
24
|
+
await install_aws(projectDir);
|
|
25
|
+
break;
|
|
26
|
+
case AvailablePackages.gcp:
|
|
27
|
+
await install_gcp(projectDir);
|
|
28
|
+
break;
|
|
29
|
+
case AvailablePackages.azure:
|
|
30
|
+
await install_azure(projectDir);
|
|
31
|
+
break;
|
|
32
|
+
case AvailablePackages.cloudflareR2:
|
|
33
|
+
await install_cloudflare_r2(projectDir);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function install_aws(projectDir: string): Promise<void> {
|
|
40
|
+
const templateDir = path.resolve(__dirname, "../templates/extras/cloud/aws");
|
|
41
|
+
await copy_template_files(templateDir, projectDir);
|
|
42
|
+
|
|
43
|
+
await add_package_dependency(projectDir, {
|
|
44
|
+
"@aws-sdk/client-s3": DEPENDENCY_VERSION_MAP["@aws-sdk/client-s3"],
|
|
45
|
+
"@aws-sdk/s3-request-presigner":
|
|
46
|
+
DEPENDENCY_VERSION_MAP["@aws-sdk/s3-request-presigner"],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await append_env_example(
|
|
50
|
+
projectDir,
|
|
51
|
+
"\n# AWS Configuration\nAWS_ACCESS_KEY_ID=your-aws-access-key\nAWS_SECRET_ACCESS_KEY=your-aws-secret-key\nAWS_REGION=us-east-1\nAWS_S3_BUCKET=your-bucket-name\n"
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function install_gcp(projectDir: string): Promise<void> {
|
|
56
|
+
const templateDir = path.resolve(__dirname, "../templates/extras/cloud/gcp");
|
|
57
|
+
await copy_template_files(templateDir, projectDir);
|
|
58
|
+
|
|
59
|
+
await add_package_dependency(projectDir, {
|
|
60
|
+
"@google-cloud/storage": DEPENDENCY_VERSION_MAP["@google-cloud/storage"],
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await append_env_example(
|
|
64
|
+
projectDir,
|
|
65
|
+
"\n# Google Cloud Platform Configuration\nGCP_PROJECT_ID=your-project-id\nGCP_BUCKET_NAME=your-bucket-name\n# GCP_KEY_FILE=path/to/service-account-key.json\n"
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function install_azure(projectDir: string): Promise<void> {
|
|
70
|
+
const templateDir = path.resolve(
|
|
71
|
+
__dirname,
|
|
72
|
+
"../templates/extras/cloud/azure"
|
|
73
|
+
);
|
|
74
|
+
await copy_template_files(templateDir, projectDir);
|
|
75
|
+
|
|
76
|
+
await add_package_dependency(projectDir, {
|
|
77
|
+
"@azure/storage-blob": DEPENDENCY_VERSION_MAP["@azure/storage-blob"],
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await append_env_example(
|
|
81
|
+
projectDir,
|
|
82
|
+
"\n# Azure Configuration\nAZURE_STORAGE_CONNECTION_STRING=your-connection-string\nAZURE_STORAGE_CONTAINER=your-container-name\n"
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function install_cloudflare_r2(projectDir: string): Promise<void> {
|
|
87
|
+
const templateDir = path.resolve(
|
|
88
|
+
__dirname,
|
|
89
|
+
"../templates/extras/cloud/cloudflare-r2"
|
|
90
|
+
);
|
|
91
|
+
await copy_template_files(templateDir, projectDir);
|
|
92
|
+
|
|
93
|
+
await add_package_dependency(projectDir, {
|
|
94
|
+
"@aws-sdk/client-s3": DEPENDENCY_VERSION_MAP["@aws-sdk/client-s3"],
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
await append_env_example(
|
|
98
|
+
projectDir,
|
|
99
|
+
"\n# Cloudflare R2 Configuration\nCLOUDFLARE_ACCOUNT_ID=your-account-id\nCLOUDFLARE_ACCESS_KEY_ID=your-access-key\nCLOUDFLARE_SECRET_ACCESS_KEY=your-secret-key\nCLOUDFLARE_R2_BUCKET=your-bucket-name\n"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function copy_template_files(
|
|
104
|
+
templateDir: string,
|
|
105
|
+
projectDir: string
|
|
106
|
+
): Promise<void> {
|
|
107
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const srcDir = path.join(templateDir, "src");
|
|
112
|
+
if (await fs.pathExists(srcDir)) {
|
|
113
|
+
const targetSrcDir = path.join(projectDir, "src");
|
|
114
|
+
await fs.copy(srcDir, targetSrcDir, {
|
|
115
|
+
overwrite: false,
|
|
116
|
+
errorOnExist: false,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function append_env_example(
|
|
122
|
+
projectDir: string,
|
|
123
|
+
content: string
|
|
124
|
+
): Promise<void> {
|
|
125
|
+
const envPath = path.join(projectDir, ".env.example");
|
|
126
|
+
await fs.appendFile(envPath, content);
|
|
127
|
+
}
|