bro-framework 1.2.8 → 2.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/README.md +16 -1
- package/bin/bro.js +15 -11
- package/package.json +7 -2
- package/src/index.d.ts +16 -12
- package/src/logger.js +22 -10
- package/src/router.js +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<strong>The zero-boilerplate Node.js framework that actually has your back.</strong>
|
|
6
6
|
</p>
|
|
7
7
|
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/bro-framework"><img src="https://img.shields.io/npm/v/bro-framework.svg?style=flat-square&color=e11d48" alt="npm version"></a>
|
|
8
9
|
<img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" alt="License: MIT">
|
|
9
10
|
<img src="https://img.shields.io/badge/Node.js-%3E%3D%2018-green.svg?style=flat-square" alt="Node.js: >= 18">
|
|
10
11
|
<img src="https://img.shields.io/badge/Architecture-Pure%20ESM-orange.svg?style=flat-square" alt="Architecture: Pure ESM">
|
|
@@ -16,7 +17,6 @@
|
|
|
16
17
|
<a href="https://brojs.yessindevs.me">Documentation Website</a>
|
|
17
18
|
</p>
|
|
18
19
|
</p>
|
|
19
|
-
|
|
20
20
|
---
|
|
21
21
|
|
|
22
22
|
> "NestJS wants four decorators, three modules, and an existential crisis just to handle a GET request. Express makes you write the same 40 lines of CORS, JSON parsing, and auth middleware for every project. bro.js gives you file routing, auto-validation, JWT auth, WebSockets, and live docs out of the box. Be honest: you just want to return an object."
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
## Table of Contents
|
|
27
27
|
|
|
28
|
+
- [Getting Started](#getting-started)
|
|
28
29
|
- [The Core Experience](#the-core-experience)
|
|
29
30
|
- [Deep-Dive Features](#deep-dive-features)
|
|
30
31
|
- [Architecture & Request Lifecycle](#architecture--request-lifecycle)
|
|
@@ -34,6 +35,20 @@
|
|
|
34
35
|
|
|
35
36
|
---
|
|
36
37
|
|
|
38
|
+
## Getting Started
|
|
39
|
+
|
|
40
|
+
Bootstrapping a new `bro.js` project is incredibly simple. We recommend using our official scaffolding tool to set everything up instantly (with your choice of JavaScript or TypeScript):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx create-bro-framework@latest my-api
|
|
44
|
+
cd my-api
|
|
45
|
+
npm run dev
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
That's it! Your zero-boilerplate backend is now running with hot-reloading enabled.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
37
52
|
## The Core Experience
|
|
38
53
|
|
|
39
54
|
In `bro.js`, everything you need is handed to you instantly. No setup, no middleware wrangling, no manual `req/res` handling. You define your route, set your validation, and return an object.
|
package/bin/bro.js
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import { pathToFileURL } from 'url';
|
|
6
|
+
import { register } from 'tsx/esm/api';
|
|
7
|
+
|
|
8
|
+
register();
|
|
9
|
+
|
|
6
10
|
import { createServer } from '../src/server.js';
|
|
7
11
|
import { colors, printBanner, printRoute, printHotReload } from '../src/logger.js';
|
|
8
12
|
import { scanTasks } from '../src/tasks.js';
|
|
@@ -44,6 +48,13 @@ export default defineConfig({
|
|
|
44
48
|
max: 100 // limit each IP to 100 requests per windowMs
|
|
45
49
|
},
|
|
46
50
|
|
|
51
|
+
// WebSockets Setup
|
|
52
|
+
sockets: async (io, db) => {
|
|
53
|
+
io.on('connection', (socket) => {
|
|
54
|
+
console.log('Client connected:', socket.id);
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
|
|
47
58
|
// Database Context Injection
|
|
48
59
|
// This instance will be injected into every route's ctx.db (if defined)
|
|
49
60
|
db: async () => {
|
|
@@ -63,13 +74,6 @@ export default defineConfig({
|
|
|
63
74
|
// return mongoose.connection;
|
|
64
75
|
// --------------------------
|
|
65
76
|
return null;
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
// WebSockets Setup
|
|
69
|
-
sockets: async (io, db) => {
|
|
70
|
-
io.on('connection', (socket) => {
|
|
71
|
-
console.log('Client connected:', socket.id);
|
|
72
|
-
});
|
|
73
77
|
}
|
|
74
78
|
});
|
|
75
79
|
`;
|
|
@@ -118,10 +122,10 @@ if (command === 'init') {
|
|
|
118
122
|
|
|
119
123
|
if (['sdk', 'generate-client', 'client'].includes(command)) {
|
|
120
124
|
generateSDK().then(() => {
|
|
121
|
-
console.log(`\n ${colors.green}
|
|
125
|
+
console.log(`\n ${colors.green} bro-client.js generated successfully!${colors.reset}\n`);
|
|
122
126
|
process.exit(0);
|
|
123
127
|
}).catch(err => {
|
|
124
|
-
console.error(`\n ${colors.red}
|
|
128
|
+
console.error(`\n ${colors.red} Error generating SDK:${colors.reset}`, err.message);
|
|
125
129
|
process.exit(1);
|
|
126
130
|
});
|
|
127
131
|
}
|
|
@@ -171,7 +175,7 @@ async function bootstrap() {
|
|
|
171
175
|
if (globalConfig.env) {
|
|
172
176
|
const envResult = globalConfig.env.safeParse(process.env);
|
|
173
177
|
if (!envResult.success) {
|
|
174
|
-
console.error(`\n ${colors.red}
|
|
178
|
+
console.error(`\n ${colors.red} Environment Validation Failed${colors.reset}`);
|
|
175
179
|
envResult.error.errors.forEach(err => {
|
|
176
180
|
console.error(` ${colors.dim}-${colors.reset} ${colors.bold}${err.path.join('.')}${colors.reset}: ${err.message}`);
|
|
177
181
|
});
|
|
@@ -218,7 +222,7 @@ async function bootstrap() {
|
|
|
218
222
|
const watcher = chokidar.watch(routesDir, { ignoreInitial: true });
|
|
219
223
|
|
|
220
224
|
watcher.on('all', async (event, filepath) => {
|
|
221
|
-
if (!filepath.endsWith('.js')) return;
|
|
225
|
+
if (!filepath.endsWith('.js') && !filepath.endsWith('.ts')) return;
|
|
222
226
|
|
|
223
227
|
try {
|
|
224
228
|
const reloadStartTime = performance.now();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bro-framework",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "The No-BS Backend Framework for Node.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,9 +10,13 @@
|
|
|
10
10
|
"author": "Yessindevs",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"main": "src/index.js",
|
|
13
|
+
"types": "src/index.d.ts",
|
|
13
14
|
"type": "module",
|
|
14
15
|
"exports": {
|
|
15
|
-
".":
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./src/index.d.ts",
|
|
18
|
+
"default": "./src/index.js"
|
|
19
|
+
}
|
|
16
20
|
},
|
|
17
21
|
"bin": {
|
|
18
22
|
"bro": "./bin/bro.js"
|
|
@@ -32,6 +36,7 @@
|
|
|
32
36
|
"multer": "^2.3.0",
|
|
33
37
|
"node-cron": "^4.6.0",
|
|
34
38
|
"socket.io": "^4.8.3",
|
|
39
|
+
"tsx": "^4.23.13",
|
|
35
40
|
"zod": "^3.23.8",
|
|
36
41
|
"zod-to-json-schema": "^3.25.2"
|
|
37
42
|
},
|
package/src/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z, ZodTypeAny } from 'zod';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
type InferZod<T> = T extends ZodTypeAny ? z.infer<T> : any;
|
|
4
|
+
|
|
5
|
+
export interface BroContext<Body = any, Params = any, Query = any> {
|
|
6
|
+
body: InferZod<Body>;
|
|
7
|
+
params: InferZod<Params>;
|
|
8
|
+
query: InferZod<Query>;
|
|
7
9
|
user?: any;
|
|
8
10
|
db?: any;
|
|
9
11
|
io?: any;
|
|
@@ -11,24 +13,26 @@ export interface BroContext {
|
|
|
11
13
|
error?: any;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
export interface RouteConfig {
|
|
16
|
+
export interface RouteConfig<Body = any, Params = any, Query = any> {
|
|
15
17
|
auth?: boolean;
|
|
16
18
|
upload?: boolean;
|
|
17
|
-
body?:
|
|
18
|
-
params?:
|
|
19
|
-
query?:
|
|
19
|
+
body?: Body;
|
|
20
|
+
params?: Params;
|
|
21
|
+
query?: Query;
|
|
20
22
|
rateLimit?: {
|
|
21
23
|
windowMs: number;
|
|
22
24
|
max: number;
|
|
23
25
|
};
|
|
24
26
|
summary?: string;
|
|
25
|
-
handler: (ctx: BroContext) => Promise<any> | any;
|
|
27
|
+
handler: (ctx: BroContext<Body, Params, Query>) => Promise<any> | any;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
export function defineRoute
|
|
30
|
+
export function defineRoute<Body = any, Params = any, Query = any>(
|
|
31
|
+
config: RouteConfig<Body, Params, Query>
|
|
32
|
+
): RouteConfig<Body, Params, Query>;
|
|
29
33
|
|
|
30
34
|
export interface BroConfig {
|
|
31
|
-
env?:
|
|
35
|
+
env?: ZodTypeAny;
|
|
32
36
|
server?: {
|
|
33
37
|
port?: number;
|
|
34
38
|
cors?: boolean | object;
|
package/src/logger.js
CHANGED
|
@@ -25,17 +25,29 @@ export function formatMethod(method) {
|
|
|
25
25
|
|
|
26
26
|
export function printBanner(port, durationMs) {
|
|
27
27
|
const time = durationMs.toFixed(0);
|
|
28
|
-
const version = "
|
|
29
|
-
|
|
28
|
+
const version = "2.0.1";
|
|
29
|
+
const innerWidth = 47;
|
|
30
|
+
|
|
31
|
+
const stripAnsi = (str) => str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
|
|
32
|
+
|
|
33
|
+
const formatLine = (content = "") => {
|
|
34
|
+
const visibleLength = stripAnsi(content).length;
|
|
35
|
+
const padding = Math.max(0, innerWidth - visibleLength);
|
|
36
|
+
return `${colors.green}│${colors.reset}${content}${" ".repeat(padding)}${colors.green}│${colors.reset}`;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const borderTop = `${colors.green}╭${"─".repeat(innerWidth)}╮${colors.reset}`;
|
|
40
|
+
const borderBottom = `${colors.green}╰${"─".repeat(innerWidth)}╯${colors.reset}`;
|
|
41
|
+
|
|
30
42
|
console.log("");
|
|
31
|
-
console.log(
|
|
32
|
-
console.log(
|
|
33
|
-
console.log(
|
|
34
|
-
console.log(
|
|
35
|
-
console.log(
|
|
36
|
-
console.log(
|
|
37
|
-
console.log(
|
|
38
|
-
console.log(
|
|
43
|
+
console.log(borderTop);
|
|
44
|
+
console.log(formatLine());
|
|
45
|
+
console.log(formatLine(` ${colors.bold}bro.js${colors.reset} v${version}`));
|
|
46
|
+
console.log(formatLine());
|
|
47
|
+
console.log(formatLine(` ➜ ${colors.bold}Local:${colors.reset} ${colors.cyan}http://localhost:${port}${colors.reset}`));
|
|
48
|
+
console.log(formatLine(` ➜ ${colors.bold}Ready in:${colors.reset} ${colors.yellow}${time}ms${colors.reset}`));
|
|
49
|
+
console.log(formatLine());
|
|
50
|
+
console.log(borderBottom);
|
|
39
51
|
console.log("");
|
|
40
52
|
}
|
|
41
53
|
|
package/src/router.js
CHANGED
|
@@ -18,7 +18,7 @@ export function scanDir(dir, fileList = []) {
|
|
|
18
18
|
const filePath = path.join(dir, file);
|
|
19
19
|
if (fs.statSync(filePath).isDirectory()) {
|
|
20
20
|
scanDir(filePath, fileList);
|
|
21
|
-
} else if (filePath.endsWith('.js')) {
|
|
21
|
+
} else if (filePath.endsWith('.js') || filePath.endsWith('.ts')) {
|
|
22
22
|
fileList.push(filePath);
|
|
23
23
|
}
|
|
24
24
|
}
|