@dangao/bun-server 1.1.2 → 1.1.4

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.
@@ -0,0 +1,361 @@
1
+ # 使用指南
2
+
3
+ 涵盖从零开始构建 Bun Server 应用的关键步骤。
4
+
5
+ ## 1. 初始化应用
6
+
7
+ ```ts
8
+ import "reflect-metadata";
9
+ import { Application } from "../src";
10
+
11
+ const app = new Application({ port: 3000 });
12
+ app.listen();
13
+ ```
14
+
15
+ > Tip: 默认端口为 3000,可通过 `app.listen(customPort)` 或
16
+ > `new Application({ port })` 调整。
17
+
18
+ ## 2. 注册控制器与依赖
19
+
20
+ ```ts
21
+ import {
22
+ Application,
23
+ Body,
24
+ Controller,
25
+ GET,
26
+ Injectable,
27
+ Param,
28
+ POST,
29
+ } from "../src";
30
+
31
+ @Injectable()
32
+ class UserService {
33
+ private readonly users = new Map<string, string>([["1", "Alice"]]);
34
+ public get(id: string) {
35
+ return this.users.get(id);
36
+ }
37
+ public create(name: string) {
38
+ const id = String(this.users.size + 1);
39
+ this.users.set(id, name);
40
+ return { id, name };
41
+ }
42
+ }
43
+
44
+ @Controller("/api/users")
45
+ class UserController {
46
+ public constructor(private readonly service: UserService) {}
47
+
48
+ @GET("/:id")
49
+ public getUser(@Param("id") id: string) {
50
+ return this.service.get(id) ?? { error: "Not Found" };
51
+ }
52
+
53
+ @POST("/")
54
+ public createUser(@Body() payload: { name: string }) {
55
+ return this.service.create(payload.name);
56
+ }
57
+ }
58
+
59
+ const app = new Application({ port: 3000 });
60
+ app.registerController(UserController);
61
+ app.listen();
62
+ ```
63
+
64
+ ## 3. 使用中间件
65
+
66
+ ```ts
67
+ import { createCorsMiddleware, createLoggerMiddleware } from "../src";
68
+
69
+ const app = new Application();
70
+ app.use(createLoggerMiddleware({ prefix: "[Example]" }));
71
+ app.use(createCorsMiddleware({ origin: "*" }));
72
+ ```
73
+
74
+ `@UseMiddleware()` 可作用于单个控制器或方法:
75
+
76
+ ```ts
77
+ import { UseMiddleware } from '../src';
78
+
79
+ const auth = async (ctx, next) => {
80
+ if (ctx.getHeader('authorization') !== 'token') {
81
+ ctx.setStatus(401);
82
+ return ctx.createResponse({ error: 'Unauthorized' });
83
+ }
84
+ return await next();
85
+ };
86
+
87
+ @UseMiddleware(auth)
88
+ @Controller('/secure')
89
+ class SecureController { ... }
90
+ ```
91
+
92
+ ## 4. 参数验证
93
+
94
+ ```ts
95
+ import { Validate, IsEmail, MinLength } from '../src';
96
+
97
+ @POST('/register')
98
+ public register(
99
+ @Body('email') @Validate(IsEmail()) email: string,
100
+ @Body('password') @Validate(MinLength(6)) password: string,
101
+ ) {
102
+ return { email };
103
+ }
104
+ ```
105
+
106
+ 验证失败将抛出 `ValidationError`,默认错误处理中间件会返回 400 + 详细 `issues`。
107
+
108
+ ## 5. WebSocket 网关
109
+
110
+ ```ts
111
+ import { OnMessage, WebSocketGateway } from "../src";
112
+
113
+ @WebSocketGateway("/ws/chat")
114
+ class ChatGateway {
115
+ @OnMessage
116
+ public onMessage(ws, message: string) {
117
+ ws.send(`echo: ${message}`);
118
+ }
119
+ }
120
+
121
+ app.registerWebSocketGateway(ChatGateway);
122
+ ```
123
+
124
+ ## 6. 文件上传与静态资源
125
+
126
+ ```ts
127
+ import { createFileUploadMiddleware, createStaticFileMiddleware } from "../src";
128
+
129
+ app.use(createFileUploadMiddleware({ maxSize: 5 * 1024 * 1024 }));
130
+ app.use(
131
+ createStaticFileMiddleware({
132
+ root: "./public",
133
+ prefix: "/assets",
134
+ enableCache: true,
135
+ }),
136
+ );
137
+ ```
138
+
139
+ 上传后的文件可在 `context.body.files` 中读取;静态资源请求会自动设置
140
+ Content-Type 与缓存头。
141
+
142
+ ## 7. 错误处理与自定义过滤器
143
+
144
+ ```ts
145
+ import { ExceptionFilterRegistry, HttpException } from "../src";
146
+
147
+ ExceptionFilterRegistry.getInstance().register({
148
+ catch(error, context) {
149
+ if (error instanceof HttpException && error.status === 403) {
150
+ return context.createResponse({ error: "No permission" }, {
151
+ status: 403,
152
+ });
153
+ }
154
+ return undefined;
155
+ },
156
+ });
157
+ ```
158
+
159
+ 默认的 `createErrorHandlingMiddleware` 已自动添加到应用,确保异常均被捕获。
160
+
161
+ ## 8. 扩展系统
162
+
163
+ Bun Server 提供了多种扩展方式,包括中间件、应用扩展、模块系统等。详细说明请参考
164
+ [扩展系统文档](./extensions.md)。
165
+
166
+ ### 快速示例
167
+
168
+ #### 使用模块方式(推荐)
169
+
170
+ ```typescript
171
+ import {
172
+ LoggerModule,
173
+ LogLevel,
174
+ Module,
175
+ SwaggerModule,
176
+ } from "@dangao/bun-server";
177
+
178
+ // 配置模块
179
+ LoggerModule.forRoot({
180
+ logger: { prefix: "App", level: LogLevel.INFO },
181
+ enableRequestLogging: true,
182
+ });
183
+
184
+ SwaggerModule.forRoot({
185
+ info: { title: "API", version: "1.0.0" },
186
+ uiPath: "/swagger",
187
+ });
188
+
189
+ @Module({
190
+ imports: [LoggerModule, SwaggerModule],
191
+ controllers: [UserController],
192
+ providers: [UserService],
193
+ })
194
+ class AppModule {}
195
+
196
+ const app = new Application({ port: 3000 });
197
+ app.registerModule(AppModule);
198
+ ```
199
+
200
+ #### 使用扩展方式
201
+
202
+ ```typescript
203
+ import { LoggerExtension, SwaggerExtension } from "@dangao/bun-server";
204
+
205
+ const app = new Application({ port: 3000 });
206
+
207
+ app.registerExtension(new LoggerExtension({ prefix: "App" }));
208
+ app.registerExtension(
209
+ new SwaggerExtension({
210
+ info: { title: "API", version: "1.0.0" },
211
+ }),
212
+ );
213
+ ```
214
+
215
+ #### 使用中间件
216
+
217
+ ```typescript
218
+ import {
219
+ createCorsMiddleware,
220
+ createLoggerMiddleware,
221
+ } from "@dangao/bun-server";
222
+
223
+ const app = new Application({ port: 3000 });
224
+
225
+ app.use(createLoggerMiddleware({ prefix: "[App]" }));
226
+ app.use(createCorsMiddleware({ origin: "*" }));
227
+ ```
228
+
229
+ 更多扩展方式和使用场景,请参考 [扩展系统文档](./extensions.md)。
230
+
231
+ ### 进阶示例:接口 + Symbol + 模块
232
+
233
+ 此示例演示如何使用接口配合 Symbol token
234
+ 和基于模块的依赖注入,实现更灵活的解耦设计:
235
+
236
+ ```typescript
237
+ import {
238
+ Application,
239
+ Body,
240
+ CONFIG_SERVICE_TOKEN,
241
+ ConfigModule,
242
+ ConfigService,
243
+ Controller,
244
+ GET,
245
+ Inject,
246
+ Injectable,
247
+ Module,
248
+ Param,
249
+ POST,
250
+ } from "@dangao/bun-server";
251
+
252
+ // 定义服务接口
253
+ interface UserService {
254
+ find(id: string): Promise<{ id: string; name: string } | undefined>;
255
+ create(name: string): { id: string; name: string };
256
+ }
257
+
258
+ // 创建 Symbol token 用于依赖注入
259
+ const UserService = Symbol("UserService");
260
+
261
+ // 实现接口
262
+ @Injectable()
263
+ class UserServiceImpl implements UserService {
264
+ private readonly users = new Map<string, { id: string; name: string }>([
265
+ ["1", { id: "1", name: "Alice" }],
266
+ ]);
267
+
268
+ public async find(id: string) {
269
+ return this.users.get(id);
270
+ }
271
+
272
+ public create(name: string) {
273
+ const id = String(this.users.size + 1);
274
+ const user = { id, name };
275
+ this.users.set(id, user);
276
+ return user;
277
+ }
278
+ }
279
+
280
+ @Controller("/api/users")
281
+ class UserController {
282
+ public constructor(
283
+ private readonly service: UserService,
284
+ @Inject(CONFIG_SERVICE_TOKEN) private readonly config: ConfigService,
285
+ ) {}
286
+
287
+ @GET("/:id")
288
+ public async getUser(@Param("id") id: string) {
289
+ const user = await this.service.find(id);
290
+ if (!user) {
291
+ return { error: "Not Found" };
292
+ }
293
+ return user;
294
+ }
295
+
296
+ @POST("/")
297
+ public createUser(@Body("name") name: string) {
298
+ return this.service.create(name);
299
+ }
300
+ }
301
+
302
+ // 使用 Symbol-based provider 定义模块
303
+ @Module({
304
+ controllers: [UserController],
305
+ providers: [
306
+ {
307
+ provide: UserService,
308
+ useClass: UserServiceImpl,
309
+ },
310
+ ],
311
+ exports: [UserService],
312
+ })
313
+ class UserModule {}
314
+
315
+ // 配置模块
316
+ ConfigModule.forRoot({
317
+ defaultConfig: {
318
+ app: {
319
+ name: "Advanced App",
320
+ port: 3100,
321
+ },
322
+ },
323
+ });
324
+
325
+ // 注册模块并启动应用
326
+ @Module({
327
+ imports: [ConfigModule],
328
+ controllers: [UserController],
329
+ providers: [
330
+ {
331
+ provide: UserService,
332
+ useClass: UserServiceImpl,
333
+ },
334
+ ],
335
+ })
336
+ class AppModule {}
337
+
338
+ const app = new Application({ port: 3100 });
339
+ app.registerModule(AppModule);
340
+ app.listen();
341
+ ```
342
+
343
+ **关键要点:**
344
+
345
+ - **基于接口的设计**:使用 TypeScript 接口定义服务契约,便于解耦和测试
346
+ - **Symbol token**:使用 `Symbol()` 创建类型安全的依赖注入 token,避免字符串
347
+ token 的命名冲突
348
+ - **模块提供者**:使用 `provide: Symbol, useClass: Implementation`
349
+ 注册提供者,支持接口与实现分离
350
+ - **类型安全注入**:在构造函数中直接使用接口类型,框架会自动通过 Symbol token
351
+ 解析对应的实现
352
+
353
+ 这种模式特别适合大型项目,可以轻松替换实现而不影响使用方代码。
354
+
355
+ ## 9. 测试建议
356
+
357
+ - 使用 `tests/utils/test-port.ts` 获取自增端口,避免本地冲突。
358
+ - 在 `afterEach` 钩子中调用 `RouteRegistry.getInstance().clear()` 和
359
+ `ControllerRegistry.getInstance().clear()`,保持全局状态干净。
360
+ - 端到端测试中可直接实例化 `Context` 并调用
361
+ `router.handle(context)`,无需真正启动服务器。
@@ -0,0 +1,86 @@
1
+ # 迁移指南
2
+
3
+ 适用于从项目早期版本或其他框架迁移到最新 Bun Server Framework 的场景。
4
+
5
+ ## 1. 项目结构调整
6
+
7
+ - 统一入口到 `src/index.ts`,示例项目可放在 `examples/`。
8
+ - 确保 `tsconfig.json` 开启:
9
+ ```json
10
+ {
11
+ "experimentalDecorators": true,
12
+ "emitDecoratorMetadata": true
13
+ }
14
+ ```
15
+ - 在应用入口(如 `main.ts`)导入一次 `reflect-metadata`:
16
+ ```ts
17
+ import 'reflect-metadata';
18
+ ```
19
+
20
+ ## 2. 路由与控制器
21
+
22
+ - 将旧的函数式注册迁移到装饰器:
23
+ ```ts
24
+ // 旧
25
+ router.get('/users/:id', handler);
26
+
27
+ // 新
28
+ @Controller('/users')
29
+ class UserController {
30
+ @GET('/:id')
31
+ public get(@Param('id') id: string) { ... }
32
+ }
33
+ app.registerController(UserController);
34
+ ```
35
+ - 若暂时需要保留函数式路由,可通过 `RouteRegistry.getInstance().register(method, path, handler)`。
36
+
37
+ ## 3. 依赖注入
38
+
39
+ - 所有可复用服务需添加 `@Injectable()`,并通过构造函数注入使用。
40
+ - 旧的单例或全局对象可改为 `app.getContainer().registerInstance(...)` 注入。
41
+
42
+ ## 4. 中间件与错误处理
43
+
44
+ - 统一使用 `app.use(createErrorHandlingMiddleware())`,并移除 Controller 内的 try/catch。
45
+ - 自定义错误响应时,使用 `ExceptionFilterRegistry`:
46
+ ```ts
47
+ ExceptionFilterRegistry.getInstance().register({
48
+ catch(error, ctx) {
49
+ if (error instanceof MyCustomError) {
50
+ return ctx.createResponse({ error: 'custom' }, { status: 418 });
51
+ }
52
+ return undefined;
53
+ },
54
+ });
55
+ ```
56
+
57
+ ## 5. 文件与静态资源
58
+
59
+ - 旧的上传实现可迁移到 `createFileUploadMiddleware()`,上传结果可从 `context.body.files` 获取。
60
+ - 静态资源统一使用 `createStaticFileMiddleware({ root, prefix })`,避免重复编写路径安全逻辑。
61
+
62
+ ## 6. WebSocket
63
+
64
+ - 将原本在 `Bun.serve({ websocket })` 中手写的逻辑迁移到 `@WebSocketGateway`:
65
+ ```ts
66
+ @WebSocketGateway('/ws/chat')
67
+ class ChatGateway {
68
+ @OnMessage onMessage(ws, msg) { ws.send(msg); }
69
+ }
70
+ app.registerWebSocketGateway(ChatGateway);
71
+ ```
72
+ - 应用启动时会自动处理升级与事件分发。
73
+
74
+ ## 7. 测试与工具
75
+
76
+ - 使用 `tests/utils/test-port.ts` 生成端口,避免冲突。
77
+ - 在 `afterEach` 中调用 `RouteRegistry.getInstance().clear()`、`ControllerRegistry.getInstance().clear()`、`WebSocketGatewayRegistry.getInstance().clear()` 保持测试隔离。
78
+ - 若需模拟 Request,可直接 new `Context(new Request(...))`。
79
+
80
+ ## 8. 配置与依赖
81
+
82
+ - 推荐 Node/Bun 版本:Bun v1.3+、TypeScript 5.4+。
83
+ - 若引入额外依赖(如数据库驱动),建议在 Service 层封装并通过 DI 注入,保持控制器轻量。
84
+
85
+ 完成以上步骤即可平滑过渡到最新的 Bun Server Framework。若遇到破坏性变更,可查阅 changelog 或提交 issue。
86
+