@scpxl/nodejs-framework 1.0.24 → 1.0.27
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.md +65 -17
- package/dist/api-requester/api-requester.d.ts.map +1 -1
- package/dist/api-requester/api-requester.js +2 -1
- package/dist/api-requester/api-requester.js.map +2 -2
- package/dist/application/base-application.d.ts.map +1 -1
- package/dist/application/base-application.js +4 -3
- package/dist/application/base-application.js.map +2 -2
- package/dist/cache/manager.d.ts.map +1 -1
- package/dist/cache/manager.js +2 -1
- package/dist/cache/manager.js.map +2 -2
- package/dist/cli/index.js +7019 -83
- package/dist/cli/index.js.map +4 -4
- package/dist/cluster/cluster-manager.d.ts +3 -0
- package/dist/cluster/cluster-manager.d.ts.map +1 -1
- package/dist/cluster/cluster-manager.js +45 -8
- package/dist/cluster/cluster-manager.js.map +2 -2
- package/dist/database/dynamic-entity-form-decorators.d.ts +2 -2
- package/dist/database/dynamic-entity-form-decorators.d.ts.map +1 -1
- package/dist/database/dynamic-entity-form-decorators.js.map +1 -1
- package/dist/database/dynamic-entity.d.ts +21 -4
- package/dist/database/dynamic-entity.d.ts.map +1 -1
- package/dist/database/dynamic-entity.js +39 -10
- package/dist/database/dynamic-entity.js.map +2 -2
- package/dist/database/manager.d.ts.map +1 -1
- package/dist/database/manager.js +3 -2
- package/dist/database/manager.js.map +2 -2
- package/dist/error/error-reporter.d.ts +20 -7
- package/dist/error/error-reporter.d.ts.map +1 -1
- package/dist/error/error-reporter.js +32 -29
- package/dist/error/error-reporter.js.map +2 -2
- package/dist/error/index.d.ts +1 -1
- package/dist/error/index.d.ts.map +1 -1
- package/dist/error/index.js +3 -2
- package/dist/error/index.js.map +2 -2
- package/dist/event/controller/base.d.ts.map +1 -1
- package/dist/event/controller/base.js +2 -1
- package/dist/event/controller/base.js.map +2 -2
- package/dist/event/manager.d.ts.map +1 -1
- package/dist/event/manager.js +5 -4
- package/dist/event/manager.js.map +2 -2
- package/dist/lifecycle/exit.d.ts.map +1 -1
- package/dist/lifecycle/exit.js.map +2 -2
- package/dist/logger/logger.d.ts.map +1 -1
- package/dist/logger/logger.js +3 -2
- package/dist/logger/logger.js.map +2 -2
- package/dist/performance/performance-monitor.d.ts.map +1 -1
- package/dist/performance/performance-monitor.js +10 -3
- package/dist/performance/performance-monitor.js.map +2 -2
- package/dist/queue/processor/base.d.ts.map +1 -1
- package/dist/queue/processor/base.js +2 -1
- package/dist/queue/processor/base.js.map +2 -2
- package/dist/redis/manager.d.ts.map +1 -1
- package/dist/redis/manager.js +3 -2
- package/dist/redis/manager.js.map +2 -2
- package/dist/schemas/common.d.ts +197 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +108 -0
- package/dist/schemas/common.js.map +7 -0
- package/dist/schemas/entity-builder.d.ts +35 -0
- package/dist/schemas/entity-builder.d.ts.map +1 -0
- package/dist/schemas/entity-builder.js +39 -0
- package/dist/schemas/entity-builder.js.map +7 -0
- package/dist/schemas/index.d.ts +6 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +2 -0
- package/dist/schemas/index.js.map +7 -0
- package/dist/util/loader.d.ts.map +1 -1
- package/dist/util/loader.js.map +2 -2
- package/dist/webserver/controller/base.d.ts.map +1 -1
- package/dist/webserver/controller/base.js +4 -4
- package/dist/webserver/controller/base.js.map +2 -2
- package/dist/webserver/controller/entity.js +2 -2
- package/dist/webserver/controller/entity.js.map +2 -2
- package/dist/webserver/controller/health.d.ts +0 -2
- package/dist/webserver/controller/health.d.ts.map +1 -1
- package/dist/webserver/controller/health.js +0 -14
- package/dist/webserver/controller/health.js.map +2 -2
- package/dist/webserver/webserver.d.ts.map +1 -1
- package/dist/webserver/webserver.interface.d.ts +2 -2
- package/dist/webserver/webserver.interface.d.ts.map +1 -1
- package/dist/webserver/webserver.interface.js.map +1 -1
- package/dist/webserver/webserver.js +2 -2
- package/dist/webserver/webserver.js.map +2 -2
- package/dist/websocket/index.d.ts +2 -0
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +2 -0
- package/dist/websocket/index.js.map +2 -2
- package/dist/websocket/websocket-auth.d.ts +17 -0
- package/dist/websocket/websocket-auth.d.ts.map +1 -0
- package/dist/websocket/websocket-auth.js +46 -0
- package/dist/websocket/websocket-auth.js.map +7 -0
- package/dist/websocket/websocket-client-manager.d.ts.map +1 -1
- package/dist/websocket/websocket-client-manager.js +6 -5
- package/dist/websocket/websocket-client-manager.js.map +2 -2
- package/dist/websocket/websocket-client.d.ts +29 -0
- package/dist/websocket/websocket-client.d.ts.map +1 -1
- package/dist/websocket/websocket-client.js +97 -3
- package/dist/websocket/websocket-client.js.map +2 -2
- package/dist/websocket/websocket-server.d.ts +10 -0
- package/dist/websocket/websocket-server.d.ts.map +1 -1
- package/dist/websocket/websocket-server.js +40 -52
- package/dist/websocket/websocket-server.js.map +2 -2
- package/dist/websocket/websocket.interface.d.ts +13 -0
- package/dist/websocket/websocket.interface.d.ts.map +1 -1
- package/dist/websocket/websocket.interface.js.map +2 -2
- package/package.json +9 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/websocket/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/websocket/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/websocket/index.js
CHANGED
|
@@ -2,7 +2,9 @@ import { WebSocketRedisSubscriberEvent } from "./websocket.interface.js";
|
|
|
2
2
|
import { default as default2 } from "./controller/server/base.js";
|
|
3
3
|
import { default as default3 } from "./controller/client/base.js";
|
|
4
4
|
import { WebSocketService } from "./websocket-service.js";
|
|
5
|
+
import { WebSocketAuthService } from "./websocket-auth.js";
|
|
5
6
|
export {
|
|
7
|
+
WebSocketAuthService,
|
|
6
8
|
default3 as WebSocketClientBaseController,
|
|
7
9
|
WebSocketRedisSubscriberEvent,
|
|
8
10
|
default2 as WebSocketServerBaseController,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/websocket/index.ts"],
|
|
4
|
-
"sourcesContent": ["export type { WebSocketRoute } from './websocket.interface.js';\nexport { WebSocketRedisSubscriberEvent } from './websocket.interface.js';\nexport { default as WebSocketServerBaseController } from './controller/server/base.js';\nexport { default as WebSocketClientBaseController } from './controller/client/base.js';\nexport { WebSocketService } from './websocket-service.js';\nexport type { WebSocketMessage, WebSocketServiceOptions } from './websocket-service.js';\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,qCAAqC;AAC9C,SAAoB,WAAXA,gBAAgD;AACzD,SAAoB,WAAXA,gBAAgD;AACzD,SAAS,wBAAwB;",
|
|
4
|
+
"sourcesContent": ["export type { WebSocketRoute } from './websocket.interface.js';\nexport { WebSocketRedisSubscriberEvent } from './websocket.interface.js';\nexport { default as WebSocketServerBaseController } from './controller/server/base.js';\nexport { default as WebSocketClientBaseController } from './controller/client/base.js';\nexport { WebSocketService } from './websocket-service.js';\nexport type { WebSocketMessage, WebSocketServiceOptions } from './websocket-service.js';\nexport { WebSocketAuthService } from './websocket-auth.js';\nexport type { WebSocketAuthResult } from './websocket-auth.js';\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,qCAAqC;AAC9C,SAAoB,WAAXA,gBAAgD;AACzD,SAAoB,WAAXA,gBAAgD;AACzD,SAAS,wBAAwB;AAEjC,SAAS,4BAA4B;",
|
|
6
6
|
"names": ["default"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { WebApplicationConfig } from '../application/web-application.interface.js';
|
|
2
|
+
export interface WebSocketAuthResult {
|
|
3
|
+
userId: number;
|
|
4
|
+
payload: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
export declare class WebSocketAuthService {
|
|
7
|
+
private readonly applicationConfig;
|
|
8
|
+
constructor(applicationConfig: WebApplicationConfig);
|
|
9
|
+
/**
|
|
10
|
+
* Validates WebSocket authentication token from URL query parameters
|
|
11
|
+
* @param url - The WebSocket connection URL
|
|
12
|
+
* @returns Authentication result with userId and payload, or null if no token provided
|
|
13
|
+
* @throws Error if authentication fails
|
|
14
|
+
*/
|
|
15
|
+
validateAuth(url: string): Promise<WebSocketAuthResult | null>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=websocket-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-auth.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAExF,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;gBAAjB,iBAAiB,EAAE,oBAAoB;IAEpE;;;;;OAKG;IACG,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;CAmCrE"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
import { URL } from "url";
|
|
4
|
+
import Jwt from "../auth/jwt.js";
|
|
5
|
+
class WebSocketAuthService {
|
|
6
|
+
constructor(applicationConfig) {
|
|
7
|
+
this.applicationConfig = applicationConfig;
|
|
8
|
+
}
|
|
9
|
+
static {
|
|
10
|
+
__name(this, "WebSocketAuthService");
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Validates WebSocket authentication token from URL query parameters
|
|
14
|
+
* @param url - The WebSocket connection URL
|
|
15
|
+
* @returns Authentication result with userId and payload, or null if no token provided
|
|
16
|
+
* @throws Error if authentication fails
|
|
17
|
+
*/
|
|
18
|
+
async validateAuth(url) {
|
|
19
|
+
try {
|
|
20
|
+
const parsedUrl = new URL(url, "ws://localhost");
|
|
21
|
+
const token = parsedUrl.searchParams.get("token");
|
|
22
|
+
if (!token) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const jwtSecretKey = this.applicationConfig.auth?.jwtSecretKey;
|
|
26
|
+
if (!jwtSecretKey) {
|
|
27
|
+
throw new Error("JWT secret key not configured");
|
|
28
|
+
}
|
|
29
|
+
const importedJwtSecretKey = await Jwt.importJwtSecretKey({
|
|
30
|
+
jwtSecretKey
|
|
31
|
+
});
|
|
32
|
+
const { payload } = await Jwt.jwtVerify(token, importedJwtSecretKey);
|
|
33
|
+
const userId = parseInt(payload.sub);
|
|
34
|
+
if (isNaN(userId)) {
|
|
35
|
+
throw new Error("Invalid user ID in token");
|
|
36
|
+
}
|
|
37
|
+
return { userId, payload };
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw new Error(`JWT verification failed: ${error.message}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
WebSocketAuthService
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=websocket-auth.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/websocket/websocket-auth.ts"],
|
|
4
|
+
"sourcesContent": ["import { URL } from 'url';\nimport Jwt from '../auth/jwt.js';\nimport type { WebApplicationConfig } from '../application/web-application.interface.js';\n\nexport interface WebSocketAuthResult {\n userId: number;\n payload: Record<string, unknown>;\n}\n\nexport class WebSocketAuthService {\n constructor(private readonly applicationConfig: WebApplicationConfig) {}\n\n /**\n * Validates WebSocket authentication token from URL query parameters\n * @param url - The WebSocket connection URL\n * @returns Authentication result with userId and payload, or null if no token provided\n * @throws Error if authentication fails\n */\n async validateAuth(url: string): Promise<WebSocketAuthResult | null> {\n try {\n const parsedUrl = new URL(url, 'ws://localhost');\n const token = parsedUrl.searchParams.get('token');\n\n if (!token) {\n return null; // No token provided, allow unauthenticated connection\n }\n\n // Get JWT secret key from application config\n const jwtSecretKey = this.applicationConfig.auth?.jwtSecretKey;\n\n if (!jwtSecretKey) {\n throw new Error('JWT secret key not configured');\n }\n\n // Import JWT secret key\n const importedJwtSecretKey = await Jwt.importJwtSecretKey({\n jwtSecretKey,\n });\n\n // Verify JWT token\n const { payload } = await Jwt.jwtVerify(token, importedJwtSecretKey);\n\n const userId = parseInt(payload.sub as string);\n\n if (isNaN(userId)) {\n throw new Error('Invalid user ID in token');\n }\n\n return { userId, payload };\n } catch (error: any) {\n throw new Error(`JWT verification failed: ${error.message}`);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": ";;AAAA,SAAS,WAAW;AACpB,OAAO,SAAS;AAQT,MAAM,qBAAqB;AAAA,EAChC,YAA6B,mBAAyC;AAAzC;AAAA,EAA0C;AAAA,EAVzE,OASkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAShC,MAAM,aAAa,KAAkD;AACnE,QAAI;AACF,YAAM,YAAY,IAAI,IAAI,KAAK,gBAAgB;AAC/C,YAAM,QAAQ,UAAU,aAAa,IAAI,OAAO;AAEhD,UAAI,CAAC,OAAO;AACV,eAAO;AAAA,MACT;AAGA,YAAM,eAAe,KAAK,kBAAkB,MAAM;AAElD,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI,MAAM,+BAA+B;AAAA,MACjD;AAGA,YAAM,uBAAuB,MAAM,IAAI,mBAAmB;AAAA,QACxD;AAAA,MACF,CAAC;AAGD,YAAM,EAAE,QAAQ,IAAI,MAAM,IAAI,UAAU,OAAO,oBAAoB;AAEnE,YAAM,SAAS,SAAS,QAAQ,GAAa;AAE7C,UAAI,MAAM,MAAM,GAAG;AACjB,cAAM,IAAI,MAAM,0BAA0B;AAAA,MAC5C;AAEA,aAAO,EAAE,QAAQ,QAAQ;AAAA,IAC3B,SAAS,OAAY;AACnB,YAAM,IAAI,MAAM,4BAA4B,MAAM,OAAO,EAAE;AAAA,IAC7D;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-client-manager.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-client-manager.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,IAAI,CAAC;AAE3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"websocket-client-manager.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-client-manager.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,IAAI,CAAC;AAE3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAKnF,MAAM,CAAC,OAAO,OAAO,sBAAsB;IACzC,OAAO,CAAC,OAAO,CAA+C;IAEvD,SAAS,CAAC,EACf,QAAQ,EACR,EAAE,EACF,YAAY,EACZ,IAAI,GACL,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,EAAE,EAAE,SAAS,GAAG,IAAI,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,GAAG,CAAA;SAAE,GAAG,IAAI,CAAC;KAChD;IAiBM,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE;QAAE,EAAE,EAAE,SAAS,CAAA;KAAE,GAAG,MAAM,GAAG,SAAS;IAI1D,SAAS,CAAC,EACf,QAAQ,EACR,SAAS,GACV,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,GAAG,mBAAmB,GAAG,SAAS;IAU5B,YAAY,CAAC,EAClB,QAAQ,EACR,GAAG,EACH,IAAI,EACJ,mBAAmB,GACpB,EAAE;QACD,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,GAAG,CAAC;QACV,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B;IA2CM,YAAY,CAAC,QAAQ,EAAE,MAAM;IAsB7B,aAAa;;kBAEN,MAAM;;IAcb,cAAc,CAAC,EACpB,GAAG,EACH,KAAK,EACL,SAAS,EACT,QAAQ,GACT,EAAE;QACD,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;;;;;;IA6BM,UAAU,CAAC,EAAE,QAAQ,EAAE,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO;IAgBnD,gBAAgB,CAAC,EAAE,QAAQ,EAAE,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE;IAwBnD,YAAY;IAwBZ,mBAAmB,CAAC,IAAI,EAAE,MAAM;IA0BhC,OAAO,IAAI,IAAI;CAsBvB"}
|
|
@@ -4,6 +4,7 @@ import WebSocket from "ws";
|
|
|
4
4
|
import { log } from "./utils.js";
|
|
5
5
|
import { Helper, Time } from "../util/index.js";
|
|
6
6
|
import cluster from "cluster";
|
|
7
|
+
import { safeSerializeError } from "../error/error-reporter.js";
|
|
7
8
|
class WebSocketClientManager {
|
|
8
9
|
static {
|
|
9
10
|
__name(this, "WebSocketClientManager");
|
|
@@ -51,7 +52,7 @@ class WebSocketClientManager {
|
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
53
54
|
if (key === "__proto__" || key === "constructor" || key === "prototype") {
|
|
54
|
-
|
|
55
|
+
log("Blocked attempt to modify dangerous property", { Property: key });
|
|
55
56
|
return;
|
|
56
57
|
}
|
|
57
58
|
const allowedClientProperties = [
|
|
@@ -67,7 +68,7 @@ class WebSocketClientManager {
|
|
|
67
68
|
"permissions"
|
|
68
69
|
];
|
|
69
70
|
if (!allowedClientProperties.includes(key)) {
|
|
70
|
-
|
|
71
|
+
log("Blocked attempt to modify unauthorized property", { Property: key });
|
|
71
72
|
return;
|
|
72
73
|
}
|
|
73
74
|
Reflect.set(client, key, data);
|
|
@@ -87,7 +88,7 @@ class WebSocketClientManager {
|
|
|
87
88
|
}
|
|
88
89
|
} catch (error) {
|
|
89
90
|
log("Error cleaning up WebSocket connection", {
|
|
90
|
-
error: error instanceof Error ? error.message :
|
|
91
|
+
error: error instanceof Error ? error.message : safeSerializeError(error)
|
|
91
92
|
});
|
|
92
93
|
}
|
|
93
94
|
}
|
|
@@ -194,7 +195,7 @@ class WebSocketClientManager {
|
|
|
194
195
|
);
|
|
195
196
|
} catch (error) {
|
|
196
197
|
log("Error broadcasting client list", {
|
|
197
|
-
error: error instanceof Error ? error.message :
|
|
198
|
+
error: error instanceof Error ? error.message : safeSerializeError(error)
|
|
198
199
|
});
|
|
199
200
|
}
|
|
200
201
|
});
|
|
@@ -210,7 +211,7 @@ class WebSocketClientManager {
|
|
|
210
211
|
} catch (error) {
|
|
211
212
|
log("Error cleaning up client connection", {
|
|
212
213
|
clientId,
|
|
213
|
-
error: error instanceof Error ? error.message :
|
|
214
|
+
error: error instanceof Error ? error.message : safeSerializeError(error)
|
|
214
215
|
});
|
|
215
216
|
}
|
|
216
217
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/websocket/websocket-client-manager.ts"],
|
|
4
|
-
"sourcesContent": ["import WebSocket from 'ws';\nimport { log } from './utils.js';\nimport type { WebSocketClientData } from './websocket-client-manager.interface.js';\nimport { Helper, Time } from '../util/index.js';\nimport cluster from 'cluster';\n\nexport default class WebSocketClientManager {\n private clients: Map<string, WebSocketClientData> = new Map();\n\n public addClient({\n clientId,\n ws,\n lastActivity,\n user,\n }: {\n clientId: string;\n ws: WebSocket | null;\n lastActivity: number;\n user?: { userId: number; payload: any } | null;\n }) {\n this.clients.set(clientId, {\n ws,\n lastActivity,\n user,\n });\n\n this.broadcastClientList('addClient');\n\n log('Client connected', {\n ID: clientId,\n UserId: user?.userId ?? 'unauthenticated',\n });\n\n this.printClients();\n }\n\n public getClientId({ ws }: { ws: WebSocket }): string | undefined {\n return [...this.clients.entries()].find(([_, value]) => value.ws === ws)?.[0];\n }\n\n public getClient({\n clientId,\n requireWs,\n }: {\n clientId: string;\n requireWs?: boolean;\n }): WebSocketClientData | undefined {\n const client = this.clients.get(clientId);\n\n if (requireWs && !client?.ws) {\n return undefined;\n }\n\n return client;\n }\n\n public updateClient({\n clientId,\n key,\n data,\n broadcastClientList,\n }: {\n clientId: string;\n key: string;\n data: any;\n broadcastClientList?: boolean;\n }) {\n const client = this.clients.get(clientId);\n\n if (!client) {\n return;\n }\n\n // Prevent prototype pollution attacks\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n
|
|
5
|
-
"mappings": ";;AAAA,OAAO,eAAe;AACtB,SAAS,WAAW;AAEpB,SAAS,QAAQ,YAAY;AAC7B,OAAO,aAAa;
|
|
4
|
+
"sourcesContent": ["import WebSocket from 'ws';\nimport { log } from './utils.js';\nimport type { WebSocketClientData } from './websocket-client-manager.interface.js';\nimport { Helper, Time } from '../util/index.js';\nimport cluster from 'cluster';\nimport { safeSerializeError } from '../error/error-reporter.js';\n\nexport default class WebSocketClientManager {\n private clients: Map<string, WebSocketClientData> = new Map();\n\n public addClient({\n clientId,\n ws,\n lastActivity,\n user,\n }: {\n clientId: string;\n ws: WebSocket | null;\n lastActivity: number;\n user?: { userId: number; payload: any } | null;\n }) {\n this.clients.set(clientId, {\n ws,\n lastActivity,\n user,\n });\n\n this.broadcastClientList('addClient');\n\n log('Client connected', {\n ID: clientId,\n UserId: user?.userId ?? 'unauthenticated',\n });\n\n this.printClients();\n }\n\n public getClientId({ ws }: { ws: WebSocket }): string | undefined {\n return [...this.clients.entries()].find(([_, value]) => value.ws === ws)?.[0];\n }\n\n public getClient({\n clientId,\n requireWs,\n }: {\n clientId: string;\n requireWs?: boolean;\n }): WebSocketClientData | undefined {\n const client = this.clients.get(clientId);\n\n if (requireWs && !client?.ws) {\n return undefined;\n }\n\n return client;\n }\n\n public updateClient({\n clientId,\n key,\n data,\n broadcastClientList,\n }: {\n clientId: string;\n key: string;\n data: any;\n broadcastClientList?: boolean;\n }) {\n const client = this.clients.get(clientId);\n\n if (!client) {\n return;\n }\n\n // Prevent prototype pollution attacks\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n log('Blocked attempt to modify dangerous property', { Property: key });\n return;\n }\n\n // Define allowed client properties to prevent unauthorized modifications\n const allowedClientProperties = [\n 'id',\n 'ws',\n 'room',\n 'userId',\n 'username',\n 'metadata',\n 'connectedAt',\n 'lastActivity',\n 'status',\n 'permissions',\n ];\n\n if (!allowedClientProperties.includes(key)) {\n log('Blocked attempt to modify unauthorized property', { Property: key });\n return;\n }\n\n Reflect.set(client, key, data);\n\n this.clients.set(clientId, client);\n\n if (broadcastClientList !== false) {\n this.broadcastClientList('updateClient');\n }\n\n this.printClients();\n }\n\n public removeClient(clientId: string) {\n const client = this.clients.get(clientId);\n\n // Clean up WebSocket connection if it exists\n if (client?.ws) {\n try {\n client.ws.removeAllListeners();\n if (client.ws.readyState === WebSocket.OPEN) {\n client.ws.close();\n }\n } catch (error) {\n log('Error cleaning up WebSocket connection', {\n error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n }\n }\n\n this.clients.delete(clientId);\n this.broadcastClientList('removeClient');\n this.printClients();\n }\n\n public getClientList() {\n const clientList: {\n clientId: string;\n [key: string]: any;\n }[] = [];\n\n this.clients.forEach((clientData, clientId) => {\n clientList.push({\n clientId,\n ...clientData,\n });\n });\n\n return clientList;\n }\n\n public getClientByKey({\n key,\n value,\n requireWs,\n userType,\n }: {\n key: string;\n value: string;\n requireWs?: boolean;\n userType?: string;\n }) {\n const clients = [...this.clients.entries()];\n\n const client = clients.find(([_, clientData]) => {\n const deepKeyValue = Helper.getValueFromObject(clientData, key);\n\n const isValueMatching = deepKeyValue === value;\n\n if (userType && clientData.user?.userType !== userType) {\n return false;\n }\n\n return isValueMatching;\n });\n\n const formattedClient = client\n ? {\n clientId: client[0],\n ...client[1],\n }\n : undefined;\n\n if (requireWs && !formattedClient?.ws) {\n return undefined;\n }\n\n return formattedClient;\n }\n\n public getClients({ userType }: { userType?: string } = {}) {\n const clients: WebSocketClientData[] = [];\n\n this.clients.forEach((clientData, clientId) => {\n if (userType && clientData.user?.userType !== userType) {\n return;\n }\n\n clientData.clientId = clientId;\n\n clients.push(clientData);\n });\n\n return clients;\n }\n\n public disconnectClient({ clientId }: { clientId: string }) {\n const clientInfo = this.clients.get(clientId);\n\n if (clientInfo?.ws) {\n const connectedTime = Date.now() - clientInfo.lastActivity;\n\n clientInfo.ws.close();\n\n log('WebSocket client was disconnected due to inactivity', {\n ID: clientId,\n 'Time Connected': Time.formatTime({\n time: connectedTime,\n format: 's',\n }),\n });\n }\n\n this.removeClient(clientId);\n\n log('Client disconnected', { ID: clientId });\n\n this.printClients();\n }\n\n public printClients() {\n const numClients = this.clients.size;\n\n const workerId = cluster.isWorker && cluster.worker ? cluster.worker.id : null;\n\n let logOutput = '\\n-------------------------------------------------------\\n';\n logOutput += `Connected clients (Count: ${numClients}${workerId ? ` | Worker: ${workerId}` : ''}):\\n`;\n logOutput += '-------------------------------------------------------\\n';\n\n if (numClients > 0) {\n this.clients.forEach((client, clientId) => {\n logOutput += `ID: ${clientId} | Username: ${client?.user?.username ?? '-'} | User Type: ${client?.user?.userType ?? '-'} | Email: ${client.user?.email ?? '-'}\\n`;\n });\n } else {\n logOutput += 'No clients';\n }\n\n logOutput += '\\n';\n\n log(logOutput, undefined, {\n muteWorker: true,\n });\n }\n\n public broadcastClientList(type: string) {\n const clientList = this.getClientList();\n\n this.clients.forEach(({ ws }) => {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n return;\n }\n\n try {\n ws.send(\n JSON.stringify({\n type: 'system',\n action: 'clientList',\n clientListType: type,\n data: clientList,\n }),\n );\n } catch (error) {\n // Handle send errors (e.g., connection closed)\n log('Error broadcasting client list', {\n error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n }\n });\n }\n\n public cleanup(): void {\n // Clean up all client connections\n this.clients.forEach((client, clientId) => {\n if (client.ws) {\n try {\n client.ws.removeAllListeners();\n if (client.ws.readyState === WebSocket.OPEN) {\n client.ws.close();\n }\n } catch (error) {\n log('Error cleaning up client connection', {\n clientId,\n error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n }\n }\n });\n\n // Clear all clients\n this.clients.clear();\n log('WebSocket client manager cleaned up');\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -14,6 +14,11 @@ export default class WebSocketClient extends WebSocketBase {
|
|
|
14
14
|
private ws?;
|
|
15
15
|
private clientId?;
|
|
16
16
|
private isConnected;
|
|
17
|
+
private reconnectAttempts;
|
|
18
|
+
private maxReconnectAttempts;
|
|
19
|
+
private reconnectDelay;
|
|
20
|
+
private reconnectTimer?;
|
|
21
|
+
private shouldReconnect;
|
|
17
22
|
constructor(props: WebSocketClientProps);
|
|
18
23
|
get type(): WebSocketType;
|
|
19
24
|
load(): Promise<void>;
|
|
@@ -31,5 +36,29 @@ export default class WebSocketClient extends WebSocketBase {
|
|
|
31
36
|
sendMessage: (data: unknown) => void;
|
|
32
37
|
disconnect(): void;
|
|
33
38
|
isClientConnected(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Schedule a reconnection attempt with exponential backoff
|
|
41
|
+
*/
|
|
42
|
+
private scheduleReconnect;
|
|
43
|
+
/**
|
|
44
|
+
* Attempt to reconnect to the server
|
|
45
|
+
*/
|
|
46
|
+
private attemptReconnect;
|
|
47
|
+
/**
|
|
48
|
+
* Enable auto-reconnection
|
|
49
|
+
*/
|
|
50
|
+
enableAutoReconnect(): void;
|
|
51
|
+
/**
|
|
52
|
+
* Disable auto-reconnection
|
|
53
|
+
*/
|
|
54
|
+
disableAutoReconnect(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Get connection status
|
|
57
|
+
*/
|
|
58
|
+
getConnectionStatus(): {
|
|
59
|
+
isConnected: boolean;
|
|
60
|
+
reconnectAttempts: number;
|
|
61
|
+
autoReconnectEnabled: boolean;
|
|
62
|
+
};
|
|
34
63
|
}
|
|
35
64
|
//# sourceMappingURL=websocket-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-client.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,cAAc,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,aAAa,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"websocket-client.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,cAAc,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAMhD,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,aAAa;IACxD,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,CAMvC;IAEF,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,EAAE,CAAC,CAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,oBAAoB,CAAc;IAC1C,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,eAAe,CAAiB;gBAE5B,KAAK,EAAE,oBAAoB;IAWvC,IAAW,IAAI,IAAI,aAAa,CAE/B;IAEY,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IA+E7C,SAAS,CAAC,yBAAyB,IAAI;QACrC,WAAW,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QACrC,aAAa,EAAE,aAAa,CAAC;QAC7B,YAAY,EAAE,YAAY,CAAC;QAC3B,gBAAgB,EAAE,gBAAgB,CAAC;KACpC;IAQD,SAAS,CAAC,iBAAiB,IAAI,OAAO;IAItC,OAAO,CAAC,qBAAqB,CAqB3B;IAEF,SAAS,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI5D,iBAAiB,GAAI,MAAM,OAAO,EAAE,SAAQ,OAAe,KAAG,IAAI,CAUvE;IAEK,WAAW,GAAI,MAAM,OAAO,KAAG,IAAI,CAExC;IAEK,UAAU,IAAI,IAAI;IAoBlB,iBAAiB,IAAI,OAAO;IAInC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAqCzB;;OAEG;YACW,gBAAgB;IA4B9B;;OAEG;IACI,mBAAmB,IAAI,IAAI;IAIlC;;OAEG;IACI,oBAAoB,IAAI,IAAI;IASnC;;OAEG;IACI,mBAAmB,IAAI;QAC5B,WAAW,EAAE,OAAO,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,oBAAoB,EAAE,OAAO,CAAC;KAC/B;CAOF"}
|
|
@@ -4,6 +4,7 @@ import WebSocket from "ws";
|
|
|
4
4
|
import { generateClientId, log, parseServerMessage } from "./utils.js";
|
|
5
5
|
import WebSocketBase from "./websocket-base.js";
|
|
6
6
|
import path from "path";
|
|
7
|
+
import { safeSerializeError } from "../error/error-reporter.js";
|
|
7
8
|
import { baseDir } from "../index.js";
|
|
8
9
|
class WebSocketClient extends WebSocketBase {
|
|
9
10
|
static {
|
|
@@ -24,6 +25,12 @@ class WebSocketClient extends WebSocketBase {
|
|
|
24
25
|
ws;
|
|
25
26
|
clientId;
|
|
26
27
|
isConnected = false;
|
|
28
|
+
reconnectAttempts = 0;
|
|
29
|
+
maxReconnectAttempts = 10;
|
|
30
|
+
reconnectDelay = 1e3;
|
|
31
|
+
// Start with 1 second
|
|
32
|
+
reconnectTimer;
|
|
33
|
+
shouldReconnect = true;
|
|
27
34
|
constructor(props) {
|
|
28
35
|
super();
|
|
29
36
|
this.applicationConfig = props.applicationConfig;
|
|
@@ -75,15 +82,18 @@ class WebSocketClient extends WebSocketBase {
|
|
|
75
82
|
resolve();
|
|
76
83
|
});
|
|
77
84
|
ws.on("message", this.handleIncomingMessage);
|
|
78
|
-
ws.on("close", () => {
|
|
85
|
+
ws.on("close", (code) => {
|
|
79
86
|
this.isConnected = false;
|
|
80
|
-
log("Connection to server closed");
|
|
87
|
+
log("Connection to server closed", { Code: code });
|
|
81
88
|
if (this.options.events?.onDisconnected) {
|
|
82
89
|
this.options.events.onDisconnected({ clientId: this.clientId });
|
|
83
90
|
}
|
|
84
91
|
ws.removeAllListeners();
|
|
85
92
|
this.ws = void 0;
|
|
86
93
|
this.clientId = void 0;
|
|
94
|
+
if (this.shouldReconnect) {
|
|
95
|
+
this.scheduleReconnect();
|
|
96
|
+
}
|
|
87
97
|
});
|
|
88
98
|
ws.on("error", (error) => {
|
|
89
99
|
log("WebSocket error", { error: error.message });
|
|
@@ -132,13 +142,17 @@ class WebSocketClient extends WebSocketBase {
|
|
|
132
142
|
return;
|
|
133
143
|
}
|
|
134
144
|
const webSocketMessage = JSON.stringify(data);
|
|
135
|
-
console.log("SENDING LCIENT MESSAGE: ", webSocketMessage);
|
|
136
145
|
this.ws.send(webSocketMessage, { binary });
|
|
137
146
|
}, "sendClientMessage");
|
|
138
147
|
sendMessage = /* @__PURE__ */ __name((data) => {
|
|
139
148
|
this.sendClientMessage(data);
|
|
140
149
|
}, "sendMessage");
|
|
141
150
|
disconnect() {
|
|
151
|
+
this.shouldReconnect = false;
|
|
152
|
+
if (this.reconnectTimer) {
|
|
153
|
+
clearTimeout(this.reconnectTimer);
|
|
154
|
+
this.reconnectTimer = void 0;
|
|
155
|
+
}
|
|
142
156
|
if (this.ws && this.isConnected) {
|
|
143
157
|
this.ws.removeAllListeners();
|
|
144
158
|
this.ws.close();
|
|
@@ -151,6 +165,86 @@ class WebSocketClient extends WebSocketBase {
|
|
|
151
165
|
isClientConnected() {
|
|
152
166
|
return this.isConnected && this.ws?.readyState === WebSocket.OPEN;
|
|
153
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Schedule a reconnection attempt with exponential backoff
|
|
170
|
+
*/
|
|
171
|
+
scheduleReconnect() {
|
|
172
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
173
|
+
log("Max reconnection attempts reached", {
|
|
174
|
+
Attempts: this.reconnectAttempts
|
|
175
|
+
});
|
|
176
|
+
if (this.options.events?.onReconnectFailed) {
|
|
177
|
+
this.options.events.onReconnectFailed({
|
|
178
|
+
attempts: this.reconnectAttempts
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts), 3e4);
|
|
184
|
+
this.reconnectAttempts++;
|
|
185
|
+
log("Scheduling reconnection", {
|
|
186
|
+
Attempt: this.reconnectAttempts,
|
|
187
|
+
Delay: `${delay}ms`
|
|
188
|
+
});
|
|
189
|
+
if (this.options.events?.onReconnecting) {
|
|
190
|
+
this.options.events.onReconnecting({
|
|
191
|
+
attempt: this.reconnectAttempts,
|
|
192
|
+
delay
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
this.reconnectTimer = setTimeout(() => {
|
|
196
|
+
this.attemptReconnect();
|
|
197
|
+
}, delay);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Attempt to reconnect to the server
|
|
201
|
+
*/
|
|
202
|
+
async attemptReconnect() {
|
|
203
|
+
try {
|
|
204
|
+
log("Attempting to reconnect...", {
|
|
205
|
+
Attempt: this.reconnectAttempts
|
|
206
|
+
});
|
|
207
|
+
await this.connectToServer();
|
|
208
|
+
this.reconnectAttempts = 0;
|
|
209
|
+
log("Reconnection successful");
|
|
210
|
+
if (this.options.events?.onReconnected) {
|
|
211
|
+
this.options.events.onReconnected({
|
|
212
|
+
clientId: this.clientId
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
} catch (error) {
|
|
216
|
+
log("Reconnection failed", {
|
|
217
|
+
Error: error instanceof Error ? error.message : safeSerializeError(error)
|
|
218
|
+
});
|
|
219
|
+
this.scheduleReconnect();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Enable auto-reconnection
|
|
224
|
+
*/
|
|
225
|
+
enableAutoReconnect() {
|
|
226
|
+
this.shouldReconnect = true;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Disable auto-reconnection
|
|
230
|
+
*/
|
|
231
|
+
disableAutoReconnect() {
|
|
232
|
+
this.shouldReconnect = false;
|
|
233
|
+
if (this.reconnectTimer) {
|
|
234
|
+
clearTimeout(this.reconnectTimer);
|
|
235
|
+
this.reconnectTimer = void 0;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get connection status
|
|
240
|
+
*/
|
|
241
|
+
getConnectionStatus() {
|
|
242
|
+
return {
|
|
243
|
+
isConnected: this.isConnected,
|
|
244
|
+
reconnectAttempts: this.reconnectAttempts,
|
|
245
|
+
autoReconnectEnabled: this.shouldReconnect
|
|
246
|
+
};
|
|
247
|
+
}
|
|
154
248
|
}
|
|
155
249
|
export {
|
|
156
250
|
WebSocketClient as default
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/websocket/websocket-client.ts"],
|
|
4
|
-
"sourcesContent": ["import WebSocket, { type RawData } from 'ws';\nimport type { WebSocketOptions, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { WebSocketClientProps } from './websocket-client.interface.js';\nimport { generateClientId, log, parseServerMessage } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport path from 'path';\nimport { baseDir } from '../index.js';\n\nexport default class WebSocketClient extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'clientList',\n controllerName: 'system',\n },\n ];\n\n private applicationConfig: ApplicationConfig;\n private options: WebSocketOptions;\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private ws?: WebSocket;\n private clientId?: string;\n private isConnected: boolean = false;\n\n constructor(props: WebSocketClientProps) {\n super();\n\n this.applicationConfig = props.applicationConfig;\n this.options = props.options;\n this.redisInstance = props.redisInstance;\n this.queueManager = props.queueManager;\n this.databaseInstance = props.databaseInstance;\n this.routes = props.routes;\n }\n\n public get type(): WebSocketType {\n return 'client';\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'client');\n\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n }\n\n public async connectToServer(): Promise<void> {\n const url = this.options.url;\n // const host = this.options.host;\n // const port = this.options.port;\n\n return new Promise(resolve => {\n const ws = new WebSocket(url);\n\n ws.on('open', () => {\n this.clientId = generateClientId();\n this.isConnected = true;\n\n log('Connected to server', { ID: this.clientId });\n\n if (this.options.events?.onConnected) {\n this.options.events.onConnected({\n ws,\n clientId: this.clientId,\n joinRoom: ({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username: string;\n roomName: string;\n }) => {\n this.sendClientMessage({\n type: 'system',\n action: 'joinRoom',\n data: {\n userId,\n userType,\n username,\n roomName,\n },\n });\n },\n });\n }\n\n resolve();\n });\n\n ws.on('message', this.handleIncomingMessage);\n\n ws.on('close',
|
|
5
|
-
"mappings": ";;AAAA,OAAO,eAAiC;AAMxC,SAAS,kBAAkB,KAAK,0BAA0B;AAC1D,OAAO,mBAAmB;AAE1B,OAAO,UAAU;AACjB,SAAS,eAAe;AAExB,MAAO,wBAAsC,cAAc;AAAA,
|
|
4
|
+
"sourcesContent": ["import WebSocket, { type RawData } from 'ws';\nimport type { WebSocketOptions, WebSocketRoute, WebSocketType } from './websocket.interface.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { WebSocketClientProps } from './websocket-client.interface.js';\nimport { generateClientId, log, parseServerMessage } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport path from 'path';\nimport { safeSerializeError } from '../error/error-reporter.js';\nimport { baseDir } from '../index.js';\n\nexport default class WebSocketClient extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'clientList',\n controllerName: 'system',\n },\n ];\n\n private applicationConfig: ApplicationConfig;\n private options: WebSocketOptions;\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private ws?: WebSocket;\n private clientId?: string;\n private isConnected: boolean = false;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = 10;\n private reconnectDelay: number = 1000; // Start with 1 second\n private reconnectTimer?: NodeJS.Timeout;\n private shouldReconnect: boolean = true;\n\n constructor(props: WebSocketClientProps) {\n super();\n\n this.applicationConfig = props.applicationConfig;\n this.options = props.options;\n this.redisInstance = props.redisInstance;\n this.queueManager = props.queueManager;\n this.databaseInstance = props.databaseInstance;\n this.routes = props.routes;\n }\n\n public get type(): WebSocketType {\n return 'client';\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'client');\n\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n }\n\n public async connectToServer(): Promise<void> {\n const url = this.options.url;\n // const host = this.options.host;\n // const port = this.options.port;\n\n return new Promise(resolve => {\n const ws = new WebSocket(url);\n\n ws.on('open', () => {\n this.clientId = generateClientId();\n this.isConnected = true;\n\n log('Connected to server', { ID: this.clientId });\n\n if (this.options.events?.onConnected) {\n this.options.events.onConnected({\n ws,\n clientId: this.clientId,\n joinRoom: ({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username: string;\n roomName: string;\n }) => {\n this.sendClientMessage({\n type: 'system',\n action: 'joinRoom',\n data: {\n userId,\n userType,\n username,\n roomName,\n },\n });\n },\n });\n }\n\n resolve();\n });\n\n ws.on('message', this.handleIncomingMessage);\n\n ws.on('close', code => {\n this.isConnected = false;\n log('Connection to server closed', { Code: code });\n\n if (this.options.events?.onDisconnected) {\n this.options.events.onDisconnected({ clientId: this.clientId });\n }\n\n // Clean up event listeners to prevent memory leaks\n ws.removeAllListeners();\n this.ws = undefined;\n this.clientId = undefined;\n\n // Attempt to reconnect if not manually disconnected\n if (this.shouldReconnect) {\n this.scheduleReconnect();\n }\n });\n\n ws.on('error', error => {\n log('WebSocket error', { error: error.message });\n\n if (this.options.events?.onError) {\n this.options.events.onError({ error });\n }\n });\n\n this.ws = ws;\n });\n }\n\n protected getControllerDependencies(): {\n sendMessage: (data: unknown) => void;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n } {\n return {\n sendMessage: this.sendMessage,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n };\n }\n protected shouldPrintRoutes(): boolean {\n return this.options.debug?.printRoutes ?? false;\n }\n\n private handleIncomingMessage = async (message: RawData): Promise<void> => {\n if (!this.ws || !this.clientId) {\n log('WebSocket not initialized or client ID not set');\n\n return;\n }\n\n if (this.options.events?.onMessage) {\n const parsedMessage = parseServerMessage(message);\n\n this.options.events.onMessage({\n ws: this.ws,\n clientId: this.clientId,\n data: parsedMessage as { type: string; action: string; data: unknown },\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n });\n }\n\n await this.handleServerMessage(this.ws, message, this.clientId);\n };\n\n protected handleMessageError(clientId: string, error: string): void {\n log(error);\n }\n\n public sendClientMessage = (data: unknown, binary: boolean = false): void => {\n if (!this.ws) {\n log('WebSocket not initialized');\n\n return;\n }\n\n const webSocketMessage = JSON.stringify(data);\n\n this.ws.send(webSocketMessage, { binary });\n };\n\n public sendMessage = (data: unknown): void => {\n this.sendClientMessage(data);\n };\n\n public disconnect(): void {\n // Disable auto-reconnect on manual disconnect\n this.shouldReconnect = false;\n\n // Clear any pending reconnect timer\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n if (this.ws && this.isConnected) {\n this.ws.removeAllListeners();\n this.ws.close();\n this.ws = undefined;\n this.clientId = undefined;\n this.isConnected = false;\n log('WebSocket client disconnected');\n }\n }\n\n public isClientConnected(): boolean {\n return this.isConnected && this.ws?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Schedule a reconnection attempt with exponential backoff\n */\n private scheduleReconnect(): void {\n // Don't reconnect if we've exceeded max attempts\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n log('Max reconnection attempts reached', {\n Attempts: this.reconnectAttempts,\n });\n\n if (this.options.events?.onReconnectFailed) {\n this.options.events.onReconnectFailed({\n attempts: this.reconnectAttempts,\n });\n }\n\n return;\n }\n\n // Calculate delay with exponential backoff (max 30 seconds)\n const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts), 30000);\n this.reconnectAttempts++;\n\n log('Scheduling reconnection', {\n Attempt: this.reconnectAttempts,\n Delay: `${delay}ms`,\n });\n\n if (this.options.events?.onReconnecting) {\n this.options.events.onReconnecting({\n attempt: this.reconnectAttempts,\n delay,\n });\n }\n\n this.reconnectTimer = setTimeout(() => {\n this.attemptReconnect();\n }, delay);\n }\n\n /**\n * Attempt to reconnect to the server\n */\n private async attemptReconnect(): Promise<void> {\n try {\n log('Attempting to reconnect...', {\n Attempt: this.reconnectAttempts,\n });\n\n await this.connectToServer();\n\n // Reset reconnect attempts on successful connection\n this.reconnectAttempts = 0;\n\n log('Reconnection successful');\n\n if (this.options.events?.onReconnected) {\n this.options.events.onReconnected({\n clientId: this.clientId,\n });\n }\n } catch (error) {\n log('Reconnection failed', {\n Error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n\n // Schedule next attempt\n this.scheduleReconnect();\n }\n }\n\n /**\n * Enable auto-reconnection\n */\n public enableAutoReconnect(): void {\n this.shouldReconnect = true;\n }\n\n /**\n * Disable auto-reconnection\n */\n public disableAutoReconnect(): void {\n this.shouldReconnect = false;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n }\n\n /**\n * Get connection status\n */\n public getConnectionStatus(): {\n isConnected: boolean;\n reconnectAttempts: number;\n autoReconnectEnabled: boolean;\n } {\n return {\n isConnected: this.isConnected,\n reconnectAttempts: this.reconnectAttempts,\n autoReconnectEnabled: this.shouldReconnect,\n };\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -17,6 +17,7 @@ export default class WebSocketServer extends WebSocketBase {
|
|
|
17
17
|
private options;
|
|
18
18
|
clientManager: WebSocketClientManager;
|
|
19
19
|
private roomManager;
|
|
20
|
+
private authService;
|
|
20
21
|
get rooms(): Map<string, Set<string>>;
|
|
21
22
|
private redisInstance;
|
|
22
23
|
private queueManager;
|
|
@@ -56,7 +57,16 @@ export default class WebSocketServer extends WebSocketBase {
|
|
|
56
57
|
private handleServerClientDisconnection;
|
|
57
58
|
private handleClientMessage;
|
|
58
59
|
protected handleMessageError(clientId: string, error: string): void;
|
|
60
|
+
/**
|
|
61
|
+
* Check and disconnect inactive clients based on configuration
|
|
62
|
+
* This helps prevent stale connections from accumulating
|
|
63
|
+
*/
|
|
59
64
|
private checkInactiveClients;
|
|
65
|
+
/**
|
|
66
|
+
* Broadcast a message to all connected WebSocket clients
|
|
67
|
+
* @param data - The data to broadcast (will be JSON stringified)
|
|
68
|
+
* @param excludeClientId - Optional client ID to exclude from broadcast
|
|
69
|
+
*/
|
|
60
70
|
broadcastToAllClients({ data, excludeClientId, }: {
|
|
61
71
|
data: {
|
|
62
72
|
[key: string]: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,eAAe,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpE,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AAEnE,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAMhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,eAAe,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpE,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,sBAAsB,MAAM,+BAA+B,CAAC;AAEnE,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAMhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG/C,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,aAAa;IACxD,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,CAWvC;IAEF,OAAO,CAAC,MAAM,CAAC,CAAK;IAEpB,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,OAAO,CAAmB;IAC3B,aAAa,yBAAgC;IACpD,OAAO,CAAC,WAAW,CAEhB;IACH,OAAO,CAAC,WAAW,CAAuB;IAE1C,IAAW,KAAK,6BAEf;IACD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAAmB;IAE3C,8BAA8B;IAC9B,OAAO,CAAC,qBAAqB,CAY3B;gBAEU,KAAK,EAAE,oBAAoB;IAcvC,IAAW,IAAI,IAAI,aAAa,CAE/B;YAEa,qBAAqB;IAMtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAUrB,KAAK,CAAC,EAAE,aAAa,EAAE,EAAE;QAAE,aAAa,EAAE,eAAe,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,EAAE,CAAA;KAAE,CAAC;IA4CrF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuClC,SAAS,CAAC,yBAAyB,IAAI;QACrC,eAAe,EAAE,eAAe,CAAC;QACjC,aAAa,EAAE,aAAa,CAAC;QAC7B,YAAY,EAAE,YAAY,CAAC;QAC3B,gBAAgB,EAAE,gBAAgB,CAAC;KACpC;IASD,SAAS,CAAC,iBAAiB,IAAI,OAAO;IAItC,OAAO,CAAC,iBAAiB,CAkCvB;IAEF;;OAEG;IACH,OAAO,CAAC,uBAAuB,CAyI7B;IAEF,OAAO,CAAC,iBAAiB,CAEvB;IAEF,OAAO,CAAC,4BAA4B,CAmDlC;IAEK,SAAS,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE;QAAE,EAAE,EAAE,SAAS,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAgD7E,OAAO,CAAC,eAAe;IAiBvB,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,+BAA+B,CAwBrC;IAEF,OAAO,CAAC,mBAAmB,CA6CzB;IAEF,SAAS,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAWnE;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA8B5B;;;;OAIG;IACI,qBAAqB,CAAC,EAC3B,IAAI,EACJ,eAAe,GAChB,EAAE;QACD,IAAI,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC;QAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,GAAG,IAAI;IAuBD,gBAAgB,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAwCzG,OAAO,CAAC,UAAU;IAwCL,QAAQ,CAAC,EACpB,EAAE,EACF,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,QAAQ,GACT,EAAE;QACD,EAAE,EAAE,SAAS,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;KAClB;IAoHM,iBAAiB,GAAI,IAAI,SAAS,EAAE,MAAM,OAAO,EAAE,SAAQ,OAAe,KAAG,IAAI,CAItF;IAEK,WAAW,GAAI,UAAU;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,KAAG,IAAI,CAUtD;IAEK,gBAAgB,GAAI,UAAU;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,KAAG,IAAI,CAU3D;IAEK,iBAAiB,GAAI,UAAU;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,KAAG,IAAI,CAO5D;IAEK,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,GAAG,EAAE;CAG9D"}
|