🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@fluojs/platform-cloudflare-workers

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fluojs/platform-cloudflare-workers - npm Package Compare versions

Comparing version
1.0.4
to
1.0.5
+15
-6
dist/adapter.d.ts

@@ -1,4 +0,3 @@

import { type Dispatcher, type HttpApplicationAdapter } from '@fluojs/http/internal';
import { type BootstrapHttpAdapterApplicationOptions } from '@fluojs/runtime/internal/http-adapter';
import type { Application, ModuleType, UploadedFile } from '@fluojs/runtime';
import type { CorsOptions, Dispatcher, HttpApplicationAdapter, MiddlewareLike, SecurityHeadersOptions } from '@fluojs/http';
import type { Application, CreateApplicationOptions, ModuleType } from '@fluojs/runtime';
import { type CreateWebRequestResponseFactoryOptions } from '@fluojs/runtime/web';

@@ -8,6 +7,13 @@ declare module '@fluojs/http' {

cloudflare?: CloudflareWorkerRequestContext;
files?: UploadedFile[];
rawBody?: Uint8Array;
}
}
declare const ADAPTER_CLOSE_SETTLED: unique symbol;
type CloudflareWorkerCorsInput = false | string | string[] | CorsOptions;
interface CloudflareWorkerMiddlewareOptions {
cors?: CloudflareWorkerCorsInput;
globalPrefix?: string;
globalPrefixExclude?: readonly string[];
middleware?: MiddlewareLike[];
securityHeaders?: false | SecurityHeadersOptions;
}
/** Minimal Worker execution context surface used by the adapter. */

@@ -59,3 +65,3 @@ export interface CloudflareWorkerExecutionContext {

/** Bootstrap options for constructing a Cloudflare Worker application shell. */
export interface BootstrapCloudflareWorkerApplicationOptions extends BootstrapHttpAdapterApplicationOptions, CloudflareWorkerAdapterOptions {
export interface BootstrapCloudflareWorkerApplicationOptions extends Omit<CreateApplicationOptions, 'adapter' | 'middleware'>, CloudflareWorkerMiddlewareOptions, CloudflareWorkerAdapterOptions {
}

@@ -86,2 +92,3 @@ /** Fetch handler shape exposed by Worker-backed application entrypoints. */

private isClosed;
private isWebSocketBindingFrozen;
private websocketBinding?;

@@ -94,2 +101,3 @@ private readonly options;

configureWebSocketBinding(binding: CloudflareWorkerWebSocketBinding | undefined): void;
[ADAPTER_CLOSE_SETTLED](): Promise<void>;
fetch<Env = unknown>(request: Request, env?: Env, executionContext?: CloudflareWorkerExecutionContext): Promise<Response>;

@@ -133,2 +141,3 @@ listen(dispatcher: Dispatcher): Promise<void>;

}
export {};
//# sourceMappingURL=adapter.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,sCAAsC,EAC5C,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,YAAY,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAGL,KAAK,sCAAsC,EAE5C,MAAM,qBAAqB,CAAC;AAG7B,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,gBAAgB;QACxB,UAAU,CAAC,EAAE,8BAA8B,CAAC;QAC5C,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,EAAE,UAAU,CAAC;KACtB;CACF;AAMD,oEAAoE;AACpE,MAAM,WAAW,gCAAgC;IAC/C,sBAAsB,CAAC,IAAI,IAAI,CAAC;IAChC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC5C;AAED,gGAAgG;AAChG,MAAM,WAAW,8BAA8B,CAAC,GAAG,GAAG,OAAO;IAC3D,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gCAAgC,CAAC;CAC9D;AAED,iEAAiE;AACjE,MAAM,MAAM,gCAAgC,GAAG,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,MAAM,CAAC;AAE7F,kFAAkF;AAClF,MAAM,WAAW,yBACf,SAAQ,IAAI,CAAC,SAAS,EAAE,kBAAkB,GAAG,OAAO,GAAG,qBAAqB,GAAG,MAAM,CAAC;IACtF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,iEAAiE;AACjE,MAAM,WAAW,6BAA6B;IAC5C,CAAC,EAAE,yBAAyB,CAAC;IAC7B,CAAC,EAAE,yBAAyB,CAAC;CAC9B;AAED,8EAA8E;AAC9E,MAAM,MAAM,oCAAoC,GAAG,MAAM,6BAA6B,CAAC;AAEvF,iFAAiF;AACjF,MAAM,WAAW,sCAAsC;IACrD,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,yBAAyB,CAAC;CACzC;AAED,gFAAgF;AAChF,MAAM,WAAW,oCAAoC;IACnD,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,sCAAsC,CAAC;CACnE;AAED,+FAA+F;AAC/F,MAAM,WAAW,gCAAgC;IAC/C,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,oCAAoC,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACnG;AAED,yEAAyE;AACzE,MAAM,WAAW,oCAAoC;IACnD,yBAAyB,CAAC,OAAO,EAAE,gCAAgC,GAAG,SAAS,GAAG,IAAI,CAAC;CACxF;AAED,uEAAuE;AACvE,MAAM,WAAW,8BAA+B,SAAQ,sCAAsC;IAC5F,mBAAmB,CAAC,EAAE,oCAAoC,CAAC;CAC5D;AAED,gFAAgF;AAChF,MAAM,WAAW,2CACf,SAAQ,sCAAsC,EAC5C,8BAA8B;CAAG;AAErC,4EAA4E;AAC5E,MAAM,WAAW,uBAAuB,CAAC,GAAG,GAAG,OAAO;IACpD,KAAK,CACH,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,gBAAgB,EAAE,gCAAgC,GACjD,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtB;AAED,gEAAgE;AAChE,MAAM,WAAW,2BAA2B,CAAC,GAAG,GAAG,OAAO,CACxD,SAAQ,uBAAuB,CAAC,GAAG,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,sCAAsC,CAAC;IACzD,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAE1B,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,sEAAsE;AACtE,MAAM,WAAW,0BAA0B,CAAC,GAAG,GAAG,OAAO,CACvD,SAAQ,uBAAuB,CAAC,GAAG,CAAC;IACpC,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,KAAK,IAAI,OAAO,CAAC,2BAA2B,CAAC,GAAG,CAAC,CAAC,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,sCACX,YAAW,sBAAsB,EAAE,oCAAoC;IACvE,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,aAAa,CAAC,CAAiB;IACvC,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,gBAAgB,CAAC,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC;gBAE/B,OAAO,GAAE,8BAAmC;IAMlD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB5B,qBAAqB;IAOrB,yBAAyB,CAAC,OAAO,EAAE,gCAAgC,GAAG,SAAS,GAAG,IAAI;IAIhF,KAAK,CAAC,GAAG,GAAG,OAAO,EACvB,OAAO,EAAE,OAAO,EAChB,GAAG,CAAC,EAAE,GAAG,EACT,gBAAgB,CAAC,EAAE,gCAAgC,GAClD,OAAO,CAAC,QAAQ,CAAC;IA+Cd,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IASnD,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,oBAAoB;YAqBd,uBAAuB;IAQrC,OAAO,CAAC,4BAA4B;CAerC;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,8BAAmC,GAC3C,sCAAsC,CAExC;AAED;;;;;;GAMG;AACH,wBAAsB,oCAAoC,CAAC,GAAG,GAAG,OAAO,EACtE,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,2CAAgD,GACxD,OAAO,CAAC,2BAA2B,CAAC,GAAG,CAAC,CAAC,CAe3C;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAAC,GAAG,GAAG,OAAO,EAC5D,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,2CAAgD,GACxD,0BAA0B,CAAC,GAAG,CAAC,CA6DjC;AAsKD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,YAAY;QACpB,SAAS,CAAC,EAAE,yBAAyB,CAAC;KACvC;IAED,UAAU,UAAU;QAClB,aAAa,CAAC,EAAE,UAAU,6BAA6B,CAAC;KACzD;CACF"}
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}

@@ -6,2 +6,5 @@ import { createFetchStyleHttpAdapterRealtimeCapability } from '@fluojs/http/internal';

const DEFAULT_SHUTDOWN_TIMEOUT_MS = 10_000;
const WEBSOCKET_CLOSED_READY_STATE = 3;
const ADAPTER_CLOSE_SETTLED = Symbol('CloudflareWorkerAdapterCloseSettled');
const WEBSOCKET_BINDING_RECONFIGURATION_MESSAGE = 'Cloudflare Workers websocket binding must be configured before listen() starts accepting Worker requests.';

@@ -47,2 +50,3 @@ /** Minimal Worker execution context surface used by the adapter. */

isClosed = false;
isWebSocketBindingFrozen = false;
websocketBinding;

@@ -80,4 +84,10 @@ options;

configureWebSocketBinding(binding) {
if (this.isWebSocketBindingFrozen && binding !== this.websocketBinding) {
throw new Error(WEBSOCKET_BINDING_RECONFIGURATION_MESSAGE);
}
this.websocketBinding = binding;
}
[ADAPTER_CLOSE_SETTLED]() {
return this.closeInFlight ?? Promise.resolve();
}
async fetch(request, env, executionContext) {

@@ -90,10 +100,15 @@ if (this.closeInFlight || this.isClosed) {

if (dispatcher && this.websocketBinding && isWebSocketUpgradeRequest(request)) {
const socketLifecycles = [];
try {
const response = await this.websocketBinding.fetch(request, {
upgrade: upgradeRequest => this.upgradeWebSocket(upgradeRequest)
upgrade: upgradeRequest => {
const upgrade = this.upgradeWebSocket(upgradeRequest);
socketLifecycles.push(createWebSocketCloseLifecycle(upgrade.serverSocket));
return upgrade;
}
});
executionContext?.waitUntil(Promise.resolve());
return response;
} finally {
release();
const lifecycle = Promise.all(socketLifecycles).then(() => undefined).finally(release);
executionContext?.waitUntil(lifecycle);
}

@@ -123,2 +138,3 @@ }

this.isClosed = false;
this.isWebSocketBindingFrozen = true;
this.dispatcher = dispatcher;

@@ -216,4 +232,8 @@ }

let closeInFlight;
let closeRecovery;
let runningApplication;
const ready = async () => {
if (closeRecovery) {
await closeRecovery;
}
if (closeError) {

@@ -233,2 +253,5 @@ throw closeError;

}
if (closeRecovery) {
await closeRecovery;
}
if (closeError) {

@@ -242,4 +265,6 @@ throw closeError;

const closing = (async () => {
let currentApplication;
try {
await (await application).close(signal);
currentApplication = await application;
await currentApplication.close(signal);
if (runningApplication === application) {

@@ -249,3 +274,19 @@ runningApplication = undefined;

} catch (error) {
closeError = error;
if (currentApplication && isShutdownTimeoutError(error)) {
closeRecovery = watchTimedOutCloseRecovery(currentApplication, {
clearRunningApplication() {
if (runningApplication === application) {
runningApplication = undefined;
}
},
setCloseError(error) {
closeError = error;
},
setCloseRecovery(recovery) {
closeRecovery = recovery;
}
});
} else {
closeError = error;
}
throw error;

@@ -260,3 +301,3 @@ } finally {

async fetch(request, env, executionContext) {
if (closeError || closeInFlight) {
if (closeError || closeInFlight || closeRecovery) {
return createShutdownResponse();

@@ -327,2 +368,15 @@ }

}
function createWebSocketCloseLifecycle(socket) {
if (socket.readyState === WEBSOCKET_CLOSED_READY_STATE) {
return Promise.resolve();
}
const lifecycle = createDeferred();
socket.addEventListener('close', () => lifecycle.resolve(), {
once: true
});
if (socket.readyState === WEBSOCKET_CLOSED_READY_STATE) {
lifecycle.resolve();
}
return lifecycle.promise;
}
function createDeferred() {

@@ -341,2 +395,21 @@ let resolve;

}
function watchTimedOutCloseRecovery(currentApplication, callbacks) {
const recovery = currentApplication.adapter[ADAPTER_CLOSE_SETTLED]().then(() => {
callbacks.clearRunningApplication();
}, error => {
callbacks.setCloseError(error);
throw error;
});
const recoveryWithCleanup = recovery.finally(() => {
callbacks.setCloseRecovery(undefined);
});
void recoveryWithCleanup.catch(() => undefined);
return recoveryWithCleanup;
}
function createShutdownTimeoutMessage(timeoutMs) {
return `Cloudflare Workers adapter shutdown timeout exceeded ${String(timeoutMs)}ms.`;
}
function isShutdownTimeoutError(error) {
return error instanceof Error && error.message === createShutdownTimeoutMessage(DEFAULT_SHUTDOWN_TIMEOUT_MS);
}
function createShutdownResponse() {

@@ -373,32 +446,37 @@ return new Response(JSON.stringify({

}
const reader = responseBody.getReader();
const trackedBody = new ReadableStream({
async cancel(reason) {
try {
await reader.cancel(reason);
lifecycle.resolve();
} catch (error) {
lifecycle.reject(error);
throw error;
}
},
async pull(controller) {
try {
const result = await reader.read();
if (result.done) {
controller.close();
try {
const reader = responseBody.getReader();
const trackedBody = new ReadableStream({
async cancel(reason) {
try {
await reader.cancel(reason);
lifecycle.resolve();
return;
} catch (error) {
lifecycle.reject(error);
throw error;
}
controller.enqueue(result.value);
} catch (error) {
controller.error(error);
lifecycle.reject(error);
},
async pull(controller) {
try {
const result = await reader.read();
if (result.done) {
controller.close();
lifecycle.resolve();
return;
}
controller.enqueue(result.value);
} catch (error) {
controller.error(error);
lifecycle.reject(error);
}
}
}
});
return {
lifecycle: lifecycle.promise.finally(release),
response: new Response(trackedBody, response)
};
});
return {
lifecycle: lifecycle.promise.finally(release),
response: new Response(trackedBody, response)
};
} catch (error) {
release();
throw error;
}
}

@@ -411,3 +489,3 @@ function isLifecycleTrackedStreamingResponse(response) {

const timeoutHandle = setTimeout(() => {
reject(new Error(`Cloudflare Workers adapter shutdown timeout exceeded ${String(timeoutMs)}ms.`));
reject(new Error(createShutdownTimeoutMessage(timeoutMs)));
}, timeoutMs);

@@ -414,0 +492,0 @@ void closePromise.then(() => {

@@ -12,3 +12,3 @@ {

],
"version": "1.0.4",
"version": "1.0.5",
"private": false,

@@ -37,4 +37,4 @@ "license": "MIT",

"dependencies": {
"@fluojs/http": "^1.1.2",
"@fluojs/runtime": "^1.1.8"
"@fluojs/http": "^2.0.1",
"@fluojs/runtime": "^2.0.1"
},

@@ -41,0 +41,0 @@ "devDependencies": {

@@ -13,2 +13,3 @@ # @fluojs/platform-cloudflare-workers

- [주요 패턴](#주요-패턴)
- [Lifecycle 및 public seam 참고](#lifecycle-및-public-seam-참고)
- [Conformance 커버리지](#conformance-커버리지)

@@ -31,5 +32,5 @@ - [공개 API 개요](#공개-api-개요)

이 어댑터는 dispatcher가 binding된 뒤 각 요청 수명주기를 `executionContext.waitUntil(...)`에 연결하고, `close()` 중에도 진행 중인 디스패치와 SSE(`text/event-stream`) response body를 유지하여 Worker 종료 도중 활성 작업이 중간에 잘리지 않도록 보장합니다.
이 어댑터는 dispatcher가 binding된 뒤 각 요청 수명주기를 `executionContext.waitUntil(...)`에 연결하고, `close()` 중에도 진행 중인 디스패치, terminal close까지의 upgraded server WebSocket, SSE(`text/event-stream`) response body를 유지하여 Worker 종료 도중 활성 작업이 중간에 잘리지 않도록 보장합니다.
애플리케이션 종료 중에는 즉시 새 ingress 수락을 중단하고, 활성 HTTP 핸들러가 정리될 수 있도록 최대 10초의 bounded drain window를 제공합니다. 이 시간을 넘기면 `close()`는 무기한 대기하지 않고 timeout 오류로 종료됩니다. 해당 drain이 아직 진행 중일 때 동시에 `listen()`을 호출하면 Worker를 다시 열지 않고 `Cloudflare Workers adapter cannot listen while shutdown is still draining.` 오류로 reject됩니다. 닫힌 뒤에는 어댑터가 명시적으로 다시 `listen()`될 때까지 후속 HTTP 및 WebSocket upgrade request가 동일한 JSON `503` shutdown response를 받습니다.
애플리케이션 종료 중에는 즉시 새 ingress 수락을 중단하고, 활성 HTTP 핸들러가 정리될 수 있도록 최대 10초의 bounded drain window를 제공합니다. 이 시간을 넘기면 `close()`는 무기한 대기하지 않고 timeout 오류로 종료됩니다. 해당 drain이 아직 진행 중일 때 동시에 `listen()`을 호출하면 Worker를 다시 열지 않고 `Cloudflare Workers adapter cannot listen while shutdown is still draining.` 오류로 reject됩니다. 닫힌 뒤에는 어댑터가 명시적으로 다시 `listen()`될 때까지 후속 HTTP 및 WebSocket upgrade request가 동일한 JSON `503` shutdown response를 받습니다. Lazy entrypoint는 timed-out close가 아직 drain 중인 동안 shutdown response를 계속 반환하지만, underlying close가 나중에 settle되면 해당 임시 gate를 해제하여 이후 request가 새 Worker application을 bootstrap할 수 있게 합니다.

@@ -73,9 +74,23 @@ ## 빠른 시작

### WebSocketPair 활용
어댑터는 `@fluojs/websockets/cloudflare-workers` 바인딩을 통해 실시간 통신을 위한 Cloudflare의 네이티브 `WebSocketPair`를 지원합니다. Upgrade handling은 해당 binding을 통한 opt-in이며, non-hosted runtime test에서는 `createWebSocketPair`를 주입할 수 있습니다.
어댑터는 `@fluojs/websockets/cloudflare-workers` 바인딩을 통해 실시간 통신을 위한 Cloudflare의 네이티브 `WebSocketPair`를 지원합니다. Upgrade handling은 해당 binding을 통한 opt-in이며, non-hosted runtime test에서는 `createWebSocketPair`를 주입할 수 있습니다. Binding은 `listen()`이 Worker dispatch boundary를 시작하기 전에 설정하세요. `listen()`이 한 번 실행된 뒤에는 해당 adapter instance의 binding identity가 frozen됩니다. 이미 public listen boundary를 지난 isolate 아래에서 upgrade ownership이 바뀌지 않도록, `close()` 이후에도 binding을 교체하거나 해제하려는 시도는 reject됩니다.
```typescript
import { Module } from '@fluojs/core';
import {
CloudflareWorkersWebSocketModule,
WebSocketGateway,
} from '@fluojs/websockets/cloudflare-workers';
@WebSocketGateway({ path: '/ws' })
export class MyGateway {}
export class EdgeGateway {}
@Module({
imports: [CloudflareWorkersWebSocketModule.forRoot()],
providers: [EdgeGateway],
})
export class RealtimeModule {}
```
Bootstrap 전에 application module graph에 `RealtimeModule`을 import하세요. Application bootstrap 중 `CloudflareWorkersWebSocketModule`이 gateway를 발견하고 `app.listen()`이 binding을 freeze하기 전에 Worker adapter binding을 구성합니다. Listen boundary 이후에는 binding을 추가하거나 교체하지 마세요.
### 엣지 네이티브 미들웨어

@@ -93,12 +108,18 @@ 표준 fluo 미들웨어(CORS, Global Prefix 등)는 Worker bootstrap helper를 통해 완전히 지원되며 Cloudflare 환경에 최적화되어 있습니다. `createCloudflareWorkerAdapter(...)`는 adapter가 소유하는 parsing 및 websocket-pair 옵션만 받습니다. Routing 및 middleware 옵션은 `bootstrapCloudflareWorkerApplication(...)` 또는 `createCloudflareWorkerEntrypoint(...)`에 전달하세요.

- `fetch()`는 `listen()` 또는 lazy entrypoint가 dispatcher를 binding한 뒤 active work를 `executionContext.waitUntil(...)`에 등록합니다. SSE(`text/event-stream`) response는 body가 끝나거나 cancel될 때까지 해당 lifecycle과 close drain을 유지합니다. 그 lifecycle boundary 전에는 upgrade request와 HTTP dispatch가 application handler에 도달하지 않습니다.
- `fetch()`는 `listen()` 또는 lazy entrypoint가 dispatcher를 binding한 뒤 active work를 `executionContext.waitUntil(...)`에 등록합니다. Upgraded server WebSocket은 terminal `close` event까지 해당 lifecycle과 close drain을 유지하고, SSE(`text/event-stream`) response는 body가 끝나거나 cancel될 때까지 이를 유지합니다. SSE reader 또는 tracked-stream setup이 동기적으로 실패하면 오류를 전파하기 전에 lifecycle을 release합니다. 그 lifecycle boundary 전에는 upgrade request와 HTTP dispatch가 application handler에 도달하지 않습니다.
- `maxBodySize` 같은 adapter option은 Worker adapter 생성 시 검증됩니다. `globalPrefix`, `cors`, `middleware`, `securityHeaders` 같은 bootstrap 전용 옵션은 `createCloudflareWorkerAdapter(...)`가 아니라 Worker bootstrap helper에 전달해야 합니다.
- WebSocket upgrade는 HTTP dispatch와 같은 listen boundary가 소유합니다. `listen()` 전의 upgrade request는 설정된 binding에 도달하지 않습니다.
- `close()`는 shutdown 중 및 shutdown 이후 새 요청에 JSON `503` response를 반환하고, active request가 끝나지 않으면 10초 뒤 timeout됩니다. 해당 close drain이 아직 활성 상태일 때 `listen()`을 호출하면 Cloudflare Workers adapter shutdown-draining 오류로 reject됩니다.
- WebSocket upgrade는 HTTP dispatch와 같은 listen boundary가 소유합니다. `listen()` 전의 upgrade request는 설정된 binding에 도달하지 않으며, adapter가 한 번이라도 listen한 뒤 defined binding을 교체하거나 해제하려는 시도는 Worker upgrade ownership을 바꾸는 대신 빠르게 실패합니다. 다른 websocket binding이 필요하면 새 adapter를 생성하세요.
- `close()`는 shutdown 중 및 shutdown 이후 새 HTTP 및 WebSocket upgrade request에 JSON `503` response를 반환하고, active request가 끝나지 않으면 10초 뒤 timeout됩니다. 해당 close drain이 아직 활성 상태일 때 `listen()`을 호출하면 Cloudflare Workers adapter shutdown-draining 오류로 reject됩니다. Lazy entrypoint는 adapter의 underlying drain이 나중에 끝나면 이 timeout을 영구적으로 캐시하지 않습니다.
- Multipart request는 `rawBody`를 보존하지 않습니다.
- Worker `env` 객체는 각 `FrameworkRequest`에 `request.cloudflare.env`로 연결되고 Worker execution context는 `request.cloudflare.executionContext`로 제공됩니다. Package-level config resolution은 application이 소유하므로, binding은 application boundary에서 명시적 provider 또는 `@fluojs/config`로 매핑하세요.
## Lifecycle 및 public seam 참고
Root `@fluojs/platform-cloudflare-workers` export는 application code와 first-party Worker websocket integration이 사용하는 Worker public seam을 소유합니다. `CloudflareWorkerExecutionContext`, `CloudflareWorkerRequestContext`, `CloudflareWorkerWebSocketBinding`, `CloudflareWorkerWebSocketPair`, `CloudflareWorkerWebSocketPairFactory`, `CloudflareWorkerWebSocketUpgradeHost`, `CloudflareWorkerWebSocketUpgradeResult` 같은 Worker-specific public type은 consumer가 `@fluojs/http/internal` 또는 `@fluojs/runtime/internal*` subpath를 import하지 않아도 되도록 이 패키지에서 export됩니다.
위의 listen, shutdown, SSE drain, websocket binding 규칙은 public lifecycle behavior입니다. 이러한 public seam type 또는 lifecycle semantic을 바꾸는 변경은 `@fluojs/platform-cloudflare-workers` release governance 대상이며, user-impacting update는 implementation, docs, tests와 함께 Changesets로 추적해야 합니다.
## Conformance 커버리지
`packages/platform-cloudflare-workers/src/adapter.test.ts`는 문서화된 Worker 계약을 검증하는 package-local regression 대상입니다. 이 파일은 shared Web dispatch delegation, Worker `env` request attachment, `executionContext.waitUntil(...)` SSE(`text/event-stream`) body tracking, websocket upgrade binding, listen-bound upgrade ownership, lazy entrypoint 재사용, shutdown gating, drain 중 `listen()` rejection, close 중 및 close 이후 JSON `503` response, bounded 10초 close timeout을 검증합니다.
`packages/platform-cloudflare-workers/src/adapter.test.ts`와 `packages/platform-cloudflare-workers/src/adapter-lifecycle.test.ts`는 문서화된 Worker 계약을 검증하는 package-local regression 대상입니다. 이 파일들은 shared Web dispatch delegation, Worker `env` request attachment, `executionContext.waitUntil(...)` SSE(`text/event-stream`) body tracking, body-cancellation 및 synchronous setup-failure drain, websocket upgrade binding, upgraded server-socket close tracking, pre-listen HTTP 및 websocket lifecycle guard, listen boundary 이후 websocket binding freeze, lazy entrypoint 재사용 및 timeout recovery, shutdown gating, drain 중 `listen()` rejection, HTTP와 websocket upgrade 모두에 대한 close 중 및 close 이후 JSON `503` response, reliable fake-timer cleanup, public seam source import, README parity, bounded 10초 close timeout을 검증합니다.

@@ -116,3 +137,3 @@ 공유 edge portability suite인 `packages/testing/src/portability/web-runtime-adapter-portability.test.ts`는 Cloudflare Workers를 Bun 및 Deno와 함께 실행해 malformed cookie 보존, query decoding, JSON/text raw-body capture, multipart raw-body 제외, SSE framing을 검증합니다. 패키지 테스트의 README parity assertion은 이 edge-runtime 커버리지 문서가 한국어 mirror와 계속 동기화되도록 확인합니다.

- `CloudflareWorkerEntrypoint`: `fetch`, `ready()`, `close()` lifecycle method를 제공하는 lazy entrypoint입니다.
- Option 및 type: `CloudflareWorkerAdapterOptions`, `BootstrapCloudflareWorkerApplicationOptions`, `CloudflareWorkerExecutionContext`, `CloudflareWorkerRequestContext`, `CloudflareWorkerWebSocketBinding`, Worker websocket pair/upgrade type.
- Option 및 type: `CloudflareWorkerAdapterOptions`, `BootstrapCloudflareWorkerApplicationOptions`, `CloudflareWorkerExecutionContext`, `CloudflareWorkerRequestContext`, `CloudflareWorkerWebSocketBinding`, `CloudflareWorkerWebSocketBindingHost`, `CloudflareWorkerWebSocket`, `CloudflareWorkerWebSocketMessage`, `CloudflareWorkerWebSocketPair`, `CloudflareWorkerWebSocketPairFactory`, `CloudflareWorkerWebSocketUpgradeHost`, `CloudflareWorkerWebSocketUpgradeResult`.

@@ -119,0 +140,0 @@ ## 관련 패키지

@@ -13,2 +13,3 @@ # @fluojs/platform-cloudflare-workers

- [Common Patterns](#common-patterns)
- [Lifecycle and Public Seam Notes](#lifecycle-and-public-seam-notes)
- [Conformance Coverage](#conformance-coverage)

@@ -31,5 +32,5 @@ - [Public API Overview](#public-api-overview)

The adapter binds each request lifecycle to `executionContext.waitUntil(...)` after the dispatcher is bound and keeps in-flight dispatches and SSE (`text/event-stream`) response bodies alive during `close()` so Worker shutdown does not drop active work mid-request.
The adapter binds each request lifecycle to `executionContext.waitUntil(...)` after the dispatcher is bound and keeps in-flight dispatches, WebSocket upgrades through the upgraded server socket's terminal close, and SSE (`text/event-stream`) response bodies alive during `close()` so Worker shutdown does not drop active work mid-request.
During application shutdown, the adapter stops accepting new ingress immediately and gives active HTTP handlers a bounded 10-second drain window before `close()` fails with a timeout instead of hanging indefinitely. While that drain is still in progress, a concurrent `listen()` call rejects with `Cloudflare Workers adapter cannot listen while shutdown is still draining.` instead of reopening the Worker. Once closed, follow-up HTTP and WebSocket upgrade requests receive the same JSON `503` shutdown response until the adapter is explicitly listened again.
During application shutdown, the adapter stops accepting new ingress immediately and gives active HTTP handlers a bounded 10-second drain window before `close()` fails with a timeout instead of hanging indefinitely. While that drain is still in progress, a concurrent `listen()` call rejects with `Cloudflare Workers adapter cannot listen while shutdown is still draining.` instead of reopening the Worker. Once closed, follow-up HTTP and WebSocket upgrade requests receive the same JSON `503` shutdown response until the adapter is explicitly listened again. Lazy entrypoints keep returning shutdown responses while a timed-out close is still draining, but they clear that temporary gate once the underlying close eventually settles so a later request can bootstrap a fresh Worker application.

@@ -73,9 +74,23 @@ ## Quick Start

### Working with WebSocketPairs
The adapter supports Cloudflare's native `WebSocketPair` for real-time communication via the `@fluojs/websockets/cloudflare-workers` binding. Upgrade handling is opt-in through that binding, and `createWebSocketPair` can be injected for non-hosted runtime tests.
The adapter supports Cloudflare's native `WebSocketPair` for real-time communication via the `@fluojs/websockets/cloudflare-workers` binding. Upgrade handling is opt-in through that binding, and `createWebSocketPair` can be injected for non-hosted runtime tests. Configure the binding before `listen()` starts the Worker dispatch boundary; once `listen()` has run, the binding identity is frozen for that adapter instance. Replacing or clearing it is rejected even after `close()`, so upgrade ownership cannot change underneath an isolate that has already crossed the public listen boundary.
```typescript
import { Module } from '@fluojs/core';
import {
CloudflareWorkersWebSocketModule,
WebSocketGateway,
} from '@fluojs/websockets/cloudflare-workers';
@WebSocketGateway({ path: '/ws' })
export class MyGateway {}
export class EdgeGateway {}
@Module({
imports: [CloudflareWorkersWebSocketModule.forRoot()],
providers: [EdgeGateway],
})
export class RealtimeModule {}
```
Import `RealtimeModule` into the application module graph before bootstrap. During application bootstrap, `CloudflareWorkersWebSocketModule` discovers the gateway and configures the Worker adapter binding before `app.listen()` freezes it; do not add or replace the binding after the listen boundary.
### Edge-Native Middleware

@@ -93,12 +108,18 @@ Standard fluo middleware (CORS, Global Prefix, etc.) is fully supported through Worker bootstrap helpers and optimized for the Cloudflare environment. `createCloudflareWorkerAdapter(...)` only accepts adapter-owned parsing and websocket-pair options; pass routing and middleware options to `bootstrapCloudflareWorkerApplication(...)` or `createCloudflareWorkerEntrypoint(...)` instead.

- `fetch()` registers active work with `executionContext.waitUntil(...)` after `listen()` or the lazy entrypoint binds the dispatcher; SSE (`text/event-stream`) responses keep that lifecycle and the close drain open until the body finishes or is canceled. Before that lifecycle boundary, upgrade requests and HTTP dispatch do not reach application handlers.
- `fetch()` registers active work with `executionContext.waitUntil(...)` after `listen()` or the lazy entrypoint binds the dispatcher; upgraded server WebSockets keep that lifecycle and the close drain open until their terminal `close` event, while SSE (`text/event-stream`) responses keep them open until the body finishes or is canceled. Synchronous SSE reader or tracked-stream setup failures release the lifecycle before propagating. Before that lifecycle boundary, upgrade requests and HTTP dispatch do not reach application handlers.
- Adapter options such as `maxBodySize` are validated when the Worker adapter is created; bootstrap-only options such as `globalPrefix`, `cors`, `middleware`, and `securityHeaders` belong on Worker bootstrap helpers rather than `createCloudflareWorkerAdapter(...)`.
- WebSocket upgrades are owned by the same listen boundary as HTTP dispatch; upgrade requests before `listen()` do not reach the configured binding.
- `close()` returns JSON `503` responses for new requests during and after shutdown and times out after 10 seconds if active requests never settle. Calling `listen()` while that close drain is still active rejects with the Cloudflare Workers adapter shutdown-draining error.
- WebSocket upgrades are owned by the same listen boundary as HTTP dispatch; upgrade requests before `listen()` do not reach the configured binding, and attempts to replace or clear a defined binding after the adapter has ever listened fail fast instead of mutating Worker upgrade ownership. Create a new adapter when a host needs a different websocket binding.
- `close()` returns JSON `503` responses for new HTTP and WebSocket upgrade requests during and after shutdown and times out after 10 seconds if active requests never settle. Calling `listen()` while that close drain is still active rejects with the Cloudflare Workers adapter shutdown-draining error. Lazy entrypoints do not permanently cache that timeout once the adapter's underlying drain later finishes.
- Multipart requests do not preserve `rawBody`.
- The Worker `env` object is attached to each `FrameworkRequest` as `request.cloudflare.env`, with the Worker execution context available as `request.cloudflare.executionContext`; package-level config resolution remains application-owned, so map bindings into explicit providers or `@fluojs/config` at the application boundary.
## Lifecycle and Public Seam Notes
The root `@fluojs/platform-cloudflare-workers` export owns the Worker public seam for application code and first-party Worker websocket integrations. Worker-specific public types such as `CloudflareWorkerExecutionContext`, `CloudflareWorkerRequestContext`, `CloudflareWorkerWebSocketBinding`, `CloudflareWorkerWebSocketPair`, `CloudflareWorkerWebSocketPairFactory`, `CloudflareWorkerWebSocketUpgradeHost`, and `CloudflareWorkerWebSocketUpgradeResult` are exported from this package instead of asking consumers to import `@fluojs/http/internal` or `@fluojs/runtime/internal*` subpaths.
The listen, shutdown, SSE drain, and websocket binding rules above are public lifecycle behavior. Changes to those public seam types or lifecycle semantics are release-governed for `@fluojs/platform-cloudflare-workers`; user-impacting updates must be tracked with Changesets alongside the implementation, docs, and tests.
## Conformance Coverage
`packages/platform-cloudflare-workers/src/adapter.test.ts` is the package-local regression target for the documented Worker contract. It covers shared Web dispatch delegation, Worker `env` request attachment, `executionContext.waitUntil(...)` SSE (`text/event-stream`) body tracking, websocket upgrade binding, listen-bound upgrade ownership, lazy entrypoint reuse, shutdown gating, drain-time `listen()` rejection, JSON `503` responses while closing and after close, and the bounded 10-second close timeout.
`packages/platform-cloudflare-workers/src/adapter.test.ts` and `packages/platform-cloudflare-workers/src/adapter-lifecycle.test.ts` are the package-local regression targets for the documented Worker contract. They cover shared Web dispatch delegation, Worker `env` request attachment, `executionContext.waitUntil(...)` SSE (`text/event-stream`) body tracking, body-cancellation and synchronous setup-failure drains, websocket upgrade binding, upgraded server-socket close tracking, pre-listen HTTP and websocket lifecycle guards, websocket binding freeze after the listen boundary, lazy entrypoint reuse and timeout recovery, shutdown gating, drain-time `listen()` rejection, JSON `503` responses while closing and after close for both HTTP and websocket upgrades, reliable fake-timer cleanup, public seam source imports, README parity, and the bounded 10-second close timeout.

@@ -116,3 +137,3 @@ The shared edge portability suite in `packages/testing/src/portability/web-runtime-adapter-portability.test.ts` exercises Cloudflare Workers beside Bun and Deno 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.

- `CloudflareWorkerEntrypoint`: Lazy entrypoint with `fetch`, `ready()`, and `close()` lifecycle methods.
- Options and types: `CloudflareWorkerAdapterOptions`, `BootstrapCloudflareWorkerApplicationOptions`, `CloudflareWorkerExecutionContext`, `CloudflareWorkerRequestContext`, `CloudflareWorkerWebSocketBinding`, and Worker websocket pair/upgrade types.
- Options and types: `CloudflareWorkerAdapterOptions`, `BootstrapCloudflareWorkerApplicationOptions`, `CloudflareWorkerExecutionContext`, `CloudflareWorkerRequestContext`, `CloudflareWorkerWebSocketBinding`, `CloudflareWorkerWebSocketBindingHost`, `CloudflareWorkerWebSocket`, `CloudflareWorkerWebSocketMessage`, `CloudflareWorkerWebSocketPair`, `CloudflareWorkerWebSocketPairFactory`, `CloudflareWorkerWebSocketUpgradeHost`, and `CloudflareWorkerWebSocketUpgradeResult`.

@@ -119,0 +140,0 @@ ## Related Packages