@fluojs/websockets 1.0.0-beta.5 → 1.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
CHANGED
|
@@ -10,6 +10,7 @@ fluo 런타임을 위한 데코레이터 기반 WebSocket 게이트웨이 작성
|
|
|
10
10
|
- [사용 시점](#사용-시점)
|
|
11
11
|
- [빠른 시작](#빠른-시작)
|
|
12
12
|
- [주요 패턴](#주요-패턴)
|
|
13
|
+
- [바이너리 페이로드](#바이너리-페이로드)
|
|
13
14
|
- [공개 API 개요](#공개-api-개요)
|
|
14
15
|
- [런타임별 서브패스](#런타임별-서브패스)
|
|
15
16
|
- [예제 소스](#예제-소스)
|
|
@@ -103,6 +104,10 @@ WebSocketModule.forRoot({
|
|
|
103
104
|
|
|
104
105
|
옵션을 생략하면 `@fluojs/websockets`는 동시 연결 수, inbound payload 크기, pending message buffer, shutdown cleanup에 bounded default를 적용합니다. 기본값은 `maxConnections: 1000`, `maxPayloadBytes: 1 MiB`, `buffer.maxPendingMessagesPerSocket: 256`, `shutdown.timeoutMs: 5000`, Node heartbeat interval `30s`, Node backpressure `maxBufferedAmountBytes: 1 MiB`와 drop behavior입니다. 또한 server-backed Node listener는 `heartbeat.enabled`를 명시적으로 `false`로 두지 않는 한 heartbeat timer를 활성화합니다. 공식 fetch-style runtime module(`@fluojs/websockets/bun`, `@fluojs/websockets/deno`, `@fluojs/websockets/cloudflare-workers`)은 애플리케이션 shutdown 시 추적 중인 websocket 클라이언트를 닫고 `shutdown.timeoutMs` 범위 안에서 `@OnDisconnect()` cleanup이 마무리될 수 있도록 bounded 기회를 제공합니다.
|
|
105
106
|
|
|
107
|
+
## 바이너리 페이로드
|
|
108
|
+
|
|
109
|
+
Gateway `@OnMessage()` handler는 지원 런타임 전반에서 하나의 정규화된 payload contract를 받습니다. Text frame은 가능한 경우 JSON으로 파싱하고, 그렇지 않으면 string으로 전달합니다. Binary frame은 런타임이 Node `Buffer`/typed array, Bun `ArrayBuffer`/view, Deno `ArrayBuffer`/view/`Blob`, Cloudflare Workers `ArrayBuffer`/view/`Blob` 중 어떤 형태로 노출하더라도 UTF-8로 디코딩한 뒤 동일한 JSON/event dispatch 단계를 거칩니다. `limits.maxPayloadBytes` 검사는 모든 표현에 byte length를 사용하며, 허용된 socket에서 oversized payload가 들어오면 close code `1009`로 닫습니다.
|
|
110
|
+
|
|
106
111
|
## 공개 API 개요
|
|
107
112
|
|
|
108
113
|
- `@WebSocketGateway(options)`: 클래스를 WebSocket 게이트웨이로 표시합니다.
|
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ Decorator-based WebSocket gateway authoring for the fluo runtime.
|
|
|
10
10
|
- [When to Use](#when-to-use)
|
|
11
11
|
- [Quick Start](#quick-start)
|
|
12
12
|
- [Common Patterns](#common-patterns)
|
|
13
|
+
- [Binary Payloads](#binary-payloads)
|
|
13
14
|
- [Public API Overview](#public-api-overview)
|
|
14
15
|
- [Runtime-Specific Subpaths](#runtime-specific-subpaths)
|
|
15
16
|
- [Example Sources](#example-sources)
|
|
@@ -103,6 +104,10 @@ WebSocketModule.forRoot({
|
|
|
103
104
|
|
|
104
105
|
When omitted, `@fluojs/websockets` applies bounded defaults for concurrent connections, inbound payload size, pending message buffers, and shutdown cleanup. Default settings are `maxConnections: 1000`, `maxPayloadBytes: 1 MiB`, `buffer.maxPendingMessagesPerSocket: 256`, `shutdown.timeoutMs: 5000`, Node heartbeat interval `30s`, and Node backpressure `maxBufferedAmountBytes: 1 MiB` with drop behavior. Server-backed Node listeners enable heartbeat timers unless you explicitly set `heartbeat.enabled` to `false`. The official fetch-style runtime modules (`@fluojs/websockets/bun`, `@fluojs/websockets/deno`, and `@fluojs/websockets/cloudflare-workers`) close tracked websocket clients during application shutdown and give `@OnDisconnect()` cleanup a bounded chance to finish within `shutdown.timeoutMs`.
|
|
105
106
|
|
|
107
|
+
## Binary Payloads
|
|
108
|
+
|
|
109
|
+
Gateway `@OnMessage()` handlers receive one normalized payload contract across supported runtimes. Text frames are parsed as JSON when possible and otherwise delivered as strings. Binary frames are decoded as UTF-8 before the same JSON/event dispatch step, whether the runtime surfaces them as Node `Buffer`/typed arrays, Bun `ArrayBuffer`/views, Deno `ArrayBuffer`/views/`Blob`, or Cloudflare Workers `ArrayBuffer`/views/`Blob`. The `limits.maxPayloadBytes` check uses byte length for every representation and closes oversized accepted sockets with close code `1009`.
|
|
110
|
+
|
|
106
111
|
## Public API Overview
|
|
107
112
|
|
|
108
113
|
- `@WebSocketGateway(options)`: Marks a class as a WebSocket gateway.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deno-service.d.ts","sourceRoot":"","sources":["../../src/deno/deno-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEzI,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAa3D,OAAO,KAAK,EAA8B,oBAAoB,EAA6B,MAAM,aAAa,CAAC;AAC/G,OAAO,KAAK,EAKV,sBAAsB,EACvB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"deno-service.d.ts","sourceRoot":"","sources":["../../src/deno/deno-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,7 +40,17 @@ function resolveMessageByteLength(message) {
|
|
|
40
40
|
if (typeof message === 'string') {
|
|
41
41
|
return new TextEncoder().encode(message).byteLength;
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
if (message instanceof Blob) {
|
|
44
|
+
return message.size;
|
|
45
|
+
}
|
|
46
|
+
if (message instanceof ArrayBuffer) {
|
|
47
|
+
return message.byteLength;
|
|
48
|
+
}
|
|
49
|
+
if (ArrayBuffer.isView(message)) {
|
|
50
|
+
return message.byteLength;
|
|
51
|
+
}
|
|
52
|
+
const unreachable = message;
|
|
53
|
+
return unreachable;
|
|
44
54
|
}
|
|
45
55
|
function createCompletionSignal() {
|
|
46
56
|
let resolve;
|
|
@@ -356,10 +366,10 @@ class DenoWebSocketGatewayLifecycleService {
|
|
|
356
366
|
this.clearQueuedMessages(state);
|
|
357
367
|
}
|
|
358
368
|
async normalizeMessage(message) {
|
|
359
|
-
if (
|
|
360
|
-
return message;
|
|
369
|
+
if (message instanceof Blob) {
|
|
370
|
+
return await message.arrayBuffer();
|
|
361
371
|
}
|
|
362
|
-
return
|
|
372
|
+
return message;
|
|
363
373
|
}
|
|
364
374
|
enqueueDisconnectDispatch(state, socket, disconnectEvent) {
|
|
365
375
|
state.handlerQueue = state.handlerQueue.then(async () => {
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { WebSocketModuleOptions as SharedWebSocketModuleOptions } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Defines the
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
* Defines the Deno websocket inbound message contract.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* Deno deployments may surface binary frames as `ArrayBuffer`, typed array views, or
|
|
7
|
+
* `Blob` values depending on the host and compatibility layer. The adapter accepts
|
|
8
|
+
* each binary representation and normalizes it before dispatching gateway handlers.
|
|
9
|
+
*/
|
|
10
|
+
export type DenoWebSocketMessage = ArrayBuffer | ArrayBufferView | Blob | string;
|
|
6
11
|
/**
|
|
7
12
|
* Describes the deno server web socket contract.
|
|
8
13
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deno-types.d.ts","sourceRoot":"","sources":["../../src/deno/deno-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,IAAI,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE1F
|
|
1
|
+
{"version":3,"file":"deno-types.d.ts","sourceRoot":"","sources":["../../src/deno/deno-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,IAAI,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE1F;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,MAAM,CAAC;AAEjF;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,SAAS,EAAE,kBAAkB,GAAG,OAAO,GAAG,qBAAqB,GAAG,MAAM,CAAC;IACzH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB;IACnG,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB;IACjG,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;CAChE;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB;IAC7F,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,wBAAwB,CAAC,OAAO,CAAC,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChG;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB;IACjG,yBAAyB,CAAC,OAAO,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;CACrF;AAED;;GAEG;AACH,MAAM,MAAM,qBAAqB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,OAAO,IAAI,CACpG,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,OAAO,KACb,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,mBAAmB,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,4BAA4B,CAAC"}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"realtime",
|
|
10
10
|
"upgrade"
|
|
11
11
|
],
|
|
12
|
-
"version": "1.0.0
|
|
12
|
+
"version": "1.0.0",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -69,17 +69,17 @@
|
|
|
69
69
|
],
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"ws": "^8.18.3",
|
|
72
|
-
"@fluojs/core": "^1.0.0
|
|
73
|
-
"@fluojs/di": "^1.0.0
|
|
74
|
-
"@fluojs/http": "^1.0.0
|
|
75
|
-
"@fluojs/runtime": "^1.0.0
|
|
72
|
+
"@fluojs/core": "^1.0.0",
|
|
73
|
+
"@fluojs/di": "^1.0.0",
|
|
74
|
+
"@fluojs/http": "^1.0.0",
|
|
75
|
+
"@fluojs/runtime": "^1.0.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@types/ws": "^8.18.1",
|
|
79
79
|
"vitest": "^3.2.4",
|
|
80
|
-
"@fluojs/platform-bun": "^1.0.0
|
|
81
|
-
"@fluojs/platform-express": "^1.0.0
|
|
82
|
-
"@fluojs/platform-fastify": "^1.0.0
|
|
80
|
+
"@fluojs/platform-bun": "^1.0.0",
|
|
81
|
+
"@fluojs/platform-express": "^1.0.0",
|
|
82
|
+
"@fluojs/platform-fastify": "^1.0.0"
|
|
83
83
|
},
|
|
84
84
|
"scripts": {
|
|
85
85
|
"prebuild": "node ../../tooling/scripts/clean-dist.mjs",
|