@fluojs/platform-bun 1.0.0-beta.2 → 1.0.0-beta.3
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.ko.md +7 -1
- package/README.md +7 -1
- package/dist/adapter.d.ts +9 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +98 -13
- package/package.json +3 -3
package/README.ko.md
CHANGED
|
@@ -71,6 +71,11 @@ Bun.serve({
|
|
|
71
71
|
export class MyGateway {}
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
### 네이티브 `routes` Object 가속
|
|
75
|
+
Bun `>=1.2.3`에서는 어댑터가 의미 보존이 가능한 static/param fluo route를 `Bun.serve({ routes })`에 선택적으로 등록한 뒤, 매칭된 요청도 다시 shared fluo dispatcher로 흘려보냅니다.
|
|
76
|
+
|
|
77
|
+
이 방식은 raw body, multipart, SSE, error response, shutdown drain, websocket upgrade delegation을 모두 기존 shared 실행 경로에 유지합니다. same-shape param route처럼 의미가 어긋날 수 있는 경우나 `ALL` 메서드 handler처럼 안전하게 선등록할 수 없는 경우에는 의미를 바꾸지 않도록 해당 route를 fetch-only dispatch로 폴백합니다.
|
|
78
|
+
|
|
74
79
|
## 공개 API 개요
|
|
75
80
|
|
|
76
81
|
- `createBunAdapter(options)`: Bun 어댑터를 위한 권장 팩토리입니다.
|
|
@@ -89,6 +94,7 @@ export class MyGateway {}
|
|
|
89
94
|
|
|
90
95
|
- **런타임 host**: 이 패키지는 listen 시점에 `globalThis.Bun.serve()`가 필요합니다. 테스트에서는 Bun 호환 test double을 제공할 수 있지만, production 사용은 Bun 전용입니다.
|
|
91
96
|
- **요청 portability**: Fetch 요청은 shared web dispatcher를 통해 변환되며 malformed cookie 값, query 배열, `rawBody: true`일 때 JSON/text raw body, SSE framing을 보존합니다.
|
|
97
|
+
- **네이티브 route 가속**: Bun의 `routes` object를 사용할 수 있고 fluo route shape를 의미 보존 상태로 선등록할 수 있을 때만 Bun이 path matching을 먼저 처리하고, 이후 요청은 다시 shared dispatcher로 넘깁니다. 지원하지 않거나 모호한 route shape는 일반 `fetch` 경로로 폴백합니다.
|
|
92
98
|
- **Multipart 동작**: Multipart 요청은 `rawBody`를 노출하지 않으며 multipart limit은 shared runtime parser를 통해 계속 적용됩니다.
|
|
93
99
|
- **시작 target**: `hostname`, `port`, `tls`는 `Bun.serve()`로 전달됩니다. 시작 로그는 설정된 HTTP 또는 HTTPS listen URL을 보고합니다.
|
|
94
100
|
- **종료 소유권**: `close()`는 새 유입을 중단하고, in-flight HTTP handler를 기다린 뒤, drain이 끝나면 adapter state를 정리하며 `runBunApplication()`이 등록한 signal listener를 제거합니다.
|
|
@@ -96,7 +102,7 @@ export class MyGateway {}
|
|
|
96
102
|
|
|
97
103
|
## Conformance 커버리지
|
|
98
104
|
|
|
99
|
-
`packages/platform-bun/src/adapter.test.ts`는 문서화된 계약을 검증하는 package-local regression 대상입니다. 이 파일은 malformed cookie, JSON/text raw-body 보존, multipart raw-body 제외, SSE framing을 검증하는 Bun fetch-style portability assertion과 startup logging, shutdown listener cleanup, in-flight drain, timeout reporting, websocket binding delegation을 검증하는 집중 테스트를 포함합니다.
|
|
105
|
+
`packages/platform-bun/src/adapter.test.ts`는 문서화된 계약을 검증하는 package-local regression 대상입니다. 이 파일은 malformed cookie, JSON/text raw-body 보존, multipart raw-body 제외, SSE framing, native-route param parity, same-shape route fallback을 검증하는 Bun fetch-style portability assertion과 startup logging, shutdown listener cleanup, in-flight drain, timeout reporting, websocket binding delegation을 검증하는 집중 테스트를 포함합니다.
|
|
100
106
|
|
|
101
107
|
저장소의 더 넓은 suite도 `packages/testing/src/portability/web-runtime-adapter-portability.test.ts`에서 `createWebRuntimeHttpAdapterPortabilityHarness(...)`로 Bun을 Deno 및 Cloudflare Workers와 함께 실행해 fetch-style platform 간 shared web-runtime portability baseline을 맞춥니다.
|
|
102
108
|
|
package/README.md
CHANGED
|
@@ -71,6 +71,11 @@ The adapter supports Bun's native `server.upgrade()` through the `@fluojs/websoc
|
|
|
71
71
|
export class MyGateway {}
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
### Native `routes` Object Acceleration
|
|
75
|
+
On Bun `>=1.2.3`, the adapter opportunistically registers safe static and parameterized fluo routes through `Bun.serve({ routes })` while still routing matched requests back through the shared fluo dispatcher.
|
|
76
|
+
|
|
77
|
+
This keeps raw body, multipart, SSE, error responses, shutdown drain behavior, and websocket upgrade delegation on the same shared execution path. If route shape parity is unsafe, such as same-shape parameter routes with different param names or `ALL`-method handlers, the adapter falls back to fetch-only dispatch for those routes instead of changing fluo semantics.
|
|
78
|
+
|
|
74
79
|
## Public API Overview
|
|
75
80
|
|
|
76
81
|
- `createBunAdapter(options)`: Recommended factory for the Bun adapter.
|
|
@@ -89,6 +94,7 @@ The adapter also exports the typed Bun integration seams used by realtime packag
|
|
|
89
94
|
|
|
90
95
|
- **Runtime host**: This package requires `globalThis.Bun.serve()` at listen time. Tests may provide a Bun-compatible test double, but production use is Bun-only.
|
|
91
96
|
- **Request portability**: Fetch requests are translated through the shared web dispatcher, preserving malformed cookie values, query arrays, JSON/text raw bodies when `rawBody: true`, and SSE framing.
|
|
97
|
+
- **Native route acceleration**: When Bun's `routes` object is available and a fluo route shape is semantically safe to pre-register, the adapter lets Bun short-circuit path matching before handing the request back to the shared dispatcher. Unsupported or ambiguous route shapes fall back to the regular `fetch` path.
|
|
92
98
|
- **Multipart behavior**: Multipart requests never expose `rawBody`, and multipart limits continue to flow through the shared runtime parser.
|
|
93
99
|
- **Startup target**: `hostname`, `port`, and `tls` are forwarded to `Bun.serve()`. Startup logs report the configured HTTP or HTTPS listen URL.
|
|
94
100
|
- **Shutdown ownership**: `close()` stops new ingress, waits for in-flight HTTP handlers, clears adapter state after drain settles, and removes signal listeners registered by `runBunApplication()`.
|
|
@@ -96,7 +102,7 @@ The adapter also exports the typed Bun integration seams used by realtime packag
|
|
|
96
102
|
|
|
97
103
|
## Conformance Coverage
|
|
98
104
|
|
|
99
|
-
`packages/platform-bun/src/adapter.test.ts` is the package-local regression target for the documented contract. It includes Bun fetch-style portability assertions for malformed cookies, JSON/text raw-body preservation, multipart raw-body exclusion,
|
|
105
|
+
`packages/platform-bun/src/adapter.test.ts` is the package-local regression target for the documented contract. It includes Bun fetch-style portability assertions for malformed cookies, JSON/text raw-body preservation, multipart raw-body exclusion, SSE framing, native-route param parity, and same-shape route fallback, plus focused tests for startup logging, shutdown listener cleanup, in-flight drain behavior, timeout reporting, and websocket binding delegation.
|
|
100
106
|
|
|
101
107
|
The broader repository suite also exercises Bun through `createWebRuntimeHttpAdapterPortabilityHarness(...)` alongside Deno and Cloudflare Workers in `packages/testing/src/portability/web-runtime-adapter-portability.test.ts`, keeping the shared web-runtime portability baseline aligned across fetch-style platforms.
|
|
102
108
|
|
package/dist/adapter.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CorsOptions, Dispatcher, HttpApplicationAdapter, MiddlewareLike, SecurityHeadersOptions } from '@fluojs/http';
|
|
1
|
+
import type { CorsOptions, Dispatcher, HttpApplicationAdapter, HttpMethod, MiddlewareLike, SecurityHeadersOptions } from '@fluojs/http';
|
|
2
2
|
import type { Application, ApplicationLogger, CreateApplicationOptions, ModuleType, MultipartOptions, UploadedFile } from '@fluojs/runtime';
|
|
3
3
|
import { type HttpAdapterListenTarget } from '@fluojs/runtime/internal/http-adapter';
|
|
4
4
|
declare module '@fluojs/http' {
|
|
@@ -8,6 +8,13 @@ declare module '@fluojs/http' {
|
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
type BunHostname = string;
|
|
11
|
+
type BunRequestLike = Request & {
|
|
12
|
+
params?: Readonly<Record<string, string>>;
|
|
13
|
+
};
|
|
14
|
+
type BunRouteHandler = (request: BunRequestLike, server: BunServerLike) => Response | Promise<Response> | undefined | Promise<Response | undefined>;
|
|
15
|
+
type BunRouteMethod = Exclude<HttpMethod, 'ALL'>;
|
|
16
|
+
type BunRouteMethodMap = Partial<Record<BunRouteMethod, BunRouteHandler | Response>>;
|
|
17
|
+
type BunRouteValue = BunRouteHandler | Response | BunRouteMethodMap;
|
|
11
18
|
/** Shutdown signal names that `runBunApplication()` can register. */
|
|
12
19
|
export type BunApplicationSignal = 'SIGINT' | 'SIGTERM';
|
|
13
20
|
/** CORS input accepted by Bun application bootstrap helpers. */
|
|
@@ -73,6 +80,7 @@ export interface BunServeOptions {
|
|
|
73
80
|
idleTimeout?: number;
|
|
74
81
|
maxRequestBodySize?: number;
|
|
75
82
|
port?: number;
|
|
83
|
+
routes?: Record<string, BunRouteValue>;
|
|
76
84
|
tls?: BunTlsOptions;
|
|
77
85
|
websocket?: BunWebSocketHandler;
|
|
78
86
|
}
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,UAAU,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter.js
CHANGED
|
@@ -36,6 +36,7 @@ import { bootstrapHttpAdapterApplication, runHttpAdapterApplication } from '@flu
|
|
|
36
36
|
const DEFAULT_PORT = 3000;
|
|
37
37
|
const DEFAULT_DISPATCHER_NOT_READY_MESSAGE = 'Bun adapter received a request before dispatcher binding completed.';
|
|
38
38
|
const DEFAULT_SHUTDOWN_TIMEOUT_MS = 10_000;
|
|
39
|
+
const MINIMUM_BUN_NATIVE_ROUTES_VERSION = '1.2.3';
|
|
39
40
|
const BUN_WEBSOCKET_SUPPORT_REASON = 'Bun exposes Bun.serve() + server.upgrade() request-upgrade hosting. Use @fluojs/websockets/bun for the official raw websocket binding.';
|
|
40
41
|
|
|
41
42
|
/** HTTP application adapter backed by native `Bun.serve()`. */
|
|
@@ -96,24 +97,26 @@ export class BunHttpApplicationAdapter {
|
|
|
96
97
|
}
|
|
97
98
|
const bun = requireBunGlobal();
|
|
98
99
|
const realtimeBinding = this.realtimeBinding;
|
|
100
|
+
const handleRequest = async (request, server) => {
|
|
101
|
+
if (this.server === undefined) {
|
|
102
|
+
this.server = server;
|
|
103
|
+
}
|
|
104
|
+
if (realtimeBinding) {
|
|
105
|
+
const handled = await realtimeBinding.fetch(request, server);
|
|
106
|
+
if (handled !== undefined || isWebSocketUpgradeRequest(request)) {
|
|
107
|
+
return handled;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return await this.dispatchHttpRequest(request);
|
|
111
|
+
};
|
|
99
112
|
this.server = bun.serve({
|
|
100
113
|
development: this.options.development,
|
|
101
|
-
fetch:
|
|
102
|
-
if (this.server === undefined) {
|
|
103
|
-
this.server = server;
|
|
104
|
-
}
|
|
105
|
-
if (realtimeBinding) {
|
|
106
|
-
const handled = await realtimeBinding.fetch(request, server);
|
|
107
|
-
if (handled !== undefined || isWebSocketUpgradeRequest(request)) {
|
|
108
|
-
return handled;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return await this.dispatchHttpRequest(request);
|
|
112
|
-
},
|
|
114
|
+
fetch: handleRequest,
|
|
113
115
|
hostname: this.options.hostname,
|
|
114
116
|
idleTimeout: realtimeBinding?.idleTimeout ?? this.options.idleTimeout,
|
|
115
117
|
maxRequestBodySize: realtimeBinding?.maxRequestBodySize ?? this.options.maxBodySize,
|
|
116
118
|
port: resolvePort(this.options.port),
|
|
119
|
+
routes: createBunNativeRoutes(dispatcher, handleRequest, bun),
|
|
117
120
|
tls: this.options.tls,
|
|
118
121
|
websocket: realtimeBinding?.websocket
|
|
119
122
|
});
|
|
@@ -274,6 +277,87 @@ function requireBunGlobal() {
|
|
|
274
277
|
function resolvePort(port) {
|
|
275
278
|
return typeof port === 'number' && Number.isFinite(port) ? port : DEFAULT_PORT;
|
|
276
279
|
}
|
|
280
|
+
function createBunNativeRoutes(dispatcher, handleRequest, bun) {
|
|
281
|
+
if (!supportsBunNativeRoutes(bun)) {
|
|
282
|
+
return undefined;
|
|
283
|
+
}
|
|
284
|
+
const descriptors = dispatcher.describeRoutes?.();
|
|
285
|
+
if (!descriptors || descriptors.length === 0) {
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
288
|
+
const unsafeShapes = collectUnsafeNativeRouteShapes(descriptors);
|
|
289
|
+
const routes = new Map();
|
|
290
|
+
for (const descriptor of descriptors) {
|
|
291
|
+
const method = toBunRouteMethod(descriptor.route.method);
|
|
292
|
+
if (!method) {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (unsafeShapes.has(`${method}:${createBunRouteShapeKey(descriptor.route.path)}`)) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const routeHandlers = routes.get(descriptor.route.path) ?? {};
|
|
299
|
+
for (const bunRouteMethod of bunRouteMethods) {
|
|
300
|
+
routeHandlers[bunRouteMethod] ??= handleRequest;
|
|
301
|
+
}
|
|
302
|
+
routes.set(descriptor.route.path, routeHandlers);
|
|
303
|
+
}
|
|
304
|
+
return routes.size > 0 ? Object.fromEntries(routes) : undefined;
|
|
305
|
+
}
|
|
306
|
+
function supportsBunNativeRoutes(bun) {
|
|
307
|
+
return compareBunVersions(bun.version, MINIMUM_BUN_NATIVE_ROUTES_VERSION) >= 0;
|
|
308
|
+
}
|
|
309
|
+
function compareBunVersions(left, right) {
|
|
310
|
+
if (typeof left !== 'string') {
|
|
311
|
+
return -1;
|
|
312
|
+
}
|
|
313
|
+
const leftSegments = parseBunVersionSegments(left);
|
|
314
|
+
const rightSegments = parseBunVersionSegments(right);
|
|
315
|
+
const length = Math.max(leftSegments.length, rightSegments.length);
|
|
316
|
+
for (let index = 0; index < length; index += 1) {
|
|
317
|
+
const leftValue = leftSegments[index] ?? 0;
|
|
318
|
+
const rightValue = rightSegments[index] ?? 0;
|
|
319
|
+
if (leftValue === rightValue) {
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
return leftValue > rightValue ? 1 : -1;
|
|
323
|
+
}
|
|
324
|
+
return 0;
|
|
325
|
+
}
|
|
326
|
+
function parseBunVersionSegments(version) {
|
|
327
|
+
return version.match(/\d+/g)?.map(segment => Number.parseInt(segment, 10)) ?? [];
|
|
328
|
+
}
|
|
329
|
+
function collectUnsafeNativeRouteShapes(descriptors) {
|
|
330
|
+
const signatures = new Map();
|
|
331
|
+
const unsafe = new Set();
|
|
332
|
+
for (const descriptor of descriptors) {
|
|
333
|
+
const shapeKey = createBunRouteShapeKey(descriptor.route.path);
|
|
334
|
+
const paramSignature = descriptor.metadata.pathParams.join(',');
|
|
335
|
+
if (descriptor.route.method === 'ALL') {
|
|
336
|
+
for (const method of bunRouteMethods) {
|
|
337
|
+
unsafe.add(`${method}:${shapeKey}`);
|
|
338
|
+
}
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
const key = `${descriptor.route.method}:${shapeKey}`;
|
|
342
|
+
const current = signatures.get(key) ?? new Set();
|
|
343
|
+
current.add(paramSignature);
|
|
344
|
+
signatures.set(key, current);
|
|
345
|
+
if (current.size > 1) {
|
|
346
|
+
unsafe.add(key);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return unsafe;
|
|
350
|
+
}
|
|
351
|
+
function createBunRouteShapeKey(path) {
|
|
352
|
+
const segments = path.split('/').filter(Boolean);
|
|
353
|
+
if (segments.length === 0) {
|
|
354
|
+
return '/';
|
|
355
|
+
}
|
|
356
|
+
return `/${segments.map(segment => segment.startsWith(':') ? ':' : segment).join('/')}`;
|
|
357
|
+
}
|
|
358
|
+
function toBunRouteMethod(method) {
|
|
359
|
+
return method === 'ALL' ? undefined : method;
|
|
360
|
+
}
|
|
277
361
|
function closeBunServerWithDrain(server, stopActiveConnections, waitForDrain) {
|
|
278
362
|
return (async () => {
|
|
279
363
|
server.stop(stopActiveConnections);
|
|
@@ -323,4 +407,5 @@ function waitForCloseWithTimeout(closePromise, timeoutMs) {
|
|
|
323
407
|
}
|
|
324
408
|
function isWebSocketUpgradeRequest(request) {
|
|
325
409
|
return request.headers.get('upgrade')?.toLowerCase() === 'websocket';
|
|
326
|
-
}
|
|
410
|
+
}
|
|
411
|
+
const bunRouteMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'];
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"platform",
|
|
9
9
|
"server"
|
|
10
10
|
],
|
|
11
|
-
"version": "1.0.0-beta.
|
|
11
|
+
"version": "1.0.0-beta.3",
|
|
12
12
|
"private": false,
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": {
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"dist"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@fluojs/http": "^1.0.0-beta.
|
|
36
|
-
"@fluojs/runtime": "^1.0.0-beta.
|
|
35
|
+
"@fluojs/http": "^1.0.0-beta.3",
|
|
36
|
+
"@fluojs/runtime": "^1.0.0-beta.4"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"vitest": "^3.2.4"
|