@synchjs/ewb 1.0.0 → 1.0.2
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 +76 -196
- package/dist/Components/ServeMemoryStore.d.ts +15 -1
- package/dist/Components/ServeMemoryStore.d.ts.map +1 -1
- package/dist/Components/ServeMemoryStore.js +210 -28
- package/dist/Components/Server.d.ts +12 -1
- package/dist/Components/Server.d.ts.map +1 -1
- package/dist/Components/Server.js +185 -42
- package/dist/Components/UserHandler.d.ts +21 -0
- package/dist/Components/UserHandler.d.ts.map +1 -0
- package/dist/Components/UserHandler.js +9 -0
- package/dist/Decorations/Authorized.d.ts +2 -5
- package/dist/Decorations/Authorized.d.ts.map +1 -1
- package/dist/Decorations/Authorized.js +6 -6
- package/dist/Decorations/Security.d.ts +0 -1
- package/dist/Decorations/Security.d.ts.map +1 -1
- package/dist/Decorations/Security.js +0 -3
- package/dist/Decorations/Serve.d.ts +1 -0
- package/dist/Decorations/Serve.d.ts.map +1 -1
- package/dist/Decorations/Serve.js +20 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/package.json +12 -9
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# @synchjs/ewb
|
|
2
2
|
|
|
3
|
-
A robust, decorator-based web server framework built on top of **Express** and optimized for **Bun**. It provides a structured way to build scalable APIs with built-in support for **OpenAPI (Swagger)**, **Validation**, **
|
|
3
|
+
A robust, decorator-based web server framework built on top of **Express** and optimized for **Bun**. It provides a structured way to build scalable APIs with built-in support for **OpenAPI (Swagger)**, **Validation**, **Custom User Management**, and **Frontend Asset Serving** with **HMR (Hot Module Replacement)**.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- 🏗 **Decorator-based Routing**: Define controllers and routes using concise decorators (`@Controller`, `@Get`, `@Post`).
|
|
8
|
-
-
|
|
8
|
+
- 👥 **Flexible User Management**: Pluggable `UserHandler` for custom Auth/Identity logic (JWT, Session, Database, etc.).
|
|
9
9
|
- 📜 **Auto-generated Swagger Docs**: Your API documentation is generated automatically from your code.
|
|
10
|
-
- ✅ **Request Validation**:
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- 🖥 **TUI
|
|
10
|
+
- ✅ **Request Validation**: Strict schema-based validation using AJV.
|
|
11
|
+
- 🔥 **Hot Module Replacement (HMR)**: Real-time frontend updates without full page reloads using Socket.io and hot script swapping.
|
|
12
|
+
- 🎨 **Frontend Serving**: Serve HTML/CSS/JS assets from memory, with built-in **Tailwind CSS** processing.
|
|
13
|
+
- 🐚 **Security Hardened**: Built-in protection with **Helmet**, **CORS**, **Rate Limiting**, and path traversal protection.
|
|
14
|
+
- 🖥 **Premium TUI Logs**: Clean, informative, and beautiful startup messages.
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
@@ -26,16 +26,14 @@ bun add @synchjs/ewb
|
|
|
26
26
|
Create a file `controllers/HomeController.ts`:
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
|
-
import { Controller, Get } from "ewb";
|
|
30
|
-
import type { Request, Response } from "express";
|
|
29
|
+
import { Controller, Get } from "@synchjs/ewb";
|
|
31
30
|
|
|
32
31
|
@Controller("/")
|
|
33
32
|
export class HomeController {
|
|
34
33
|
@Get("/", {
|
|
35
34
|
summary: "Welcome endpoint",
|
|
36
|
-
description: "Returns a welcome message.",
|
|
37
35
|
})
|
|
38
|
-
public index(
|
|
36
|
+
public index() {
|
|
39
37
|
return { message: "Hello from @synchjs/ewb!" };
|
|
40
38
|
}
|
|
41
39
|
}
|
|
@@ -46,246 +44,128 @@ export class HomeController {
|
|
|
46
44
|
Create `index.ts`:
|
|
47
45
|
|
|
48
46
|
```typescript
|
|
49
|
-
import { Server } from "ewb";
|
|
47
|
+
import { Server } from "@synchjs/ewb";
|
|
50
48
|
|
|
51
49
|
const server = new Server({
|
|
52
50
|
id: "main",
|
|
53
51
|
port: 3000,
|
|
54
|
-
controllersDir: "controllers",
|
|
55
|
-
enableSwagger: true, // Enable Swagger UI at /api-docs
|
|
52
|
+
controllersDir: "controllers",
|
|
56
53
|
});
|
|
57
54
|
|
|
58
|
-
server.init();
|
|
55
|
+
await server.init();
|
|
59
56
|
```
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
bun run index.ts
|
|
65
|
-
```
|
|
58
|
+
## Authentication & User Management
|
|
66
59
|
|
|
67
|
-
|
|
60
|
+
The framework uses a `UserHandler` system to give you full control over identity.
|
|
68
61
|
|
|
69
|
-
|
|
62
|
+
### 1. Define your User Handler
|
|
70
63
|
|
|
71
64
|
```typescript
|
|
72
|
-
|
|
73
|
-
id: "main",
|
|
74
|
-
port: 3000,
|
|
75
|
-
enableSwagger: true,
|
|
76
|
-
swaggerPath: "/docs", // Now available at http://localhost:3000/docs
|
|
77
|
-
});
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Detailed Usage
|
|
81
|
-
|
|
82
|
-
### Controllers & Routing
|
|
83
|
-
|
|
84
|
-
Use `@Controller` to define a base path and HTTP method decorators for routes.
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
import { Controller, Get, Post, Put, Delete } from "ewb";
|
|
65
|
+
import { UserHandler } from "@synchjs/ewb";
|
|
88
66
|
import type { Request, Response } from "express";
|
|
89
67
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
68
|
+
class MyUserHandler extends UserHandler {
|
|
69
|
+
// Determine who the user is for every request
|
|
70
|
+
public async authenticate(req: Request, res: Response) {
|
|
71
|
+
const token = req.headers.authorization?.replace("Bearer ", "");
|
|
72
|
+
if (token === "admin-secret") {
|
|
73
|
+
return { id: 1, name: "Admin", roles: ["admin"] };
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
96
76
|
}
|
|
97
77
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
201: { description: "User created" },
|
|
102
|
-
},
|
|
103
|
-
})
|
|
104
|
-
public createUser(req: Request, res: Response) {
|
|
105
|
-
// Logic to create user
|
|
106
|
-
return { id: 1, ...req.body };
|
|
78
|
+
// Optional: Automatic routes for /auth/signin, signup, logout
|
|
79
|
+
public signin(req: Request, res: Response) {
|
|
80
|
+
/* ... */
|
|
107
81
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
### Authentication
|
|
112
|
-
|
|
113
|
-
Secure your endpoints using `@BearerAuth`. It integrates with JWT verification automatically.
|
|
114
|
-
|
|
115
|
-
- **Class Level:** Protects all routes in the controller.
|
|
116
|
-
- **Method Level:** Protects specific routes.
|
|
117
|
-
- **@Public():** Excludes a route from class-level auth.
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
import { Controller, Get, BearerAuth, Public } from "ewb";
|
|
121
|
-
|
|
122
|
-
@Controller("/secure")
|
|
123
|
-
@BearerAuth("my_secret_key") // Optional: Custom secret, defaults to process.env.JWT_SECRET
|
|
124
|
-
export class SecureController {
|
|
125
|
-
@Get("/dashboard")
|
|
126
|
-
public dashboard(req: Request, res: Response) {
|
|
127
|
-
// Access user data attached by middleware (req.user)
|
|
128
|
-
const user = (req as any).user;
|
|
129
|
-
return { message: "Secret data", user };
|
|
82
|
+
public signup(req: Request, res: Response) {
|
|
83
|
+
/* ... */
|
|
130
84
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
@Public() // Accessible without token
|
|
134
|
-
public status(req: Request, res: Response) {
|
|
135
|
-
return { status: "OK" };
|
|
85
|
+
public logout(req: Request, res: Response) {
|
|
86
|
+
/* ... */
|
|
136
87
|
}
|
|
137
88
|
}
|
|
138
89
|
```
|
|
139
90
|
|
|
140
|
-
|
|
91
|
+
### 2. Protect Routes
|
|
141
92
|
|
|
142
|
-
|
|
93
|
+
Use `@Authorized` to require a user, or specify roles.
|
|
143
94
|
|
|
144
95
|
```typescript
|
|
145
|
-
import { Controller, Get,
|
|
96
|
+
import { Controller, Get, Authorized } from "@synchjs/ewb";
|
|
146
97
|
|
|
147
|
-
@Controller("/
|
|
148
|
-
export class
|
|
98
|
+
@Controller("/dashboard")
|
|
99
|
+
export class DashboardController {
|
|
149
100
|
@Get("/profile")
|
|
150
|
-
@
|
|
151
|
-
public getProfile() {
|
|
152
|
-
return {
|
|
101
|
+
@Authorized() // Requires a non-null return from your UserHandler
|
|
102
|
+
public getProfile({ user }: { user: any }) {
|
|
103
|
+
return { message: `Hello ${user.name}` };
|
|
153
104
|
}
|
|
154
105
|
|
|
155
|
-
@Get("/
|
|
156
|
-
@
|
|
157
|
-
public
|
|
158
|
-
return {
|
|
106
|
+
@Get("/admin")
|
|
107
|
+
@Authorized(["admin"]) // Checks roles array from UserHandler
|
|
108
|
+
public adminOnly() {
|
|
109
|
+
return { message: "Admin area" };
|
|
159
110
|
}
|
|
160
111
|
}
|
|
161
112
|
```
|
|
162
113
|
|
|
163
|
-
|
|
114
|
+
### 3. Register the Handler
|
|
164
115
|
|
|
165
116
|
```typescript
|
|
166
|
-
const server = new Server({
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
oauth2: {
|
|
170
|
-
type: "oauth2",
|
|
171
|
-
flows: {
|
|
172
|
-
/* ... standard OpenAPI flow definition ... */
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
},
|
|
176
|
-
securityHandlers: {
|
|
177
|
-
oauth2: (req, res, next) => {
|
|
178
|
-
// Your OAuth validation logic here
|
|
179
|
-
next();
|
|
180
|
-
},
|
|
181
|
-
},
|
|
182
|
-
});
|
|
117
|
+
const server = new Server({ ... });
|
|
118
|
+
server.setUserHandler(new MyUserHandler()); // Routes /auth/* are created automatically
|
|
119
|
+
await server.init();
|
|
183
120
|
```
|
|
184
121
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
Define a JSON schema in the `@Post` (or other method) decorator to automatically validate the request body using AJV.
|
|
122
|
+
## Hot Module Replacement (HMR)
|
|
188
123
|
|
|
189
|
-
|
|
190
|
-
@Post("/register", {
|
|
191
|
-
summary: "Register new user",
|
|
192
|
-
requestBody: {
|
|
193
|
-
content: {
|
|
194
|
-
"application/json": {
|
|
195
|
-
schema: {
|
|
196
|
-
type: "object",
|
|
197
|
-
properties: {
|
|
198
|
-
username: { type: "string" },
|
|
199
|
-
email: { type: "string", format: "email" },
|
|
200
|
-
age: { type: "integer", minimum: 18 }
|
|
201
|
-
},
|
|
202
|
-
required: ["username", "email"]
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
})
|
|
208
|
-
public register(req: Request, res: Response) {
|
|
209
|
-
// If execution reaches here, req.body is valid
|
|
210
|
-
return { success: true };
|
|
211
|
-
}
|
|
212
|
-
```
|
|
124
|
+
HMR is active by default when `NODE_ENV` is not set to `production`. It uses Socket.io to sync changes.
|
|
213
125
|
|
|
214
|
-
|
|
126
|
+
- **Fast Refresh**: Specifically optimized for React applications.
|
|
127
|
+
- **Hot Script Swapping**: Updates code in the browser without losing state or full page reloads.
|
|
128
|
+
- **Cache Control**: Automatically disables browser caching during development.
|
|
215
129
|
|
|
216
|
-
|
|
130
|
+
## Serving Frontend Assets
|
|
217
131
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
```
|
|
221
|
-
/views
|
|
222
|
-
src/
|
|
223
|
-
index.html
|
|
224
|
-
index.css (imports tailwind, or handled via plugin)
|
|
225
|
-
frontend.tsx
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
2. **Controller Setup**:
|
|
132
|
+
Use `@Serve` to bundle and serve frontend entry points.
|
|
229
133
|
|
|
230
134
|
```typescript
|
|
231
|
-
import { Controller, Get, Serve, Tailwindcss } from "ewb";
|
|
135
|
+
import { Controller, Get, Serve, Tailwindcss } from "@synchjs/ewb";
|
|
232
136
|
|
|
233
137
|
@Controller("/")
|
|
234
|
-
@Tailwindcss({
|
|
235
|
-
enable: true,
|
|
236
|
-
plugins: [
|
|
237
|
-
/* Bun plugins or custom PostCSS wrappers */
|
|
238
|
-
],
|
|
239
|
-
})
|
|
138
|
+
@Tailwindcss({ enable: true })
|
|
240
139
|
export class FrontendController {
|
|
241
140
|
@Get("/")
|
|
242
|
-
@Serve("views/src/index.html")
|
|
243
|
-
public app(
|
|
244
|
-
//
|
|
141
|
+
@Serve("views/src/index.html")
|
|
142
|
+
public app() {
|
|
143
|
+
// Handled by memory store
|
|
245
144
|
}
|
|
246
145
|
}
|
|
247
146
|
```
|
|
248
147
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
Apply custom Express middleware to controllers or routes using `@Middleware`.
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
import { Controller, Get, Middleware } from "ewb";
|
|
255
|
-
|
|
256
|
-
const logAccess = (req: Request, res: Response, next: NextFunction) => {
|
|
257
|
-
console.log("Accessed!");
|
|
258
|
-
next();
|
|
259
|
-
};
|
|
148
|
+
## Security & Best Practices
|
|
260
149
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
public index(req: Request, res: Response) {
|
|
266
|
-
return { message: "Audited" };
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
```
|
|
150
|
+
- **Strict Validation**: AJV validates all request bodies defined in Swagger options. It automatically removes additional properties and enforces strict types.
|
|
151
|
+
- **Rate Limiting**: Protects your API from brute-force/DoS. (Static assets are automatically exempt).
|
|
152
|
+
- **Security Headers**: Powered by Helmet, with dynamic CSP adjustments for HMR.
|
|
153
|
+
- **Error Handling**: Production mode masks internal errors and stack traces.
|
|
270
154
|
|
|
271
155
|
## Server Configuration
|
|
272
156
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
|
276
|
-
|
|
|
277
|
-
| `
|
|
278
|
-
| `
|
|
279
|
-
| `
|
|
280
|
-
| `
|
|
281
|
-
| `
|
|
282
|
-
| `
|
|
283
|
-
| `
|
|
284
|
-
| `
|
|
285
|
-
| `rateLimitOptions` | `RateLimitOptions` | Configuration for rate limiting. |
|
|
286
|
-
| `securitySchemes` | `object` | custom OpenAPI security schemes definitions. |
|
|
287
|
-
| `securityHandlers` | `object` | Middleware handlers for security schemes. |
|
|
288
|
-
| `container` | `object` | IoC container for dependency injection (must have `get` method). |
|
|
157
|
+
| Option | Type | Description |
|
|
158
|
+
| ------------------ | ---------- | ------------------------------------------------------ |
|
|
159
|
+
| `id` | `string` | ID for logging and console output. |
|
|
160
|
+
| `port` | `number` | Port to listen on. |
|
|
161
|
+
| `controllersDir` | `string` | Location of your controllers (default: `controllers`). |
|
|
162
|
+
| `viewsDir` | `string` | Base directory for frontend views. |
|
|
163
|
+
| `enableSwagger` | `boolean` | Enable Swagger UI (default: `false`). |
|
|
164
|
+
| `swaggerPath` | `string` | Path for docs (default: `/api-docs`). |
|
|
165
|
+
| `helmetOptions` | `object` | Custom Helmet configuration. |
|
|
166
|
+
| `corsOptions` | `object` | Custom CORS configuration. |
|
|
167
|
+
| `rateLimitOptions` | `object` | Custom Rate Limit configuration. |
|
|
168
|
+
| `roleHandler` | `function` | Custom function for advanced role checking logic. |
|
|
289
169
|
|
|
290
170
|
## License
|
|
291
171
|
|
|
@@ -3,12 +3,26 @@ export declare class ServeMemoryStore {
|
|
|
3
3
|
private static _instance;
|
|
4
4
|
private _assets;
|
|
5
5
|
private _htmlCache;
|
|
6
|
+
private _cacheDir;
|
|
7
|
+
private _devMode;
|
|
8
|
+
private _watchers;
|
|
9
|
+
private _listeners;
|
|
6
10
|
private constructor();
|
|
11
|
+
private ensureCacheDir;
|
|
12
|
+
clearCache(): void;
|
|
7
13
|
static get instance(): ServeMemoryStore;
|
|
8
|
-
|
|
14
|
+
setDevMode(enabled: boolean): void;
|
|
15
|
+
onRebuild(listener: (data?: {
|
|
16
|
+
html: string;
|
|
17
|
+
}) => void): void;
|
|
18
|
+
private notify;
|
|
19
|
+
getAsset(rawPath: string): {
|
|
9
20
|
type: string;
|
|
10
21
|
content: Uint8Array;
|
|
11
22
|
};
|
|
23
|
+
private getCacheKey;
|
|
24
|
+
private loadFromDisk;
|
|
25
|
+
private setupWatcher;
|
|
12
26
|
buildAndCache(htmlPath: string, options?: TailwindOptions): Promise<string>;
|
|
13
27
|
}
|
|
14
28
|
//# sourceMappingURL=ServeMemoryStore.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServeMemoryStore.d.ts","sourceRoot":"","sources":["../../src/Components/ServeMemoryStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"ServeMemoryStore.d.ts","sourceRoot":"","sources":["../../src/Components/ServeMemoryStore.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAK/D,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAmB;IAC3C,OAAO,CAAC,OAAO,CACH;IACZ,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,SAAS,CAA0C;IAC3D,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAwC;IACzD,OAAO,CAAC,UAAU,CAA6C;IAE/D,OAAO;IAIP,OAAO,CAAC,cAAc;IAUf,UAAU;IAgBjB,WAAkB,QAAQ,IAAI,gBAAgB,CAK7C;IAEM,UAAU,CAAC,OAAO,EAAE,OAAO;IAI3B,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI;IAI5D,OAAO,CAAC,MAAM;IAIP,QAAQ,CAAC,OAAO,EAAE,MAAM;cAzDM,MAAM;iBAAW,UAAU;;IAgEhE,OAAO,CAAC,WAAW;YAQL,YAAY;IAyB1B,OAAO,CAAC,YAAY;IA4CP,aAAa,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,eAAgD,GACxD,OAAO,CAAC,MAAM,CAAC;CA4JnB"}
|