@fluojs/platform-deno 1.0.8 → 1.1.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 CHANGED
@@ -45,31 +45,49 @@ await runDenoApplication(AppModule, {
45
45
 
46
46
  ## 주요 패턴
47
47
 
48
- ### 수동 요청 디스패칭
49
- 테스트나 커스텀 `Deno.serve` 구현을 위해 어댑터의 `handle` 메서드를 사용하여 네이티브 요청을 수동으로 디스패치할 있습니다. 다만 `handle(...)`은 런타임 dispatcher가 바인딩된 뒤에만 동작하므로, 먼저 `app.listen()`(또는 `runDenoApplication(...)`)으로 부트스트랩을 완료해야 합니다.
48
+ ### Host-Owned Deno.serve
49
+ 애플리케이션이 `Deno.serve(...)`를 소유한다면 `app.listen()`을 호출하지 않고 fluo 애플리케이션을 bootstrap한 public dispatcher로 request handler를 만드세요. `createDenoFetchHandler(...)`는 request 변환과 dispatch만 수행하며 server를 시작하거나 shutdown, signal, websocket upgrade를 소유하지 않습니다.
50
50
 
51
51
  ```typescript
52
- import { createDenoAdapter } from '@fluojs/platform-deno';
52
+ import { createDenoAdapter, createDenoFetchHandler } from '@fluojs/platform-deno';
53
53
  import { fluoFactory } from '@fluojs/runtime';
54
54
 
55
- const adapter = createDenoAdapter({ port: 3000 });
55
+ const adapter = createDenoAdapter();
56
56
  const app = await fluoFactory.create(AppModule, { adapter });
57
+ const handler = createDenoFetchHandler({
58
+ dispatcher: app.dispatcher,
59
+ rawBody: true,
60
+ });
57
61
 
58
- await app.listen();
62
+ const server = Deno.serve({ port: 3000 }, handler);
59
63
 
60
- const response = await adapter.handle(new Request('http://localhost:3000/health'));
64
+ try {
65
+ await server.finished;
66
+ } finally {
67
+ await app.close();
68
+ }
61
69
  ```
62
70
 
63
- ### Deno 네이티브 WebSocket 지원
71
+ 주변 host는 `server` 중지와 process signal 조율을 소유하고 websocket upgrade를 별도로 처리할지 결정해야 합니다. fluo가 해당 lifecycle seam을 소유해야 한다면 managed `runDenoApplication(...)` 또는 `app.listen()` 경로를 사용하세요. `adapter.handle(...)`은 managed adapter의 `listen(dispatcher)` binding이 끝난 뒤에만 사용할 수 있습니다.
72
+
73
+ ### 직접 어댑터 생성
74
+ 애플리케이션 코드는 보통 `createDenoAdapter(options)`, `bootstrapDenoApplication(...)`, `runDenoApplication(...)`을 사용해 adapter setup 경계를 명확히 유지하는 편을 권장합니다. 커스텀 orchestration이나 테스트에서는 `new DenoHttpApplicationAdapter(options?)`를 직접 사용할 수 있으며, constructor는 factory와 같은 optional public `DenoAdapterOptions`를 받고 options가 생략되면 기본 port를 적용하며, portable `host` alias보다 `hostname`을 우선하고, 잘못된 `port` 또는 `maxBodySize` 값은 setup 시점에 거절합니다.
75
+
76
+ ### Opt-in Deno WebSocket 바인딩
64
77
  어댑터는 애플리케이션이 `@fluojs/websockets/deno` 바인딩을 import하고 설정한 뒤에 Deno의 네이티브 `Deno.upgradeWebSocket`을 지원합니다. 해당 바인딩이 없으면 websocket upgrade 요청은 암묵적으로 upgrade되지 않고 일반 HTTP dispatch 경로를 계속 따릅니다.
65
78
 
66
79
  ```typescript
67
80
  import { Module } from '@fluojs/core';
68
- import { WebSocketGateway } from '@fluojs/websockets';
69
- import { DenoWebSocketModule } from '@fluojs/websockets/deno';
81
+ import { DenoWebSocketModule, OnMessage, WebSocketGateway } from '@fluojs/websockets/deno';
82
+ import type { DenoServerWebSocket } from '@fluojs/websockets/deno';
70
83
 
71
84
  @WebSocketGateway({ path: '/ws' })
72
- export class MyGateway {}
85
+ export class MyGateway {
86
+ @OnMessage('ping')
87
+ handlePing(_payload: unknown, socket: DenoServerWebSocket) {
88
+ socket.send(JSON.stringify({ event: 'pong', data: 'hello from deno' }));
89
+ }
90
+ }
73
91
 
74
92
  @Module({
75
93
  imports: [DenoWebSocketModule.forRoot()],
@@ -95,23 +113,30 @@ await runDenoApplication(AppModule, {
95
113
 
96
114
  `hostname`은 Deno 네이티브 옵션 이름으로 유지됩니다. 공유 HTTP 어댑터 테스트와 교차 런타임 설정 헬퍼를 위해 `host`도 이식성 alias로 허용하며, 둘 다 제공하면 `Deno.serve(...)` bind target과 보고되는 listen URL에는 `hostname`이 우선합니다.
97
115
 
98
- Advanced option에는 test 또는 non-hosted runtime을 위한 injectable `serve`, `upgradeWebSocket` seam, `rawBody`, `maxBodySize`, `multipart`, `shutdownSignals`가 포함됩니다. Seam을 주입하지 않으면 어댑터는 listen/upgrade 시점에 `globalThis.Deno.serve`와 `globalThis.Deno.upgradeWebSocket`으로 fallback합니다. `runDenoApplication(...)`은 기본적으로 `SIGINT`/`SIGTERM`을 연결하고, `shutdownSignals: false`는 signal registration을 끄며, 여러 signal을 등록하다 실패하면 이미 연결한 listener를 rollback합니다. Close는 Deno serve signal을 abort하기 전에 active request drain을 최대 10초 기다립니다. `handle(...)`은 `listen()`이 dispatcher를 bind하기 전에는 JSON `500`, shutdown 진행 중에는 JSON `503`을 반환합니다.
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`을 반환합니다.
99
117
 
100
118
  ## Conformance 커버리지
101
119
 
102
- `packages/platform-deno/src/adapter.test.ts`는 문서화된 Deno 계약을 검증하는 package-local regression 대상입니다. 이 파일은 shared Web dispatch delegation, HTTPS startup forwarding, `host` alias 및 `hostname` 우선순위 listen-target handling, 기본 `SIGINT`/`SIGTERM` signal listener 등록, `shutdownSignals: false`, partial signal-registration failure 이후 listener rollback, websocket upgrade binding 및 no-binding HTTP fallback, global Deno serve/upgrade fallback seam, listen 전 `500` 처리, shutdown 중 `503` 처리, serve-signal abort 전 in-flight request drain, bounded 10초 close timeout을 검증합니다.
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을 검증합니다.
103
121
 
104
122
  공유 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, multipart raw-body 제외, SSE framing을 검증합니다. 패키지 테스트의 README parity assertion은 이 edge-runtime 커버리지 문서가 한국어 mirror와 계속 동기화되도록 확인합니다.
105
123
 
106
124
  ## 공개 API 개요
107
125
 
108
- - `createDenoAdapter(options)`: Deno HTTP 어댑터를 위한 팩토리입니다.
126
+ - `createDenoAdapter(options)`: Deno HTTP 어댑터를 위한 팩토리이며, 직접 생성과 같은 validation 및 normalization을 공유합니다.
127
+ - `createDenoFetchHandler(options)`: 이미 bootstrap된 `app.dispatcher`에서 `Deno.serve(...)`를 시작하거나 소유하지 않는 `Request` handler를 동기적으로 생성합니다.
109
128
  - `bootstrapDenoApplication(module, options)`: 커스텀 오케스트레이션을 위한 고급 부트스트랩입니다.
110
129
  - `runDenoApplication(module, options)`: Deno를 위한 권장 빠른 시작 헬퍼입니다.
111
- - `DenoHttpApplicationAdapter`: `handle(...)`, `getListenTarget()`, `getRealtimeCapability()`, `getServer()`, `configureWebSocketBinding(...)`를 제공하는 핵심 adapter 구현체입니다.
112
- - `handle(request)`: 수동 `Request` to `Response` 디스패처입니다.
130
+ - `DenoHttpApplicationAdapter(options?)`: 핵심 adapter 구현체입니다. Direct `new DenoHttpApplicationAdapter()` 또는 `new DenoHttpApplicationAdapter(options)`는 `createDenoAdapter(options)`와 같은 기본 port, `host` alias 처리, `hostname` 우선순위, 숫자 option validation을 적용합니다.
131
+ - `listen(dispatcher)`: fluo HTTP dispatcher를 bind하고 `Deno.serve`를 시작합니다. 중복 호출은 원래 dispatcher를 보존하는 no-op입니다.
132
+ - `close()`: 새 유입을 중단하고 active request를 최대 10초 drain한 뒤, shutdown이 끝나지 않으면 Deno serve signal을 abort합니다.
133
+ - `handle(request)`: 수동 `Request` to `Response` 디스패처입니다. `listen(dispatcher)`가 runtime dispatcher를 bind한 뒤에는 성공 경로를 실행하고, bind 전에는 JSON `500`, shutdown 중에는 JSON `503`을 반환합니다.
134
+ - `getListenTarget()`: Deno `hostname` 또는 portable `host` alias를 사용해 bind target과 public URL을 보고합니다.
135
+ - `getRealtimeCapability()`: runtime integration을 위한 fetch-style Deno websocket upgrade capability를 보고합니다.
136
+ - `getServer()`: adapter가 listen 중일 때 active `Deno.serve` controller를 반환합니다.
137
+ - `configureWebSocketBinding(...)`: `listen(dispatcher)`가 server를 시작하기 전에 `@fluojs/websockets/deno` binding을 설치합니다.
113
138
  - `https: { cert, key }`: `Deno.serve`로 전달되고 보고되는 listen URL에 반영되는 HTTPS 시작 옵션입니다.
114
- - Option 및 seam type: `DenoServeOptions`, `DenoServeController`, `DenoServerWebSocket`, websocket binding interface, bootstrap/run option, listen-target helper.
139
+ - Option 및 seam type: `CreateDenoFetchHandlerOptions`, `DenoServeOptions`, `DenoServeController`, `DenoServerWebSocket`, websocket binding interface, bootstrap/run option, listen-target helper.
115
140
 
116
141
  ## 관련 패키지
117
142
 
@@ -122,4 +147,5 @@ Advanced option에는 test 또는 non-hosted runtime을 위한 injectable `serve
122
147
  ## 예제 소스
123
148
 
124
149
  - `packages/platform-deno/src/adapter.test.ts`
150
+ - `packages/platform-deno/src/fetch-handler.test.ts`
125
151
  - `packages/websockets/src/deno/deno.test.ts`
package/README.md CHANGED
@@ -45,31 +45,49 @@ await runDenoApplication(AppModule, {
45
45
 
46
46
  ## Common Patterns
47
47
 
48
- ### Manual Request Dispatching
49
- For testing or custom `Deno.serve` implementations, you can use the adapter's `handle` method to dispatch native web requests manually. Bind the dispatcher first via `app.listen()` (or `runDenoApplication(...)`), because `handle(...)` only works after the runtime has been bootstrapped.
48
+ ### Host-Owned Deno.serve
49
+ 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
50
 
51
51
  ```typescript
52
- import { createDenoAdapter } from '@fluojs/platform-deno';
52
+ import { createDenoAdapter, createDenoFetchHandler } from '@fluojs/platform-deno';
53
53
  import { fluoFactory } from '@fluojs/runtime';
54
54
 
55
- const adapter = createDenoAdapter({ port: 3000 });
55
+ const adapter = createDenoAdapter();
56
56
  const app = await fluoFactory.create(AppModule, { adapter });
57
+ const handler = createDenoFetchHandler({
58
+ dispatcher: app.dispatcher,
59
+ rawBody: true,
60
+ });
57
61
 
58
- await app.listen();
62
+ const server = Deno.serve({ port: 3000 }, handler);
59
63
 
60
- const response = await adapter.handle(new Request('http://localhost:3000/health'));
64
+ try {
65
+ await server.finished;
66
+ } finally {
67
+ await app.close();
68
+ }
61
69
  ```
62
70
 
63
- ### Deno-Native WebSocket Support
71
+ The surrounding host must stop `server`, coordinate process signals, and decide whether websocket upgrades are handled separately. Use the managed `runDenoApplication(...)` or `app.listen()` path when fluo should own those lifecycle seams. `adapter.handle(...)` remains available only after the managed adapter's `listen(dispatcher)` binding has completed.
72
+
73
+ ### Direct Adapter Construction
74
+ 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.
75
+
76
+ ### Opt-in Deno WebSocket Binding
64
77
  The adapter supports Deno's native `Deno.upgradeWebSocket` after the application imports and configures the `@fluojs/websockets/deno` binding. Without that binding, websocket upgrade requests continue through normal HTTP dispatch instead of being upgraded implicitly.
65
78
 
66
79
  ```typescript
67
80
  import { Module } from '@fluojs/core';
68
- import { WebSocketGateway } from '@fluojs/websockets';
69
- import { DenoWebSocketModule } from '@fluojs/websockets/deno';
81
+ import { DenoWebSocketModule, OnMessage, WebSocketGateway } from '@fluojs/websockets/deno';
82
+ import type { DenoServerWebSocket } from '@fluojs/websockets/deno';
70
83
 
71
84
  @WebSocketGateway({ path: '/ws' })
72
- export class MyGateway {}
85
+ export class MyGateway {
86
+ @OnMessage('ping')
87
+ handlePing(_payload: unknown, socket: DenoServerWebSocket) {
88
+ socket.send(JSON.stringify({ event: 'pong', data: 'hello from deno' }));
89
+ }
90
+ }
73
91
 
74
92
  @Module({
75
93
  imports: [DenoWebSocketModule.forRoot()],
@@ -95,23 +113,30 @@ await runDenoApplication(AppModule, {
95
113
 
96
114
  `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.
97
115
 
98
- Advanced options include injectable `serve` and `upgradeWebSocket` seams for tests or non-hosted runtimes, `rawBody`, `maxBodySize`, `multipart`, and `shutdownSignals`. When a seam is not injected, the 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. 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 and a JSON `503` while shutdown is in progress.
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.
99
117
 
100
118
  ## Conformance Coverage
101
119
 
102
- `packages/platform-deno/src/adapter.test.ts` is the package-local regression target for the documented Deno contract. It covers shared Web dispatch delegation, HTTPS startup forwarding, `host` alias and `hostname` precedence listen-target handling, default `SIGINT`/`SIGTERM` signal listener registration, `shutdownSignals: false`, listener rollback after partial signal-registration failure, websocket upgrade binding and no-binding HTTP fallback, 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.
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.
103
121
 
104
122
  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, 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.
105
123
 
106
124
  ## Public API Overview
107
125
 
108
- - `createDenoAdapter(options)`: Factory for the Deno HTTP adapter.
126
+ - `createDenoAdapter(options)`: Factory for the Deno HTTP adapter; it shares validation and normalization with direct construction.
127
+ - `createDenoFetchHandler(options)`: Synchronously creates a `Request` handler from an already bootstrapped `app.dispatcher` without starting or owning `Deno.serve(...)`.
109
128
  - `bootstrapDenoApplication(module, options)`: Advanced bootstrap for custom orchestration.
110
129
  - `runDenoApplication(module, options)`: Recommended quick-start helper for Deno.
111
- - `DenoHttpApplicationAdapter`: Core adapter implementation with `handle(...)`, `getListenTarget()`, `getRealtimeCapability()`, `getServer()`, and `configureWebSocketBinding(...)`.
112
- - `handle(request)`: Manual `Request` to `Response` dispatcher.
130
+ - `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
+ - `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.
133
+ - `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
+ - `getListenTarget()`: Reports the bind target and public URL using Deno `hostname` or the portable `host` alias.
135
+ - `getRealtimeCapability()`: Reports the fetch-style Deno websocket upgrade capability for runtime integration.
136
+ - `getServer()`: Returns the active `Deno.serve` controller while the adapter is listening.
137
+ - `configureWebSocketBinding(...)`: Installs the `@fluojs/websockets/deno` binding before `listen(dispatcher)` starts the server.
113
138
  - `https: { cert, key }`: HTTPS startup options forwarded to `Deno.serve` and reflected in the reported listen URL.
114
- - Option and seam types: `DenoServeOptions`, `DenoServeController`, `DenoServerWebSocket`, websocket binding interfaces, bootstrap/run options, and listen-target helpers.
139
+ - Option and seam types: `CreateDenoFetchHandlerOptions`, `DenoServeOptions`, `DenoServeController`, `DenoServerWebSocket`, websocket binding interfaces, bootstrap/run options, and listen-target helpers.
115
140
 
116
141
  ## Related Packages
117
142
 
@@ -122,4 +147,5 @@ The shared edge portability suite in `packages/testing/src/portability/web-runti
122
147
  ## Example Sources
123
148
 
124
149
  - `packages/platform-deno/src/adapter.test.ts`
150
+ - `packages/platform-deno/src/fetch-handler.test.ts`
125
151
  - `packages/websockets/src/deno/deno.test.ts`
package/dist/adapter.d.ts CHANGED
@@ -91,6 +91,9 @@ declare global {
91
91
  }
92
92
  /**
93
93
  * Deno-backed HTTP adapter that preserves request draining and websocket binding seams.
94
+ *
95
+ * Direct construction accepts the same public options as `createDenoAdapter(...)` and applies the
96
+ * same default port, `host` alias, `hostname` precedence, and numeric option validation.
94
97
  */
95
98
  export declare class DenoHttpApplicationAdapter implements HttpApplicationAdapter {
96
99
  private abortController?;
@@ -103,7 +106,12 @@ export declare class DenoHttpApplicationAdapter implements HttpApplicationAdapte
103
106
  private websocketBinding?;
104
107
  private readonly options;
105
108
  private readonly webRequestResponseFactory;
106
- constructor(options: Required<Pick<DenoAdapterOptions, 'hostname' | 'port'>> & DenoAdapterOptions);
109
+ /**
110
+ * Create a Deno adapter with the same normalization rules as `createDenoAdapter(...)`.
111
+ *
112
+ * @param options Transport, parsing, and websocket-host configuration for the Deno runtime.
113
+ */
114
+ constructor(options?: DenoAdapterOptions);
107
115
  getServer(): DenoServeController | undefined;
108
116
  getListenTarget(): HttpAdapterListenTarget;
109
117
  getRealtimeCapability(): import("@fluojs/http").FetchStyleHttpAdapterRealtimeCapability;
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
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,7 @@
1
1
  import { createFetchStyleHttpAdapterRealtimeCapability } from '@fluojs/http/internal';
2
2
  import { bootstrapHttpAdapterApplication, createDefaultApplicationLogger, runHttpAdapterApplication } from '@fluojs/runtime/internal/http-adapter';
3
3
  import { createWebRequestResponseFactory, dispatchWebRequest } from '@fluojs/runtime/web';
4
+ import { validateNonNegativeIntegerOption } from './options.js';
4
5
 
5
6
  /** Listen target metadata reported by `Deno.serve(...)` callbacks. */
6
7
 
@@ -41,7 +42,11 @@ const DEFAULT_PORT = 3000;
41
42
  const DEFAULT_SHUTDOWN_TIMEOUT_MS = 10_000;
42
43
  /**
43
44
  * Deno-backed HTTP adapter that preserves request draining and websocket binding seams.
45
+ *
46
+ * Direct construction accepts the same public options as `createDenoAdapter(...)` and applies the
47
+ * same default port, `host` alias, `hostname` precedence, and numeric option validation.
44
48
  */
49
+ // allow: SIZE_OK — Deno serve, websocket, signal, and shutdown state form one adapter lifecycle state machine.
45
50
  export class DenoHttpApplicationAdapter {
46
51
  abortController;
47
52
  closeInFlight;
@@ -53,12 +58,19 @@ export class DenoHttpApplicationAdapter {
53
58
  websocketBinding;
54
59
  options;
55
60
  webRequestResponseFactory;
56
- constructor(options) {
57
- this.options = options;
61
+
62
+ /**
63
+ * Create a Deno adapter with the same normalization rules as `createDenoAdapter(...)`.
64
+ *
65
+ * @param options Transport, parsing, and websocket-host configuration for the Deno runtime.
66
+ */
67
+ constructor(options = {}) {
68
+ const resolvedOptions = normalizeDenoAdapterOptions(options);
69
+ this.options = resolvedOptions;
58
70
  this.webRequestResponseFactory = createWebRequestResponseFactory({
59
- maxBodySize: options.maxBodySize,
60
- multipart: options.multipart,
61
- rawBody: options.rawBody
71
+ maxBodySize: resolvedOptions.maxBodySize,
72
+ multipart: resolvedOptions.multipart,
73
+ rawBody: resolvedOptions.rawBody
62
74
  });
63
75
  }
64
76
  getServer() {
@@ -84,6 +96,14 @@ export class DenoHttpApplicationAdapter {
84
96
  }
85
97
  const release = this.trackInFlightRequest();
86
98
  try {
99
+ if (!this.dispatcher) {
100
+ return await dispatchWebRequest({
101
+ dispatcher: this.dispatcher,
102
+ dispatcherNotReadyMessage: 'Deno adapter received a request before dispatcher binding completed.',
103
+ factory: this.webRequestResponseFactory,
104
+ request
105
+ });
106
+ }
87
107
  if (this.websocketBinding && isWebSocketUpgradeRequest(request)) {
88
108
  const upgradeWebSocket = resolveUpgradeWebSocket(this.options.upgradeWebSocket);
89
109
  return await this.websocketBinding.fetch(request, {
@@ -101,10 +121,10 @@ export class DenoHttpApplicationAdapter {
101
121
  }
102
122
  }
103
123
  async listen(dispatcher) {
104
- this.dispatcher = dispatcher;
105
124
  if (this.server) {
106
125
  return;
107
126
  }
127
+ this.dispatcher = dispatcher;
108
128
  const abortController = new AbortController();
109
129
  const serve = resolveServe(this.options.serve);
110
130
  const listenReady = this.options.port === 0 ? createDeferred() : undefined;
@@ -185,12 +205,15 @@ export class DenoHttpApplicationAdapter {
185
205
  * @returns A Deno-backed `HttpApplicationAdapter`.
186
206
  */
187
207
  export function createDenoAdapter(options = {}) {
208
+ return new DenoHttpApplicationAdapter(options);
209
+ }
210
+ function normalizeDenoAdapterOptions(options) {
188
211
  validateNonNegativeIntegerOption('maxBodySize', options.maxBodySize);
189
- return new DenoHttpApplicationAdapter({
212
+ return {
190
213
  ...options,
191
214
  hostname: options.hostname ?? options.host ?? DEFAULT_HOSTNAME,
192
215
  port: resolveDenoPort(options.port)
193
- });
216
+ };
194
217
  }
195
218
 
196
219
  /**
@@ -247,7 +270,11 @@ function createDenoShutdownSignalRegistration(signals) {
247
270
  });
248
271
  }
249
272
  } catch (error) {
250
- removeDenoSignalBindings(denoGlobal, bindings);
273
+ try {
274
+ removeDenoSignalBindings(denoGlobal, bindings);
275
+ } catch (cleanupError) {
276
+ throw new AggregateError([error, cleanupError], 'Failed to register Deno shutdown signals and roll back registered listeners.');
277
+ }
251
278
  throw error;
252
279
  }
253
280
  return () => {
@@ -256,8 +283,19 @@ function createDenoShutdownSignalRegistration(signals) {
256
283
  };
257
284
  }
258
285
  function removeDenoSignalBindings(denoGlobal, bindings) {
286
+ const errors = [];
259
287
  for (const binding of bindings) {
260
- denoGlobal.removeSignalListener(binding.signal, binding.handler);
288
+ try {
289
+ denoGlobal.removeSignalListener(binding.signal, binding.handler);
290
+ } catch (error) {
291
+ errors.push(error);
292
+ }
293
+ }
294
+ if (errors.length === 1) {
295
+ throw errors[0];
296
+ }
297
+ if (errors.length > 1) {
298
+ throw new AggregateError(errors, 'Failed to remove Deno shutdown signal listeners.');
261
299
  }
262
300
  }
263
301
  function createListenTarget(hostname, port, usesHttps) {
@@ -277,14 +315,6 @@ function resolveDenoPort(value) {
277
315
  }
278
316
  return port;
279
317
  }
280
- function validateNonNegativeIntegerOption(name, value) {
281
- if (value === undefined) {
282
- return;
283
- }
284
- if (!Number.isInteger(value) || value < 0) {
285
- throw new Error(`Invalid ${name} value: ${String(value)}. Expected a non-negative integer.`);
286
- }
287
- }
288
318
  function formatHostForAuthority(hostname) {
289
319
  return hostname.includes(':') && !hostname.startsWith('[') ? `[${hostname}]` : hostname;
290
320
  }
@@ -0,0 +1,26 @@
1
+ import type { Dispatcher } from '@fluojs/http/internal';
2
+ import type { MultipartOptions } from '@fluojs/runtime';
3
+ import type { DenoServeHandler } from './adapter.js';
4
+ /** Options for creating a Deno request handler for a host-owned `Deno.serve(...)` lifecycle. */
5
+ export interface CreateDenoFetchHandlerOptions {
6
+ /** Already bootstrapped dispatcher that receives translated fluo framework requests. */
7
+ readonly dispatcher: Dispatcher;
8
+ /** Maximum request body size enforced by the shared Web request parser. */
9
+ readonly maxBodySize?: number;
10
+ /** Multipart parsing limits enforced by the shared Web request parser. */
11
+ readonly multipart?: MultipartOptions;
12
+ /** Preserves byte-exact raw bodies for JSON and text requests when enabled. */
13
+ readonly rawBody?: boolean;
14
+ }
15
+ /**
16
+ * Create a Deno `Request` handler without starting or owning `Deno.serve(...)`.
17
+ *
18
+ * @remarks
19
+ * The surrounding host owns server startup, shutdown, signals, and websocket upgrades. The
20
+ * dispatcher must come from an already bootstrapped fluo application, such as `app.dispatcher`.
21
+ *
22
+ * @param options - Bootstrapped dispatcher and shared Web request parsing options.
23
+ * @returns A handler suitable for a host-owned `Deno.serve(handler)` call.
24
+ */
25
+ export declare function createDenoFetchHandler({ dispatcher, maxBodySize, multipart, rawBody, }: CreateDenoFetchHandlerOptions): DenoServeHandler;
26
+ //# sourceMappingURL=fetch-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-handler.d.ts","sourceRoot":"","sources":["../src/fetch-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrD,gGAAgG;AAChG,MAAM,WAAW,6BAA6B;IAC5C,wFAAwF;IACxF,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IACtC,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,UAAU,EACV,WAAW,EACX,SAAS,EACT,OAAO,GACR,EAAE,6BAA6B,GAAG,gBAAgB,CAiBlD"}
@@ -0,0 +1,36 @@
1
+ import { createWebRequestResponseFactory, dispatchWebRequest } from '@fluojs/runtime/web';
2
+ import { validateNonNegativeIntegerOption } from './options.js';
3
+
4
+ /** Options for creating a Deno request handler for a host-owned `Deno.serve(...)` lifecycle. */
5
+
6
+ /**
7
+ * Create a Deno `Request` handler without starting or owning `Deno.serve(...)`.
8
+ *
9
+ * @remarks
10
+ * The surrounding host owns server startup, shutdown, signals, and websocket upgrades. The
11
+ * dispatcher must come from an already bootstrapped fluo application, such as `app.dispatcher`.
12
+ *
13
+ * @param options - Bootstrapped dispatcher and shared Web request parsing options.
14
+ * @returns A handler suitable for a host-owned `Deno.serve(handler)` call.
15
+ */
16
+ export function createDenoFetchHandler({
17
+ dispatcher,
18
+ maxBodySize,
19
+ multipart,
20
+ rawBody
21
+ }) {
22
+ validateNonNegativeIntegerOption('maxBodySize', maxBodySize);
23
+ const factory = createWebRequestResponseFactory({
24
+ maxBodySize,
25
+ multipart,
26
+ rawBody
27
+ });
28
+ return async function denoFetchHandler(request) {
29
+ return await dispatchWebRequest({
30
+ dispatcher,
31
+ dispatcherNotReadyMessage: 'Deno fetch handler received a request before dispatcher binding completed.',
32
+ factory,
33
+ request
34
+ });
35
+ };
36
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './adapter.js';
2
+ export * from './fetch-handler.js';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
- export * from './adapter.js';
1
+ export * from './adapter.js';
2
+ export * from './fetch-handler.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Validate an optional non-negative integer adapter option.
3
+ *
4
+ * @param name - Option name included in validation errors.
5
+ * @param value - Optional numeric value to validate.
6
+ */
7
+ export declare function validateNonNegativeIntegerOption(name: string, value: number | undefined): void;
8
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAQ9F"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Validate an optional non-negative integer adapter option.
3
+ *
4
+ * @param name - Option name included in validation errors.
5
+ * @param value - Optional numeric value to validate.
6
+ */
7
+ export function validateNonNegativeIntegerOption(name, value) {
8
+ if (value === undefined) {
9
+ return;
10
+ }
11
+ if (!Number.isInteger(value) || value < 0) {
12
+ throw new Error(`Invalid ${name} value: ${String(value)}. Expected a non-negative integer.`);
13
+ }
14
+ }
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "platform",
9
9
  "server"
10
10
  ],
11
- "version": "1.0.8",
11
+ "version": "1.1.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": "^1.1.2",
36
- "@fluojs/runtime": "^1.1.8"
35
+ "@fluojs/http": "^2.0.1",
36
+ "@fluojs/runtime": "^2.0.1"
37
37
  },
38
38
  "devDependencies": {
39
39
  "vitest": "^3.2.4",
40
- "@fluojs/testing": "^1.0.6"
40
+ "@fluojs/testing": "^2.0.0"
41
41
  },
42
42
  "scripts": {
43
43
  "prebuild": "node ../../tooling/scripts/clean-dist.mjs",