@fluojs/socket.io 1.0.6 → 1.0.7

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
@@ -77,6 +77,34 @@ class MyService {
77
77
  }
78
78
  ```
79
79
 
80
+ Raw server 접근은 좁게 유지하고, 공유 room 계약이 의도적으로 감싸지 않는 Socket.IO 전용 의미론에 사용하세요. 예를 들어 native multi-room emit이나 volatile delivery는 raw server 경계에 둡니다:
81
+
82
+ ```ts
83
+ @Inject(SOCKETIO_SERVER)
84
+ class SupportBroadcasts {
85
+ constructor(private readonly io: Server) {}
86
+
87
+ broadcastUrgent(message: string) {
88
+ this.io.of('/support').to(['ticket:active', 'staff:updates']).emit('announcement', { message });
89
+ }
90
+
91
+ sendTyping(ticketId: string, userId: string) {
92
+ this.io.of('/support').volatile.to(`ticket:${ticketId}`).emit('typing', { userId });
93
+ }
94
+ }
95
+ ```
96
+
97
+ ### Handler return value와 ACK reply
98
+
99
+ Socket.IO gateway handler는 공유 `@fluojs/websockets` positional handler 모델인 `(payload, socket, request, acknowledgement)`를 사용합니다. 반환값은 오류 격리와 순서를 위해 await되지만 무시됩니다. fluo는 handler 반환값을 암묵적인 Socket.IO emit 또는 ACK reply로 변환하지 않습니다. NestJS `@SubscribeMessage()` handler가 반환값으로 ACK payload를 보내던 경우에는 `acknowledgement` callback을 명시적으로 호출하거나 `SOCKETIO_SERVER`를 주입해 raw server 경계에서 emit하도록 재작성하세요.
100
+
101
+ ```ts
102
+ @OnMessage('ping')
103
+ handlePing(payload: unknown, _socket: Socket, _request: SocketIoHandshakeRequest, ack?: (response: unknown) => void) {
104
+ ack?.({ event: 'pong', payload });
105
+ }
106
+ ```
107
+
80
108
  ### auth guard, 안전한 CORS 기본값, bounded payload
81
109
  `SocketIoModule.forRoot(...)`로 namespace/message 인증을 명시하고, CORS를 deny-by-default로 유지하며, 인바운드 Engine.IO payload 크기를 제한할 수 있습니다.
82
110
 
@@ -124,15 +152,15 @@ Socket.IO 등록은 소유 모듈의 import 경로에서 구성하여 namespace/
124
152
 
125
153
  ## 공개 API 개요
126
154
 
127
- - `SocketIoModule.forRoot(options)`
155
+ - `SocketIoModule.forRoot(options)`: Socket.IO 통합의 기본 모듈입니다.
128
156
  - `SocketIoModule.forRoot({ global, auth, cors, engine, ... })`: provider visibility, namespace/message guard, 명시적 CORS, Engine.IO payload bound를 구성합니다.
129
- - `SOCKETIO_SERVER`
130
- - `SOCKETIO_ROOM_SERVICE`
157
+ - `SOCKETIO_SERVER`: raw Socket.IO `Server`를 주입하기 위한 토큰입니다.
158
+ - `SOCKETIO_ROOM_SERVICE`: `SocketIoRoomService`를 주입하기 위한 토큰입니다.
131
159
  - `SocketIoRoomService`: 공유 room 계약에 Socket.IO namespace-aware `joinRoom`, `leaveRoom`, `broadcastToRoom`, `getRooms` helper를 더한 타입입니다.
132
160
  - `SocketIoLifecycleService`: server와 room-service token 뒤에서 동작하는 lifecycle 기반 구현입니다. 애플리케이션 코드는 일반적으로 `SOCKETIO_SERVER` 또는 `SOCKETIO_ROOM_SERVICE`를 주입하세요.
133
161
  - 타입: `SocketIoModuleOptions`, `SocketIoHandshakeRequest`, `SocketIoConnectionGuardContext`, `SocketIoConnectionGuard`, `SocketIoMessageGuardContext`, `SocketIoMessageGuard`, `SocketIoGuardRejection`.
134
162
 
135
- `SocketIoModuleOptions`는 `global`, `auth`, `buffer`, `cors`, `engine`, `shutdown`, `transports`를 포함합니다. `global`의 기본값은 `true`이므로 `SOCKETIO_SERVER`와 `SOCKETIO_ROOM_SERVICE`가 앱 전체에서 보입니다. module-local provider visibility가 필요하면 `false`로 설정하세요. 지원되는 server-backed runtime adapter가 필요하며, unsupported/noop adapter는 bootstrap 중 빠르게 실패합니다.
163
+ `SocketIoModuleOptions`는 `global`, `auth`, `buffer`, `cors`, `engine`, `shutdown`, `transports`를 포함합니다. `global`의 기본값은 `true`이므로 `SOCKETIO_SERVER`와 `SOCKETIO_ROOM_SERVICE`가 앱 전체에서 보입니다. module-local provider visibility가 필요하면 `false`로 설정하세요. 지원되는 Node.js server-backed runtime adapter 또는 공식 Bun engine host가 필요하며, unsupported/noop adapter는 bootstrap 중 빠르게 실패합니다.
136
164
 
137
165
  ## 지원 플랫폼
138
166
 
@@ -145,5 +173,6 @@ Socket.IO 등록은 소유 모듈의 import 경로에서 구성하여 namespace/
145
173
 
146
174
  ## 예제 소스
147
175
 
176
+ - `packages/socket.io/src/config.internal.test.ts`
148
177
  - `packages/socket.io/src/module.test.ts`
149
178
  - `packages/socket.io/src/public-surface.test.ts`
package/README.md CHANGED
@@ -79,6 +79,34 @@ class MyService {
79
79
  }
80
80
  ```
81
81
 
82
+ Keep raw server access narrow and use it for Socket.IO-specific semantics that the shared room contract intentionally does not wrap, such as multi-room native emits or volatile delivery:
83
+
84
+ ```typescript
85
+ @Inject(SOCKETIO_SERVER)
86
+ class SupportBroadcasts {
87
+ constructor(private readonly io: Server) {}
88
+
89
+ broadcastUrgent(message: string) {
90
+ this.io.of('/support').to(['ticket:active', 'staff:updates']).emit('announcement', { message });
91
+ }
92
+
93
+ sendTyping(ticketId: string, userId: string) {
94
+ this.io.of('/support').volatile.to(`ticket:${ticketId}`).emit('typing', { userId });
95
+ }
96
+ }
97
+ ```
98
+
99
+ ### Handler return values and ACK replies
100
+
101
+ Socket.IO gateway handlers use the shared `@fluojs/websockets` positional handler model: `(payload, socket, request, acknowledgement)`. Return values are awaited for error containment and ordering, but they are ignored; fluo does not convert a returned value into an implicit Socket.IO emit or ACK reply. When a migrated NestJS `@SubscribeMessage()` handler previously returned an ACK payload, rewrite it to call the `acknowledgement` callback explicitly or inject `SOCKETIO_SERVER` and emit through the raw server boundary.
102
+
103
+ ```typescript
104
+ @OnMessage('ping')
105
+ handlePing(payload: unknown, _socket: Socket, _request: SocketIoHandshakeRequest, ack?: (response: unknown) => void) {
106
+ ack?.({ event: 'pong', payload });
107
+ }
108
+ ```
109
+
82
110
  ### Auth guards, safe CORS defaults, and bounded payloads
83
111
  Use `SocketIoModule.forRoot(...)` to require explicit namespace/message auth, keep CORS in a deny-by-default posture, and cap inbound Engine.IO payload size.
84
112
 
@@ -134,7 +162,7 @@ Register Socket.IO through module imports in the owning module so namespace/mess
134
162
  - `SocketIoLifecycleService`: Lifecycle-backed implementation behind the server and room-service tokens; application code should usually inject `SOCKETIO_SERVER` or `SOCKETIO_ROOM_SERVICE` instead.
135
163
  - Types: `SocketIoModuleOptions`, `SocketIoHandshakeRequest`, `SocketIoConnectionGuardContext`, `SocketIoConnectionGuard`, `SocketIoMessageGuardContext`, `SocketIoMessageGuard`, `SocketIoGuardRejection`.
136
164
 
137
- `SocketIoModuleOptions` covers `global`, `auth`, `buffer`, `cors`, `engine`, `shutdown`, and `transports`. `global` defaults to `true`, which keeps `SOCKETIO_SERVER` and `SOCKETIO_ROOM_SERVICE` visible across the app; set it to `false` when you want module-local provider visibility. A supported server-backed runtime adapter is required; unsupported/noop adapters fail fast during bootstrap.
165
+ `SocketIoModuleOptions` covers `global`, `auth`, `buffer`, `cors`, `engine`, `shutdown`, and `transports`. `global` defaults to `true`, which keeps `SOCKETIO_SERVER` and `SOCKETIO_ROOM_SERVICE` visible across the app; set it to `false` when you want module-local provider visibility. A supported Node.js server-backed runtime adapter or the official Bun engine host is required; unsupported/noop adapters fail fast during bootstrap.
138
166
 
139
167
  ## Supported Platforms
140
168
 
@@ -147,5 +175,6 @@ Register Socket.IO through module imports in the owning module so namespace/mess
147
175
 
148
176
  ## Example Sources
149
177
 
178
+ - `packages/socket.io/src/config.internal.test.ts`
150
179
  - `packages/socket.io/src/module.test.ts`
151
180
  - `packages/socket.io/src/public-surface.test.ts`
package/dist/adapter.d.ts CHANGED
@@ -19,7 +19,8 @@ export declare class SocketIoLifecycleService implements OnApplicationBootstrap,
19
19
  private attachments;
20
20
  private bunEngine;
21
21
  private io;
22
- private readonly namespaceContext;
22
+ private namespaceContext;
23
+ private namespaceContextPromise;
23
24
  private readonly socketRegistry;
24
25
  private shutdownPromise;
25
26
  private shutdownStarted;
@@ -110,6 +111,7 @@ export declare class SocketIoLifecycleService implements OnApplicationBootstrap,
110
111
  private handleDisconnect;
111
112
  private runHandlers;
112
113
  private invokeGatewayMethod;
114
+ private resolveNamespaceContext;
113
115
  private resolveGatewayInstance;
114
116
  private discoverGatewayDescriptors;
115
117
  private shouldSkipGatewayCandidate;
@@ -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
@@ -4,14 +4,12 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
4
4
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
5
  function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
6
6
  function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
7
- import { AsyncLocalStorage } from 'node:async_hooks';
8
7
  import { Inject } from '@fluojs/core';
9
- import { getClassDiMetadata } from '@fluojs/core/internal';
10
- import { APPLICATION_LOGGER, COMPILED_MODULES, HTTP_APPLICATION_ADAPTER, RUNTIME_CONTAINER } from '@fluojs/runtime/internal';
8
+ import { APPLICATION_LOGGER, COMPILED_MODULES, getRuntimeClassDiMetadata, HTTP_APPLICATION_ADAPTER, RUNTIME_CONTAINER } from '@fluojs/runtime/internal';
11
9
  import { getWebSocketGatewayMetadata, getWebSocketHandlerMetadataEntries } from '@fluojs/websockets';
12
10
  import { Server } from 'socket.io';
13
- import { SOCKETIO_OPTIONS_INTERNAL } from './options-token.internal.js';
14
11
  import { DEFAULT_SOCKETIO_ENGINE_PATH, resolveSocketIoMaxHttpBufferSize, resolveSocketIoMaxPendingMessagesPerSocket, resolveSocketIoShutdownTimeoutMs } from './config.internal.js';
12
+ import { SOCKETIO_OPTIONS_INTERNAL } from './options-token.internal.js';
15
13
  import { closeSocketIoServerWithTimeout } from './shutdown.internal.js';
16
14
  async function loadBunEngineServer() {
17
15
  return (await import('@socket.io/bun-engine')).Server;
@@ -55,11 +53,11 @@ function normalizeRejectedGuardError(error, defaultMessage) {
55
53
  }
56
54
  function scopeFromProvider(provider) {
57
55
  if (typeof provider === 'function') {
58
- return getClassDiMetadata(provider)?.scope ?? 'singleton';
56
+ return getRuntimeClassDiMetadata(provider)?.scope ?? 'singleton';
59
57
  }
60
58
  if ('useClass' in provider) {
61
59
  const classProvider = provider;
62
- return classProvider.scope ?? getClassDiMetadata(classProvider.useClass)?.scope ?? 'singleton';
60
+ return classProvider.scope ?? getRuntimeClassDiMetadata(classProvider.useClass)?.scope ?? 'singleton';
63
61
  }
64
62
  return 'scope' in provider ? provider.scope ?? 'singleton' : 'singleton';
65
63
  }
@@ -164,7 +162,8 @@ class SocketIoLifecycleService {
164
162
  attachments = [];
165
163
  bunEngine;
166
164
  io;
167
- namespaceContext = new AsyncLocalStorage();
165
+ namespaceContext;
166
+ namespaceContextPromise;
168
167
  socketRegistry = new Map();
169
168
  shutdownPromise;
170
169
  shutdownStarted = false;
@@ -427,7 +426,7 @@ class SocketIoLifecycleService {
427
426
  return this.attachments.find(attachment => attachment.path === path)?.namespace;
428
427
  }
429
428
  resolveContextNamespace() {
430
- const namespaceName = this.namespaceContext.getStore();
429
+ const namespaceName = this.namespaceContext?.getStore();
431
430
  if (!namespaceName) {
432
431
  return undefined;
433
432
  }
@@ -683,11 +682,27 @@ class SocketIoLifecycleService {
683
682
  return;
684
683
  }
685
684
  try {
686
- await this.namespaceContext.run(descriptor.path, async () => await Promise.resolve(value.call(instance, ...args)));
685
+ const namespaceContext = await this.resolveNamespaceContext();
686
+ await namespaceContext.run(descriptor.path, async () => await Promise.resolve(value.call(instance, ...args)));
687
687
  } catch (error) {
688
688
  this.logger.error(`Socket.IO gateway handler ${descriptor.targetName}.${handler.methodName} failed.`, error, 'SocketIoLifecycleService');
689
689
  }
690
690
  }
691
+ async resolveNamespaceContext() {
692
+ if (this.namespaceContext) {
693
+ return this.namespaceContext;
694
+ }
695
+ this.namespaceContextPromise ??= import('node:async_hooks').then(({
696
+ AsyncLocalStorage
697
+ }) => {
698
+ this.namespaceContext = new AsyncLocalStorage();
699
+ return this.namespaceContext;
700
+ }).catch(error => {
701
+ this.namespaceContextPromise = undefined;
702
+ throw error;
703
+ });
704
+ return this.namespaceContextPromise;
705
+ }
691
706
  async resolveGatewayInstance(descriptor) {
692
707
  try {
693
708
  return await this.runtimeContainer.resolve(descriptor.token);
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { IncomingMessage } from 'node:http';
2
- import type { ServerOptions, Socket } from 'socket.io';
3
2
  import type { WebSocketRoomService } from '@fluojs/websockets';
3
+ import type { ServerOptions, Socket } from 'socket.io';
4
4
  /** Runtime-specific Socket.IO handshake request surfaced to guard callbacks. */
5
5
  export type SocketIoHandshakeRequest = IncomingMessage | Request;
6
6
  /**
@@ -34,6 +34,13 @@ export interface SocketIoRoomService extends WebSocketRoomService {
34
34
  * @param namespacePath Optional namespace path when targeting a non-default namespace.
35
35
  */
36
36
  leaveRoom(socketId: string, room: string, namespacePath?: string): void;
37
+ /**
38
+ * Returns a snapshot of rooms currently joined by one connected socket.
39
+ *
40
+ * @param socketId Socket identifier to inspect.
41
+ * @returns Current room names for the socket, or an empty set when the socket is not registered.
42
+ */
43
+ getRooms(socketId: string): ReadonlySet<string>;
37
44
  }
38
45
  /**
39
46
  * Rejection details returned by Socket.IO auth guards when a connection or message should be blocked.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "realtime",
10
10
  "platform"
11
11
  ],
12
- "version": "1.0.6",
12
+ "version": "1.0.7",
13
13
  "private": false,
14
14
  "license": "MIT",
15
15
  "repository": {
@@ -39,9 +39,9 @@
39
39
  "@socket.io/bun-engine": "^0.1.0",
40
40
  "@fluojs/core": "^1.0.3",
41
41
  "@fluojs/di": "^1.1.0",
42
- "@fluojs/http": "^1.1.1",
43
- "@fluojs/runtime": "^1.1.7",
44
- "@fluojs/websockets": "^1.0.6"
42
+ "@fluojs/http": "^1.1.2",
43
+ "@fluojs/runtime": "^1.1.8",
44
+ "@fluojs/websockets": "^1.0.7"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "socket.io": "^4.0.0"
@@ -51,7 +51,7 @@
51
51
  "socket.io-client": "^4.8.1",
52
52
  "vitest": "^3.2.4",
53
53
  "@fluojs/platform-express": "^1.0.6",
54
- "@fluojs/platform-fastify": "^1.0.7",
54
+ "@fluojs/platform-fastify": "^1.0.8",
55
55
  "@fluojs/platform-nodejs": "^1.0.5"
56
56
  },
57
57
  "scripts": {