@dangao/bun-server 1.9.0 → 1.10.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/README.md +55 -6
- package/dist/core/application.d.ts +7 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/server.d.ts +7 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/index.js +20 -21
- package/docs/custom-decorators.md +1 -7
- package/docs/extensions.md +0 -2
- package/docs/guide.md +0 -1
- package/docs/zh/custom-decorators.md +1 -7
- package/docs/zh/extensions.md +0 -2
- package/docs/zh/guide.md +0 -1
- package/docs/zh/migration.md +0 -5
- package/package.json +4 -4
- package/src/core/application.ts +9 -0
- package/src/core/server.ts +9 -0
- package/tests/auth/auth-decorators.test.ts +0 -1
- package/tests/auth/oauth2-service.test.ts +0 -1
- package/tests/cache/cache-decorators-extended.test.ts +0 -1
- package/tests/cache/cache-decorators.test.ts +0 -1
- package/tests/cache/cache-interceptors.test.ts +0 -1
- package/tests/cache/cache-module.test.ts +0 -1
- package/tests/cache/cache-service-proxy.test.ts +0 -1
- package/tests/config/config-center-integration.test.ts +0 -1
- package/tests/config/config-module-extended.test.ts +0 -1
- package/tests/config/config-module.test.ts +0 -1
- package/tests/controller/controller.test.ts +0 -1
- package/tests/controller/param-binder.test.ts +0 -1
- package/tests/controller/path-combination.test.ts +0 -1
- package/tests/core/application.test.ts +34 -0
- package/tests/database/database-module.test.ts +0 -1
- package/tests/database/orm.test.ts +0 -1
- package/tests/database/postgres-mysql-integration.test.ts +0 -1
- package/tests/database/transaction.test.ts +0 -1
- package/tests/di/container.test.ts +0 -1
- package/tests/error/error-handler.test.ts +0 -1
- package/tests/events/event-decorators.test.ts +0 -1
- package/tests/events/event-listener-scanner.test.ts +0 -1
- package/tests/events/event-module.test.ts +0 -1
- package/tests/extensions/logger-module.test.ts +0 -1
- package/tests/health/health-module.test.ts +0 -1
- package/tests/integration/oauth2-e2e.test.ts +0 -1
- package/tests/integration/session-e2e.test.ts +0 -1
- package/tests/interceptor/base-interceptor.test.ts +0 -1
- package/tests/interceptor/builtin/cache-interceptor.test.ts +0 -1
- package/tests/interceptor/builtin/log-interceptor.test.ts +0 -1
- package/tests/interceptor/builtin/permission-interceptor.test.ts +0 -1
- package/tests/interceptor/interceptor-advanced-integration.test.ts +0 -1
- package/tests/interceptor/interceptor-chain.test.ts +0 -1
- package/tests/interceptor/interceptor-integration.test.ts +0 -1
- package/tests/interceptor/interceptor-metadata.test.ts +0 -1
- package/tests/interceptor/interceptor-registry.test.ts +0 -1
- package/tests/interceptor/perf/interceptor-performance.test.ts +0 -1
- package/tests/metrics/metrics-module.test.ts +0 -1
- package/tests/microservice/config-center.test.ts +0 -1
- package/tests/microservice/service-client-decorators.test.ts +0 -1
- package/tests/microservice/service-registry-decorators.test.ts +0 -1
- package/tests/microservice/service-registry.test.ts +0 -1
- package/tests/middleware/builtin/middleware-builtin-extended.test.ts +0 -1
- package/tests/middleware/builtin/rate-limit.test.ts +0 -1
- package/tests/middleware/middleware-decorators.test.ts +0 -1
- package/tests/middleware/middleware-pipeline.test.ts +0 -1
- package/tests/middleware/middleware.test.ts +0 -1
- package/tests/perf/optimization.test.ts +0 -1
- package/tests/queue/queue-decorators.test.ts +0 -1
- package/tests/queue/queue-module.test.ts +0 -1
- package/tests/queue/queue-service.test.ts +0 -1
- package/tests/router/router-decorators.test.ts +0 -1
- package/tests/router/router-extended.test.ts +0 -1
- package/tests/security/guards/guards-integration.test.ts +0 -1
- package/tests/security/guards/guards.test.ts +0 -1
- package/tests/security/guards/reflector.test.ts +0 -1
- package/tests/security/security-filter.test.ts +0 -1
- package/tests/security/security-module-extended.test.ts +0 -1
- package/tests/security/security-module.test.ts +0 -1
- package/tests/session/session-decorators.test.ts +0 -1
- package/tests/session/session-module.test.ts +0 -1
- package/tests/swagger/decorators.test.ts +0 -1
- package/tests/swagger/swagger-module.test.ts +0 -1
- package/tests/swagger/ui.test.ts +0 -1
- package/tests/validation/class-validator.test.ts +0 -1
- package/tests/validation/controller-validation.test.ts +0 -1
package/README.md
CHANGED
|
@@ -433,22 +433,71 @@ learning paths, difficulty ratings, and usage scenarios.
|
|
|
433
433
|
|
|
434
434
|
## Benchmark Suite
|
|
435
435
|
|
|
436
|
-
|
|
437
|
-
|
|
436
|
+
### Internal Micro-benchmarks
|
|
437
|
+
|
|
438
|
+
`PerformanceHarness` & `StressTester` based benchmarks:
|
|
438
439
|
|
|
439
440
|
| Script | Description |
|
|
440
441
|
| ----------------- | --------------------------------------------------------------------- |
|
|
441
442
|
| `router.bench.ts` | static/dynamic route hits, `router.handle` and stress runs |
|
|
442
443
|
| `di.bench.ts` | singleton vs factory resolves, nested dependencies, concurrent stress |
|
|
443
444
|
|
|
444
|
-
Run directly:
|
|
445
|
-
|
|
446
445
|
```bash
|
|
447
446
|
bun benchmark/router.bench.ts
|
|
448
447
|
bun benchmark/di.bench.ts
|
|
449
448
|
```
|
|
450
449
|
|
|
451
|
-
|
|
450
|
+
### Framework Comparison (bun-server vs Express vs NestJS)
|
|
451
|
+
|
|
452
|
+
Real HTTP load testing with [wrk](https://github.com/wg/wrk), comparing
|
|
453
|
+
bun-server against Express 5 and NestJS 11. All frameworks run on the same Bun
|
|
454
|
+
runtime to isolate framework overhead.
|
|
455
|
+
|
|
456
|
+
**Prerequisites:** wrk (`brew install wrk` / `apt install wrk`). The script
|
|
457
|
+
automatically raises `ulimit -n` to 10240 for child processes.
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
bun benchmark/run-wrk-compare.ts # full comparison (3 tiers)
|
|
461
|
+
TIER=0 bun benchmark/run-wrk-compare.ts # Light tier only
|
|
462
|
+
bun benchmark/run-wrk.ts # bun-server only (3 tiers)
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
> **Environment:** Apple M2 Pro (8P + 4E cores) / darwin arm64 / Bun 1.3.10
|
|
466
|
+
|
|
467
|
+
#### Req/Sec (Light: -t2 -c50 -d10s)
|
|
468
|
+
|
|
469
|
+
| Endpoint | bun-server | Express | NestJS |
|
|
470
|
+
|-----------------------|--------------|----------|----------|
|
|
471
|
+
| GET /ping | **31.41k** | 30.01k | 26.52k |
|
|
472
|
+
| GET /json | **28.22k** | 25.99k | 23.64k |
|
|
473
|
+
| GET /users/:id | **30.88k** | 29.91k | 25.62k |
|
|
474
|
+
| GET /search?q= | **29.96k** | 28.70k | 25.17k |
|
|
475
|
+
| POST /users | **27.65k** | 21.37k | 19.38k |
|
|
476
|
+
| POST /users/validated | **26.60k** | 21.28k | 18.93k |
|
|
477
|
+
| GET /middleware | **29.52k** | 28.57k | 24.69k |
|
|
478
|
+
| GET /headers | **30.98k** | 29.57k | 26.43k |
|
|
479
|
+
| GET /io | **21.37k** | 19.46k | 18.49k |
|
|
480
|
+
|
|
481
|
+
Zero errors across all frameworks and tiers. See the full report for Medium and
|
|
482
|
+
Heavy tier results.
|
|
483
|
+
|
|
484
|
+
> 📊 Full comparison report (3 tiers, latency breakdown, per-framework
|
|
485
|
+
> details): [`benchmark/REPORT_COMPARE.md`](./benchmark/REPORT_COMPARE.md)
|
|
486
|
+
>
|
|
487
|
+
> 📋 Single-framework detailed report:
|
|
488
|
+
> [`benchmark/REPORT.md`](./benchmark/REPORT.md)
|
|
489
|
+
|
|
490
|
+
### Multi-process Benchmark (reusePort, Linux only)
|
|
491
|
+
|
|
492
|
+
```bash
|
|
493
|
+
bun benchmark/run-wrk-cluster.ts # default: 1 worker per CPU core
|
|
494
|
+
WORKERS=4 bun benchmark/run-wrk-cluster.ts
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Spawns N workers sharing the same port via `SO_REUSEPORT`. The kernel
|
|
498
|
+
distributes connections across processes. Report saved to
|
|
499
|
+
`benchmark/REPORT_CLUSTER.md`. Note: `reusePort` only works on **Linux**;
|
|
500
|
+
macOS/Windows silently ignore it.
|
|
452
501
|
|
|
453
502
|
## Docs & Localization
|
|
454
503
|
|
|
@@ -525,6 +574,6 @@ Released under the [MIT License](./LICENSE).
|
|
|
525
574
|
|
|
526
575
|
## Other Languages
|
|
527
576
|
|
|
528
|
-
- [中文 README](./
|
|
577
|
+
- [中文 README](./README_ZH.md)
|
|
529
578
|
|
|
530
579
|
Enjoy building on Bun Server!
|
|
@@ -25,6 +25,13 @@ export interface ApplicationOptions {
|
|
|
25
25
|
* 默认 true
|
|
26
26
|
*/
|
|
27
27
|
enableSignalHandlers?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* 是否启用 SO_REUSEPORT
|
|
30
|
+
* 允许多进程绑定同一端口,用于多进程负载均衡
|
|
31
|
+
* 仅 Linux 有效,macOS/Windows 会忽略
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
reusePort?: boolean;
|
|
28
35
|
}
|
|
29
36
|
/**
|
|
30
37
|
* 应用主类
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../../src/core/application.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAsB,MAAM,UAAU,CAAC;AAMzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAS3C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../../src/core/application.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAsB,MAAM,UAAU,CAAC;AAMzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAS3C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,CAAY;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA2B;IAC7D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,uBAAuB,CAAkB;gBAE9B,OAAO,GAAE,kBAAuB;IAsBnD;;;OAGG;IACI,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAIxC;;OAEG;IACU,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCpE;;OAEG;YACW,oBAAoB;IAqBlC;;;OAGG;YACW,sBAAsB;IAyBpC;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAqBhC;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAYlC;;;;;OAKG;IACU,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB9D;;OAEG;YACW,eAAe;IAkB7B;;;;OAIG;YACW,aAAa;IAyC3B;;;OAGG;IACI,kBAAkB,CAAC,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAKtE;;;OAGG;IACI,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAqBrD;;;OAGG;IACH,OAAO,CAAC,kCAAkC;IAc1C;;;OAGG;IACI,wBAAwB,CAAC,YAAY,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI;IAIzE;;;OAGG;IACI,iBAAiB,CAAC,SAAS,EAAE,oBAAoB,GAAG,IAAI;IAK/D;;;OAGG;IACI,SAAS,IAAI,SAAS,GAAG,SAAS;IAIzC;;;OAGG;YACW,gBAAgB;IAsB9B;;;OAGG;YACW,kBAAkB;IAwBhC;;;OAGG;IACI,YAAY;IAInB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA2B7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAS7B"}
|
package/dist/core/server.d.ts
CHANGED
|
@@ -27,6 +27,13 @@ export interface ServerOptions {
|
|
|
27
27
|
* 默认 30 秒
|
|
28
28
|
*/
|
|
29
29
|
gracefulShutdownTimeout?: number;
|
|
30
|
+
/**
|
|
31
|
+
* 是否启用 SO_REUSEPORT
|
|
32
|
+
* 允许多进程绑定同一端口,用于多进程负载均衡
|
|
33
|
+
* 仅 Linux 有效,macOS/Windows 会忽略
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
reusePort?: boolean;
|
|
30
37
|
}
|
|
31
38
|
/**
|
|
32
39
|
* 服务器封装类
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE1D;;OAEG;IACH,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAE7C;;;OAGG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE1D;;OAEG;IACH,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAE7C;;;OAGG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,CAAkC;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,eAAe,CAAC,CAAgB;IACxC,OAAO,CAAC,eAAe,CAAC,CAAa;gBAElB,OAAO,EAAE,aAAa;IAIzC;;OAEG;IACI,KAAK,IAAI,IAAI;IAqGpB;;OAEG;IACI,IAAI,IAAI,IAAI;IAWnB;;;;;OAKG;IACU,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA2C9D;;OAEG;IACI,iBAAiB,IAAI,MAAM;IAIlC;;OAEG;IACI,mBAAmB,IAAI,OAAO;IAIrC;;;OAGG;IACI,SAAS,IAAI,MAAM,CAAC,uBAAuB,CAAC,GAAG,SAAS;IAI/D;;;OAGG;IACI,SAAS,IAAI,OAAO;IAI3B;;OAEG;IACI,OAAO,IAAI,MAAM;IAIxB;;OAEG;IACI,WAAW,IAAI,MAAM,GAAG,SAAS;CAGzC"}
|
package/dist/index.js
CHANGED
|
@@ -1,42 +1,39 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
2
|
var __defProp = Object.defineProperty;
|
|
5
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
for (let key of __getOwnPropNames(mod))
|
|
12
|
-
if (!__hasOwnProp.call(to, key))
|
|
13
|
-
__defProp(to, key, {
|
|
14
|
-
get: () => mod[key],
|
|
15
|
-
enumerable: true
|
|
16
|
-
});
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
function __accessProp(key) {
|
|
7
|
+
return this[key];
|
|
8
|
+
}
|
|
20
9
|
var __toCommonJS = (from) => {
|
|
21
|
-
var entry = __moduleCache.get(from), desc;
|
|
10
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
22
11
|
if (entry)
|
|
23
12
|
return entry;
|
|
24
13
|
entry = __defProp({}, "__esModule", { value: true });
|
|
25
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (var key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(entry, key))
|
|
17
|
+
__defProp(entry, key, {
|
|
18
|
+
get: __accessProp.bind(from, key),
|
|
19
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
20
|
+
});
|
|
21
|
+
}
|
|
30
22
|
__moduleCache.set(from, entry);
|
|
31
23
|
return entry;
|
|
32
24
|
};
|
|
25
|
+
var __moduleCache;
|
|
26
|
+
var __returnValue = (v) => v;
|
|
27
|
+
function __exportSetter(name, newValue) {
|
|
28
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
29
|
+
}
|
|
33
30
|
var __export = (target, all) => {
|
|
34
31
|
for (var name in all)
|
|
35
32
|
__defProp(target, name, {
|
|
36
33
|
get: all[name],
|
|
37
34
|
enumerable: true,
|
|
38
35
|
configurable: true,
|
|
39
|
-
set: (
|
|
36
|
+
set: __exportSetter.bind(all, name)
|
|
40
37
|
});
|
|
41
38
|
};
|
|
42
39
|
var __legacyDecorateClassTS = function(decorators, target, key, desc) {
|
|
@@ -4006,6 +4003,7 @@ class BunServer {
|
|
|
4006
4003
|
this.server = Bun.serve({
|
|
4007
4004
|
port: this.options.port ?? 3000,
|
|
4008
4005
|
hostname: this.options.hostname,
|
|
4006
|
+
reusePort: this.options.reusePort,
|
|
4009
4007
|
fetch: (request, server) => {
|
|
4010
4008
|
if (this.isShuttingDown) {
|
|
4011
4009
|
return new Response("Server is shutting down", { status: 503 });
|
|
@@ -5860,6 +5858,7 @@ class Application {
|
|
|
5860
5858
|
const serverOptions = {
|
|
5861
5859
|
port: finalPort,
|
|
5862
5860
|
hostname: finalHostname,
|
|
5861
|
+
reusePort: this.options.reusePort,
|
|
5863
5862
|
fetch: this.handleRequest.bind(this),
|
|
5864
5863
|
websocketRegistry: this.websocketRegistry,
|
|
5865
5864
|
gracefulShutdownTimeout: this.options.gracefulShutdownTimeout
|
|
@@ -27,11 +27,9 @@ Bun Server Framework provides a powerful interceptor mechanism that allows you t
|
|
|
27
27
|
|
|
28
28
|
### Basic Decorator Pattern
|
|
29
29
|
|
|
30
|
-
A custom decorator is a function that returns a `MethodDecorator`. It uses
|
|
30
|
+
A custom decorator is a function that returns a `MethodDecorator`. It uses the Reflect metadata API to store metadata on the method.
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
|
-
import 'reflect-metadata';
|
|
34
|
-
|
|
35
33
|
// 1. Define a metadata key (use Symbol for uniqueness)
|
|
36
34
|
export const MY_METADATA_KEY = Symbol('@my-app:my-decorator');
|
|
37
35
|
|
|
@@ -260,8 +258,6 @@ class MyInterceptor extends BaseInterceptor {
|
|
|
260
258
|
### Storing Metadata
|
|
261
259
|
|
|
262
260
|
```typescript
|
|
263
|
-
import 'reflect-metadata';
|
|
264
|
-
|
|
265
261
|
const METADATA_KEY = Symbol('my-metadata');
|
|
266
262
|
|
|
267
263
|
// Store metadata
|
|
@@ -337,7 +333,6 @@ class MyInterceptor extends BaseInterceptor {
|
|
|
337
333
|
### Example 1: Simple Logging Interceptor
|
|
338
334
|
|
|
339
335
|
```typescript
|
|
340
|
-
import 'reflect-metadata';
|
|
341
336
|
import { BaseInterceptor } from '@dangao/bun-server';
|
|
342
337
|
import type { Container } from '@dangao/bun-server';
|
|
343
338
|
import type { Context } from '@dangao/bun-server';
|
|
@@ -375,7 +370,6 @@ export class LogInterceptor extends BaseInterceptor {
|
|
|
375
370
|
### Example 2: Rate Limiting Interceptor
|
|
376
371
|
|
|
377
372
|
```typescript
|
|
378
|
-
import 'reflect-metadata';
|
|
379
373
|
import { BaseInterceptor, HttpException } from '@dangao/bun-server';
|
|
380
374
|
import type { Container } from '@dangao/bun-server';
|
|
381
375
|
import type { Context } from '@dangao/bun-server';
|
package/docs/extensions.md
CHANGED
|
@@ -499,8 +499,6 @@ You can create custom decorators to extend controller and route functionality.
|
|
|
499
499
|
### Creating Decorators
|
|
500
500
|
|
|
501
501
|
```typescript
|
|
502
|
-
import 'reflect-metadata';
|
|
503
|
-
|
|
504
502
|
// Cache decorator
|
|
505
503
|
export function Cache(ttl: number) {
|
|
506
504
|
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
|
package/docs/guide.md
CHANGED
|
@@ -29,12 +29,10 @@ AOP(面向切面编程)。这使您能够添加横切关注点,如缓存
|
|
|
29
29
|
|
|
30
30
|
### 基本装饰器模式
|
|
31
31
|
|
|
32
|
-
自定义装饰器是一个返回 `MethodDecorator` 的函数。它使用
|
|
32
|
+
自定义装饰器是一个返回 `MethodDecorator` 的函数。它使用 Reflect 元数据 API
|
|
33
33
|
在方法上存储元数据。
|
|
34
34
|
|
|
35
35
|
```typescript
|
|
36
|
-
import "reflect-metadata";
|
|
37
|
-
|
|
38
36
|
// 1. 定义元数据键(使用 Symbol 确保唯一性)
|
|
39
37
|
export const MY_METADATA_KEY = Symbol("@my-app:my-decorator");
|
|
40
38
|
|
|
@@ -280,8 +278,6 @@ class MyInterceptor extends BaseInterceptor {
|
|
|
280
278
|
### 存储元数据
|
|
281
279
|
|
|
282
280
|
```typescript
|
|
283
|
-
import "reflect-metadata";
|
|
284
|
-
|
|
285
281
|
const METADATA_KEY = Symbol("my-metadata");
|
|
286
282
|
|
|
287
283
|
// 存储元数据
|
|
@@ -364,7 +360,6 @@ class MyInterceptor extends BaseInterceptor {
|
|
|
364
360
|
### 示例 1:简单日志拦截器
|
|
365
361
|
|
|
366
362
|
```typescript
|
|
367
|
-
import 'reflect-metadata';
|
|
368
363
|
import { BaseInterceptor } from '@dangao/bun-server';
|
|
369
364
|
import type { Container } from '@dangao/bun-server';
|
|
370
365
|
import type { Context } from '@dangao/bun-server';
|
|
@@ -402,7 +397,6 @@ export class LogInterceptor extends BaseInterceptor {
|
|
|
402
397
|
### 示例 2:限流拦截器
|
|
403
398
|
|
|
404
399
|
```typescript
|
|
405
|
-
import 'reflect-metadata';
|
|
406
400
|
import { BaseInterceptor, HttpException } from '@dangao/bun-server';
|
|
407
401
|
import type { Container } from '@dangao/bun-server';
|
|
408
402
|
import type { Context } from '@dangao/bun-server';
|
package/docs/zh/extensions.md
CHANGED
package/docs/zh/guide.md
CHANGED
package/docs/zh/migration.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dangao/bun-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
],
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
|
-
"
|
|
28
|
+
"README.md",
|
|
29
29
|
"LICENSE",
|
|
30
30
|
"src",
|
|
31
31
|
"tests",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"url": "https://github.com/dangaogit/bun-server/issues"
|
|
39
39
|
},
|
|
40
40
|
"engines": {
|
|
41
|
-
"bun": ">=1.3.
|
|
41
|
+
"bun": ">=1.3.10"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"dev": "bun --watch src/index.ts",
|
|
@@ -58,6 +58,6 @@
|
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"reflect-metadata": "^0.2.2",
|
|
60
60
|
"@dangao/logsmith": "0.1.1",
|
|
61
|
-
"@dangao/nacos-client": "0.1.
|
|
61
|
+
"@dangao/nacos-client": "0.1.1"
|
|
62
62
|
}
|
|
63
63
|
}
|
package/src/core/application.ts
CHANGED
|
@@ -45,6 +45,14 @@ export interface ApplicationOptions {
|
|
|
45
45
|
* 默认 true
|
|
46
46
|
*/
|
|
47
47
|
enableSignalHandlers?: boolean;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 是否启用 SO_REUSEPORT
|
|
51
|
+
* 允许多进程绑定同一端口,用于多进程负载均衡
|
|
52
|
+
* 仅 Linux 有效,macOS/Windows 会忽略
|
|
53
|
+
* @default false
|
|
54
|
+
*/
|
|
55
|
+
reusePort?: boolean;
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
/**
|
|
@@ -112,6 +120,7 @@ export class Application {
|
|
|
112
120
|
const serverOptions: ServerOptions = {
|
|
113
121
|
port: finalPort,
|
|
114
122
|
hostname: finalHostname,
|
|
123
|
+
reusePort: this.options.reusePort,
|
|
115
124
|
fetch: this.handleRequest.bind(this),
|
|
116
125
|
websocketRegistry: this.websocketRegistry,
|
|
117
126
|
gracefulShutdownTimeout: this.options.gracefulShutdownTimeout,
|
package/src/core/server.ts
CHANGED
|
@@ -33,6 +33,14 @@ export interface ServerOptions {
|
|
|
33
33
|
* 默认 30 秒
|
|
34
34
|
*/
|
|
35
35
|
gracefulShutdownTimeout?: number;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 是否启用 SO_REUSEPORT
|
|
39
|
+
* 允许多进程绑定同一端口,用于多进程负载均衡
|
|
40
|
+
* 仅 Linux 有效,macOS/Windows 会忽略
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
reusePort?: boolean;
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
/**
|
|
@@ -70,6 +78,7 @@ export class BunServer {
|
|
|
70
78
|
this.server = Bun.serve({
|
|
71
79
|
port: this.options.port ?? 3000,
|
|
72
80
|
hostname: this.options.hostname,
|
|
81
|
+
reusePort: this.options.reusePort,
|
|
73
82
|
fetch: (
|
|
74
83
|
request: Request,
|
|
75
84
|
server: Server<WebSocketConnectionData>,
|
|
@@ -53,5 +53,39 @@ describe('Application', () => {
|
|
|
53
53
|
const data = await response.json();
|
|
54
54
|
expect(data.error).toBe('Not Found');
|
|
55
55
|
});
|
|
56
|
+
|
|
57
|
+
test('should accept reusePort option', async () => {
|
|
58
|
+
const port = getTestPort();
|
|
59
|
+
app = new Application({ port, reusePort: true });
|
|
60
|
+
await app.listen();
|
|
61
|
+
|
|
62
|
+
const server = app.getServer();
|
|
63
|
+
expect(server).toBeDefined();
|
|
64
|
+
expect(server?.isRunning()).toBe(true);
|
|
65
|
+
|
|
66
|
+
const response = await fetch(`http://localhost:${port}/api/ping`);
|
|
67
|
+
expect(response.status).toBe(404);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('should allow two servers on same port with reusePort (Linux only)', async () => {
|
|
71
|
+
if (process.platform !== 'linux') {
|
|
72
|
+
console.log('Skipping reusePort dual-bind test: only works on Linux');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const port = getTestPort();
|
|
77
|
+
app = new Application({ port, reusePort: true });
|
|
78
|
+
await app.listen();
|
|
79
|
+
|
|
80
|
+
const app2 = new Application({ port, reusePort: true });
|
|
81
|
+
await app2.listen();
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const response = await fetch(`http://localhost:${port}/api/test`);
|
|
85
|
+
expect(response.status).toBe(404);
|
|
86
|
+
} finally {
|
|
87
|
+
await app2.stop();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
56
90
|
});
|
|
57
91
|
|
|
@@ -3,7 +3,6 @@ import { DatabaseModule, DatabaseService, DATABASE_SERVICE_TOKEN } from '../../s
|
|
|
3
3
|
import { Container } from '../../src/di/container';
|
|
4
4
|
import { ModuleRegistry } from '../../src/di/module-registry';
|
|
5
5
|
import { MODULE_METADATA_KEY } from '../../src/di/module';
|
|
6
|
-
import 'reflect-metadata';
|
|
7
6
|
|
|
8
7
|
describe('DatabaseModule', () => {
|
|
9
8
|
let container: Container;
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
} from '../../src/database/orm';
|
|
10
10
|
import { DatabaseService, DATABASE_SERVICE_TOKEN } from '../../src/database';
|
|
11
11
|
import { Container } from '../../src/di/container';
|
|
12
|
-
import 'reflect-metadata';
|
|
13
12
|
|
|
14
13
|
describe('TransactionManager', () => {
|
|
15
14
|
let container: Container;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
|
-
import 'reflect-metadata';
|
|
3
2
|
|
|
4
3
|
import { handleError } from '../../src/error/handler';
|
|
5
4
|
import { HttpException, BadRequestException, UnauthorizedException, ForbiddenException, NotFoundException } from '../../src/error';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
|
-
import 'reflect-metadata';
|
|
3
2
|
|
|
4
3
|
import { Application } from '../../src/core/application';
|
|
5
4
|
import { MetricsModule, MetricsCollector, createHttpMetricsMiddleware, type CustomMetric } from '../../src/metrics';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
|
-
import 'reflect-metadata';
|
|
3
2
|
import { ConfigCenterModule, CONFIG_CENTER_TOKEN, type ConfigCenter } from '../../src/microservice/config-center';
|
|
4
3
|
import { Container } from '../../src/di/container';
|
|
5
4
|
import { ModuleRegistry } from '../../src/di/module-registry';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
|
-
import 'reflect-metadata';
|
|
3
2
|
import { ServiceRegistryModule, SERVICE_REGISTRY_TOKEN, type ServiceRegistry } from '../../src/microservice/service-registry';
|
|
4
3
|
import { MODULE_METADATA_KEY } from '../../src/di/module';
|
|
5
4
|
import { ControllerRegistry } from '../../src/controller/controller';
|
|
@@ -5,7 +5,6 @@ import { MiddlewarePipeline } from '../../src/middleware/pipeline';
|
|
|
5
5
|
import { Container } from '../../src/di/container';
|
|
6
6
|
import { Injectable, Inject } from '../../src/di/decorators';
|
|
7
7
|
import { PerformanceHarness } from '../../src/testing/harness';
|
|
8
|
-
import 'reflect-metadata';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* 性能优化验证测试
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { describe, expect, test, beforeEach, afterEach } from 'bun:test';
|
|
2
|
-
import 'reflect-metadata';
|
|
3
2
|
import { Application } from '../../../src/core/application';
|
|
4
3
|
import { Controller } from '../../../src/controller';
|
|
5
4
|
import { GET, POST } from '../../../src/router/decorators';
|
|
@@ -3,7 +3,6 @@ import { SecurityModule } from '../../src/security/security-module';
|
|
|
3
3
|
import { MODULE_METADATA_KEY } from '../../src/di/module';
|
|
4
4
|
import { JWT_UTIL_TOKEN, OAUTH2_SERVICE_TOKEN } from '../../src/auth/controller';
|
|
5
5
|
import { AuthenticationManager } from '../../src/security/authentication-manager';
|
|
6
|
-
import 'reflect-metadata';
|
|
7
6
|
|
|
8
7
|
describe('SecurityModule', () => {
|
|
9
8
|
beforeEach(() => {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test, beforeEach } from 'bun:test';
|
|
2
2
|
import { SwaggerModule } from '../../src/swagger/swagger-module';
|
|
3
3
|
import { MODULE_METADATA_KEY } from '../../src/di/module';
|
|
4
|
-
import 'reflect-metadata';
|
|
5
4
|
|
|
6
5
|
describe('SwaggerModule', () => {
|
|
7
6
|
beforeEach(() => {
|
package/tests/swagger/ui.test.ts
CHANGED