@fluojs/platform-deno 1.1.0 → 2.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.ko.md +40 -5
- package/README.md +40 -5
- package/dist/adapter.d.ts +1 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +90 -27
- package/dist/testing-web-runtime-adapter-portability.d.js +0 -0
- package/package.json +5 -5
package/README.ko.md
CHANGED
|
@@ -43,8 +43,32 @@ await runDenoApplication(AppModule, {
|
|
|
43
43
|
});
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
Managed startup 경로는 network listener를 열고 기본적으로 `SIGINT`/`SIGTERM` listener를 등록합니다. Network 접근 권한을 부여해 entrypoint를 실행하세요.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
deno run --allow-net main.ts
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Signal listener 등록에는 별도의 Deno permission이 필요하지 않습니다. Adapter 자체는 environment variable을 읽지 않습니다. 애플리케이션 코드가 해당 key를 읽을 때만 `--allow-env=PORT,DATABASE_URL`처럼 범위를 제한한 권한을 추가하세요. Signal로 트리거된 애플리케이션 close 실패는 helper가 log한 뒤 swallow하며 exit status를 설정하지 않습니다. Failure-status propagation 또는 forced termination이 필요한 host는 `runDenoApplication(...)`에 `shutdownSignals: false`를 전달하고 signal과 shutdown을 직접 조율해야 합니다.
|
|
53
|
+
|
|
46
54
|
## 주요 패턴
|
|
47
55
|
|
|
56
|
+
### Early Hints 미지원
|
|
57
|
+
|
|
58
|
+
Deno의 Fetch `Response`는 final response 이전 informational response를 표현할 수 없으므로 `context.response.earlyHints`가 없습니다. 사용 전에 capability 존재 여부를 확인하세요. Adapter는 요청된 `103`을 silent no-op 또는 final-response header로 바꾸지 않습니다.
|
|
59
|
+
|
|
60
|
+
### 스트리밍 멀티파트 소비
|
|
61
|
+
|
|
62
|
+
애플리케이션 bootstrap에서 `multipart: { strategy: 'stream' }`을 설정하면 멀티파트 데이터를 점진적으로
|
|
63
|
+
받습니다. 멀티파트 route에서 `RequestContext.request.body`는 `AsyncIterableIterator<MultipartPart>`입니다.
|
|
64
|
+
field part는 `kind: 'field'`, `name`, `value`, `headers`를, file part는 `kind: 'file'`, `name`, `filename`,
|
|
65
|
+
`contentType`, `headers`, 그리고 `stream`의 single-consumer `ReadableStream<Uint8Array>`를 제공합니다. 다음
|
|
66
|
+
part를 요청하기 전에 각 file stream을 끝까지 소비하거나 cancel하세요.
|
|
67
|
+
|
|
68
|
+
Runtime route dispatch는 route를 위해 만든 iterator를 소유하며 handler가 끝난 뒤 자동으로 `return()`을 호출해
|
|
69
|
+
active source를 cancel하고 release합니다. Standalone `parseMultipartStream(...)` consumer는 이 책임을 직접
|
|
70
|
+
집니다. iterator를 끝까지 소비하거나 일찍 끝낼 때 `return()`을 호출하세요.
|
|
71
|
+
|
|
48
72
|
### Host-Owned Deno.serve
|
|
49
73
|
애플리케이션이 `Deno.serve(...)`를 소유한다면 `app.listen()`을 호출하지 않고 fluo 애플리케이션을 bootstrap한 뒤 public dispatcher로 request handler를 만드세요. `createDenoFetchHandler(...)`는 request 변환과 dispatch만 수행하며 server를 시작하거나 shutdown, signal, websocket upgrade를 소유하지 않습니다.
|
|
50
74
|
|
|
@@ -68,7 +92,7 @@ try {
|
|
|
68
92
|
}
|
|
69
93
|
```
|
|
70
94
|
|
|
71
|
-
주변 host는 `server` 중지와 process signal 조율을 소유하고 websocket upgrade를 별도로 처리할지 결정해야 합니다.
|
|
95
|
+
주변 host는 `server` 중지와 process signal 조율을 소유하고 websocket upgrade를 별도로 처리할지 결정해야 합니다. Fluo가 managed server lifecycle을 소유해야 한다면 `app.listen()`을 사용하고, shutdown signal listener까지 추가로 설치해야 한다면 `runDenoApplication(...)`을 사용하세요. `adapter.handle(...)`은 managed adapter의 `listen(dispatcher)` binding이 끝난 뒤에만 사용할 수 있습니다.
|
|
72
96
|
|
|
73
97
|
### 직접 어댑터 생성
|
|
74
98
|
애플리케이션 코드는 보통 `createDenoAdapter(options)`, `bootstrapDenoApplication(...)`, `runDenoApplication(...)`을 사용해 adapter setup 경계를 명확히 유지하는 편을 권장합니다. 커스텀 orchestration이나 테스트에서는 `new DenoHttpApplicationAdapter(options?)`를 직접 사용할 수 있으며, constructor는 factory와 같은 optional public `DenoAdapterOptions`를 받고 options가 생략되면 기본 port를 적용하며, portable `host` alias보다 `hostname`을 우선하고, 잘못된 `port` 또는 `maxBodySize` 값은 setup 시점에 거절합니다.
|
|
@@ -96,6 +120,14 @@ export class MyGateway {
|
|
|
96
120
|
export class RealtimeModule {}
|
|
97
121
|
```
|
|
98
122
|
|
|
123
|
+
#### Deno websocket 수신 payload
|
|
124
|
+
|
|
125
|
+
`DenoWebSocketMessage`는 Deno binding이 전달할 수 있는 모든 payload form,
|
|
126
|
+
`ArrayBuffer | ArrayBufferView | Blob | string`을 나타냅니다. 기존에 이 public
|
|
127
|
+
union을 `Blob | string`으로 exhaustive narrowing한 handler는 `ArrayBuffer`와
|
|
128
|
+
`ArrayBufferView` branch를 추가해야 합니다. `@fluojs/websockets/deno` binding은
|
|
129
|
+
이미 gateway handler를 dispatch하기 전에 이 binary payload를 수용하고 normalize합니다.
|
|
130
|
+
|
|
99
131
|
## HTTPS와 런타임 이식성
|
|
100
132
|
|
|
101
133
|
`https` 옵션으로 Deno TLS 인증서 자료를 전달하면 `Deno.serve`를 HTTPS 모드로 시작할 수 있습니다. 어댑터는 `https.cert`와 `https.key`를 Deno의 `cert` 및 `key`로 전달하며, 시작 로그도 `https://` listen URL을 보고하므로 Deno 패키지가 공유 HTTP 어댑터 이식성 계약과 정렬됩니다.
|
|
@@ -113,13 +145,15 @@ await runDenoApplication(AppModule, {
|
|
|
113
145
|
|
|
114
146
|
`hostname`은 Deno 네이티브 옵션 이름으로 유지됩니다. 공유 HTTP 어댑터 테스트와 교차 런타임 설정 헬퍼를 위해 `host`도 이식성 alias로 허용하며, 둘 다 제공하면 `Deno.serve(...)` bind target과 보고되는 listen URL에는 `hostname`이 우선합니다.
|
|
115
147
|
|
|
116
|
-
Advanced option에는 test 또는 non-hosted runtime을 위한 injectable `serve`, `upgradeWebSocket` seam, `rawBody`, `maxBodySize`, `multipart`, `shutdownSignals`가 포함됩니다. `createDenoFetchHandler(...)`는 같은 request parsing option을 받으며 byte-exact JSON/text raw body를 보존하고 multipart request에서는 `rawBody`를 제외합니다. Seam을 주입하지 않으면 managed adapter는 listen/upgrade 시점에 `globalThis.Deno.serve`와 `globalThis.Deno.upgradeWebSocket`으로 fallback합니다. `runDenoApplication(...)`은 기본적으로 `SIGINT`/`SIGTERM`을 연결하고, `shutdownSignals: false`는 signal registration을 끄며, 여러 signal을 등록하다 실패하면 이미 연결한 listener를 rollback합니다. 이미 실행 중인 adapter에 대한 중복 `listen(...)` 호출은 원래 dispatcher pipeline을 보존하는 no-op입니다. Close는 Deno serve signal을 abort하기 전에 active request drain을 최대 10초 기다립니다. `handle(...)`은 websocket upgrade 요청을 포함해 `listen()`이 dispatcher를 bind하기 전에는 JSON `500`, shutdown 진행 중에는 JSON `503`을 반환합니다.
|
|
148
|
+
Advanced option에는 test 또는 non-hosted runtime을 위한 injectable `serve`, `upgradeWebSocket` seam, `rawBody`, `maxBodySize`, `multipart`, `shutdownSignals`가 포함됩니다. `createDenoFetchHandler(...)`는 같은 request parsing option을 받으며 byte-exact JSON/text raw body를 보존하고 multipart request에서는 `rawBody`를 제외합니다. Seam을 주입하지 않으면 managed adapter는 listen/upgrade 시점에 `globalThis.Deno.serve`와 `globalThis.Deno.upgradeWebSocket`으로 fallback합니다. `runDenoApplication(...)`은 기본적으로 `SIGINT`/`SIGTERM`을 연결하고, `shutdownSignals: false`는 signal registration을 끄며, 여러 signal을 등록하다 실패하면 이미 연결한 listener를 rollback합니다. 이미 실행 중인 adapter에 대한 중복 `listen(...)` 호출은 원래 dispatcher pipeline을 보존하는 no-op입니다. Close는 Deno serve signal을 abort하기 전에 active request drain을 최대 10초 기다립니다. Graceful shutdown이 reject되면 adapter는 ingress를 abort하지만 `server.finished`가 settle될 때까지 active server controller를 유지하고, 그 뒤에만 managed lifecycle을 해제한 다음 원래 shutdown error를 다시 throw합니다. `handle(...)`은 websocket upgrade 요청을 포함해 `listen()`이 dispatcher를 bind하기 전에는 JSON `500`, shutdown 진행 중에는 JSON `503`을 반환합니다.
|
|
117
149
|
|
|
118
150
|
## Conformance 커버리지
|
|
119
151
|
|
|
120
|
-
`packages/platform-deno/src/adapter.test.ts`는 managed Deno 계약을 검증하는 package-local regression 대상입니다. 이 파일은 shared Web dispatch delegation, `listen(dispatcher)` 이후 direct `adapter.handle(...)` success-path dispatch, 직접 constructor/factory option normalization, HTTPS startup forwarding, `Deno.serve(...)` bind target과 startup log에 대한 `host` alias 및 `hostname` 우선순위, 중복 `listen(...)` no-op dispatcher 보존, 기본 `SIGINT`/`SIGTERM` signal listener 등록, `shutdownSignals: false`, partial signal-registration failure 이후 listener rollback, websocket upgrade binding 및 no-binding HTTP fallback, websocket listen 전 bootstrap gating, global Deno serve/upgrade fallback seam, listen 전 `500` 처리, shutdown 중 `503` 처리, serve-signal abort 전 in-flight request drain, bounded 10초 close timeout을 검증합니다. `packages/platform-deno/src/fetch-handler.test.ts`는 host-owned handler에 shared web-runtime portability harness를 적용하여 cookie/query decoding, JSON/text와 byte-exact raw body, multipart exclusion, SSE framing, dispatch가 `Deno.serve(...)`를 호출하지 않는다는 사실을 검증합니다. `packages/platform-deno/src/declaration-surface.test.ts`는 package를 다시 build하고 manifest가 export하는 declaration을 검증합니다.
|
|
152
|
+
`packages/platform-deno/src/adapter.test.ts`는 managed Deno 계약을 검증하는 package-local regression 대상입니다. 이 파일은 shared Web dispatch delegation, `listen(dispatcher)` 이후 direct `adapter.handle(...)` success-path dispatch, 직접 constructor/factory option normalization, HTTPS startup forwarding, `Deno.serve(...)` bind target과 startup log에 대한 `host` alias 및 `hostname` 우선순위, 중복 `listen(...)` no-op dispatcher 보존, 기본 `SIGINT`/`SIGTERM` signal listener 등록, `shutdownSignals: false`, partial signal-registration failure 이후 listener rollback, websocket upgrade binding 및 no-binding HTTP fallback, websocket listen 전 bootstrap gating, global Deno serve/upgrade fallback seam, listen 전 `500` 처리, shutdown 중 `503` 처리, serve-signal abort 전 in-flight request drain, `server.finished`까지 shutdown failure ownership 유지, bounded 10초 close timeout을 검증합니다. `packages/platform-deno/src/fetch-handler.test.ts`는 host-owned handler에 shared web-runtime portability harness를 적용하여 cookie/query decoding, JSON/text와 byte-exact raw body, multipart exclusion, SSE framing, dispatch가 `Deno.serve(...)`를 호출하지 않는다는 사실을 검증합니다. `packages/platform-deno/src/declaration-surface.test.ts`는 package를 다시 build하고 manifest가 export하는 declaration을 검증합니다.
|
|
153
|
+
|
|
154
|
+
공유 edge portability suite인 `packages/testing/src/portability/web-runtime-adapter-portability.test.ts`는 Deno를 Bun 및 Cloudflare Workers와 함께 실행해 malformed cookie 보존, query decoding, JSON/text raw-body capture, 단일 byte-range status/header/body semantic, multipart raw-body 제외, SSE framing을 검증합니다. 패키지 테스트의 README parity assertion은 이 edge-runtime 커버리지 문서가 한국어 mirror와 계속 동기화되도록 확인합니다.
|
|
121
155
|
|
|
122
|
-
|
|
156
|
+
Deno 2 smoke lane은 public `npm:@fluojs/platform-deno` root import를 검사하고 built adapter closure를 네이티브로 실행합니다. Listener 없이 host-owned `createDenoFetchHandler(...)` request를 dispatch한 뒤, port `0`과 `shutdownSignals: false`로 `runDenoApplication(...)`을 시작하고 실제 route를 fetch한 다음 애플리케이션을 닫습니다. 이 managed-listener test에서는 signal ownership을 의도적으로 비활성화하며, signal registration은 별도의 package-local contract suite에서 다룹니다.
|
|
123
157
|
|
|
124
158
|
## 공개 API 개요
|
|
125
159
|
|
|
@@ -129,12 +163,13 @@ Advanced option에는 test 또는 non-hosted runtime을 위한 injectable `serve
|
|
|
129
163
|
- `runDenoApplication(module, options)`: Deno를 위한 권장 빠른 시작 헬퍼입니다.
|
|
130
164
|
- `DenoHttpApplicationAdapter(options?)`: 핵심 adapter 구현체입니다. Direct `new DenoHttpApplicationAdapter()` 또는 `new DenoHttpApplicationAdapter(options)`는 `createDenoAdapter(options)`와 같은 기본 port, `host` alias 처리, `hostname` 우선순위, 숫자 option validation을 적용합니다.
|
|
131
165
|
- `listen(dispatcher)`: fluo HTTP dispatcher를 bind하고 `Deno.serve`를 시작합니다. 중복 호출은 원래 dispatcher를 보존하는 no-op입니다.
|
|
132
|
-
- `close()`: 새 유입을 중단하고 active request를 최대 10초 drain한 뒤, shutdown이 끝나지 않으면 Deno serve signal을 abort합니다.
|
|
166
|
+
- `close()`: 새 유입을 중단하고 active request를 최대 10초 drain한 뒤, shutdown이 끝나지 않으면 Deno serve signal을 abort합니다. Graceful shutdown이 reject되면 `server.finished`가 settle될 때까지 `getServer()` ownership을 유지하고, 이후 managed lifecycle을 해제한 다음 원래 shutdown error를 다시 throw합니다.
|
|
133
167
|
- `handle(request)`: 수동 `Request` to `Response` 디스패처입니다. `listen(dispatcher)`가 runtime dispatcher를 bind한 뒤에는 성공 경로를 실행하고, bind 전에는 JSON `500`, shutdown 중에는 JSON `503`을 반환합니다.
|
|
134
168
|
- `getListenTarget()`: Deno `hostname` 또는 portable `host` alias를 사용해 bind target과 public URL을 보고합니다.
|
|
135
169
|
- `getRealtimeCapability()`: runtime integration을 위한 fetch-style Deno websocket upgrade capability를 보고합니다.
|
|
136
170
|
- `getServer()`: adapter가 listen 중일 때 active `Deno.serve` controller를 반환합니다.
|
|
137
171
|
- `configureWebSocketBinding(...)`: `listen(dispatcher)`가 server를 시작하기 전에 `@fluojs/websockets/deno` binding을 설치합니다.
|
|
172
|
+
- `DenoWebSocketMessage`: 전체 수신 websocket payload union인 `ArrayBuffer | ArrayBufferView | Blob | string`입니다.
|
|
138
173
|
- `https: { cert, key }`: `Deno.serve`로 전달되고 보고되는 listen URL에 반영되는 HTTPS 시작 옵션입니다.
|
|
139
174
|
- Option 및 seam type: `CreateDenoFetchHandlerOptions`, `DenoServeOptions`, `DenoServeController`, `DenoServerWebSocket`, websocket binding interface, bootstrap/run option, listen-target helper.
|
|
140
175
|
|
package/README.md
CHANGED
|
@@ -43,8 +43,32 @@ await runDenoApplication(AppModule, {
|
|
|
43
43
|
});
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
The managed startup path opens a network listener and registers `SIGINT`/`SIGTERM` listeners by default. Run the entrypoint with network access:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
deno run --allow-net main.ts
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Signal listener registration does not require a separate Deno permission. The adapter does not read environment variables. Add a scoped grant such as `--allow-env=PORT,DATABASE_URL` only when application code reads those keys. Signal-triggered application-close failures are logged and swallowed by the helper; it does not set an exit status. Hosts that require failure-status propagation or forced termination must pass `shutdownSignals: false` to `runDenoApplication(...)` and coordinate signals and shutdown themselves.
|
|
53
|
+
|
|
46
54
|
## Common Patterns
|
|
47
55
|
|
|
56
|
+
### Early Hints are unsupported
|
|
57
|
+
|
|
58
|
+
Deno's Fetch `Response` cannot represent an informational response before the final response, so `context.response.earlyHints` is absent. Check for capability presence before use. The adapter never turns a requested `103` into a silent no-op or a final-response header.
|
|
59
|
+
|
|
60
|
+
### Streaming multipart consumption
|
|
61
|
+
|
|
62
|
+
Set `multipart: { strategy: 'stream' }` at application bootstrap to receive multipart data incrementally. For
|
|
63
|
+
multipart routes, `RequestContext.request.body` is an `AsyncIterableIterator<MultipartPart>`: field parts expose
|
|
64
|
+
`kind: 'field'`, `name`, `value`, and `headers`; file parts expose `kind: 'file'`, `name`, `filename`,
|
|
65
|
+
`contentType`, `headers`, and a single-consumer `ReadableStream<Uint8Array>` at `stream`. Finish or cancel each file
|
|
66
|
+
stream before requesting the next part.
|
|
67
|
+
|
|
68
|
+
Runtime route dispatch owns an iterator created for a route and automatically calls `return()` after the handler
|
|
69
|
+
finishes, cancelling and releasing an active source. Standalone `parseMultipartStream(...)` consumers own that
|
|
70
|
+
responsibility: consume the iterator to completion or call `return()` when ending early.
|
|
71
|
+
|
|
48
72
|
### Host-Owned Deno.serve
|
|
49
73
|
If your application owns `Deno.serve(...)`, bootstrap the fluo application without calling `app.listen()` and create a request handler from its public dispatcher. `createDenoFetchHandler(...)` only translates and dispatches requests; it never starts a server or owns shutdown, signals, or websocket upgrades.
|
|
50
74
|
|
|
@@ -68,7 +92,7 @@ try {
|
|
|
68
92
|
}
|
|
69
93
|
```
|
|
70
94
|
|
|
71
|
-
The surrounding host must stop `server`, coordinate process signals, and decide whether websocket upgrades are handled separately. Use
|
|
95
|
+
The surrounding host must stop `server`, coordinate process signals, and decide whether websocket upgrades are handled separately. Use `app.listen()` when fluo should own the managed server lifecycle, or `runDenoApplication(...)` when fluo should additionally install shutdown signal listeners. `adapter.handle(...)` remains available only after the managed adapter's `listen(dispatcher)` binding has completed.
|
|
72
96
|
|
|
73
97
|
### Direct Adapter Construction
|
|
74
98
|
Application code should usually prefer `createDenoAdapter(options)`, `bootstrapDenoApplication(...)`, or `runDenoApplication(...)` so adapter setup stays explicit. Custom orchestration and tests may use `new DenoHttpApplicationAdapter(options?)` directly; the constructor accepts the same optional public `DenoAdapterOptions` as the factory, applies the default port when options are omitted, preserves `hostname` over the portable `host` alias, and rejects invalid `port` or `maxBodySize` values during setup.
|
|
@@ -96,6 +120,14 @@ export class MyGateway {
|
|
|
96
120
|
export class RealtimeModule {}
|
|
97
121
|
```
|
|
98
122
|
|
|
123
|
+
#### Deno websocket inbound payloads
|
|
124
|
+
|
|
125
|
+
`DenoWebSocketMessage` represents every payload form the Deno binding can deliver:
|
|
126
|
+
`ArrayBuffer | ArrayBufferView | Blob | string`. Existing handlers that narrowed this
|
|
127
|
+
public union exhaustively for `Blob | string` must add `ArrayBuffer` and
|
|
128
|
+
`ArrayBufferView` branches. The `@fluojs/websockets/deno` binding already accepts and
|
|
129
|
+
normalizes these binary payloads before it dispatches gateway handlers.
|
|
130
|
+
|
|
99
131
|
## HTTPS and Runtime Portability
|
|
100
132
|
|
|
101
133
|
Pass Deno TLS certificate material through the `https` option to start `Deno.serve` in HTTPS mode. The adapter forwards `https.cert` and `https.key` to Deno as `cert` and `key`, and startup logging reports an `https://` listen URL so the Deno package stays aligned with the shared HTTP adapter portability contract.
|
|
@@ -113,13 +145,15 @@ await runDenoApplication(AppModule, {
|
|
|
113
145
|
|
|
114
146
|
`hostname` remains the Deno-native option name. The adapter also accepts `host` as a portability alias for shared HTTP adapter tests and cross-runtime configuration helpers; when both are provided, `hostname` wins for the `Deno.serve(...)` bind target and reported listen URL.
|
|
115
147
|
|
|
116
|
-
Advanced options include injectable `serve` and `upgradeWebSocket` seams for tests or non-hosted runtimes, `rawBody`, `maxBodySize`, `multipart`, and `shutdownSignals`. `createDenoFetchHandler(...)` accepts the same request parsing options and preserves byte-exact JSON/text raw bodies while excluding `rawBody` for multipart requests. When a seam is not injected, the managed adapter falls back to `globalThis.Deno.serve` and `globalThis.Deno.upgradeWebSocket` at listen/upgrade time. `runDenoApplication(...)` wires `SIGINT`/`SIGTERM` by default, `shutdownSignals: false` disables signal registration, and failed multi-signal registration rolls back listeners that were already attached. Duplicate `listen(...)` calls on an already-running adapter are no-ops that preserve the original dispatcher pipeline. Close waits up to 10 seconds for active requests to drain before aborting the Deno serve signal. `handle(...)` returns a JSON `500` before `listen()` binds the dispatcher, including websocket upgrade requests, and a JSON `503` while shutdown is in progress.
|
|
148
|
+
Advanced options include injectable `serve` and `upgradeWebSocket` seams for tests or non-hosted runtimes, `rawBody`, `maxBodySize`, `multipart`, and `shutdownSignals`. `createDenoFetchHandler(...)` accepts the same request parsing options and preserves byte-exact JSON/text raw bodies while excluding `rawBody` for multipart requests. When a seam is not injected, the managed adapter falls back to `globalThis.Deno.serve` and `globalThis.Deno.upgradeWebSocket` at listen/upgrade time. `runDenoApplication(...)` wires `SIGINT`/`SIGTERM` by default, `shutdownSignals: false` disables signal registration, and failed multi-signal registration rolls back listeners that were already attached. Duplicate `listen(...)` calls on an already-running adapter are no-ops that preserve the original dispatcher pipeline. Close waits up to 10 seconds for active requests to drain before aborting the Deno serve signal. If graceful shutdown rejects, the adapter aborts ingress but retains the active server controller until `server.finished` settles; only then does it release the managed lifecycle and rethrow the original shutdown error. `handle(...)` returns a JSON `500` before `listen()` binds the dispatcher, including websocket upgrade requests, and a JSON `503` while shutdown is in progress.
|
|
117
149
|
|
|
118
150
|
## Conformance Coverage
|
|
119
151
|
|
|
120
|
-
`packages/platform-deno/src/adapter.test.ts` is the package-local regression target for the managed Deno contract. It covers shared Web dispatch delegation, direct `adapter.handle(...)` success-path dispatch after `listen(dispatcher)`, direct constructor/factory option normalization, HTTPS startup forwarding, `host` alias and `hostname` precedence for the `Deno.serve(...)` bind target and startup log, duplicate `listen(...)` no-op dispatcher preservation, default `SIGINT`/`SIGTERM` signal listener registration, `shutdownSignals: false`, listener rollback after partial signal-registration failure, websocket upgrade binding and no-binding HTTP fallback, websocket pre-listen bootstrap gating, global Deno serve/upgrade fallback seams, pre-listen `500` handling, shutdown `503` handling, in-flight request drain before serve-signal abort, and the bounded 10-second close timeout. `packages/platform-deno/src/fetch-handler.test.ts` applies the shared web-runtime portability harness to the host-owned handler, covering cookies/query decoding, JSON/text and byte-exact raw bodies, multipart exclusion, SSE framing, and proof that dispatch does not call `Deno.serve(...)`. `packages/platform-deno/src/declaration-surface.test.ts` rebuilds the package and verifies the manifest-exported declarations.
|
|
152
|
+
`packages/platform-deno/src/adapter.test.ts` is the package-local regression target for the managed Deno contract. It covers shared Web dispatch delegation, direct `adapter.handle(...)` success-path dispatch after `listen(dispatcher)`, direct constructor/factory option normalization, HTTPS startup forwarding, `host` alias and `hostname` precedence for the `Deno.serve(...)` bind target and startup log, duplicate `listen(...)` no-op dispatcher preservation, default `SIGINT`/`SIGTERM` signal listener registration, `shutdownSignals: false`, listener rollback after partial signal-registration failure, websocket upgrade binding and no-binding HTTP fallback, websocket pre-listen bootstrap gating, global Deno serve/upgrade fallback seams, pre-listen `500` handling, shutdown `503` handling, in-flight request drain before serve-signal abort, shutdown-failure ownership until `server.finished`, and the bounded 10-second close timeout. `packages/platform-deno/src/fetch-handler.test.ts` applies the shared web-runtime portability harness to the host-owned handler, covering cookies/query decoding, JSON/text and byte-exact raw bodies, multipart exclusion, SSE framing, and proof that dispatch does not call `Deno.serve(...)`. `packages/platform-deno/src/declaration-surface.test.ts` rebuilds the package and verifies the manifest-exported declarations.
|
|
153
|
+
|
|
154
|
+
The shared edge portability suite in `packages/testing/src/portability/web-runtime-adapter-portability.test.ts` exercises Deno beside Bun and Cloudflare Workers for malformed cookie preservation, query decoding, JSON/text raw-body capture, single byte-range status/header/body semantics, multipart raw-body exclusion, and SSE framing. The README parity assertion in the package test keeps these documented edge-runtime coverage claims synchronized with the Korean mirror.
|
|
121
155
|
|
|
122
|
-
The
|
|
156
|
+
The Deno 2 smoke lane checks the public `npm:@fluojs/platform-deno` root import and executes the built adapter closure natively. It dispatches a host-owned `createDenoFetchHandler(...)` request without a listener, then starts `runDenoApplication(...)` on port `0` with `shutdownSignals: false`, fetches a real route, and closes the application. Signal ownership remains disabled for that managed-listener test; signal registration is covered separately by the package-local contract suite.
|
|
123
157
|
|
|
124
158
|
## Public API Overview
|
|
125
159
|
|
|
@@ -129,12 +163,13 @@ The shared edge portability suite in `packages/testing/src/portability/web-runti
|
|
|
129
163
|
- `runDenoApplication(module, options)`: Recommended quick-start helper for Deno.
|
|
130
164
|
- `DenoHttpApplicationAdapter(options?)`: Core adapter implementation. Direct `new DenoHttpApplicationAdapter()` or `new DenoHttpApplicationAdapter(options)` applies the same default port, `host` alias handling, `hostname` precedence, and numeric option validation as `createDenoAdapter(options)`.
|
|
131
165
|
- `listen(dispatcher)`: Binds the fluo HTTP dispatcher and starts `Deno.serve`; duplicate calls are no-ops while preserving the original dispatcher.
|
|
132
|
-
- `close()`: Stops ingress, drains active requests for up to 10 seconds, and aborts the Deno serve signal if shutdown does not settle.
|
|
166
|
+
- `close()`: Stops ingress, drains active requests for up to 10 seconds, and aborts the Deno serve signal if shutdown does not settle. A rejected graceful shutdown retains `getServer()` ownership until `server.finished` settles, then releases the managed lifecycle and rethrows the original shutdown error.
|
|
133
167
|
- `handle(request)`: Manual `Request` to `Response` dispatcher. It succeeds after `listen(dispatcher)` binds the runtime dispatcher, returns JSON `500` before binding, and returns JSON `503` while shutdown is in progress.
|
|
134
168
|
- `getListenTarget()`: Reports the bind target and public URL using Deno `hostname` or the portable `host` alias.
|
|
135
169
|
- `getRealtimeCapability()`: Reports the fetch-style Deno websocket upgrade capability for runtime integration.
|
|
136
170
|
- `getServer()`: Returns the active `Deno.serve` controller while the adapter is listening.
|
|
137
171
|
- `configureWebSocketBinding(...)`: Installs the `@fluojs/websockets/deno` binding before `listen(dispatcher)` starts the server.
|
|
172
|
+
- `DenoWebSocketMessage`: The full inbound websocket payload union: `ArrayBuffer | ArrayBufferView | Blob | string`.
|
|
138
173
|
- `https: { cert, key }`: HTTPS startup options forwarded to `Deno.serve` and reflected in the reported listen URL.
|
|
139
174
|
- Option and seam types: `CreateDenoFetchHandlerOptions`, `DenoServeOptions`, `DenoServeController`, `DenoServerWebSocket`, websocket binding interfaces, bootstrap/run options, and listen-target helpers.
|
|
140
175
|
|
package/dist/adapter.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface DenoServeController {
|
|
|
23
23
|
/** Deno shutdown signals supported by `runDenoApplication(...)`. */
|
|
24
24
|
export type DenoApplicationSignal = 'SIGINT' | 'SIGTERM';
|
|
25
25
|
/** Message payloads delivered through Deno server websocket bindings. */
|
|
26
|
-
export type DenoWebSocketMessage = Blob | string;
|
|
26
|
+
export type DenoWebSocketMessage = ArrayBuffer | ArrayBufferView | Blob | string;
|
|
27
27
|
/** Server-side websocket shape used by the Deno platform binding seam. */
|
|
28
28
|
export interface DenoServerWebSocket extends Pick<WebSocket, 'addEventListener' | 'close' | 'removeEventListener' | 'send'> {
|
|
29
29
|
readonly readyState: number;
|
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,EAAiD,KAAK,UAAU,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpI,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACpG,OAAO,EACL,KAAK,sCAAsC,EAG3C,KAAK,uBAAuB,EAC5B,KAAK,gCAAgC,EAEtC,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createFetchStyleHttpAdapterRealtimeCapability } from '@fluojs/http/internal';
|
|
2
2
|
import { bootstrapHttpAdapterApplication, createDefaultApplicationLogger, runHttpAdapterApplication } from '@fluojs/runtime/internal/http-adapter';
|
|
3
|
-
import { createWebRequestResponseFactory,
|
|
3
|
+
import { createWebRequestResponseFactory, startWebRequestDispatch } from '@fluojs/runtime/web';
|
|
4
4
|
import { validateNonNegativeIntegerOption } from './options.js';
|
|
5
5
|
|
|
6
6
|
/** Listen target metadata reported by `Deno.serve(...)` callbacks. */
|
|
@@ -95,14 +95,18 @@ export class DenoHttpApplicationAdapter {
|
|
|
95
95
|
return createShutdownResponse();
|
|
96
96
|
}
|
|
97
97
|
const release = this.trackInFlightRequest();
|
|
98
|
+
let releaseAfterResponse = true;
|
|
98
99
|
try {
|
|
99
100
|
if (!this.dispatcher) {
|
|
100
|
-
|
|
101
|
+
const dispatch = startWebRequestDispatch({
|
|
101
102
|
dispatcher: this.dispatcher,
|
|
102
103
|
dispatcherNotReadyMessage: 'Deno adapter received a request before dispatcher binding completed.',
|
|
103
104
|
factory: this.webRequestResponseFactory,
|
|
104
105
|
request
|
|
105
106
|
});
|
|
107
|
+
releaseAfterResponse = false;
|
|
108
|
+
void dispatch.completion.finally(release).catch(() => {});
|
|
109
|
+
return await dispatch.response;
|
|
106
110
|
}
|
|
107
111
|
if (this.websocketBinding && isWebSocketUpgradeRequest(request)) {
|
|
108
112
|
const upgradeWebSocket = resolveUpgradeWebSocket(this.options.upgradeWebSocket);
|
|
@@ -110,40 +114,56 @@ export class DenoHttpApplicationAdapter {
|
|
|
110
114
|
upgrade: upgradeRequest => upgradeWebSocket(upgradeRequest)
|
|
111
115
|
});
|
|
112
116
|
}
|
|
113
|
-
|
|
117
|
+
const dispatch = startWebRequestDispatch({
|
|
114
118
|
dispatcher: this.dispatcher,
|
|
115
119
|
dispatcherNotReadyMessage: 'Deno adapter received a request before dispatcher binding completed.',
|
|
116
120
|
factory: this.webRequestResponseFactory,
|
|
117
121
|
request
|
|
118
122
|
});
|
|
123
|
+
releaseAfterResponse = false;
|
|
124
|
+
void dispatch.completion.finally(release).catch(() => {});
|
|
125
|
+
return await dispatch.response;
|
|
119
126
|
} finally {
|
|
120
|
-
|
|
127
|
+
if (releaseAfterResponse) {
|
|
128
|
+
release();
|
|
129
|
+
}
|
|
121
130
|
}
|
|
122
131
|
}
|
|
123
132
|
async listen(dispatcher) {
|
|
124
133
|
if (this.server) {
|
|
125
134
|
return;
|
|
126
135
|
}
|
|
127
|
-
|
|
136
|
+
const previousAbortController = this.abortController;
|
|
137
|
+
const previousDispatcher = this.dispatcher;
|
|
138
|
+
const previousListenAddress = this.listenAddress;
|
|
128
139
|
const abortController = new AbortController();
|
|
129
|
-
const serve = resolveServe(this.options.serve);
|
|
130
140
|
const listenReady = this.options.port === 0 ? createDeferred() : undefined;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
this.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
141
|
+
try {
|
|
142
|
+
const serve = resolveServe(this.options.serve);
|
|
143
|
+
this.dispatcher = dispatcher;
|
|
144
|
+
this.abortController = abortController;
|
|
145
|
+
this.server = serve({
|
|
146
|
+
cert: this.options.https?.cert,
|
|
147
|
+
hostname: this.options.hostname,
|
|
148
|
+
key: this.options.https?.key,
|
|
149
|
+
onListen: localAddr => {
|
|
150
|
+
this.listenAddress = localAddr;
|
|
151
|
+
listenReady?.resolve();
|
|
152
|
+
this.options.onListen?.(localAddr);
|
|
153
|
+
},
|
|
154
|
+
port: this.options.port,
|
|
155
|
+
signal: abortController.signal
|
|
156
|
+
}, async request => {
|
|
157
|
+
return await this.handle(request);
|
|
158
|
+
});
|
|
159
|
+
await listenReady?.promise;
|
|
160
|
+
} catch (error) {
|
|
161
|
+
abortController.abort();
|
|
162
|
+
this.abortController = previousAbortController;
|
|
163
|
+
this.dispatcher = previousDispatcher;
|
|
164
|
+
this.listenAddress = previousListenAddress;
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
147
167
|
}
|
|
148
168
|
async close() {
|
|
149
169
|
if (this.closeInFlight) {
|
|
@@ -343,15 +363,58 @@ function isWebSocketUpgradeRequest(request) {
|
|
|
343
363
|
}
|
|
344
364
|
function closeDenoServerWithDrain(server, abortController, waitForDrain) {
|
|
345
365
|
return (async () => {
|
|
366
|
+
let closeFailure;
|
|
367
|
+
const shutdown = Promise.resolve(server.shutdown());
|
|
368
|
+
const drain = waitForDrain();
|
|
369
|
+
const gracefulClose = Promise.allSettled([shutdown, drain]).then(results => ({
|
|
370
|
+
kind: 'graceful',
|
|
371
|
+
results
|
|
372
|
+
}));
|
|
373
|
+
const forcedClose = abortController ? waitForAbort(abortController.signal).then(() => ({
|
|
374
|
+
kind: 'forced'
|
|
375
|
+
})) : undefined;
|
|
376
|
+
const closeResult = forcedClose ? await Promise.race([gracefulClose, forcedClose]) : await gracefulClose;
|
|
377
|
+
if (closeResult.kind === 'graceful') {
|
|
378
|
+
const rejected = closeResult.results.find(result => result.status === 'rejected');
|
|
379
|
+
if (rejected?.status === 'rejected') {
|
|
380
|
+
abortController?.abort();
|
|
381
|
+
closeFailure = {
|
|
382
|
+
error: rejected.reason
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
} else {
|
|
386
|
+
try {
|
|
387
|
+
await drain;
|
|
388
|
+
} catch (error) {
|
|
389
|
+
closeFailure = {
|
|
390
|
+
error
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
}
|
|
346
394
|
try {
|
|
347
|
-
await server.
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
395
|
+
await server.finished;
|
|
396
|
+
} catch (error) {
|
|
397
|
+
if (!closeFailure) {
|
|
398
|
+
throw error;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (closeFailure) {
|
|
402
|
+
throw closeFailure.error;
|
|
351
403
|
}
|
|
352
|
-
await server.finished;
|
|
353
404
|
})();
|
|
354
405
|
}
|
|
406
|
+
function waitForAbort(signal) {
|
|
407
|
+
if (signal.aborted) {
|
|
408
|
+
return Promise.resolve();
|
|
409
|
+
}
|
|
410
|
+
return new Promise(resolve => {
|
|
411
|
+
signal.addEventListener('abort', () => {
|
|
412
|
+
resolve();
|
|
413
|
+
}, {
|
|
414
|
+
once: true
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
}
|
|
355
418
|
function createDeferred() {
|
|
356
419
|
let resolve;
|
|
357
420
|
let reject;
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"platform",
|
|
9
9
|
"server"
|
|
10
10
|
],
|
|
11
|
-
"version": "
|
|
11
|
+
"version": "2.0.0",
|
|
12
12
|
"private": false,
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": {
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"dist"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@fluojs/http": "^
|
|
36
|
-
"@fluojs/runtime": "^
|
|
35
|
+
"@fluojs/http": "^3.0.0",
|
|
36
|
+
"@fluojs/runtime": "^3.0.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"vitest": "^
|
|
40
|
-
"@fluojs/testing": "^
|
|
39
|
+
"vitest": "^4.1.11",
|
|
40
|
+
"@fluojs/testing": "^3.0.0"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|