@dangao/bun-server 2.2.0 → 3.0.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 +81 -3
- package/dist/ai/providers/anthropic-provider.d.ts.map +1 -1
- package/dist/ai/providers/google-provider.d.ts.map +1 -1
- package/dist/ai/providers/ollama-provider.d.ts.map +1 -1
- package/dist/ai/providers/openai-provider.d.ts.map +1 -1
- package/dist/ai/service.d.ts.map +1 -1
- package/dist/ai/types.d.ts +5 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/auth/jwt.d.ts.map +1 -1
- package/dist/config/service.d.ts +0 -1
- package/dist/config/service.d.ts.map +1 -1
- package/dist/core/application.d.ts +30 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/context.d.ts +5 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/server.d.ts +29 -9
- package/dist/core/server.d.ts.map +1 -1
- package/dist/dashboard/controller.d.ts.map +1 -1
- package/dist/database/connection-pool.d.ts +3 -3
- package/dist/database/connection-pool.d.ts.map +1 -1
- package/dist/database/sql-manager.d.ts +8 -4
- package/dist/database/sql-manager.d.ts.map +1 -1
- package/dist/database/sqlite-adapter.d.ts +7 -3
- package/dist/database/sqlite-adapter.d.ts.map +1 -1
- package/dist/debug/recorder.d.ts +0 -1
- package/dist/debug/recorder.d.ts.map +1 -1
- package/dist/files/static-middleware.d.ts.map +1 -1
- package/dist/files/storage.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40335 -3523
- package/dist/index.node.mjs +17689 -0
- package/dist/mcp/server.d.ts +5 -2
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/middleware/builtin/static-file.d.ts +4 -2
- package/dist/middleware/builtin/static-file.d.ts.map +1 -1
- package/dist/platform/bun/crypto.d.ts +3 -0
- package/dist/platform/bun/crypto.d.ts.map +1 -0
- package/dist/platform/bun/fs.d.ts +3 -0
- package/dist/platform/bun/fs.d.ts.map +1 -0
- package/dist/platform/bun/http.d.ts +15 -0
- package/dist/platform/bun/http.d.ts.map +1 -0
- package/dist/platform/bun/index.d.ts +3 -0
- package/dist/platform/bun/index.d.ts.map +1 -0
- package/dist/platform/bun/parser.d.ts +3 -0
- package/dist/platform/bun/parser.d.ts.map +1 -0
- package/dist/platform/bun/process.d.ts +3 -0
- package/dist/platform/bun/process.d.ts.map +1 -0
- package/dist/platform/detector.d.ts +9 -0
- package/dist/platform/detector.d.ts.map +1 -0
- package/dist/platform/index.d.ts +4 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/node/crypto.d.ts +3 -0
- package/dist/platform/node/crypto.d.ts.map +1 -0
- package/dist/platform/node/fs.d.ts +3 -0
- package/dist/platform/node/fs.d.ts.map +1 -0
- package/dist/platform/node/http.d.ts +3 -0
- package/dist/platform/node/http.d.ts.map +1 -0
- package/dist/platform/node/index.d.ts +3 -0
- package/dist/platform/node/index.d.ts.map +1 -0
- package/dist/platform/node/parser.d.ts +3 -0
- package/dist/platform/node/parser.d.ts.map +1 -0
- package/dist/platform/node/process.d.ts +3 -0
- package/dist/platform/node/process.d.ts.map +1 -0
- package/dist/platform/runtime.d.ts +14 -0
- package/dist/platform/runtime.d.ts.map +1 -0
- package/dist/platform/types.d.ts +139 -0
- package/dist/platform/types.d.ts.map +1 -0
- package/dist/prompt/stores/file-store.d.ts.map +1 -1
- package/dist/rag/service.d.ts.map +1 -1
- package/dist/request/response.d.ts +3 -1
- package/dist/request/response.d.ts.map +1 -1
- package/dist/security/guards/execution-context.d.ts +2 -2
- package/dist/security/guards/execution-context.d.ts.map +1 -1
- package/dist/security/guards/types.d.ts +2 -2
- package/dist/security/guards/types.d.ts.map +1 -1
- package/dist/swagger/generator.d.ts.map +1 -1
- package/dist/websocket/registry.d.ts +4 -4
- package/dist/websocket/registry.d.ts.map +1 -1
- package/docs/deployment.md +31 -7
- package/docs/design/query-interceptor-design.md +381 -0
- package/docs/idle-timeout.md +101 -8
- package/docs/migration.md +43 -0
- package/docs/platform.md +299 -0
- package/docs/testing.md +60 -0
- package/docs/zh/deployment.md +30 -7
- package/docs/zh/idle-timeout.md +99 -6
- package/docs/zh/migration.md +42 -0
- package/docs/zh/platform.md +299 -0
- package/docs/zh/testing.md +60 -0
- package/package.json +24 -6
- package/src/ai/providers/anthropic-provider.ts +5 -2
- package/src/ai/providers/google-provider.ts +3 -0
- package/src/ai/providers/ollama-provider.ts +3 -0
- package/src/ai/providers/openai-provider.ts +5 -2
- package/src/ai/service.ts +17 -5
- package/src/ai/types.ts +5 -0
- package/src/auth/jwt.ts +4 -3
- package/src/config/service.ts +7 -6
- package/src/core/application.ts +38 -1
- package/src/core/cluster.ts +16 -14
- package/src/core/context.ts +7 -0
- package/src/core/server.ts +162 -46
- package/src/dashboard/controller.ts +3 -2
- package/src/database/connection-pool.ts +32 -20
- package/src/database/database-module.ts +1 -1
- package/src/database/db-proxy.ts +2 -2
- package/src/database/orm/transaction-manager.ts +1 -1
- package/src/database/sql-manager.ts +48 -13
- package/src/database/sqlite-adapter.ts +45 -12
- package/src/debug/recorder.ts +4 -3
- package/src/files/static-middleware.ts +3 -2
- package/src/files/storage.ts +2 -1
- package/src/index.ts +13 -0
- package/src/mcp/server.ts +6 -15
- package/src/middleware/builtin/static-file.ts +8 -5
- package/src/platform/bun/crypto.ts +30 -0
- package/src/platform/bun/fs.ts +52 -0
- package/src/platform/bun/http.ts +106 -0
- package/src/platform/bun/index.ts +17 -0
- package/src/platform/bun/parser.ts +19 -0
- package/src/platform/bun/process.ts +37 -0
- package/src/platform/detector.ts +36 -0
- package/src/platform/index.ts +20 -0
- package/src/platform/node/crypto.ts +40 -0
- package/src/platform/node/fs.ts +115 -0
- package/src/platform/node/http.ts +196 -0
- package/src/platform/node/index.ts +17 -0
- package/src/platform/node/parser.ts +34 -0
- package/src/platform/node/process.ts +51 -0
- package/src/platform/runtime.ts +50 -0
- package/src/platform/types.ts +150 -0
- package/src/prompt/stores/file-store.ts +6 -5
- package/src/rag/service.ts +2 -1
- package/src/request/response.ts +7 -4
- package/src/security/guards/execution-context.ts +4 -4
- package/src/security/guards/types.ts +2 -2
- package/src/swagger/generator.ts +2 -1
- package/src/websocket/registry.ts +6 -7
- package/tests/controller/path-combination.test.ts +196 -2
- package/tests/files/static-middleware.test.ts +5 -2
- package/tests/middleware/static-file.test.ts +5 -2
- package/tests/platform/bun/crypto.test.ts +8 -0
- package/tests/platform/bun/database.test.ts +8 -0
- package/tests/platform/bun/fs.test.ts +8 -0
- package/tests/platform/bun/parser.test.ts +8 -0
- package/tests/platform/bun/process.test.ts +8 -0
- package/tests/platform/bun/websocket.test.ts +8 -0
- package/tests/platform/detector.test.ts +57 -0
- package/tests/platform/node/build-smoke.test.ts +92 -0
- package/tests/platform/node/crypto.test.ts +9 -0
- package/tests/platform/node/database.test.ts +9 -0
- package/tests/platform/node/fs.test.ts +9 -0
- package/tests/platform/node/parser.test.ts +9 -0
- package/tests/platform/node/process.test.ts +9 -0
- package/tests/platform/node/websocket.test.ts +9 -0
- package/tests/platform/shared/crypto.cases.ts +49 -0
- package/tests/platform/shared/database.cases.ts +43 -0
- package/tests/platform/shared/fs.cases.ts +82 -0
- package/tests/platform/shared/parser.cases.ts +55 -0
- package/tests/platform/shared/process.cases.ts +26 -0
- package/tests/platform/shared/suite.ts +33 -0
- package/tests/platform/shared/websocket.cases.ts +61 -0
- package/tests/request/response.test.ts +5 -2
- package/tests/router/router-extended.test.ts +53 -0
package/docs/platform.md
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
# Platform Adapter Guide
|
|
2
|
+
|
|
3
|
+
**English** | [中文](./zh/platform.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Bun Server runs natively on **Bun** and **Node.js 22+** through an internal Platform Adapter Layer. All runtime-specific APIs (HTTP server, file I/O, crypto, parsers, process management, WebSocket) are abstracted behind unified TypeScript interfaces. You write one codebase; the framework picks the right implementation at startup — no extra configuration required.
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Architecture](#architecture)
|
|
12
|
+
- [Runtime Detection](#runtime-detection)
|
|
13
|
+
- [Platform Configuration](#platform-configuration)
|
|
14
|
+
- [Support Matrix](#support-matrix)
|
|
15
|
+
- [Database Auto-Adaptation](#database-auto-adaptation)
|
|
16
|
+
- [Public API Changes](#public-api-changes)
|
|
17
|
+
- [Bun-Exclusive Features](#bun-exclusive-features)
|
|
18
|
+
- [Node.js Startup Guide](#nodejs-startup-guide)
|
|
19
|
+
- [Testing on Multiple Runtimes](#testing-on-multiple-runtimes)
|
|
20
|
+
- [Known Limitations](#known-limitations)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Architecture
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
┌──────────────────────────────────────────────────────┐
|
|
28
|
+
│ Application Layer │
|
|
29
|
+
│ Controllers / Services / Modules / Middleware │
|
|
30
|
+
└──────────────────────────┬───────────────────────────┘
|
|
31
|
+
│ getRuntime()
|
|
32
|
+
┌──────────────────────────▼───────────────────────────┐
|
|
33
|
+
│ Platform Adapter Layer │
|
|
34
|
+
│ IFsAdapter · ICryptoAdapter · IParserAdapter │
|
|
35
|
+
│ IProcessAdapter · IHttpDriver · IWebSocket │
|
|
36
|
+
└──────┬───────────────────────────────┬───────────────┘
|
|
37
|
+
│ │
|
|
38
|
+
┌──────▼──────┐ ┌──────▼──────┐
|
|
39
|
+
│ BunPlatform │ │ NodePlatform│
|
|
40
|
+
│ Bun.serve │ │ node:http │
|
|
41
|
+
│ Bun.file │ │ node:fs │
|
|
42
|
+
│ Bun.Crypto │ │ node:crypto │
|
|
43
|
+
│ spawn(bun) │ │ ws package │
|
|
44
|
+
└─────────────┘ └─────────────┘
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Each adapter surface has a corresponding TypeScript interface:
|
|
48
|
+
|
|
49
|
+
| Interface | Bun Implementation | Node.js Implementation |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `IFsAdapter` | `Bun.file`, `Bun.write`, `Bun.Glob` | `node:fs/promises`, `node:fs` glob |
|
|
52
|
+
| `ICryptoAdapter` | `Bun.CryptoHasher` | `node:crypto` HMAC/hash |
|
|
53
|
+
| `IParserAdapter` | `Bun.JSONC`, `Bun.JSON5`, `Bun.JSONL`, `Bun.markdown` | `jsonc-parser`, `json5`, custom JSONL, `marked` |
|
|
54
|
+
| `IProcessAdapter` | `spawn` (bun), `Bun.sleep` | `node:child_process`, `setTimeout` |
|
|
55
|
+
| `IHttpDriver` | `Bun.serve` | `node:http.createServer` |
|
|
56
|
+
| `IWebSocket<T>` | `Bun.ServerWebSocket<T>` | `ws` package |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Runtime Detection
|
|
61
|
+
|
|
62
|
+
Platform is resolved at `Application` construction time following this priority chain:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
1. Bootstrap config → new Application({ platform: 'node' })
|
|
66
|
+
2. CLI argument → --platform=node
|
|
67
|
+
3. Environment var → BUN_SERVER_PLATFORM=node
|
|
68
|
+
4. Auto-detect → typeof Bun !== 'undefined' ? 'bun' : 'node'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Once resolved, the singleton is frozen for the lifetime of the process. Subsequent calls to `getRuntime()` return the same instance.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Platform Configuration
|
|
76
|
+
|
|
77
|
+
### Option 1 — Code (highest priority)
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { Application } from '@dangao/bun-server';
|
|
81
|
+
|
|
82
|
+
const app = new Application({ platform: 'node' }); // 'bun' | 'node'
|
|
83
|
+
app.registerModule(AppModule);
|
|
84
|
+
await app.listen(3000);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Option 2 — CLI argument
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Bun runtime, but force Node.js adapter
|
|
91
|
+
bun run src/main.ts --platform=node
|
|
92
|
+
|
|
93
|
+
# Node.js runtime (auto-detected even without the flag)
|
|
94
|
+
node dist/main.js
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Option 3 — Environment variable
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
BUN_SERVER_PLATFORM=node node dist/main.js
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Option 4 — Auto-detect (default)
|
|
104
|
+
|
|
105
|
+
No configuration needed. If `typeof Bun !== 'undefined'`, `BunPlatform` is selected; otherwise `NodePlatform` is selected automatically.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Support Matrix
|
|
110
|
+
|
|
111
|
+
| Feature | Bun | Node.js 22+ |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| HTTP server | `Bun.serve` (native) | `node:http` |
|
|
114
|
+
| WebSocket | `Bun.ServerWebSocket` (native) | `ws` package |
|
|
115
|
+
| File I/O | `Bun.file / Bun.write` | `node:fs/promises` |
|
|
116
|
+
| Crypto / JWT | `Bun.CryptoHasher` | `node:crypto` |
|
|
117
|
+
| JSONC parsing | `Bun.JSONC` | `jsonc-parser` package |
|
|
118
|
+
| JSON5 parsing | `Bun.JSON5` | `json5` package |
|
|
119
|
+
| JSONL parsing | `Bun.JSONL` | Custom streaming parser |
|
|
120
|
+
| Markdown render | `Bun.markdown` | `marked` package |
|
|
121
|
+
| Cluster spawn | Bun `spawn` | `node:child_process` |
|
|
122
|
+
| SQLite | `bun:sqlite` | `better-sqlite3` |
|
|
123
|
+
| PostgreSQL | `Bun.SQL` | `postgres` package |
|
|
124
|
+
| MySQL | `Bun.SQL` | `mysql2` package |
|
|
125
|
+
| `idleTimeout` | Yes | Silently ignored |
|
|
126
|
+
| `reusePort` | Yes | Silently ignored |
|
|
127
|
+
| SSE TCP keepalive | Yes (via `server.timeout`) | Not available |
|
|
128
|
+
| Overall performance | Optimal | Good |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Database Auto-Adaptation
|
|
133
|
+
|
|
134
|
+
`DatabaseModule` automatically selects drivers based on the detected platform. **No additional user configuration is required.**
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Bun platform Node.js platform
|
|
138
|
+
───────────────────────────── ─────────────────────────────
|
|
139
|
+
SQLite → bun:sqlite SQLite → better-sqlite3
|
|
140
|
+
PostgreSQL → Bun.SQL PostgreSQL → postgres package
|
|
141
|
+
MySQL → Bun.SQL MySQL → mysql2 package
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Your `DatabaseModule` configuration remains identical across platforms:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
DatabaseModule.forRoot({
|
|
148
|
+
connections: [
|
|
149
|
+
{
|
|
150
|
+
name: 'default',
|
|
151
|
+
type: 'sqlite',
|
|
152
|
+
database: './data/app.db',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'pg',
|
|
156
|
+
type: 'postgres',
|
|
157
|
+
url: process.env.DATABASE_URL,
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Public API Changes
|
|
166
|
+
|
|
167
|
+
### `BunServer.getServer()`
|
|
168
|
+
|
|
169
|
+
Returns `IServerHandle | undefined` (previously `Bun.Server | undefined`).
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
const handle: IServerHandle | undefined = app.getServer();
|
|
173
|
+
handle?.port; // number
|
|
174
|
+
handle?.hostname; // string
|
|
175
|
+
await handle?.stop();
|
|
176
|
+
|
|
177
|
+
// Access the raw underlying server (not recommended — type is unknown)
|
|
178
|
+
const native: unknown = app.getNativeServer();
|
|
179
|
+
// Bun: native as Bun.Server<any>
|
|
180
|
+
// Node.js: native as import('node:http').Server
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### `WsArgumentsHost.getClient()`
|
|
184
|
+
|
|
185
|
+
Returns `IWebSocket<T>` instead of Bun's `ServerWebSocket<T>`. This is the only breaking WebSocket API change.
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import type { IWebSocket } from '@dangao/bun-server';
|
|
189
|
+
|
|
190
|
+
@WebSocketGateway()
|
|
191
|
+
class ChatGateway {
|
|
192
|
+
@OnMessage('chat')
|
|
193
|
+
onChat(client: IWebSocket<unknown>, data: unknown) {
|
|
194
|
+
client.send('pong');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`IWebSocket<T>` exposes the same core methods as `ServerWebSocket<T>`:
|
|
200
|
+
`send`, `close`, `data`, `readyState`, `remoteAddress`.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Bun-Exclusive Features
|
|
205
|
+
|
|
206
|
+
The following options are accepted in `ApplicationOptions` but only take effect on Bun. They are silently ignored on Node.js.
|
|
207
|
+
|
|
208
|
+
| Option | Effect on Bun | Node.js |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| `idleTimeout` | TCP idle timeout via `Bun.serve` | Ignored |
|
|
211
|
+
| `reusePort` | Port reuse via `Bun.serve` | Ignored |
|
|
212
|
+
| `sseKeepAlive` | Uses `server.timeout(req, 0)` | Heartbeat injection only |
|
|
213
|
+
|
|
214
|
+
If your application relies on these features, document the Bun runtime requirement explicitly.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Node.js Startup Guide
|
|
219
|
+
|
|
220
|
+
### 1. Install
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
npm install @dangao/bun-server
|
|
224
|
+
# Node.js peer dependencies are included automatically
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 2. Build
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# Compile TypeScript to plain JS targeting Node.js
|
|
231
|
+
bun build src/main.ts --target=node --outdir=dist
|
|
232
|
+
|
|
233
|
+
# Or use tsc:
|
|
234
|
+
npx tsc
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### 3. Run
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
node dist/main.js
|
|
241
|
+
# Platform auto-detected as 'node' — no extra flags needed
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 4. Smoke test (verify bun build output runs on Node.js)
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
bun run test:node
|
|
248
|
+
# Runs: vitest run tests/platform/node
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Testing on Multiple Runtimes
|
|
254
|
+
|
|
255
|
+
Shared test cases live in `tests/platform/shared/*.cases.ts`. Both Bun and Node.js runners import the same assertions, guaranteeing identical coverage.
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
tests/platform/
|
|
259
|
+
├── shared/
|
|
260
|
+
│ ├── suite.ts ← TestSuite interface (test / expect / beforeEach)
|
|
261
|
+
│ ├── fs.cases.ts
|
|
262
|
+
│ ├── crypto.cases.ts
|
|
263
|
+
│ ├── parser.cases.ts
|
|
264
|
+
│ ├── process.cases.ts
|
|
265
|
+
│ ├── websocket.cases.ts
|
|
266
|
+
│ └── database.cases.ts
|
|
267
|
+
├── bun/ ← bun:test runners
|
|
268
|
+
│ └── *.test.ts
|
|
269
|
+
├── node/ ← vitest runners
|
|
270
|
+
│ ├── *.test.ts
|
|
271
|
+
│ └── build-smoke.test.ts ← verifies bun build --target=node output
|
|
272
|
+
└── detector.test.ts ← priority chain unit tests
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Run tests
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# Bun platform tests
|
|
279
|
+
bun run test:bun
|
|
280
|
+
|
|
281
|
+
# Node.js platform tests
|
|
282
|
+
bun run test:node
|
|
283
|
+
|
|
284
|
+
# Both platforms
|
|
285
|
+
bun run test:platform
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Known Limitations
|
|
291
|
+
|
|
292
|
+
| Limitation | Details |
|
|
293
|
+
|---|---|
|
|
294
|
+
| `idleTimeout` / `reusePort` | Bun-only; no Node.js equivalent |
|
|
295
|
+
| SSE TCP keepalive (`server.timeout`) | Bun-only API; Node.js gets heartbeat injection only |
|
|
296
|
+
| `Bun.SQL` features | Some advanced Bun.SQL options (e.g., prepared statement caching) are unavailable in `postgres` / `mysql2` |
|
|
297
|
+
| Cluster mode on Node.js | Uses `node:child_process`; may behave differently from Bun's cluster |
|
|
298
|
+
| `bun:sqlite` extensions | Bun SQLite supports extensions; `better-sqlite3` extension loading differs |
|
|
299
|
+
| Performance | Bun native APIs outperform Node.js polyfills, especially for file I/O and crypto |
|
package/docs/testing.md
CHANGED
|
@@ -72,6 +72,66 @@ await client.close();
|
|
|
72
72
|
|
|
73
73
|
Options support `headers`, `body`, and `query`.
|
|
74
74
|
|
|
75
|
+
## Multi-Runtime Testing
|
|
76
|
+
|
|
77
|
+
The framework ships with a shared test strategy that runs the same test cases on both Bun and Node.js.
|
|
78
|
+
|
|
79
|
+
### Test Structure
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
tests/platform/
|
|
83
|
+
├── shared/ ← platform-neutral assertion helpers
|
|
84
|
+
│ ├── suite.ts ← TestSuite interface (test / expect / beforeEach)
|
|
85
|
+
│ ├── fs.cases.ts
|
|
86
|
+
│ ├── crypto.cases.ts
|
|
87
|
+
│ ├── parser.cases.ts
|
|
88
|
+
│ ├── process.cases.ts
|
|
89
|
+
│ ├── websocket.cases.ts
|
|
90
|
+
│ └── database.cases.ts
|
|
91
|
+
├── bun/ ← bun:test runners (initRuntime('bun'))
|
|
92
|
+
│ └── *.test.ts
|
|
93
|
+
└── node/ ← vitest runners (initRuntime('node'))
|
|
94
|
+
├── *.test.ts
|
|
95
|
+
└── build-smoke.test.ts
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Running Platform Tests
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Bun platform tests only
|
|
102
|
+
bun run test:bun
|
|
103
|
+
|
|
104
|
+
# Node.js platform tests only (uses vitest)
|
|
105
|
+
bun run test:node
|
|
106
|
+
|
|
107
|
+
# Both platforms
|
|
108
|
+
bun run test:platform
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Writing Tests that Work on Both Runtimes
|
|
112
|
+
|
|
113
|
+
Always call `initRuntime()` at the start of your test file:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
// tests/platform/bun/fs.test.ts
|
|
117
|
+
import { describe, test, expect, beforeEach } from 'bun:test';
|
|
118
|
+
import { initRuntime, _resetRuntime } from '../../../src/platform/runtime';
|
|
119
|
+
import { runFsCases } from '../shared/fs.cases';
|
|
120
|
+
|
|
121
|
+
initRuntime('bun');
|
|
122
|
+
runFsCases({ test, expect, beforeEach });
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
// tests/platform/node/fs.test.ts
|
|
127
|
+
import { describe, test, expect, beforeEach } from 'vitest';
|
|
128
|
+
import { initRuntime, _resetRuntime } from '../../../src/platform/runtime';
|
|
129
|
+
import { runFsCases } from '../shared/fs.cases';
|
|
130
|
+
|
|
131
|
+
beforeEach(() => { _resetRuntime(); initRuntime('node'); });
|
|
132
|
+
runFsCases({ test, expect, beforeEach });
|
|
133
|
+
```
|
|
134
|
+
|
|
75
135
|
## Example with bun:test
|
|
76
136
|
|
|
77
137
|
```ts
|
package/docs/zh/deployment.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# 生产部署指南
|
|
2
2
|
|
|
3
|
-
本文档介绍将 Bun Server Framework
|
|
3
|
+
本文档介绍将 Bun Server Framework 应用部署到生产环境的最佳实践。框架同时支持 **Bun**(最优性能)和 **Node.js 22+** 运行时,请根据基础设施选择合适的方案。
|
|
4
4
|
|
|
5
5
|
## 目录
|
|
6
6
|
|
|
7
7
|
- [前置要求](#前置要求)
|
|
8
|
+
- [运行时选择](#运行时选择)
|
|
8
9
|
- [环境设置](#环境设置)
|
|
9
10
|
- [配置](#配置)
|
|
10
11
|
- [进程管理](#进程管理)
|
|
@@ -15,23 +16,45 @@
|
|
|
15
16
|
|
|
16
17
|
## 前置要求
|
|
17
18
|
|
|
18
|
-
- Bun
|
|
19
|
-
-
|
|
20
|
-
- 生产级数据库(PostgreSQL、MySQL 等)
|
|
19
|
+
- **Bun** >= 1.3.10(Bun 部署方案)**或** **Node.js** >= 22.0.0(Node.js 部署方案)
|
|
20
|
+
- 生产级数据库(PostgreSQL、MySQL、SQLite 等)
|
|
21
21
|
- 反向代理(Nginx、Caddy 等)
|
|
22
22
|
|
|
23
|
+
## 运行时选择
|
|
24
|
+
|
|
25
|
+
| 维度 | Bun | Node.js |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| 性能 | 最优(原生 API) | 良好 |
|
|
28
|
+
| 生态成熟度 | 持续增长 | 成熟 |
|
|
29
|
+
| Docker 镜像 | `oven/bun` | `node:22-alpine` |
|
|
30
|
+
| `idleTimeout` / `reusePort` | 支持 | 不可用 |
|
|
31
|
+
| 推荐场景 | 新项目、延迟敏感型应用 | 已有 Node.js 基础设施 |
|
|
32
|
+
|
|
33
|
+
框架在启动时自动检测运行时。详见[平台适配指南](./platform.md)。
|
|
34
|
+
|
|
23
35
|
## 环境设置
|
|
24
36
|
|
|
25
|
-
###
|
|
37
|
+
### 方案 A — Bun 运行时
|
|
26
38
|
|
|
27
39
|
```bash
|
|
28
|
-
#
|
|
40
|
+
# 安装 Bun(Linux/macOS)
|
|
29
41
|
curl -fsSL https://bun.sh/install | bash
|
|
30
42
|
|
|
31
|
-
#
|
|
43
|
+
# 验证
|
|
32
44
|
bun --version
|
|
33
45
|
```
|
|
34
46
|
|
|
47
|
+
### 方案 B — Node.js 运行时
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# 使用 Node.js 22+(LTS)
|
|
51
|
+
node --version # 应为 v22+
|
|
52
|
+
|
|
53
|
+
# 构建 TypeScript 为 JS
|
|
54
|
+
bun build src/main.ts --target=node --outdir=dist
|
|
55
|
+
# 或:npx tsc
|
|
56
|
+
```
|
|
57
|
+
|
|
35
58
|
### 设置环境变量
|
|
36
59
|
|
|
37
60
|
创建 `.env.production` 文件:
|
package/docs/zh/idle-timeout.md
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
|
-
# idleTimeout
|
|
1
|
+
# idleTimeout 与 SSE 保活
|
|
2
2
|
|
|
3
|
-
`idleTimeout`
|
|
3
|
+
> **平台说明:** `idleTimeout`、`reusePort` 以及基于 `server.timeout` 的 SSE TCP 保活是 **Bun 独有**特性,在 Node.js 上会被静默忽略。`@IdleTimeout(ms)` 装饰器(handler 级超时)在两个平台均可用。详见[平台适配指南](./platform.md#bun-独有特性)。
|
|
4
|
+
|
|
5
|
+
## 两层超时机制
|
|
6
|
+
|
|
7
|
+
Bun Server 有**两套独立的超时机制**——理解它们的区别对 SSE / 流式场景至关重要。
|
|
8
|
+
|
|
9
|
+
| 层面 | 配置方式 | 作用域 | 机制 | Bun | Node.js |
|
|
10
|
+
|------|----------|--------|------|-----|---------|
|
|
11
|
+
| **TCP 连接级** | `Application({ idleTimeout })` | Bun.serve 底层 | Bun 内核在连接无数据流动 N 秒后直接断开 socket | 支持 | 忽略 |
|
|
12
|
+
| **Handler 逻辑级** | `@IdleTimeout(ms)` 装饰器 | 路由粒度的 `Promise.race` | handler 未在指定时间内 resolve 则返回 `408 Request Timeout` | 支持 | 支持 |
|
|
13
|
+
|
|
14
|
+
> **关键:** 对于 SSE 响应,handler 会立即返回一个带流式 body 的 `Response`。此时 handler 层面的 `@IdleTimeout` 已经 resolve,**不会**保护或终止该流。只有 TCP 级别的 `idleTimeout` 才能断开 SSE 连接。
|
|
15
|
+
|
|
16
|
+
---
|
|
4
17
|
|
|
5
18
|
## 全局 idleTimeout(毫秒)
|
|
6
19
|
|
|
7
|
-
在 `Application`
|
|
20
|
+
在 `Application` 中按毫秒设置,框架内部自动转换后传给 `Bun.serve`(`Math.ceil(ms / 1000)` → 秒)。
|
|
8
21
|
|
|
9
22
|
```ts
|
|
10
23
|
const app = new Application({
|
|
11
24
|
port: 3000,
|
|
12
|
-
idleTimeout: 15000, //
|
|
25
|
+
idleTimeout: 15000, // 15 秒 — 对所有非 SSE 连接生效
|
|
13
26
|
});
|
|
14
27
|
```
|
|
15
28
|
|
|
16
|
-
##
|
|
29
|
+
## 路由级超时 — `@IdleTimeout(ms)`
|
|
17
30
|
|
|
18
31
|
使用 `@IdleTimeout(ms)` 装饰器配置控制器级或方法级超时。
|
|
19
32
|
|
|
@@ -37,5 +50,85 @@ class ApiController {
|
|
|
37
50
|
}
|
|
38
51
|
```
|
|
39
52
|
|
|
40
|
-
|
|
53
|
+
### 匹配与生效规则
|
|
54
|
+
|
|
55
|
+
1. **方法级** `@IdleTimeout` 优先检测——存在即生效。
|
|
56
|
+
2. **类级** `@IdleTimeout` 作为兜底。
|
|
57
|
+
3. 若均未设置,则不应用 handler 级超时(路由将持续运行直到 TCP 超时或自然完成)。
|
|
58
|
+
|
|
59
|
+
handler 级超时触发时,框架抛出 `HttpException(408, "Request Timeout")`。
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## SSE 保活(自动)
|
|
64
|
+
|
|
65
|
+
当框架检测到响应的 `Content-Type` 包含 `text/event-stream` 时,会自动执行:
|
|
66
|
+
|
|
67
|
+
1. **禁用该请求的 TCP 空闲超时** —— 通过 `server.timeout(req, 0)` 阻止 Bun 断开长连接。
|
|
68
|
+
2. **注入 SSE 注释心跳** —— 按配置间隔发送 `: keepalive\n\n`,防止中间代理(nginx、云 LB)因空闲而断连。
|
|
69
|
+
|
|
70
|
+
### 配置
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const app = new Application({
|
|
74
|
+
port: 3000,
|
|
75
|
+
idleTimeout: 10000, // 普通请求:10 秒
|
|
76
|
+
|
|
77
|
+
// SSE 保活 — 以下为默认值
|
|
78
|
+
sseKeepAlive: {
|
|
79
|
+
enabled: true, // 自动检测 SSE 并注入心跳
|
|
80
|
+
intervalMs: 15000, // 每 15 秒一次心跳
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
```
|
|
41
84
|
|
|
85
|
+
| 选项 | 类型 | 默认值 | 说明 |
|
|
86
|
+
|------|------|--------|------|
|
|
87
|
+
| `sseKeepAlive.enabled` | `boolean` | `true` | 启用 SSE 自动检测、TCP 超时解除和心跳注入 |
|
|
88
|
+
| `sseKeepAlive.intervalMs` | `number` | `15000` | 心跳间隔(毫秒) |
|
|
89
|
+
|
|
90
|
+
当 `enabled` 为 `true`(默认)时,任何 `Content-Type` 头包含 `text/event-stream` 的响应都会触发 SSE 后处理器。**无需任何特殊装饰器或注解**——纯粹基于响应头自动检测。
|
|
91
|
+
|
|
92
|
+
当 `enabled` 为 `false` 时,框架不做任何 SSE 特殊处理。你需要自行管理 keep-alive 和 `server.timeout`。
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 信号级联(`ctx.signal`)
|
|
97
|
+
|
|
98
|
+
`Context` 通过 `ctx.signal` 暴露客户端的 `AbortSignal`。当客户端断连(网络故障、关闭浏览器标签、中断 `curl`)时,该信号会 abort。
|
|
99
|
+
|
|
100
|
+
对于 AI 流式端点,将 `ctx.signal` 传递给 `AiService`,可立即取消上游 API 请求——**停止 token 消耗**:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { Controller, GET, Context as Ctx } from '@dangao/bun-server';
|
|
104
|
+
import type { Context } from '@dangao/bun-server';
|
|
105
|
+
|
|
106
|
+
@Controller('/chat')
|
|
107
|
+
class ChatController {
|
|
108
|
+
constructor(private readonly ai: AiService) {}
|
|
109
|
+
|
|
110
|
+
@GET('/stream')
|
|
111
|
+
public stream(@Ctx() ctx: Context) {
|
|
112
|
+
const stream = this.ai.stream({
|
|
113
|
+
messages: [{ role: 'user', content: 'Hello' }],
|
|
114
|
+
signal: ctx.signal, // ← 级联客户端断连
|
|
115
|
+
});
|
|
116
|
+
return new Response(stream, {
|
|
117
|
+
headers: { 'Content-Type': 'text/event-stream' },
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
> **注意:** `Context` 参数装饰器既可通过 `Context`(从 `'./controller'`)导入,也可通过包根导出的别名 `ContextParam` 导入。推荐使用 `ContextParam` 或 `Context as Ctx` 以避免与 `Context` 类型名冲突。
|
|
124
|
+
|
|
125
|
+
完整取消链路:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
客户端断连
|
|
129
|
+
→ request.signal abort
|
|
130
|
+
→ 心跳定时器清理
|
|
131
|
+
→ 包裹流取消
|
|
132
|
+
→ AI Provider 内部 fetch() abort
|
|
133
|
+
→ 上游 API 连接关闭(节省 token)
|
|
134
|
+
```
|
package/docs/zh/migration.md
CHANGED
|
@@ -2,6 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
适用于从项目早期版本或其他框架迁移到最新 Bun Server Framework 的场景。
|
|
4
4
|
|
|
5
|
+
## v2.x → v3.0(平台适配层)
|
|
6
|
+
|
|
7
|
+
v3.0.0 引入 **Platform Adapter Layer**,在保留 Bun 最优性能的同时支持 Node.js 22+。
|
|
8
|
+
|
|
9
|
+
### 破坏性变更
|
|
10
|
+
|
|
11
|
+
| 变更点 | 之前 | 之后 |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `BunServer.getServer()` 返回类型 | `Bun.Server \| undefined` | `IServerHandle \| undefined` |
|
|
14
|
+
| `WsArgumentsHost.getClient()` 返回类型 | `ServerWebSocket<T>` | `IWebSocket<T>` |
|
|
15
|
+
|
|
16
|
+
### 迁移步骤
|
|
17
|
+
|
|
18
|
+
**1. 更新 WebSocket 守卫类型**
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// 之前
|
|
22
|
+
import type { ServerWebSocket } from 'bun';
|
|
23
|
+
getClient(): ServerWebSocket<unknown>
|
|
24
|
+
|
|
25
|
+
// 之后
|
|
26
|
+
import type { IWebSocket } from '@dangao/bun-server';
|
|
27
|
+
getClient(): IWebSocket<unknown>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**2. 更新服务器句柄访问**
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// 之前
|
|
34
|
+
const server: Bun.Server | undefined = app.getServer();
|
|
35
|
+
|
|
36
|
+
// 之后
|
|
37
|
+
import type { IServerHandle } from '@dangao/bun-server';
|
|
38
|
+
const server: IServerHandle | undefined = app.getServer();
|
|
39
|
+
// 原生访问(不推荐,类型为 unknown):
|
|
40
|
+
const native: unknown = app.getNativeServer();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**3. 其他均向后兼容。** 数据库配置、模块 API、控制器、服务和中间件无需修改。
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
5
47
|
## 1. 项目结构调整
|
|
6
48
|
|
|
7
49
|
- 统一入口到 `src/index.ts`,示例项目可放在 `examples/`。
|