@fluojs/platform-bun 1.0.0-beta.1
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/LICENSE +21 -0
- package/README.ko.md +88 -0
- package/README.md +88 -0
- package/dist/adapter.d.ts +144 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +249 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 fluo contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.ko.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# @fluojs/platform-bun
|
|
2
|
+
|
|
3
|
+
<p><a href="./README.md"><kbd>English</kbd></a> <strong><kbd>한국어</kbd></strong></p>
|
|
4
|
+
|
|
5
|
+
네이티브 `Bun.serve()`를 기반으로 구축된 fluo 런타임용 Bun 기반 HTTP 어댑터 패키지입니다.
|
|
6
|
+
|
|
7
|
+
## 목차
|
|
8
|
+
|
|
9
|
+
- [설치](#설치)
|
|
10
|
+
- [사용 시점](#사용-시점)
|
|
11
|
+
- [빠른 시작](#빠른-시작)
|
|
12
|
+
- [주요 패턴](#주요-패턴)
|
|
13
|
+
- [공개 API 개요](#공개-api-개요)
|
|
14
|
+
- [관련 패키지](#관련-패키지)
|
|
15
|
+
- [예제 소스](#예제-소스)
|
|
16
|
+
|
|
17
|
+
## 설치
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @fluojs/platform-bun
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
이 패키지는 Bun에서 실행하는 것을 전제로 합니다. 배포 manifest는 npm 메타데이터가 Bun 런타임 계약과 어긋나지 않도록 의도적으로 `engines.node`를 선언하지 않으며, 저장소의 Node.js 20+ 요구사항은 메인테이너용 빌드/테스트 툴체인에만 적용됩니다.
|
|
24
|
+
|
|
25
|
+
## 사용 시점
|
|
26
|
+
|
|
27
|
+
fluo 애플리케이션을 [Bun](https://bun.sh/) 런타임에서 실행할 때 이 패키지를 사용합니다. 이 어댑터는 Bun의 고성능 `Request`/`Response` 브리지와 네이티브 `fetch` 방식의 아키텍처를 활용하여 Bun 사용자에게 원활하고 빠른 경험을 제공합니다.
|
|
28
|
+
|
|
29
|
+
애플리케이션 종료 중에는 새 유입을 중단하고, Bun이 서버를 강제로 내리기 전에 활성 HTTP 핸들러가 bounded drain window 안에서 마무리될 수 있도록 동작합니다. 시그널 기반 종료가 `forceExitTimeoutMs`를 넘기거나 실패하면 fluo는 그 상태를 로그와 `process.exitCode`로 보고하고, 최종 프로세스 종료는 Bun 또는 주변 호스트에 맡깁니다.
|
|
30
|
+
|
|
31
|
+
## 빠른 시작
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { createBunAdapter } from '@fluojs/platform-bun';
|
|
35
|
+
import { fluoFactory } from '@fluojs/runtime';
|
|
36
|
+
import { AppModule } from './app.module';
|
|
37
|
+
|
|
38
|
+
const app = await fluoFactory.create(AppModule, {
|
|
39
|
+
adapter: createBunAdapter({ port: 3000 }),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await app.listen();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 주요 패턴
|
|
46
|
+
|
|
47
|
+
### 수동 Fetch 처리
|
|
48
|
+
Bun 서버를 직접 관리하려는 경우 fetch 핸들러를 직접 사용할 수 있습니다.
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { createBunFetchHandler } from '@fluojs/platform-bun';
|
|
52
|
+
|
|
53
|
+
const handler = await createBunFetchHandler({
|
|
54
|
+
dispatcher: app.getHttpDispatcher(),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
Bun.serve({
|
|
58
|
+
fetch: handler,
|
|
59
|
+
port: 3000,
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 네이티브 WebSocket 업그레이드
|
|
64
|
+
어댑터는 `@fluojs/websockets/bun` 바인딩을 통해 Bun의 네이티브 `server.upgrade()`를 지원합니다.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// Bun 어댑터가 활성화된 경우 게이트웨이는 자동으로 Bun의 네이티브 업그레이드를 사용합니다.
|
|
68
|
+
@WebSocketGateway({ path: '/ws' })
|
|
69
|
+
export class MyGateway {}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 공개 API 개요
|
|
73
|
+
|
|
74
|
+
- `createBunAdapter(options)`: Bun 어댑터를 위한 권장 팩토리입니다.
|
|
75
|
+
- `createBunFetchHandler(options)`: 커스텀 `Bun.serve()` 설정을 위한 네이티브 `fetch(request)` 핸들러를 생성합니다.
|
|
76
|
+
- `bootstrapBunApplication(module, options)`: 암시적 시작 로그 없이 애플리케이션을 부트스트랩하는 고급 헬퍼입니다.
|
|
77
|
+
- `runBunApplication(module, options)`: 시그널 연결을 포함한 빠른 시작을 위한 호환 헬퍼입니다.
|
|
78
|
+
|
|
79
|
+
## 관련 패키지
|
|
80
|
+
|
|
81
|
+
- `@fluojs/runtime`: 핵심 런타임입니다.
|
|
82
|
+
- `@fluojs/websockets`: 전용 서브패스 `@fluojs/websockets/bun`을 포함합니다.
|
|
83
|
+
- `@fluojs/socket.io`: 네이티브 Bun 엔진을 지원합니다.
|
|
84
|
+
|
|
85
|
+
## 예제 소스
|
|
86
|
+
|
|
87
|
+
- `packages/platform-bun/src/adapter.test.ts`
|
|
88
|
+
- `packages/websockets/src/bun/bun.test.ts`
|
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# @fluojs/platform-bun
|
|
2
|
+
|
|
3
|
+
<p><strong><kbd>English</kbd></strong> <a href="./README.ko.md"><kbd>한국어</kbd></a></p>
|
|
4
|
+
|
|
5
|
+
Bun-backed HTTP adapter for the fluo runtime, built on native `Bun.serve()`.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [When to Use](#when-to-use)
|
|
11
|
+
- [Quick Start](#quick-start)
|
|
12
|
+
- [Common Patterns](#common-patterns)
|
|
13
|
+
- [Public API Overview](#public-api-overview)
|
|
14
|
+
- [Related Packages](#related-packages)
|
|
15
|
+
- [Example Sources](#example-sources)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @fluojs/platform-bun
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This package is intended to run on Bun. The published manifest intentionally does not declare `engines.node`, so npm metadata stays aligned with the Bun runtime contract; the repository's Node.js 20+ requirement only applies to the maintainer build/test toolchain.
|
|
24
|
+
|
|
25
|
+
## When to Use
|
|
26
|
+
|
|
27
|
+
Use this package when running fluo applications on the [Bun](https://bun.sh/) runtime. This adapter leverages Bun's high-performance `Request`/`Response` bridge and native `fetch`-style architecture, providing a seamless and fast experience for Bun users.
|
|
28
|
+
|
|
29
|
+
During application shutdown, the adapter stops new ingress and gives active HTTP handlers a bounded drain window before Bun forcefully tears the server down. If signal-driven shutdown exceeds `forceExitTimeoutMs` or fails, fluo reports that condition through logging and `process.exitCode` while leaving final process termination to Bun or the surrounding host.
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { createBunAdapter } from '@fluojs/platform-bun';
|
|
35
|
+
import { fluoFactory } from '@fluojs/runtime';
|
|
36
|
+
import { AppModule } from './app.module';
|
|
37
|
+
|
|
38
|
+
const app = await fluoFactory.create(AppModule, {
|
|
39
|
+
adapter: createBunAdapter({ port: 3000 }),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await app.listen();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Common Patterns
|
|
46
|
+
|
|
47
|
+
### Manual Fetch Handling
|
|
48
|
+
If you prefer to manage the Bun server yourself, you can use the fetch handler directly.
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { createBunFetchHandler } from '@fluojs/platform-bun';
|
|
52
|
+
|
|
53
|
+
const handler = await createBunFetchHandler({
|
|
54
|
+
dispatcher: app.getHttpDispatcher(),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
Bun.serve({
|
|
58
|
+
fetch: handler,
|
|
59
|
+
port: 3000,
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Native WebSocket Upgrade
|
|
64
|
+
The adapter supports Bun's native `server.upgrade()` through the `@fluojs/websockets/bun` binding.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// gateways automatically use Bun's native upgrade when the Bun adapter is active
|
|
68
|
+
@WebSocketGateway({ path: '/ws' })
|
|
69
|
+
export class MyGateway {}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Public API Overview
|
|
73
|
+
|
|
74
|
+
- `createBunAdapter(options)`: Recommended factory for the Bun adapter.
|
|
75
|
+
- `createBunFetchHandler(options)`: Creates a native `fetch(request)` handler for custom `Bun.serve()` setups.
|
|
76
|
+
- `bootstrapBunApplication(module, options)`: Advanced bootstrap without implicit startup logging.
|
|
77
|
+
- `runBunApplication(module, options)`: Compatibility helper for quick startup with signal wiring.
|
|
78
|
+
|
|
79
|
+
## Related Packages
|
|
80
|
+
|
|
81
|
+
- `@fluojs/runtime`: Core framework runtime.
|
|
82
|
+
- `@fluojs/websockets`: Includes specific subpath `@fluojs/websockets/bun`.
|
|
83
|
+
- `@fluojs/socket.io`: Supports the native Bun engine.
|
|
84
|
+
|
|
85
|
+
## Example Sources
|
|
86
|
+
|
|
87
|
+
- `packages/platform-bun/src/adapter.test.ts`
|
|
88
|
+
- `packages/websockets/src/bun/bun.test.ts`
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { CorsOptions, Dispatcher, HttpApplicationAdapter, MiddlewareLike, SecurityHeadersOptions } from '@fluojs/http';
|
|
2
|
+
import type { Application, ApplicationLogger, CreateApplicationOptions, ModuleType, MultipartOptions, UploadedFile } from '@fluojs/runtime';
|
|
3
|
+
import { type HttpAdapterListenTarget } from '@fluojs/runtime/internal/http-adapter';
|
|
4
|
+
declare module '@fluojs/http' {
|
|
5
|
+
interface FrameworkRequest {
|
|
6
|
+
files?: UploadedFile[];
|
|
7
|
+
rawBody?: Uint8Array;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
type BunHostname = string;
|
|
11
|
+
export type BunApplicationSignal = 'SIGINT' | 'SIGTERM';
|
|
12
|
+
export type BunCorsInput = false | string | string[] | CorsOptions;
|
|
13
|
+
export type BunTlsOptions = Record<string, unknown>;
|
|
14
|
+
export type BunWebSocketMessage = string | ArrayBuffer | Uint8Array;
|
|
15
|
+
export interface BunServerWebSocket<TData = unknown> {
|
|
16
|
+
readonly data: TData;
|
|
17
|
+
readonly readyState: number;
|
|
18
|
+
readonly remoteAddress: string;
|
|
19
|
+
readonly subscriptions: string[];
|
|
20
|
+
close(code?: number, reason?: string): void;
|
|
21
|
+
cork(callback: (socket: BunServerWebSocket<TData>) => void): void;
|
|
22
|
+
isSubscribed(topic: string): boolean;
|
|
23
|
+
publish(topic: string, message: BunWebSocketMessage): void;
|
|
24
|
+
send(message: BunWebSocketMessage, compress?: boolean): number;
|
|
25
|
+
subscribe(topic: string): void;
|
|
26
|
+
unsubscribe(topic: string): void;
|
|
27
|
+
}
|
|
28
|
+
export interface BunWebSocketHandler<TData = unknown> {
|
|
29
|
+
backpressureLimit?: number;
|
|
30
|
+
close?(socket: BunServerWebSocket<TData>, code: number, reason: string): void | Promise<void>;
|
|
31
|
+
closeOnBackpressureLimit?: boolean;
|
|
32
|
+
data?: TData;
|
|
33
|
+
drain?(socket: BunServerWebSocket<TData>): void | Promise<void>;
|
|
34
|
+
error?(socket: BunServerWebSocket<TData>, error: Error): void | Promise<void>;
|
|
35
|
+
idleTimeout?: number;
|
|
36
|
+
maxPayloadLength?: number;
|
|
37
|
+
message?(socket: BunServerWebSocket<TData>, message: BunWebSocketMessage): void | Promise<void>;
|
|
38
|
+
open?(socket: BunServerWebSocket<TData>): void | Promise<void>;
|
|
39
|
+
perMessageDeflate?: boolean | {
|
|
40
|
+
compress?: boolean | '128KB' | '16KB' | '256KB' | '32KB' | '3KB' | '4KB' | '64KB' | '8KB' | 'dedicated' | 'disable' | 'shared';
|
|
41
|
+
decompress?: boolean | '128KB' | '16KB' | '256KB' | '32KB' | '3KB' | '4KB' | '64KB' | '8KB' | 'dedicated' | 'disable' | 'shared';
|
|
42
|
+
};
|
|
43
|
+
publishToSelf?: boolean;
|
|
44
|
+
sendPings?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface BunWebSocketBinding<TData = unknown> {
|
|
47
|
+
fetch(request: Request, server: BunServerLike): Response | Promise<Response> | undefined | Promise<Response | undefined>;
|
|
48
|
+
idleTimeout?: number;
|
|
49
|
+
maxRequestBodySize?: number;
|
|
50
|
+
websocket: BunWebSocketHandler<TData>;
|
|
51
|
+
}
|
|
52
|
+
export interface BunRealtimeBindingHost {
|
|
53
|
+
configureRealtimeBinding<TData>(binding: BunWebSocketBinding<TData> | undefined): void;
|
|
54
|
+
}
|
|
55
|
+
export interface BunWebSocketBindingHost extends BunRealtimeBindingHost {
|
|
56
|
+
configureWebSocketBinding<TData>(binding: BunWebSocketBinding<TData> | undefined): void;
|
|
57
|
+
}
|
|
58
|
+
export interface BunServeOptions {
|
|
59
|
+
development?: boolean;
|
|
60
|
+
error?: (error: Error) => Response | Promise<Response>;
|
|
61
|
+
fetch(request: Request, server: BunServerLike): Response | Promise<Response> | undefined | Promise<Response | undefined>;
|
|
62
|
+
hostname?: BunHostname;
|
|
63
|
+
idleTimeout?: number;
|
|
64
|
+
maxRequestBodySize?: number;
|
|
65
|
+
port?: number;
|
|
66
|
+
tls?: BunTlsOptions;
|
|
67
|
+
websocket?: BunWebSocketHandler;
|
|
68
|
+
}
|
|
69
|
+
export interface BunServerLike {
|
|
70
|
+
fetch?(request: Request): Response | Promise<Response> | undefined | Promise<Response | undefined>;
|
|
71
|
+
hostname?: BunHostname;
|
|
72
|
+
port?: number;
|
|
73
|
+
stop(closeActiveConnections?: boolean): void;
|
|
74
|
+
upgrade<TData = unknown>(request: Request, options?: {
|
|
75
|
+
data?: TData;
|
|
76
|
+
headers?: HeadersInit;
|
|
77
|
+
}): boolean;
|
|
78
|
+
url?: URL;
|
|
79
|
+
}
|
|
80
|
+
export interface BunAdapterOptions {
|
|
81
|
+
development?: boolean;
|
|
82
|
+
hostname?: BunHostname;
|
|
83
|
+
idleTimeout?: number;
|
|
84
|
+
maxBodySize?: number;
|
|
85
|
+
multipart?: MultipartOptions;
|
|
86
|
+
port?: number;
|
|
87
|
+
rawBody?: boolean;
|
|
88
|
+
stopActiveConnections?: boolean;
|
|
89
|
+
tls?: BunTlsOptions;
|
|
90
|
+
}
|
|
91
|
+
export interface CreateBunFetchHandlerOptions {
|
|
92
|
+
dispatcher: Dispatcher;
|
|
93
|
+
dispatcherNotReadyMessage?: string;
|
|
94
|
+
maxBodySize?: number;
|
|
95
|
+
multipart?: MultipartOptions;
|
|
96
|
+
rawBody?: boolean;
|
|
97
|
+
}
|
|
98
|
+
export interface BootstrapBunApplicationOptions extends Omit<CreateApplicationOptions, 'adapter' | 'logger' | 'middleware'> {
|
|
99
|
+
cors?: BunCorsInput;
|
|
100
|
+
development?: boolean;
|
|
101
|
+
globalPrefix?: string;
|
|
102
|
+
globalPrefixExclude?: readonly string[];
|
|
103
|
+
hostname?: BunHostname;
|
|
104
|
+
idleTimeout?: number;
|
|
105
|
+
logger?: ApplicationLogger;
|
|
106
|
+
maxBodySize?: number;
|
|
107
|
+
middleware?: MiddlewareLike[];
|
|
108
|
+
multipart?: MultipartOptions;
|
|
109
|
+
port?: number;
|
|
110
|
+
rawBody?: boolean;
|
|
111
|
+
securityHeaders?: false | SecurityHeadersOptions;
|
|
112
|
+
stopActiveConnections?: boolean;
|
|
113
|
+
tls?: BunTlsOptions;
|
|
114
|
+
}
|
|
115
|
+
export interface RunBunApplicationOptions extends BootstrapBunApplicationOptions {
|
|
116
|
+
forceExitTimeoutMs?: number;
|
|
117
|
+
shutdownSignals?: false | readonly BunApplicationSignal[];
|
|
118
|
+
}
|
|
119
|
+
export declare class BunHttpApplicationAdapter implements HttpApplicationAdapter, BunWebSocketBindingHost {
|
|
120
|
+
private readonly options;
|
|
121
|
+
private closeInFlight?;
|
|
122
|
+
private dispatcher?;
|
|
123
|
+
private inFlightDrain?;
|
|
124
|
+
private inFlightRequestCount;
|
|
125
|
+
private server?;
|
|
126
|
+
private realtimeBinding?;
|
|
127
|
+
constructor(options?: BunAdapterOptions);
|
|
128
|
+
getServer(): BunServerLike | undefined;
|
|
129
|
+
getListenTarget(): HttpAdapterListenTarget;
|
|
130
|
+
getRealtimeCapability(): import("@fluojs/http").FetchStyleHttpAdapterRealtimeCapability;
|
|
131
|
+
configureRealtimeBinding<TData>(binding: BunWebSocketBinding<TData> | undefined): void;
|
|
132
|
+
configureWebSocketBinding<TData>(binding: BunWebSocketBinding<TData> | undefined): void;
|
|
133
|
+
listen(dispatcher: Dispatcher): Promise<void>;
|
|
134
|
+
close(): Promise<void>;
|
|
135
|
+
private dispatchHttpRequest;
|
|
136
|
+
private trackInFlightRequest;
|
|
137
|
+
private waitForInFlightRequests;
|
|
138
|
+
}
|
|
139
|
+
export declare function createBunFetchHandler({ dispatcher, dispatcherNotReadyMessage, maxBodySize, multipart, rawBody, }: CreateBunFetchHandlerOptions): (request: Request) => Promise<Response>;
|
|
140
|
+
export declare function createBunAdapter(options?: BunAdapterOptions): HttpApplicationAdapter;
|
|
141
|
+
export declare function bootstrapBunApplication(rootModule: ModuleType, options: BootstrapBunApplicationOptions): Promise<Application>;
|
|
142
|
+
export declare function runBunApplication(rootModule: ModuleType, options: RunBunApplicationOptions): Promise<Application>;
|
|
143
|
+
export {};
|
|
144
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { createFetchStyleHttpAdapterRealtimeCapability } from '@fluojs/http';
|
|
2
|
+
import { createNodeShutdownSignalRegistration, defaultNodeShutdownSignals } from '@fluojs/runtime/node';
|
|
3
|
+
import { dispatchWebRequest } from '@fluojs/runtime/web';
|
|
4
|
+
import { bootstrapHttpAdapterApplication, runHttpAdapterApplication } from '@fluojs/runtime/internal/http-adapter';
|
|
5
|
+
const DEFAULT_PORT = 3000;
|
|
6
|
+
const DEFAULT_DISPATCHER_NOT_READY_MESSAGE = 'Bun adapter received a request before dispatcher binding completed.';
|
|
7
|
+
const DEFAULT_SHUTDOWN_TIMEOUT_MS = 10_000;
|
|
8
|
+
const BUN_WEBSOCKET_SUPPORT_REASON = 'Bun exposes Bun.serve() + server.upgrade() request-upgrade hosting. Use @fluojs/websockets/bun for the official raw websocket binding.';
|
|
9
|
+
export class BunHttpApplicationAdapter {
|
|
10
|
+
closeInFlight;
|
|
11
|
+
dispatcher;
|
|
12
|
+
inFlightDrain;
|
|
13
|
+
inFlightRequestCount = 0;
|
|
14
|
+
server;
|
|
15
|
+
realtimeBinding;
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.options = options;
|
|
18
|
+
}
|
|
19
|
+
getServer() {
|
|
20
|
+
return this.server;
|
|
21
|
+
}
|
|
22
|
+
getListenTarget() {
|
|
23
|
+
const protocol = this.options.tls ? 'https' : 'http';
|
|
24
|
+
const configuredHostname = this.options.hostname ?? 'localhost';
|
|
25
|
+
const port = this.server?.port ?? this.options.port ?? DEFAULT_PORT;
|
|
26
|
+
const url = this.server?.url?.origin ?? `${protocol}://${configuredHostname}:${String(port)}`;
|
|
27
|
+
const bindHost = this.server?.hostname ?? this.options.hostname ?? configuredHostname;
|
|
28
|
+
return {
|
|
29
|
+
bindTarget: `${bindHost}:${String(port)}`,
|
|
30
|
+
url
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
getRealtimeCapability() {
|
|
34
|
+
return createFetchStyleHttpAdapterRealtimeCapability(BUN_WEBSOCKET_SUPPORT_REASON, {
|
|
35
|
+
support: 'supported'
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
configureRealtimeBinding(binding) {
|
|
39
|
+
if (this.server && binding !== undefined) {
|
|
40
|
+
throw new Error('Bun websocket binding must be configured before Bun adapter listen() starts the server.');
|
|
41
|
+
}
|
|
42
|
+
this.realtimeBinding = binding;
|
|
43
|
+
}
|
|
44
|
+
configureWebSocketBinding(binding) {
|
|
45
|
+
this.configureRealtimeBinding(binding);
|
|
46
|
+
}
|
|
47
|
+
async listen(dispatcher) {
|
|
48
|
+
this.dispatcher = dispatcher;
|
|
49
|
+
if (this.server) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const bun = requireBunGlobal();
|
|
53
|
+
const realtimeBinding = this.realtimeBinding;
|
|
54
|
+
this.server = bun.serve({
|
|
55
|
+
development: this.options.development,
|
|
56
|
+
fetch: async (request, server) => {
|
|
57
|
+
if (this.server === undefined) {
|
|
58
|
+
this.server = server;
|
|
59
|
+
}
|
|
60
|
+
if (realtimeBinding) {
|
|
61
|
+
const handled = await realtimeBinding.fetch(request, server);
|
|
62
|
+
if (handled !== undefined || isWebSocketUpgradeRequest(request)) {
|
|
63
|
+
return handled;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return await this.dispatchHttpRequest(request);
|
|
67
|
+
},
|
|
68
|
+
hostname: this.options.hostname,
|
|
69
|
+
idleTimeout: realtimeBinding?.idleTimeout ?? this.options.idleTimeout,
|
|
70
|
+
maxRequestBodySize: realtimeBinding?.maxRequestBodySize ?? this.options.maxBodySize,
|
|
71
|
+
port: resolvePort(this.options.port),
|
|
72
|
+
tls: this.options.tls,
|
|
73
|
+
websocket: realtimeBinding?.websocket
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async close() {
|
|
77
|
+
if (this.closeInFlight) {
|
|
78
|
+
await waitForCloseWithTimeout(this.closeInFlight, DEFAULT_SHUTDOWN_TIMEOUT_MS);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (!this.server) {
|
|
82
|
+
this.dispatcher = undefined;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const server = this.server;
|
|
86
|
+
const closePromise = closeBunServerWithDrain(server, this.options.stopActiveConnections, () => this.waitForInFlightRequests());
|
|
87
|
+
const closeInFlight = closePromise.finally(() => {
|
|
88
|
+
if (this.server === server) {
|
|
89
|
+
this.server = undefined;
|
|
90
|
+
}
|
|
91
|
+
this.closeInFlight = undefined;
|
|
92
|
+
this.dispatcher = undefined;
|
|
93
|
+
});
|
|
94
|
+
this.closeInFlight = closeInFlight;
|
|
95
|
+
void closeInFlight.catch(() => {});
|
|
96
|
+
await waitForCloseWithTimeout(closeInFlight, DEFAULT_SHUTDOWN_TIMEOUT_MS);
|
|
97
|
+
}
|
|
98
|
+
async dispatchHttpRequest(request) {
|
|
99
|
+
if (this.closeInFlight) {
|
|
100
|
+
return createShutdownResponse();
|
|
101
|
+
}
|
|
102
|
+
const release = this.trackInFlightRequest();
|
|
103
|
+
try {
|
|
104
|
+
return await dispatchWebRequest({
|
|
105
|
+
dispatcher: this.dispatcher,
|
|
106
|
+
dispatcherNotReadyMessage: DEFAULT_DISPATCHER_NOT_READY_MESSAGE,
|
|
107
|
+
maxBodySize: this.options.maxBodySize,
|
|
108
|
+
multipart: this.options.multipart,
|
|
109
|
+
rawBody: this.options.rawBody,
|
|
110
|
+
request
|
|
111
|
+
});
|
|
112
|
+
} finally {
|
|
113
|
+
release();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
trackInFlightRequest() {
|
|
117
|
+
this.inFlightRequestCount += 1;
|
|
118
|
+
if (this.inFlightRequestCount === 1) {
|
|
119
|
+
this.inFlightDrain = createDeferred();
|
|
120
|
+
}
|
|
121
|
+
return () => {
|
|
122
|
+
if (this.inFlightRequestCount === 0) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this.inFlightRequestCount -= 1;
|
|
126
|
+
if (this.inFlightRequestCount === 0) {
|
|
127
|
+
this.inFlightDrain?.resolve();
|
|
128
|
+
this.inFlightDrain = undefined;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
async waitForInFlightRequests() {
|
|
133
|
+
if (this.inFlightRequestCount === 0) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
await this.inFlightDrain?.promise;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export function createBunFetchHandler({
|
|
140
|
+
dispatcher,
|
|
141
|
+
dispatcherNotReadyMessage = DEFAULT_DISPATCHER_NOT_READY_MESSAGE,
|
|
142
|
+
maxBodySize,
|
|
143
|
+
multipart,
|
|
144
|
+
rawBody
|
|
145
|
+
}) {
|
|
146
|
+
return async function bunFetchHandler(request) {
|
|
147
|
+
return await dispatchWebRequest({
|
|
148
|
+
dispatcher,
|
|
149
|
+
dispatcherNotReadyMessage,
|
|
150
|
+
maxBodySize,
|
|
151
|
+
multipart,
|
|
152
|
+
rawBody,
|
|
153
|
+
request
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
export function createBunAdapter(options = {}) {
|
|
158
|
+
return new BunHttpApplicationAdapter(options);
|
|
159
|
+
}
|
|
160
|
+
export async function bootstrapBunApplication(rootModule, options) {
|
|
161
|
+
return bootstrapHttpAdapterApplication(rootModule, options, createBunAdapter({
|
|
162
|
+
development: options.development,
|
|
163
|
+
hostname: options.hostname,
|
|
164
|
+
idleTimeout: options.idleTimeout,
|
|
165
|
+
maxBodySize: options.maxBodySize,
|
|
166
|
+
multipart: options.multipart,
|
|
167
|
+
port: options.port,
|
|
168
|
+
rawBody: options.rawBody,
|
|
169
|
+
stopActiveConnections: options.stopActiveConnections,
|
|
170
|
+
tls: options.tls
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
export async function runBunApplication(rootModule, options) {
|
|
174
|
+
const adapter = createBunAdapter({
|
|
175
|
+
development: options.development,
|
|
176
|
+
hostname: options.hostname,
|
|
177
|
+
idleTimeout: options.idleTimeout,
|
|
178
|
+
maxBodySize: options.maxBodySize,
|
|
179
|
+
multipart: options.multipart,
|
|
180
|
+
port: options.port,
|
|
181
|
+
rawBody: options.rawBody,
|
|
182
|
+
stopActiveConnections: options.stopActiveConnections,
|
|
183
|
+
tls: options.tls
|
|
184
|
+
});
|
|
185
|
+
return runHttpAdapterApplication(rootModule, {
|
|
186
|
+
...options,
|
|
187
|
+
shutdownRegistration: createNodeShutdownSignalRegistration(options.shutdownSignals ?? defaultNodeShutdownSignals())
|
|
188
|
+
}, adapter);
|
|
189
|
+
}
|
|
190
|
+
function requireBunGlobal() {
|
|
191
|
+
const bun = globalThis.Bun;
|
|
192
|
+
if (!bun || typeof bun.serve !== 'function') {
|
|
193
|
+
throw new Error('Bun adapter requires globalThis.Bun.serve(). Run this package inside Bun or provide a Bun-compatible test double.');
|
|
194
|
+
}
|
|
195
|
+
return bun;
|
|
196
|
+
}
|
|
197
|
+
function resolvePort(port) {
|
|
198
|
+
return typeof port === 'number' && Number.isFinite(port) ? port : DEFAULT_PORT;
|
|
199
|
+
}
|
|
200
|
+
function closeBunServerWithDrain(server, stopActiveConnections, waitForDrain) {
|
|
201
|
+
return (async () => {
|
|
202
|
+
server.stop(stopActiveConnections);
|
|
203
|
+
await waitForDrain();
|
|
204
|
+
})();
|
|
205
|
+
}
|
|
206
|
+
function createDeferred() {
|
|
207
|
+
let resolve;
|
|
208
|
+
let reject;
|
|
209
|
+
const promise = new Promise((res, rej) => {
|
|
210
|
+
resolve = res;
|
|
211
|
+
reject = rej;
|
|
212
|
+
});
|
|
213
|
+
return {
|
|
214
|
+
promise,
|
|
215
|
+
reject,
|
|
216
|
+
resolve
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function createShutdownResponse() {
|
|
220
|
+
return new Response(JSON.stringify({
|
|
221
|
+
error: {
|
|
222
|
+
code: 'SERVICE_UNAVAILABLE',
|
|
223
|
+
message: 'Server is shutting down.',
|
|
224
|
+
status: 503
|
|
225
|
+
}
|
|
226
|
+
}), {
|
|
227
|
+
headers: {
|
|
228
|
+
'content-type': 'application/json'
|
|
229
|
+
},
|
|
230
|
+
status: 503
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
function waitForCloseWithTimeout(closePromise, timeoutMs) {
|
|
234
|
+
return new Promise((resolve, reject) => {
|
|
235
|
+
const timeoutHandle = setTimeout(() => {
|
|
236
|
+
reject(new Error(`Bun adapter shutdown timeout exceeded ${String(timeoutMs)}ms.`));
|
|
237
|
+
}, timeoutMs);
|
|
238
|
+
void closePromise.then(() => {
|
|
239
|
+
clearTimeout(timeoutHandle);
|
|
240
|
+
resolve();
|
|
241
|
+
}, error => {
|
|
242
|
+
clearTimeout(timeoutHandle);
|
|
243
|
+
reject(error);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function isWebSocketUpgradeRequest(request) {
|
|
248
|
+
return request.headers.get('upgrade')?.toLowerCase() === 'websocket';
|
|
249
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './adapter.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluojs/platform-bun",
|
|
3
|
+
"description": "Bun-based HTTP adapter for the Fluo runtime.",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"fluo",
|
|
6
|
+
"bun",
|
|
7
|
+
"http-adapter",
|
|
8
|
+
"platform",
|
|
9
|
+
"server"
|
|
10
|
+
],
|
|
11
|
+
"version": "1.0.0-beta.1",
|
|
12
|
+
"private": false,
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/fluojs/fluo.git",
|
|
17
|
+
"directory": "packages/platform-bun"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@fluojs/http": "^1.0.0-beta.1",
|
|
36
|
+
"@fluojs/runtime": "^1.0.0-beta.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"vitest": "^3.2.4"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|
|
43
|
+
"build": "pnpm exec babel src --extensions .ts --ignore 'src/**/*.test.ts' --out-dir dist --config-file ../../tooling/babel/babel.config.cjs && pnpm exec tsc -p tsconfig.build.json",
|
|
44
|
+
"typecheck": "pnpm exec tsc -p tsconfig.json --noEmit",
|
|
45
|
+
"test": "pnpm exec vitest run -c vitest.config.ts",
|
|
46
|
+
"test:watch": "pnpm exec vitest -c vitest.config.ts"
|
|
47
|
+
}
|
|
48
|
+
}
|