bffgen 1.2.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 RichGod Usen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # bffgen
2
+
3
+ **Backend-for-Frontend (BFF) generator** - Scaffold secure, production-ready BFF services in **Go**, **Node.js (Express)**, or **Node.js (Fastify)** with JWT auth, rate limiting, CORS, and comprehensive logging.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/bffgen.svg)](https://www.npmjs.com/package/bffgen)
6
+ [![Downloads](https://img.shields.io/npm/dm/bffgen.svg)](https://www.npmjs.com/package/bffgen)
7
+ [![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
8
+
9
+ ---
10
+
11
+ ## ⚔ Quick Start
12
+
13
+ ### Using npx (No Installation)
14
+
15
+ ```bash
16
+ # Create Express BFF
17
+ npx bffgen init my-express-bff --lang nodejs-express
18
+ cd my-express-bff
19
+ npm install && npm run dev
20
+
21
+ # Create Fastify BFF
22
+ npx bffgen init my-fastify-bff --lang nodejs-fastify
23
+
24
+ # Create Go BFF
25
+ npx bffgen init my-go-bff --lang go --framework chi
26
+ ```
27
+
28
+ ### Global Installation
29
+
30
+ ```bash
31
+ # Install globally
32
+ npm install -g bffgen
33
+
34
+ # Use anywhere
35
+ bffgen init my-project --lang nodejs-express
36
+ cd my-project && npm run dev
37
+ ```
38
+
39
+ ---
40
+
41
+ ## ✨ Features
42
+
43
+ ### 🌐 **Multi-Runtime Support**
44
+
45
+ - **Node.js Express** - Popular, flexible web framework
46
+ - **Node.js Fastify** - Fast, schema-based framework
47
+ - **Go (Chi/Echo/Fiber)** - High-performance, compiled servers
48
+
49
+ ### šŸš€ **Production-Ready Aggregation (v1.2.0)**
50
+
51
+ - **Parallel Service Calls** - Fetch from multiple backends simultaneously
52
+ - **Redis Caching** - Built-in caching with automatic fallback
53
+ - **Circuit Breakers** - Prevent cascade failures
54
+ - **Request Batching** - Avoid N+1 queries
55
+ - **Response Transformation** - Filter and optimize API responses
56
+ - **Field Selection** - GraphQL-like field filtering for REST
57
+
58
+ ### šŸ”’ **Security Features**
59
+
60
+ - **JWT Authentication** - Token validation with user context
61
+ - **Rate Limiting** - Built-in for all runtimes
62
+ - **Security Headers** - Helmet, CSP, HSTS, XSS protection
63
+ - **CORS Configuration** - Restrictive origins, credentials support
64
+
65
+ ### šŸŽØ **Developer Experience**
66
+
67
+ - **Interactive CLI** - Guided project setup
68
+ - **Template System** - Pre-built templates (auth, ecommerce, content)
69
+ - **Code Generation** - Auto-generate routes, controllers, services
70
+ - **Hot Reload** - Development mode with auto-restart
71
+ - **Comprehensive Tests** - Jest setup with sample tests
72
+
73
+ ---
74
+
75
+ ## šŸ› ļø Commands
76
+
77
+ ```bash
78
+ # Initialize new BFF project
79
+ bffgen init my-bff --lang nodejs-express
80
+
81
+ # Add route interactively
82
+ bffgen add-route
83
+
84
+ # Add template (auth, ecommerce, content)
85
+ bffgen add-template auth
86
+
87
+ # Generate routes, controllers, and services
88
+ bffgen generate
89
+
90
+ # Generate API documentation
91
+ bffgen generate-docs
92
+
93
+ # Create Postman collection
94
+ bffgen postman
95
+
96
+ # Health check
97
+ bffgen doctor
98
+
99
+ # Run development server (Go only)
100
+ bffgen dev
101
+
102
+ # Show version
103
+ bffgen version
104
+ ```
105
+
106
+ ---
107
+
108
+ ## šŸ“š Examples
109
+
110
+ ### Node.js Express Example
111
+
112
+ ```bash
113
+ # Create project
114
+ npx bffgen init my-express-bff --lang nodejs-express
115
+
116
+ # Project structure:
117
+ my-express-bff/
118
+ ā”œā”€ā”€ src/
119
+ │ ā”œā”€ā”€ index.js # Express server
120
+ │ ā”œā”€ā”€ routes/ # Route handlers
121
+ │ ā”œā”€ā”€ controllers/ # Business logic with aggregation
122
+ │ ā”œā”€ā”€ services/ # HTTP clients
123
+ │ ā”œā”€ā”€ middleware/ # Auth, validation, logging
124
+ │ ā”œā”€ā”€ utils/ # Aggregation utilities (NEW v1.2.0)
125
+ │ │ ā”œā”€ā”€ aggregator.js # Parallel requests
126
+ │ │ ā”œā”€ā”€ cache-manager.js # Redis caching
127
+ │ │ ā”œā”€ā”€ circuit-breaker.js # Fault tolerance
128
+ │ │ └── ...
129
+ │ └── examples/ # Working aggregation examples
130
+ ā”œā”€ā”€ tests/ # Jest tests
131
+ ā”œā”€ā”€ docker-compose.yml # Redis setup
132
+ ā”œā”€ā”€ package.json
133
+ └── bffgen.config.json # BFF configuration
134
+ ```
135
+
136
+ ### Aggregation Example (v1.2.0)
137
+
138
+ ```javascript
139
+ const ParallelAggregator = require("./utils/aggregator");
140
+ const CacheManager = require("./utils/cache-manager");
141
+
142
+ const aggregator = new ParallelAggregator({ timeout: 5000 });
143
+ const cache = new CacheManager({ ttl: 300 });
144
+
145
+ // Fetch from multiple services in parallel
146
+ const results = await aggregator.fetchParallel([
147
+ { name: "user", fetch: () => UserService.getProfile(userId) },
148
+ { name: "orders", fetch: () => OrdersService.getOrders(userId) },
149
+ { name: "preferences", fetch: () => PreferencesService.get(userId) },
150
+ ]);
151
+
152
+ // Combine results with graceful degradation
153
+ const dashboard = {
154
+ user: results.find((r) => r.service === "user" && r.success)?.data,
155
+ orders: results.find((r) => r.service === "orders" && r.success)?.data || [],
156
+ preferences:
157
+ results.find((r) => r.service === "preferences" && r.success)?.data || {},
158
+ };
159
+ ```
160
+
161
+ ---
162
+
163
+ ## šŸ”§ Programmatic API
164
+
165
+ ```javascript
166
+ const bffgen = require("bffgen");
167
+
168
+ // Initialize project programmatically
169
+ await bffgen.init({
170
+ name: "my-project",
171
+ lang: "nodejs-express",
172
+ framework: "express",
173
+ skipTests: false,
174
+ });
175
+
176
+ // Generate code
177
+ await bffgen.generate();
178
+
179
+ // Get version
180
+ const version = bffgen.getVersion();
181
+ ```
182
+
183
+ ---
184
+
185
+ ## šŸ“– Documentation
186
+
187
+ - [Full Documentation](https://github.com/RichGod93/bffgen)
188
+ - [Node.js Aggregation Guide](https://github.com/RichGod93/bffgen/blob/main/docs/NODEJS_AGGREGATION.md)
189
+ - [Quick Reference](https://github.com/RichGod93/bffgen/blob/main/docs/QUICK_REFERENCE.md)
190
+ - [Examples](https://github.com/RichGod93/bffgen/tree/main/examples)
191
+
192
+ ---
193
+
194
+ ## šŸŒ Platform Support
195
+
196
+ Supported platforms:
197
+
198
+ - āœ… macOS (Intel & Apple Silicon)
199
+ - āœ… Linux (x64 & ARM64)
200
+ - āœ… Windows (x64)
201
+
202
+ The appropriate binary for your platform is automatically downloaded during installation.
203
+
204
+ ---
205
+
206
+ ## šŸ› Troubleshooting
207
+
208
+ ### Installation Issues
209
+
210
+ If installation fails:
211
+
212
+ 1. **Check your internet connection**
213
+ 2. **Clear npm cache:**
214
+
215
+ ```bash
216
+ npm cache clean --force
217
+ npm install -g bffgen
218
+ ```
219
+
220
+ 3. **Manual installation:**
221
+ Download from [GitHub Releases](https://github.com/RichGod93/bffgen/releases)
222
+
223
+ ### Platform Not Supported
224
+
225
+ If your platform isn't supported, you can:
226
+
227
+ - Install via Go: `go install github.com/RichGod93/bffgen/cmd/bffgen@latest`
228
+ - Build from source: Clone the repo and run `make build`
229
+
230
+ ---
231
+
232
+ ## šŸ¤ Contributing
233
+
234
+ Contributions are welcome! Please see the [Contributing Guide](https://github.com/RichGod93/bffgen/blob/main/CONTRIBUTING.md).
235
+
236
+ ---
237
+
238
+ ## šŸ“ License
239
+
240
+ MIT License - see [LICENSE](LICENSE) file for details.
241
+
242
+ ---
243
+
244
+ ## šŸ”— Links
245
+
246
+ - [GitHub Repository](https://github.com/RichGod93/bffgen)
247
+ - [Documentation](https://github.com/RichGod93/bffgen#readme)
248
+ - [Issue Tracker](https://github.com/RichGod93/bffgen/issues)
249
+ - [npm Package](https://www.npmjs.com/package/bffgen)
250
+
251
+ ---
252
+
253
+ **Made with ā¤ļø for the Backend-for-Frontend pattern**
package/bin/bffgen.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * bffgen npm binary wrapper
5
+ * Executes the platform-specific downloaded binary
6
+ */
7
+
8
+ const { spawn } = require("child_process");
9
+ const path = require("path");
10
+ const fs = require("fs");
11
+ const { getBinaryName } = require("../scripts/platform");
12
+
13
+ // Find binary
14
+ const binaryName = getBinaryName();
15
+ const binaryPath = path.join(__dirname, binaryName);
16
+
17
+ // Check if binary exists
18
+ if (!fs.existsSync(binaryPath)) {
19
+ console.error("āŒ bffgen binary not found!");
20
+ console.error(
21
+ "\nThe binary should have been downloaded during installation."
22
+ );
23
+ console.error("Try reinstalling:");
24
+ console.error(" npm install -g bffgen");
25
+ console.error("\nOr install via Go:");
26
+ console.error(" go install github.com/RichGod93/bffgen/cmd/bffgen@latest");
27
+ process.exit(1);
28
+ }
29
+
30
+ // Execute binary with all arguments
31
+ const args = process.argv.slice(2);
32
+ const child = spawn(binaryPath, args, {
33
+ stdio: "inherit",
34
+ cwd: process.cwd(),
35
+ env: process.env,
36
+ });
37
+
38
+ // Handle exit
39
+ child.on("error", (error) => {
40
+ console.error("Failed to execute bffgen:", error.message);
41
+ process.exit(1);
42
+ });
43
+
44
+ child.on("exit", (code, signal) => {
45
+ if (signal) {
46
+ process.kill(process.pid, signal);
47
+ } else {
48
+ process.exit(code || 0);
49
+ }
50
+ });
51
+
52
+ // Handle signals
53
+ process.on("SIGINT", () => {
54
+ child.kill("SIGINT");
55
+ });
56
+
57
+ process.on("SIGTERM", () => {
58
+ child.kill("SIGTERM");
59
+ });
package/lib/index.js ADDED
@@ -0,0 +1,142 @@
1
+ /**
2
+ * bffgen Programmatic API
3
+ * Use bffgen from JavaScript/TypeScript code
4
+ */
5
+
6
+ const { execSync: nodeExecSync, spawn } = require("child_process");
7
+ const path = require("path");
8
+ const { getBinaryName } = require("../scripts/platform");
9
+
10
+ const BINARY_PATH = path.join(__dirname, "..", "bin", getBinaryName());
11
+
12
+ /**
13
+ * Execute bffgen command synchronously
14
+ * @param {string[]} args - Command arguments
15
+ * @param {Object} options - Execution options
16
+ * @returns {Buffer} - Command output
17
+ */
18
+ function execBffgenSync(args, options = {}) {
19
+ const command = `"${BINARY_PATH}" ${args.join(" ")}`;
20
+ return nodeExecSync(command, {
21
+ encoding: "utf8",
22
+ ...options,
23
+ });
24
+ }
25
+
26
+ /**
27
+ * Execute bffgen command asynchronously
28
+ * @param {string[]} args - Command arguments
29
+ * @param {Object} options - Execution options
30
+ * @returns {Promise<string>} - Command output
31
+ */
32
+ function exec(args, options = {}) {
33
+ return new Promise((resolve, reject) => {
34
+ const child = spawn(BINARY_PATH, args, {
35
+ ...options,
36
+ cwd: options.cwd || process.cwd(),
37
+ });
38
+
39
+ let stdout = "";
40
+ let stderr = "";
41
+
42
+ if (child.stdout) {
43
+ child.stdout.on("data", (data) => {
44
+ stdout += data.toString();
45
+ });
46
+ }
47
+
48
+ if (child.stderr) {
49
+ child.stderr.on("data", (data) => {
50
+ stderr += data.toString();
51
+ });
52
+ }
53
+
54
+ child.on("error", reject);
55
+
56
+ child.on("exit", (code) => {
57
+ if (code !== 0) {
58
+ const error = new Error(`bffgen exited with code ${code}`);
59
+ error.code = code;
60
+ error.stderr = stderr;
61
+ error.stdout = stdout;
62
+ reject(error);
63
+ } else {
64
+ resolve(stdout);
65
+ }
66
+ });
67
+ });
68
+ }
69
+
70
+ /**
71
+ * Initialize a new BFF project
72
+ * @param {Object} options - Project options
73
+ * @param {string} options.name - Project name
74
+ * @param {string} options.lang - Language/runtime (go, nodejs-express, nodejs-fastify)
75
+ * @param {string} options.framework - Framework (chi, echo, fiber, express, fastify)
76
+ * @param {boolean} options.skipTests - Skip test generation
77
+ * @param {boolean} options.skipDocs - Skip documentation generation
78
+ * @returns {Promise<string>}
79
+ */
80
+ async function init(options) {
81
+ const args = ["init", options.name];
82
+
83
+ if (options.lang) {
84
+ args.push("--lang", options.lang);
85
+ }
86
+
87
+ if (options.framework) {
88
+ args.push("--framework", options.framework);
89
+ }
90
+
91
+ if (options.skipTests) {
92
+ args.push("--skip-tests");
93
+ }
94
+
95
+ if (options.skipDocs) {
96
+ args.push("--skip-docs");
97
+ }
98
+
99
+ return exec(args, { stdio: "inherit" });
100
+ }
101
+
102
+ /**
103
+ * Generate code from configuration
104
+ * @param {Object} options - Generation options
105
+ * @returns {Promise<string>}
106
+ */
107
+ async function generate(options = {}) {
108
+ const args = ["generate"];
109
+
110
+ if (options.check) {
111
+ args.push("--check");
112
+ }
113
+
114
+ if (options.dryRun) {
115
+ args.push("--dry-run");
116
+ }
117
+
118
+ return exec(args, { stdio: "inherit" });
119
+ }
120
+
121
+ /**
122
+ * Get bffgen version
123
+ * @returns {string}
124
+ */
125
+ function getVersion() {
126
+ try {
127
+ const output = execBffgenSync(["version"]);
128
+ const match = output.match(/bffgen version (v?[\d.]+)/);
129
+ return match ? match[1] : require("../package.json").version;
130
+ } catch (error) {
131
+ return require("../package.json").version;
132
+ }
133
+ }
134
+
135
+ module.exports = {
136
+ exec,
137
+ execSync: execBffgenSync,
138
+ init,
139
+ generate,
140
+ getVersion,
141
+ version: require("../package.json").version,
142
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "bffgen",
3
+ "version": "1.2.0",
4
+ "description": "Backend-for-Frontend (BFF) generator - Scaffold secure, production-ready BFF services in Go, Express, or Fastify",
5
+ "main": "lib/index.js",
6
+ "bin": {
7
+ "bffgen": "bin/bffgen.js"
8
+ },
9
+ "scripts": {
10
+ "postinstall": "node scripts/install.js",
11
+ "test": "node bin/bffgen.js version"
12
+ },
13
+ "keywords": [
14
+ "bff",
15
+ "backend-for-frontend",
16
+ "generator",
17
+ "cli",
18
+ "scaffold",
19
+ "scaffolding",
20
+ "express",
21
+ "expressjs",
22
+ "fastify",
23
+ "go",
24
+ "golang",
25
+ "microservices",
26
+ "api",
27
+ "rest",
28
+ "graphql",
29
+ "aggregation",
30
+ "proxy",
31
+ "gateway"
32
+ ],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/RichGod93/bffgen.git",
36
+ "directory": "npm"
37
+ },
38
+ "homepage": "https://github.com/RichGod93/bffgen#readme",
39
+ "bugs": {
40
+ "url": "https://github.com/RichGod93/bffgen/issues"
41
+ },
42
+ "author": "RichGod93",
43
+ "license": "MIT",
44
+ "engines": {
45
+ "node": ">=14.0.0"
46
+ },
47
+ "files": [
48
+ "bin",
49
+ "scripts",
50
+ "lib",
51
+ "README.md",
52
+ "LICENSE"
53
+ ],
54
+ "os": [
55
+ "darwin",
56
+ "linux",
57
+ "win32"
58
+ ],
59
+ "cpu": [
60
+ "x64",
61
+ "arm64"
62
+ ]
63
+ }
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Post-install script for bffgen npm package
5
+ * Downloads the appropriate binary from GitHub Releases
6
+ */
7
+
8
+ const https = require("https");
9
+ const fs = require("fs");
10
+ const path = require("path");
11
+ const crypto = require("crypto");
12
+ const {
13
+ getBinaryName,
14
+ getDownloadUrl,
15
+ getChecksumsUrl,
16
+ isSupported,
17
+ SUPPORTED_PLATFORMS,
18
+ } = require("./platform");
19
+
20
+ const PACKAGE_VERSION = require("../package.json").version;
21
+ const BIN_DIR = path.join(__dirname, "..", "bin");
22
+ const BINARY_PATH = path.join(BIN_DIR, getBinaryName());
23
+
24
+ // Colors for output
25
+ const colors = {
26
+ reset: "\x1b[0m",
27
+ blue: "\x1b[34m",
28
+ green: "\x1b[32m",
29
+ red: "\x1b[31m",
30
+ yellow: "\x1b[33m",
31
+ };
32
+
33
+ function log(message, color = "reset") {
34
+ console.log(`${colors[color]}${message}${colors.reset}`);
35
+ }
36
+
37
+ /**
38
+ * Check if platform is supported
39
+ */
40
+ function checkPlatform() {
41
+ if (!isSupported()) {
42
+ log("āŒ Platform not supported", "red");
43
+ log(`\nSupported platforms: ${SUPPORTED_PLATFORMS.join(", ")}`, "yellow");
44
+ log("\nšŸ“¦ Manual Installation:", "blue");
45
+ log(
46
+ ` Download from: https://github.com/RichGod93/bffgen/releases/v${PACKAGE_VERSION}`
47
+ );
48
+ log(" Extract and add to PATH");
49
+ process.exit(1);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Download file from URL
55
+ */
56
+ function downloadFile(url) {
57
+ return new Promise((resolve, reject) => {
58
+ log(`šŸ“„ Downloading from: ${url}`, "blue");
59
+
60
+ https
61
+ .get(url, { timeout: 30000 }, (response) => {
62
+ if (response.statusCode === 302 || response.statusCode === 301) {
63
+ // Follow redirect
64
+ https
65
+ .get(
66
+ response.headers.location,
67
+ { timeout: 30000 },
68
+ (redirectResponse) => {
69
+ if (redirectResponse.statusCode !== 200) {
70
+ reject(
71
+ new Error(
72
+ `HTTP ${redirectResponse.statusCode}: ${redirectResponse.statusMessage}`
73
+ )
74
+ );
75
+ return;
76
+ }
77
+
78
+ const chunks = [];
79
+ redirectResponse.on("data", (chunk) => chunks.push(chunk));
80
+ redirectResponse.on("end", () =>
81
+ resolve(Buffer.concat(chunks))
82
+ );
83
+ redirectResponse.on("error", reject);
84
+ }
85
+ )
86
+ .on("error", reject);
87
+ } else if (response.statusCode === 200) {
88
+ const chunks = [];
89
+ response.on("data", (chunk) => chunks.push(chunk));
90
+ response.on("end", () => resolve(Buffer.concat(chunks)));
91
+ response.on("error", reject);
92
+ } else {
93
+ reject(
94
+ new Error(
95
+ `HTTP ${response.statusCode}: ${response.statusMessage}\nURL: ${url}`
96
+ )
97
+ );
98
+ }
99
+ })
100
+ .on("error", reject);
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Verify binary checksum
106
+ */
107
+ async function verifyChecksum(binaryBuffer, binaryName) {
108
+ try {
109
+ log("šŸ” Verifying checksum...", "blue");
110
+
111
+ const checksumsUrl = getChecksumsUrl(PACKAGE_VERSION);
112
+ const checksumsData = await downloadFile(checksumsUrl);
113
+ const checksumsText = checksumsData.toString("utf8");
114
+
115
+ // Find checksum for our binary
116
+ const lines = checksumsText.split("\n");
117
+ const checksumLine = lines.find((line) => line.includes(binaryName));
118
+
119
+ if (!checksumLine) {
120
+ log("āš ļø Warning: Checksum not found in checksums.txt", "yellow");
121
+ return true; // Continue anyway
122
+ }
123
+
124
+ const expectedChecksum = checksumLine.split(/\s+/)[0];
125
+
126
+ // Calculate actual checksum
127
+ const hash = crypto.createHash("sha256");
128
+ hash.update(binaryBuffer);
129
+ const actualChecksum = hash.digest("hex");
130
+
131
+ if (expectedChecksum !== actualChecksum) {
132
+ log("āŒ Checksum verification failed!", "red");
133
+ log(` Expected: ${expectedChecksum}`, "red");
134
+ log(` Actual: ${actualChecksum}`, "red");
135
+ log("\nāš ļø Binary may be corrupted. Try reinstalling:", "yellow");
136
+ log(" npm cache clean --force", "yellow");
137
+ log(" npm install -g bffgen", "yellow");
138
+ return false;
139
+ }
140
+
141
+ log("āœ… Checksum verified", "green");
142
+ return true;
143
+ } catch (error) {
144
+ log(`āš ļø Warning: Could not verify checksum: ${error.message}`, "yellow");
145
+ return true; // Continue anyway
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Main installation process
151
+ */
152
+ async function install() {
153
+ try {
154
+ log(`\nšŸ“¦ Installing bffgen v${PACKAGE_VERSION}...`, "blue");
155
+
156
+ // Check platform support
157
+ checkPlatform();
158
+
159
+ const binaryName = getBinaryName();
160
+ log(` Platform: ${binaryName}`, "blue");
161
+
162
+ // Create bin directory
163
+ if (!fs.existsSync(BIN_DIR)) {
164
+ fs.mkdirSync(BIN_DIR, { recursive: true });
165
+ }
166
+
167
+ // Download binary
168
+ const downloadUrl = getDownloadUrl(PACKAGE_VERSION);
169
+ const binaryBuffer = await downloadFile(downloadUrl);
170
+
171
+ // Verify checksum
172
+ const checksumValid = await verifyChecksum(binaryBuffer, binaryName);
173
+ if (!checksumValid) {
174
+ process.exit(1);
175
+ }
176
+
177
+ // Write binary file
178
+ fs.writeFileSync(BINARY_PATH, binaryBuffer);
179
+
180
+ // Make executable (Unix only)
181
+ if (process.platform !== "win32") {
182
+ fs.chmodSync(BINARY_PATH, 0o755);
183
+ }
184
+
185
+ log("āœ… bffgen installed successfully!", "green");
186
+ log("\nšŸ“š Quick Start:", "blue");
187
+ log(" npx bffgen init my-project --lang nodejs-express", "blue");
188
+ log(" npx bffgen --help", "blue");
189
+ log("\nšŸ“– Documentation: https://github.com/RichGod93/bffgen", "blue");
190
+ } catch (error) {
191
+ log("\nāŒ Installation failed!", "red");
192
+ log(` Error: ${error.message}`, "red");
193
+ log("\nšŸ“¦ Manual Installation:", "yellow");
194
+ log(
195
+ ` 1. Download from: https://github.com/RichGod93/bffgen/releases/v${PACKAGE_VERSION}`,
196
+ "yellow"
197
+ );
198
+ log(` 2. Extract the binary for your platform`, "yellow");
199
+ log(` 3. Add to your PATH`, "yellow");
200
+ log("\nšŸ’” Or install via Go:", "yellow");
201
+ log(
202
+ ` go install github.com/RichGod93/bffgen/cmd/bffgen@v${PACKAGE_VERSION}`,
203
+ "yellow"
204
+ );
205
+
206
+ process.exit(1);
207
+ }
208
+ }
209
+
210
+ // Run installation
211
+ install();
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Platform Detection Utilities
3
+ * Maps Node.js platform/arch to Go binary names
4
+ */
5
+
6
+ const os = require("os");
7
+
8
+ const PLATFORM_MAP = {
9
+ darwin: {
10
+ x64: "darwin-amd64",
11
+ arm64: "darwin-arm64",
12
+ },
13
+ linux: {
14
+ x64: "linux-amd64",
15
+ arm64: "linux-arm64",
16
+ },
17
+ win32: {
18
+ x64: "windows-amd64",
19
+ },
20
+ };
21
+
22
+ const SUPPORTED_PLATFORMS = [
23
+ "darwin-x64",
24
+ "darwin-arm64",
25
+ "linux-x64",
26
+ "linux-arm64",
27
+ "win32-x64",
28
+ ];
29
+
30
+ /**
31
+ * Get current platform and architecture
32
+ */
33
+ function getPlatform() {
34
+ const platform = os.platform();
35
+ const arch = os.arch();
36
+ return { platform, arch };
37
+ }
38
+
39
+ /**
40
+ * Map Node.js platform/arch to Go binary name
41
+ */
42
+ function getBinaryName() {
43
+ const { platform, arch } = getPlatform();
44
+
45
+ if (!PLATFORM_MAP[platform] || !PLATFORM_MAP[platform][arch]) {
46
+ throw new Error(
47
+ `Unsupported platform: ${platform}-${arch}\n` +
48
+ `Supported platforms: ${SUPPORTED_PLATFORMS.join(", ")}\n` +
49
+ `Please install manually from: https://github.com/RichGod93/bffgen/releases`
50
+ );
51
+ }
52
+
53
+ const goPlatform = PLATFORM_MAP[platform][arch];
54
+ const ext = platform === "win32" ? ".exe" : "";
55
+
56
+ return `bffgen-${goPlatform}${ext}`;
57
+ }
58
+
59
+ /**
60
+ * Get download URL for current platform
61
+ */
62
+ function getDownloadUrl(version) {
63
+ const binaryName = getBinaryName();
64
+ return `https://github.com/RichGod93/bffgen/releases/download/v${version}/${binaryName}`;
65
+ }
66
+
67
+ /**
68
+ * Get checksums URL for version
69
+ */
70
+ function getChecksumsUrl(version) {
71
+ return `https://github.com/RichGod93/bffgen/releases/download/v${version}/checksums.txt`;
72
+ }
73
+
74
+ /**
75
+ * Check if platform is supported
76
+ */
77
+ function isSupported() {
78
+ try {
79
+ getBinaryName();
80
+ return true;
81
+ } catch (error) {
82
+ return false;
83
+ }
84
+ }
85
+
86
+ module.exports = {
87
+ getPlatform,
88
+ getBinaryName,
89
+ getDownloadUrl,
90
+ getChecksumsUrl,
91
+ isSupported,
92
+ SUPPORTED_PLATFORMS,
93
+ };