From 7213cd999ade791517f81e92c77b479bdf862439 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Fri, 12 Sep 2025 14:48:11 +0530 Subject: [PATCH 01/49] feat: Implement WebSocket provider with middleware support and protocol codec --- .gitignore | 2 + .talismanrc | 38 +++-- websocket-provider/.npmignore | 20 +++ .../core/web-socket-provider.ts | 84 +++++++++ websocket-provider/core/ws-protocol-codec.ts | 16 ++ websocket-provider/index.ts | 2 + websocket-provider/mocks/express-response.ts | 39 +++++ websocket-provider/package-lock.json | 160 ++++++++++++++++++ websocket-provider/package.json | 20 +++ websocket-provider/tsconfig.json | 10 ++ websocket-provider/types/add-route-params.ts | 7 + .../types/express-middleware.ts | 3 + websocket-provider/types/ws-controller.ts | 3 + .../utils/inject-http-request.ts | 22 +++ .../utils/middleware-adapter.ts | 54 ++++++ 15 files changed, 462 insertions(+), 18 deletions(-) create mode 100644 .gitignore create mode 100644 websocket-provider/.npmignore create mode 100644 websocket-provider/core/web-socket-provider.ts create mode 100644 websocket-provider/core/ws-protocol-codec.ts create mode 100644 websocket-provider/index.ts create mode 100644 websocket-provider/mocks/express-response.ts create mode 100644 websocket-provider/package-lock.json create mode 100644 websocket-provider/package.json create mode 100644 websocket-provider/tsconfig.json create mode 100644 websocket-provider/types/add-route-params.ts create mode 100644 websocket-provider/types/express-middleware.ts create mode 100644 websocket-provider/types/ws-controller.ts create mode 100644 websocket-provider/utils/inject-http-request.ts create mode 100644 websocket-provider/utils/middleware-adapter.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b4a4e49 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**/dist/** +**/node_modules/** \ No newline at end of file diff --git a/.talismanrc b/.talismanrc index 7bea482..974ffd9 100644 --- a/.talismanrc +++ b/.talismanrc @@ -1,19 +1,21 @@ -threshold: medium fileignoreconfig: - - filename: aws-credentials-utils/store-credentials.sh - checksum: 784aec6e80314be796af73887ba630fbaf0e116cc4d11bd5cba787a20f9c4bbb - - filename: jwks-slim/README.md - checksum: a1954df51e49fc6a09d7fe04bac198fe60a4fb39b2569180475a749a72df472d - - filename: jwks-slim/package-lock.json - checksum: d014d548f9f2997cbe1d7c4f7ec312f8c634e88788bc453ccc606ea70e081a77 - - filename: jwks-slim/tests/cache.test.js - checksum: 716f25000789d7ca18adfe07f968bae6eb2fbfa1c3d05e9e92897b9597ac5f17 - - filename: jwks-slim/tests/mock.js - checksum: 0d2fd2ec4847acda384c398e04e8aab9a615a8599b0a06d685e7fb100e71537c - - filename: jwks-slim/tests/keys.js - checksum: 207c0d07dea4c069883822b2b268d3b34c8b18bdfd645b8aa3b2be20f280c270 - - filename: jwks-slim/tests/index.test.js - checksum: 992a5c1f6c254fd344ae52955aa0c1c22a59e0472fe836b0450ff499255ef6f8 - - filename: aws-ssm/package-lock.json - checksum: 4cf91061e42ed9b1aafb17bdf68c9b4b24a7f86b191133ab4095fa635f8f01a0 -version: "" +- filename: aws-credentials-utils/store-credentials.sh + checksum: 784aec6e80314be796af73887ba630fbaf0e116cc4d11bd5cba787a20f9c4bbb +- filename: aws-ssm/package-lock.json + checksum: 4cf91061e42ed9b1aafb17bdf68c9b4b24a7f86b191133ab4095fa635f8f01a0 +- filename: jwks-slim/README.md + checksum: a1954df51e49fc6a09d7fe04bac198fe60a4fb39b2569180475a749a72df472d +- filename: jwks-slim/package-lock.json + checksum: d014d548f9f2997cbe1d7c4f7ec312f8c634e88788bc453ccc606ea70e081a77 +- filename: jwks-slim/tests/cache.test.js + checksum: 716f25000789d7ca18adfe07f968bae6eb2fbfa1c3d05e9e92897b9597ac5f17 +- filename: jwks-slim/tests/index.test.js + checksum: 992a5c1f6c254fd344ae52955aa0c1c22a59e0472fe836b0450ff499255ef6f8 +- filename: jwks-slim/tests/keys.js + checksum: 207c0d07dea4c069883822b2b268d3b34c8b18bdfd645b8aa3b2be20f280c270 +- filename: jwks-slim/tests/mock.js + checksum: 0d2fd2ec4847acda384c398e04e8aab9a615a8599b0a06d685e7fb100e71537c +- filename: websocket-provider/package-lock.json + checksum: 605a2d92b91f08ee577d3b1e7ed38d27eef43573a044608c22466f05ab6eaff7 +threshold: medium +version: "1.0" diff --git a/websocket-provider/.npmignore b/websocket-provider/.npmignore new file mode 100644 index 0000000..de53100 --- /dev/null +++ b/websocket-provider/.npmignore @@ -0,0 +1,20 @@ +# Exclude TypeScript source files and configs +src/ +*.ts +*.tsx +tsconfig.json +# Exclude node_modules +node_modules/ +# Exclude test files and folders +test/ +*.spec.* +*.test.* +# Exclude build scripts and configs +*.log +*.env +# Exclude editor and OS files +.DS_Store +.vscode/ +.idea/ +# Exclude other common files +coverage/ diff --git a/websocket-provider/core/web-socket-provider.ts b/websocket-provider/core/web-socket-provider.ts new file mode 100644 index 0000000..985d457 --- /dev/null +++ b/websocket-provider/core/web-socket-provider.ts @@ -0,0 +1,84 @@ +import { WebSocketServer, WebSocket as WSWebSocket } from 'ws'; +import { IncomingMessage } from 'http'; +import { Duplex } from 'stream'; +import { decode } from "@msgpack/msgpack"; + +import { WSProtocolCodec } from './ws-protocol-codec'; +import { runExpressMiddleware } from '../utils/middleware-adapter'; +import { injectHttpRequest } from '../utils/inject-http-request'; + +import { WSController } from '../types/ws-controller'; +import { AddRouteParams } from '../types/add-route-params'; + +export class WebSocketProvider { + public server: WebSocketServer; + private routes: Record; + + constructor() { + this.server = new WebSocketServer({ noServer: true }); + this.server.on('connection', this.handleConnection); + this.routes = {}; + } + + public addRoute = ( + path: string, + { + onConnect, + onMessage, + } : AddRouteParams + ) => { + this.routes[path] = { + onConnect, + onMessage + } + } + public handleUpgrade = (request: IncomingMessage, socket: Duplex, head: Buffer) => { + const { pathname } = new URL(request.url!, 'wss://base.url'); + + if (this.routes[pathname]) { + this.server.handleUpgrade(request, socket, head, (ws: any) => { + this.server.emit('connection', ws, request); + }); + } else { + // socket.write('HTTP/1.1 404 Not Found\r\n\r\n'); + socket.end(); + } + }; + + private handleConnection = async (ws: WSWebSocket, request: IncomingMessage) => { + const { pathname } = new URL(request.url!, 'wss://base.url'); + + const httpRequest = WSProtocolCodec.decode(ws.protocol || ''); + const injectedRequest = injectHttpRequest(request, httpRequest); + + if(!this.routes[pathname]) { + ws.close(1000, 'Unknown path'); + return; + } + + const { onConnect, onMessage } = this.routes[pathname]; + + for (const middleware of onConnect) { + const res = await runExpressMiddleware(middleware, injectedRequest, ws); + if (!res.success) { + console.error("Middleware rejected connection:", res.error); + ws.send(JSON.stringify({ error: res.error })); + ws.close(1000, res.error); + return; + } + } + + ws.on('message', this.handleMessage(ws, onMessage)); + ws.send(JSON.stringify({ type: "connection:ack" })); + }; + + private handleMessage = (socket: WSWebSocket, onMessage: WSController[]) => { + return async (message) => { + const request = decode(message) as IncomingMessage; + + for (const controller of onMessage) { + await controller(request, socket); + } + }; + } +} \ No newline at end of file diff --git a/websocket-provider/core/ws-protocol-codec.ts b/websocket-provider/core/ws-protocol-codec.ts new file mode 100644 index 0000000..c6e9dec --- /dev/null +++ b/websocket-provider/core/ws-protocol-codec.ts @@ -0,0 +1,16 @@ +export class WSProtocolCodec { + static encode(data: unknown): string { + const json = JSON.stringify(data); + return btoa(json) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/, ""); + } + + static decode(encoded: string): T { + let str = encoded.replace(/-/g, "+").replace(/_/g, "/"); + while (str.length % 4) str += "="; + const json = atob(str); + return JSON.parse(json) as T; + } +} diff --git a/websocket-provider/index.ts b/websocket-provider/index.ts new file mode 100644 index 0000000..800b0de --- /dev/null +++ b/websocket-provider/index.ts @@ -0,0 +1,2 @@ +export * from './core/web-socket-provider'; +export * from './core/ws-protocol-codec'; \ No newline at end of file diff --git a/websocket-provider/mocks/express-response.ts b/websocket-provider/mocks/express-response.ts new file mode 100644 index 0000000..959f2f4 --- /dev/null +++ b/websocket-provider/mocks/express-response.ts @@ -0,0 +1,39 @@ +import { WebSocket } from "ws"; + +export class MockResponse { + private socket: WebSocket; + public statusCode: number = 200; + + constructor(socket: WebSocket) { + this.socket = socket; + } + + status(code: number) { + this.statusCode = code; + return this; + } + + send(data) { + this.socket.send(`HTTP/1.1 ${this.statusCode} ${this.getStatusText()}\r\n\r\n`); + this.socket.close(); + return this; + } + + sendStatus(code: number) { + this.statusCode = code; + this.socket.send(`HTTP/1.1 ${code} ${this.getStatusText()}\r\n\r\n`); + this.socket.close(); + return this; + } + + private getStatusText(): string { + const statusTexts: { [key: number]: string } = { + 200: 'OK', + 401: 'Unauthorized', + 403: 'Forbidden', + 404: 'Not Found', + 500: 'Internal Server Error' + }; + return statusTexts[this.statusCode] || 'Unknown'; + } +}; \ No newline at end of file diff --git a/websocket-provider/package-lock.json b/websocket-provider/package-lock.json new file mode 100644 index 0000000..c4de3b9 --- /dev/null +++ b/websocket-provider/package-lock.json @@ -0,0 +1,160 @@ +{ + "name": "websocket-provider", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "websocket-provider", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@msgpack/msgpack": "^3.1.2", + "ws": "^8.18.3" + }, + "devDependencies": { + "@types/express": "^5.0.3", + "@types/ws": "^8.18.1" + } + }, + "node_modules/@msgpack/msgpack": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.1.2.tgz", + "integrity": "sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", + "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", + "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/node": { + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "dev": true, + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "dev": true + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/websocket-provider/package.json b/websocket-provider/package.json new file mode 100644 index 0000000..74b66cc --- /dev/null +++ b/websocket-provider/package.json @@ -0,0 +1,20 @@ +{ + "name": "websocket-provider", + "version": "1.0.0", + "main": "dist/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "tsc" + }, + "author": "", + "license": "ISC", + "description": "", + "devDependencies": { + "@types/express": "^5.0.3", + "@types/ws": "^8.18.1" + }, + "dependencies": { + "@msgpack/msgpack": "^3.1.2", + "ws": "^8.18.3" + } +} diff --git a/websocket-provider/tsconfig.json b/websocket-provider/tsconfig.json new file mode 100644 index 0000000..17b7552 --- /dev/null +++ b/websocket-provider/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "outDir": "./dist", + } +} diff --git a/websocket-provider/types/add-route-params.ts b/websocket-provider/types/add-route-params.ts new file mode 100644 index 0000000..fa07c52 --- /dev/null +++ b/websocket-provider/types/add-route-params.ts @@ -0,0 +1,7 @@ +import { ExpressMiddleware } from "./express-middleware"; +import { WSController } from "./ws-controller"; + +export type AddRouteParams = { + onConnect: ExpressMiddleware[], + onMessage: WSController[], + } \ No newline at end of file diff --git a/websocket-provider/types/express-middleware.ts b/websocket-provider/types/express-middleware.ts new file mode 100644 index 0000000..ca8875a --- /dev/null +++ b/websocket-provider/types/express-middleware.ts @@ -0,0 +1,3 @@ +import { Request, Response, NextFunction } from 'express'; + +export type ExpressMiddleware = (req: Request, res: Response, next: NextFunction) => any; \ No newline at end of file diff --git a/websocket-provider/types/ws-controller.ts b/websocket-provider/types/ws-controller.ts new file mode 100644 index 0000000..1b86c85 --- /dev/null +++ b/websocket-provider/types/ws-controller.ts @@ -0,0 +1,3 @@ +import { WebSocket } from 'ws'; + +export type WSController = (message: any, socket: WebSocket) => any; \ No newline at end of file diff --git a/websocket-provider/utils/inject-http-request.ts b/websocket-provider/utils/inject-http-request.ts new file mode 100644 index 0000000..9f8944e --- /dev/null +++ b/websocket-provider/utils/inject-http-request.ts @@ -0,0 +1,22 @@ +import { IncomingMessage } from "http"; + +type HttpRequest = { + headers?: Record; + body?: unknown; +}; + +export function injectHttpRequest(request: IncomingMessage, httpRequest: HttpRequest) { + // Merge headers + if (httpRequest.headers) { + for (const [key, value] of Object.entries(httpRequest.headers)) { + request.headers[key.toLowerCase()] = value; + } + } + + // Attach body as a custom property + if (httpRequest.body) { + (request as any).body = httpRequest.body; + } + + return request; +} diff --git a/websocket-provider/utils/middleware-adapter.ts b/websocket-provider/utils/middleware-adapter.ts new file mode 100644 index 0000000..885756c --- /dev/null +++ b/websocket-provider/utils/middleware-adapter.ts @@ -0,0 +1,54 @@ +import { IncomingMessage } from 'http'; +import { WebSocket } from 'ws'; +import { MockResponse } from '../mocks/express-response'; + +export function runExpressMiddleware( + middleware: (req, res, next) => void, + request: IncomingMessage, + socket: WebSocket +): Promise<{ success: boolean; error?: string }> { + return new Promise((resolve) => { + const mockRes = new MockResponse(socket); + let nextCalled = false; + + const next = (error) => { + if (nextCalled) return; + nextCalled = true; + + if (error) { + resolve({ success: false, error: error.message || 'Middleware error' }); + } else { + resolve({ success: true }); + } + }; + + const originalSend = mockRes.send.bind(mockRes); + const originalSendStatus = mockRes.sendStatus.bind(mockRes); + + mockRes.send = (data) => { + if (!nextCalled) { + nextCalled = true; + resolve({ success: false, error: `HTTP ${mockRes.statusCode}` }); + } + return mockRes; + }; + + mockRes.sendStatus = (code: number) => { + if (!nextCalled) { + nextCalled = true; + resolve({ success: false, error: `HTTP ${code}` }); + } + return mockRes; + }; + + try { + middleware(request, mockRes, next); + } catch (error) { + console.error("Middleware exception:", error); + if (!nextCalled) { + nextCalled = true; + resolve({ success: false, error: error.message || 'Middleware exception' }); + } + } + }); +} \ No newline at end of file From fe359a558a50a7395e648457df87ec769cd11540 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Mon, 15 Sep 2025 16:12:02 +0530 Subject: [PATCH 02/49] temp: update workflow to release and publish websocket-provider instead of JWKS-slim --- .github/workflows/npm-publish.yml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 022c5fb..bae7390 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -1,9 +1,6 @@ -name: Release and Publish JWKS-slim +name: Release and Publish websocket-provider -on: - push: - paths: - - "jwks-slim/**" +on: workflow_dispatch env: BRANCH_TAG: "${{ github.ref_name == 'main' && 'latest' || github.ref_name }}" @@ -15,7 +12,7 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: "jwks-slim" + working-directory: "websocket-provider" steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 @@ -28,12 +25,12 @@ jobs: publish_and_release: needs: test - name: Publish JWKS-slim package + name: Publish websocket-provider package environment: "${{ github.ref_name == 'main' && 'Prod' || 'Dev' }}" runs-on: ubuntu-latest defaults: run: - working-directory: "jwks-slim" + working-directory: "websocket-provider" steps: - name: Generate token if: ${{ github.ref_name == 'main'}} @@ -60,7 +57,7 @@ jobs: patch-wording: ${{ null }} rc-wording: ${{ null }} default: "${{ env.BRANCH == 'main' && 'patch' || 'prerelease' }}" - PACKAGEJSON_DIR: "jwks-slim" + PACKAGEJSON_DIR: "websocket-provider" preid: "${{ env.BRANCH }}" skip-tag: "true" skip-push: "true" @@ -73,7 +70,7 @@ jobs: run: | git config user.email "fundabot@fundwave.com" git config user.name "fundabot" - git commit -a -m "CI: bumps jwks-slim to $VERSION" -m "[skip ci]" + git commit -a -m "CI: bumps websocket-provider to $VERSION" -m "[skip ci]" - name: Publish package to npm if: ${{ github.ref_name == 'main'}} From 3d310224ff823ee5650c7c1e1af03983d8301034 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Mon, 15 Sep 2025 16:15:34 +0530 Subject: [PATCH 03/49] Revert "temp: update workflow to release and publish websocket-provider instead of JWKS-slim" This reverts commit fe359a558a50a7395e648457df87ec769cd11540. --- .github/workflows/npm-publish.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index bae7390..022c5fb 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -1,6 +1,9 @@ -name: Release and Publish websocket-provider +name: Release and Publish JWKS-slim -on: workflow_dispatch +on: + push: + paths: + - "jwks-slim/**" env: BRANCH_TAG: "${{ github.ref_name == 'main' && 'latest' || github.ref_name }}" @@ -12,7 +15,7 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: "websocket-provider" + working-directory: "jwks-slim" steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 @@ -25,12 +28,12 @@ jobs: publish_and_release: needs: test - name: Publish websocket-provider package + name: Publish JWKS-slim package environment: "${{ github.ref_name == 'main' && 'Prod' || 'Dev' }}" runs-on: ubuntu-latest defaults: run: - working-directory: "websocket-provider" + working-directory: "jwks-slim" steps: - name: Generate token if: ${{ github.ref_name == 'main'}} @@ -57,7 +60,7 @@ jobs: patch-wording: ${{ null }} rc-wording: ${{ null }} default: "${{ env.BRANCH == 'main' && 'patch' || 'prerelease' }}" - PACKAGEJSON_DIR: "websocket-provider" + PACKAGEJSON_DIR: "jwks-slim" preid: "${{ env.BRANCH }}" skip-tag: "true" skip-push: "true" @@ -70,7 +73,7 @@ jobs: run: | git config user.email "fundabot@fundwave.com" git config user.name "fundabot" - git commit -a -m "CI: bumps websocket-provider to $VERSION" -m "[skip ci]" + git commit -a -m "CI: bumps jwks-slim to $VERSION" -m "[skip ci]" - name: Publish package to npm if: ${{ github.ref_name == 'main'}} From 64a467104e8713bea9e2bcc3023982b394a25163 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Mon, 15 Sep 2025 16:16:53 +0530 Subject: [PATCH 04/49] feat: Add GitHub Actions workflow for releasing and publishing websocket-provider --- .../npm-publish-websocket-provider.yml | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 .github/workflows/npm-publish-websocket-provider.yml diff --git a/.github/workflows/npm-publish-websocket-provider.yml b/.github/workflows/npm-publish-websocket-provider.yml new file mode 100644 index 0000000..bae7390 --- /dev/null +++ b/.github/workflows/npm-publish-websocket-provider.yml @@ -0,0 +1,97 @@ +name: Release and Publish websocket-provider + +on: workflow_dispatch + +env: + BRANCH_TAG: "${{ github.ref_name == 'main' && 'latest' || github.ref_name }}" + BRANCH: ${{ github.ref_name }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + test: + runs-on: ubuntu-latest + defaults: + run: + working-directory: "websocket-provider" + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - name: Install dependencies + run: npm ci + - name: Run tests + run: npm run test + + publish_and_release: + needs: test + name: Publish websocket-provider package + environment: "${{ github.ref_name == 'main' && 'Prod' || 'Dev' }}" + runs-on: ubuntu-latest + defaults: + run: + working-directory: "websocket-provider" + steps: + - name: Generate token + if: ${{ github.ref_name == 'main'}} + id: generate_token + uses: tibdex/github-app-token@v1 + with: + app_id: ${{ vars.FUNDABOT_APP_ID }} + private_key: ${{ secrets.FUNDABOT_PRIVATE_KEY }} + + - uses: actions/setup-node@v3 + with: + node-version: 18 + + - uses: actions/checkout@v3 + with: + token: ${{ github.ref_name == 'main' && steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} + + - name: Version bump + id: version + uses: phips28/gh-action-bump-version@v9.1.0 + with: + major-wording: ${{ env.BRANCH == 'main' && '[bump major]' || '[bump major --force]' }} + minor-wording: ${{ env.BRANCH == 'main' && '[bump minor]' || '[bump minor --force]' }} + patch-wording: ${{ null }} + rc-wording: ${{ null }} + default: "${{ env.BRANCH == 'main' && 'patch' || 'prerelease' }}" + PACKAGEJSON_DIR: "websocket-provider" + preid: "${{ env.BRANCH }}" + skip-tag: "true" + skip-push: "true" + skip-commit: "true" + bump-policy: "ignore" + + - name: Commit changes + env: + VERSION: ${{ steps.version.outputs.newTag }} + run: | + git config user.email "fundabot@fundwave.com" + git config user.name "fundabot" + git commit -a -m "CI: bumps websocket-provider to $VERSION" -m "[skip ci]" + + - name: Publish package to npm + if: ${{ github.ref_name == 'main'}} + run: | + echo //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} > ~/.npmrc + echo registry=https://registry.npmjs.org/ >> ~/.npmrc + npm publish --tag $BRANCH_TAG --access public + env: + NODE_AUTH_TOKEN: ${{secrets.NPMJS_TOKEN}} + + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ env.GITHUB_TOKEN }} + branch: ${{ github.ref }} + + - name: Release + if: ${{ github.ref_name == 'main'}} + env: + VERSION: ${{ steps.version.outputs.newTag }} + run: | + if [ "${BRANCH}" != "main" ]; then PRERELEASE="-p"; fi + echo "Releasing version ${VERSION} on branch ${BRANCH}" + gh release create ${VERSION} --target ${BRANCH} --generate-notes ${PRERELEASE} From 62657b4cf5f7a5eab1b550311680237bf8b8bcb2 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Mon, 15 Sep 2025 16:25:05 +0530 Subject: [PATCH 05/49] fix: Update workflow trigger to push on websocket-provider branch --- .github/workflows/npm-publish-websocket-provider.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish-websocket-provider.yml b/.github/workflows/npm-publish-websocket-provider.yml index bae7390..9edab9b 100644 --- a/.github/workflows/npm-publish-websocket-provider.yml +++ b/.github/workflows/npm-publish-websocket-provider.yml @@ -1,6 +1,8 @@ name: Release and Publish websocket-provider -on: workflow_dispatch +on: + push: + branches: [websocket-provider] env: BRANCH_TAG: "${{ github.ref_name == 'main' && 'latest' || github.ref_name }}" From 6603205d7893718431f9f99de9b3b35f96f683d9 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Mon, 15 Sep 2025 16:28:11 +0530 Subject: [PATCH 06/49] fix: Rename job from 'test' to 'setup' and update dependencies for workflow --- .github/workflows/npm-publish-websocket-provider.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/npm-publish-websocket-provider.yml b/.github/workflows/npm-publish-websocket-provider.yml index 9edab9b..3e70bae 100644 --- a/.github/workflows/npm-publish-websocket-provider.yml +++ b/.github/workflows/npm-publish-websocket-provider.yml @@ -10,7 +10,7 @@ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: - test: + setup: runs-on: ubuntu-latest defaults: run: @@ -22,11 +22,9 @@ jobs: node-version: 18 - name: Install dependencies run: npm ci - - name: Run tests - run: npm run test publish_and_release: - needs: test + needs: setup name: Publish websocket-provider package environment: "${{ github.ref_name == 'main' && 'Prod' || 'Dev' }}" runs-on: ubuntu-latest From 42c7e4367b647fbecd0e0f18a0328f9052334271 Mon Sep 17 00:00:00 2001 From: fundabot Date: Mon, 15 Sep 2025 10:58:50 +0000 Subject: [PATCH 07/49] CI: bumps websocket-provider to 1.0.1-websocket-provider.0 [skip ci] --- websocket-provider/package-lock.json | 4 ++-- websocket-provider/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/websocket-provider/package-lock.json b/websocket-provider/package-lock.json index c4de3b9..81f8e61 100644 --- a/websocket-provider/package-lock.json +++ b/websocket-provider/package-lock.json @@ -1,12 +1,12 @@ { "name": "websocket-provider", - "version": "1.0.0", + "version": "1.0.1-websocket-provider.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "websocket-provider", - "version": "1.0.0", + "version": "1.0.1-websocket-provider.0", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/websocket-provider/package.json b/websocket-provider/package.json index 74b66cc..c9cdd8c 100644 --- a/websocket-provider/package.json +++ b/websocket-provider/package.json @@ -1,6 +1,6 @@ { "name": "websocket-provider", - "version": "1.0.0", + "version": "1.0.1-websocket-provider.0", "main": "dist/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", From 14933751169b84e5dd9518cbd128cf476d09925c Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Mon, 15 Sep 2025 16:40:35 +0530 Subject: [PATCH 08/49] fix: Publish websocket-provider package from feature branches --- .github/workflows/npm-publish-websocket-provider.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/npm-publish-websocket-provider.yml b/.github/workflows/npm-publish-websocket-provider.yml index 3e70bae..584d683 100644 --- a/.github/workflows/npm-publish-websocket-provider.yml +++ b/.github/workflows/npm-publish-websocket-provider.yml @@ -73,11 +73,10 @@ jobs: git commit -a -m "CI: bumps websocket-provider to $VERSION" -m "[skip ci]" - name: Publish package to npm - if: ${{ github.ref_name == 'main'}} run: | echo //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} > ~/.npmrc echo registry=https://registry.npmjs.org/ >> ~/.npmrc - npm publish --tag $BRANCH_TAG --access public + npm run publish -- $VERSION --yes --dist-tag=$BRANCH_TAG --no-push --preid ${{ github.ref_name }} ${{ github.ref_name == 'main' && '' || '--include-merged-tags' }} env: NODE_AUTH_TOKEN: ${{secrets.NPMJS_TOKEN}} From 1c369358520e40bef50c31129bfb26a8c3ca51ec Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Mon, 15 Sep 2025 16:42:19 +0530 Subject: [PATCH 09/49] fix: Correct npm command in publish step of workflow --- .github/workflows/npm-publish-websocket-provider.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish-websocket-provider.yml b/.github/workflows/npm-publish-websocket-provider.yml index 584d683..b0fa6d9 100644 --- a/.github/workflows/npm-publish-websocket-provider.yml +++ b/.github/workflows/npm-publish-websocket-provider.yml @@ -76,7 +76,7 @@ jobs: run: | echo //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} > ~/.npmrc echo registry=https://registry.npmjs.org/ >> ~/.npmrc - npm run publish -- $VERSION --yes --dist-tag=$BRANCH_TAG --no-push --preid ${{ github.ref_name }} ${{ github.ref_name == 'main' && '' || '--include-merged-tags' }} + npm publish -- $VERSION --yes --dist-tag=$BRANCH_TAG --no-push --preid ${{ github.ref_name }} ${{ github.ref_name == 'main' && '' || '--include-merged-tags' }} env: NODE_AUTH_TOKEN: ${{secrets.NPMJS_TOKEN}} From 95ea7e8f7e061b26b269958ceff8a612dc31f499 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Mon, 15 Sep 2025 16:53:04 +0530 Subject: [PATCH 10/49] fix: pass correct flags to npm publish command in publish-websocket workflow --- .github/workflows/npm-publish-websocket-provider.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish-websocket-provider.yml b/.github/workflows/npm-publish-websocket-provider.yml index b0fa6d9..6bb8b98 100644 --- a/.github/workflows/npm-publish-websocket-provider.yml +++ b/.github/workflows/npm-publish-websocket-provider.yml @@ -76,7 +76,7 @@ jobs: run: | echo //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} > ~/.npmrc echo registry=https://registry.npmjs.org/ >> ~/.npmrc - npm publish -- $VERSION --yes --dist-tag=$BRANCH_TAG --no-push --preid ${{ github.ref_name }} ${{ github.ref_name == 'main' && '' || '--include-merged-tags' }} + npm publish --tag $BRANCH_TAG --access public env: NODE_AUTH_TOKEN: ${{secrets.NPMJS_TOKEN}} From 36477e82ac97b16eba85ca9ee30bf59adb46ba95 Mon Sep 17 00:00:00 2001 From: Mohit Garg Date: Tue, 16 Sep 2025 15:59:52 +0530 Subject: [PATCH 11/49] rename to secure-ws --- .talismanrc | 2 + secure-ws/.npmignore | 20 +++++ secure-ws/core/web-socket-provider.ts | 84 +++++++++++++++++++ secure-ws/core/ws-protocol-codec.ts | 16 ++++ secure-ws/index.ts | 2 + secure-ws/mocks/express-response.ts | 39 +++++++++ .../package-lock.json | 47 +++++++---- .../package.json | 6 +- secure-ws/tsconfig.json | 10 +++ secure-ws/types/add-route-params.ts | 7 ++ secure-ws/types/express-middleware.ts | 3 + secure-ws/types/ws-controller.ts | 3 + secure-ws/utils/inject-http-request.ts | 22 +++++ secure-ws/utils/middleware-adapter.ts | 54 ++++++++++++ 14 files changed, 296 insertions(+), 19 deletions(-) create mode 100644 secure-ws/.npmignore create mode 100644 secure-ws/core/web-socket-provider.ts create mode 100644 secure-ws/core/ws-protocol-codec.ts create mode 100644 secure-ws/index.ts create mode 100644 secure-ws/mocks/express-response.ts rename {websocket-provider => secure-ws}/package-lock.json (85%) rename {websocket-provider => secure-ws}/package.json (78%) create mode 100644 secure-ws/tsconfig.json create mode 100644 secure-ws/types/add-route-params.ts create mode 100644 secure-ws/types/express-middleware.ts create mode 100644 secure-ws/types/ws-controller.ts create mode 100644 secure-ws/utils/inject-http-request.ts create mode 100644 secure-ws/utils/middleware-adapter.ts diff --git a/.talismanrc b/.talismanrc index 974ffd9..1d1b710 100644 --- a/.talismanrc +++ b/.talismanrc @@ -15,6 +15,8 @@ fileignoreconfig: checksum: 207c0d07dea4c069883822b2b268d3b34c8b18bdfd645b8aa3b2be20f280c270 - filename: jwks-slim/tests/mock.js checksum: 0d2fd2ec4847acda384c398e04e8aab9a615a8599b0a06d685e7fb100e71537c +- filename: secure-ws/mocks/express-response.ts + checksum: 7774e72616894119c419f7ad86a3da579036b0391fd208766bcdcb96401b8d2c - filename: websocket-provider/package-lock.json checksum: 605a2d92b91f08ee577d3b1e7ed38d27eef43573a044608c22466f05ab6eaff7 threshold: medium diff --git a/secure-ws/.npmignore b/secure-ws/.npmignore new file mode 100644 index 0000000..de53100 --- /dev/null +++ b/secure-ws/.npmignore @@ -0,0 +1,20 @@ +# Exclude TypeScript source files and configs +src/ +*.ts +*.tsx +tsconfig.json +# Exclude node_modules +node_modules/ +# Exclude test files and folders +test/ +*.spec.* +*.test.* +# Exclude build scripts and configs +*.log +*.env +# Exclude editor and OS files +.DS_Store +.vscode/ +.idea/ +# Exclude other common files +coverage/ diff --git a/secure-ws/core/web-socket-provider.ts b/secure-ws/core/web-socket-provider.ts new file mode 100644 index 0000000..985d457 --- /dev/null +++ b/secure-ws/core/web-socket-provider.ts @@ -0,0 +1,84 @@ +import { WebSocketServer, WebSocket as WSWebSocket } from 'ws'; +import { IncomingMessage } from 'http'; +import { Duplex } from 'stream'; +import { decode } from "@msgpack/msgpack"; + +import { WSProtocolCodec } from './ws-protocol-codec'; +import { runExpressMiddleware } from '../utils/middleware-adapter'; +import { injectHttpRequest } from '../utils/inject-http-request'; + +import { WSController } from '../types/ws-controller'; +import { AddRouteParams } from '../types/add-route-params'; + +export class WebSocketProvider { + public server: WebSocketServer; + private routes: Record; + + constructor() { + this.server = new WebSocketServer({ noServer: true }); + this.server.on('connection', this.handleConnection); + this.routes = {}; + } + + public addRoute = ( + path: string, + { + onConnect, + onMessage, + } : AddRouteParams + ) => { + this.routes[path] = { + onConnect, + onMessage + } + } + public handleUpgrade = (request: IncomingMessage, socket: Duplex, head: Buffer) => { + const { pathname } = new URL(request.url!, 'wss://base.url'); + + if (this.routes[pathname]) { + this.server.handleUpgrade(request, socket, head, (ws: any) => { + this.server.emit('connection', ws, request); + }); + } else { + // socket.write('HTTP/1.1 404 Not Found\r\n\r\n'); + socket.end(); + } + }; + + private handleConnection = async (ws: WSWebSocket, request: IncomingMessage) => { + const { pathname } = new URL(request.url!, 'wss://base.url'); + + const httpRequest = WSProtocolCodec.decode(ws.protocol || ''); + const injectedRequest = injectHttpRequest(request, httpRequest); + + if(!this.routes[pathname]) { + ws.close(1000, 'Unknown path'); + return; + } + + const { onConnect, onMessage } = this.routes[pathname]; + + for (const middleware of onConnect) { + const res = await runExpressMiddleware(middleware, injectedRequest, ws); + if (!res.success) { + console.error("Middleware rejected connection:", res.error); + ws.send(JSON.stringify({ error: res.error })); + ws.close(1000, res.error); + return; + } + } + + ws.on('message', this.handleMessage(ws, onMessage)); + ws.send(JSON.stringify({ type: "connection:ack" })); + }; + + private handleMessage = (socket: WSWebSocket, onMessage: WSController[]) => { + return async (message) => { + const request = decode(message) as IncomingMessage; + + for (const controller of onMessage) { + await controller(request, socket); + } + }; + } +} \ No newline at end of file diff --git a/secure-ws/core/ws-protocol-codec.ts b/secure-ws/core/ws-protocol-codec.ts new file mode 100644 index 0000000..c6e9dec --- /dev/null +++ b/secure-ws/core/ws-protocol-codec.ts @@ -0,0 +1,16 @@ +export class WSProtocolCodec { + static encode(data: unknown): string { + const json = JSON.stringify(data); + return btoa(json) + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/, ""); + } + + static decode(encoded: string): T { + let str = encoded.replace(/-/g, "+").replace(/_/g, "/"); + while (str.length % 4) str += "="; + const json = atob(str); + return JSON.parse(json) as T; + } +} diff --git a/secure-ws/index.ts b/secure-ws/index.ts new file mode 100644 index 0000000..800b0de --- /dev/null +++ b/secure-ws/index.ts @@ -0,0 +1,2 @@ +export * from './core/web-socket-provider'; +export * from './core/ws-protocol-codec'; \ No newline at end of file diff --git a/secure-ws/mocks/express-response.ts b/secure-ws/mocks/express-response.ts new file mode 100644 index 0000000..959f2f4 --- /dev/null +++ b/secure-ws/mocks/express-response.ts @@ -0,0 +1,39 @@ +import { WebSocket } from "ws"; + +export class MockResponse { + private socket: WebSocket; + public statusCode: number = 200; + + constructor(socket: WebSocket) { + this.socket = socket; + } + + status(code: number) { + this.statusCode = code; + return this; + } + + send(data) { + this.socket.send(`HTTP/1.1 ${this.statusCode} ${this.getStatusText()}\r\n\r\n`); + this.socket.close(); + return this; + } + + sendStatus(code: number) { + this.statusCode = code; + this.socket.send(`HTTP/1.1 ${code} ${this.getStatusText()}\r\n\r\n`); + this.socket.close(); + return this; + } + + private getStatusText(): string { + const statusTexts: { [key: number]: string } = { + 200: 'OK', + 401: 'Unauthorized', + 403: 'Forbidden', + 404: 'Not Found', + 500: 'Internal Server Error' + }; + return statusTexts[this.statusCode] || 'Unknown'; + } +}; \ No newline at end of file diff --git a/websocket-provider/package-lock.json b/secure-ws/package-lock.json similarity index 85% rename from websocket-provider/package-lock.json rename to secure-ws/package-lock.json index 81f8e61..5f1dc11 100644 --- a/websocket-provider/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { - "name": "websocket-provider", - "version": "1.0.1-websocket-provider.0", + "name": "secure-ws", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "websocket-provider", - "version": "1.0.1-websocket-provider.0", + "name": "secure-ws", + "version": "0.0.1", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", @@ -21,6 +21,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.1.2.tgz", "integrity": "sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==", + "license": "ISC", "engines": { "node": ">= 18" } @@ -30,6 +31,7 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -40,6 +42,7 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -49,6 +52,7 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", @@ -60,6 +64,7 @@ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz", "integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -71,40 +76,46 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "24.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", - "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.0.tgz", + "integrity": "sha512-y1dMvuvJspJiPSDZUQ+WMBvF7dpnEqN4x9DDC9ie5Fs/HUZJA3wFp7EhHoVaKX/iI0cRoECV8X2jL8zi0xrHCg==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~7.10.0" + "undici-types": "~7.12.0" } }, "node_modules/@types/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/send": { "version": "0.17.5", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", "dev": true, + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -115,6 +126,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -126,20 +138,23 @@ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", - "dev": true + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", + "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", + "dev": true, + "license": "MIT" }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, diff --git a/websocket-provider/package.json b/secure-ws/package.json similarity index 78% rename from websocket-provider/package.json rename to secure-ws/package.json index c9cdd8c..1c58ed2 100644 --- a/websocket-provider/package.json +++ b/secure-ws/package.json @@ -1,12 +1,12 @@ { - "name": "websocket-provider", - "version": "1.0.1-websocket-provider.0", + "name": "secure-ws", + "version": "0.0.1", "main": "dist/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "tsc" }, - "author": "", + "author": "The Fundwave Authors", "license": "ISC", "description": "", "devDependencies": { diff --git a/secure-ws/tsconfig.json b/secure-ws/tsconfig.json new file mode 100644 index 0000000..17b7552 --- /dev/null +++ b/secure-ws/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "outDir": "./dist", + } +} diff --git a/secure-ws/types/add-route-params.ts b/secure-ws/types/add-route-params.ts new file mode 100644 index 0000000..fa07c52 --- /dev/null +++ b/secure-ws/types/add-route-params.ts @@ -0,0 +1,7 @@ +import { ExpressMiddleware } from "./express-middleware"; +import { WSController } from "./ws-controller"; + +export type AddRouteParams = { + onConnect: ExpressMiddleware[], + onMessage: WSController[], + } \ No newline at end of file diff --git a/secure-ws/types/express-middleware.ts b/secure-ws/types/express-middleware.ts new file mode 100644 index 0000000..ca8875a --- /dev/null +++ b/secure-ws/types/express-middleware.ts @@ -0,0 +1,3 @@ +import { Request, Response, NextFunction } from 'express'; + +export type ExpressMiddleware = (req: Request, res: Response, next: NextFunction) => any; \ No newline at end of file diff --git a/secure-ws/types/ws-controller.ts b/secure-ws/types/ws-controller.ts new file mode 100644 index 0000000..1b86c85 --- /dev/null +++ b/secure-ws/types/ws-controller.ts @@ -0,0 +1,3 @@ +import { WebSocket } from 'ws'; + +export type WSController = (message: any, socket: WebSocket) => any; \ No newline at end of file diff --git a/secure-ws/utils/inject-http-request.ts b/secure-ws/utils/inject-http-request.ts new file mode 100644 index 0000000..9f8944e --- /dev/null +++ b/secure-ws/utils/inject-http-request.ts @@ -0,0 +1,22 @@ +import { IncomingMessage } from "http"; + +type HttpRequest = { + headers?: Record; + body?: unknown; +}; + +export function injectHttpRequest(request: IncomingMessage, httpRequest: HttpRequest) { + // Merge headers + if (httpRequest.headers) { + for (const [key, value] of Object.entries(httpRequest.headers)) { + request.headers[key.toLowerCase()] = value; + } + } + + // Attach body as a custom property + if (httpRequest.body) { + (request as any).body = httpRequest.body; + } + + return request; +} diff --git a/secure-ws/utils/middleware-adapter.ts b/secure-ws/utils/middleware-adapter.ts new file mode 100644 index 0000000..885756c --- /dev/null +++ b/secure-ws/utils/middleware-adapter.ts @@ -0,0 +1,54 @@ +import { IncomingMessage } from 'http'; +import { WebSocket } from 'ws'; +import { MockResponse } from '../mocks/express-response'; + +export function runExpressMiddleware( + middleware: (req, res, next) => void, + request: IncomingMessage, + socket: WebSocket +): Promise<{ success: boolean; error?: string }> { + return new Promise((resolve) => { + const mockRes = new MockResponse(socket); + let nextCalled = false; + + const next = (error) => { + if (nextCalled) return; + nextCalled = true; + + if (error) { + resolve({ success: false, error: error.message || 'Middleware error' }); + } else { + resolve({ success: true }); + } + }; + + const originalSend = mockRes.send.bind(mockRes); + const originalSendStatus = mockRes.sendStatus.bind(mockRes); + + mockRes.send = (data) => { + if (!nextCalled) { + nextCalled = true; + resolve({ success: false, error: `HTTP ${mockRes.statusCode}` }); + } + return mockRes; + }; + + mockRes.sendStatus = (code: number) => { + if (!nextCalled) { + nextCalled = true; + resolve({ success: false, error: `HTTP ${code}` }); + } + return mockRes; + }; + + try { + middleware(request, mockRes, next); + } catch (error) { + console.error("Middleware exception:", error); + if (!nextCalled) { + nextCalled = true; + resolve({ success: false, error: error.message || 'Middleware exception' }); + } + } + }); +} \ No newline at end of file From 6ff441ed49129f7d788e6bbe49a7fa99ce2e1bfb Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Tue, 16 Sep 2025 16:08:03 +0530 Subject: [PATCH 12/49] refactor: remove duplicate websocket-provider and related files --- websocket-provider/.npmignore | 20 ----- .../core/web-socket-provider.ts | 84 ------------------- websocket-provider/core/ws-protocol-codec.ts | 16 ---- websocket-provider/index.ts | 2 - websocket-provider/mocks/express-response.ts | 39 --------- websocket-provider/tsconfig.json | 10 --- websocket-provider/types/add-route-params.ts | 7 -- .../types/express-middleware.ts | 3 - websocket-provider/types/ws-controller.ts | 3 - .../utils/inject-http-request.ts | 22 ----- .../utils/middleware-adapter.ts | 54 ------------ 11 files changed, 260 deletions(-) delete mode 100644 websocket-provider/.npmignore delete mode 100644 websocket-provider/core/web-socket-provider.ts delete mode 100644 websocket-provider/core/ws-protocol-codec.ts delete mode 100644 websocket-provider/index.ts delete mode 100644 websocket-provider/mocks/express-response.ts delete mode 100644 websocket-provider/tsconfig.json delete mode 100644 websocket-provider/types/add-route-params.ts delete mode 100644 websocket-provider/types/express-middleware.ts delete mode 100644 websocket-provider/types/ws-controller.ts delete mode 100644 websocket-provider/utils/inject-http-request.ts delete mode 100644 websocket-provider/utils/middleware-adapter.ts diff --git a/websocket-provider/.npmignore b/websocket-provider/.npmignore deleted file mode 100644 index de53100..0000000 --- a/websocket-provider/.npmignore +++ /dev/null @@ -1,20 +0,0 @@ -# Exclude TypeScript source files and configs -src/ -*.ts -*.tsx -tsconfig.json -# Exclude node_modules -node_modules/ -# Exclude test files and folders -test/ -*.spec.* -*.test.* -# Exclude build scripts and configs -*.log -*.env -# Exclude editor and OS files -.DS_Store -.vscode/ -.idea/ -# Exclude other common files -coverage/ diff --git a/websocket-provider/core/web-socket-provider.ts b/websocket-provider/core/web-socket-provider.ts deleted file mode 100644 index 985d457..0000000 --- a/websocket-provider/core/web-socket-provider.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { WebSocketServer, WebSocket as WSWebSocket } from 'ws'; -import { IncomingMessage } from 'http'; -import { Duplex } from 'stream'; -import { decode } from "@msgpack/msgpack"; - -import { WSProtocolCodec } from './ws-protocol-codec'; -import { runExpressMiddleware } from '../utils/middleware-adapter'; -import { injectHttpRequest } from '../utils/inject-http-request'; - -import { WSController } from '../types/ws-controller'; -import { AddRouteParams } from '../types/add-route-params'; - -export class WebSocketProvider { - public server: WebSocketServer; - private routes: Record; - - constructor() { - this.server = new WebSocketServer({ noServer: true }); - this.server.on('connection', this.handleConnection); - this.routes = {}; - } - - public addRoute = ( - path: string, - { - onConnect, - onMessage, - } : AddRouteParams - ) => { - this.routes[path] = { - onConnect, - onMessage - } - } - public handleUpgrade = (request: IncomingMessage, socket: Duplex, head: Buffer) => { - const { pathname } = new URL(request.url!, 'wss://base.url'); - - if (this.routes[pathname]) { - this.server.handleUpgrade(request, socket, head, (ws: any) => { - this.server.emit('connection', ws, request); - }); - } else { - // socket.write('HTTP/1.1 404 Not Found\r\n\r\n'); - socket.end(); - } - }; - - private handleConnection = async (ws: WSWebSocket, request: IncomingMessage) => { - const { pathname } = new URL(request.url!, 'wss://base.url'); - - const httpRequest = WSProtocolCodec.decode(ws.protocol || ''); - const injectedRequest = injectHttpRequest(request, httpRequest); - - if(!this.routes[pathname]) { - ws.close(1000, 'Unknown path'); - return; - } - - const { onConnect, onMessage } = this.routes[pathname]; - - for (const middleware of onConnect) { - const res = await runExpressMiddleware(middleware, injectedRequest, ws); - if (!res.success) { - console.error("Middleware rejected connection:", res.error); - ws.send(JSON.stringify({ error: res.error })); - ws.close(1000, res.error); - return; - } - } - - ws.on('message', this.handleMessage(ws, onMessage)); - ws.send(JSON.stringify({ type: "connection:ack" })); - }; - - private handleMessage = (socket: WSWebSocket, onMessage: WSController[]) => { - return async (message) => { - const request = decode(message) as IncomingMessage; - - for (const controller of onMessage) { - await controller(request, socket); - } - }; - } -} \ No newline at end of file diff --git a/websocket-provider/core/ws-protocol-codec.ts b/websocket-provider/core/ws-protocol-codec.ts deleted file mode 100644 index c6e9dec..0000000 --- a/websocket-provider/core/ws-protocol-codec.ts +++ /dev/null @@ -1,16 +0,0 @@ -export class WSProtocolCodec { - static encode(data: unknown): string { - const json = JSON.stringify(data); - return btoa(json) - .replace(/\+/g, "-") - .replace(/\//g, "_") - .replace(/=+$/, ""); - } - - static decode(encoded: string): T { - let str = encoded.replace(/-/g, "+").replace(/_/g, "/"); - while (str.length % 4) str += "="; - const json = atob(str); - return JSON.parse(json) as T; - } -} diff --git a/websocket-provider/index.ts b/websocket-provider/index.ts deleted file mode 100644 index 800b0de..0000000 --- a/websocket-provider/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './core/web-socket-provider'; -export * from './core/ws-protocol-codec'; \ No newline at end of file diff --git a/websocket-provider/mocks/express-response.ts b/websocket-provider/mocks/express-response.ts deleted file mode 100644 index 959f2f4..0000000 --- a/websocket-provider/mocks/express-response.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { WebSocket } from "ws"; - -export class MockResponse { - private socket: WebSocket; - public statusCode: number = 200; - - constructor(socket: WebSocket) { - this.socket = socket; - } - - status(code: number) { - this.statusCode = code; - return this; - } - - send(data) { - this.socket.send(`HTTP/1.1 ${this.statusCode} ${this.getStatusText()}\r\n\r\n`); - this.socket.close(); - return this; - } - - sendStatus(code: number) { - this.statusCode = code; - this.socket.send(`HTTP/1.1 ${code} ${this.getStatusText()}\r\n\r\n`); - this.socket.close(); - return this; - } - - private getStatusText(): string { - const statusTexts: { [key: number]: string } = { - 200: 'OK', - 401: 'Unauthorized', - 403: 'Forbidden', - 404: 'Not Found', - 500: 'Internal Server Error' - }; - return statusTexts[this.statusCode] || 'Unknown'; - } -}; \ No newline at end of file diff --git a/websocket-provider/tsconfig.json b/websocket-provider/tsconfig.json deleted file mode 100644 index 17b7552..0000000 --- a/websocket-provider/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "es2016", - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "outDir": "./dist", - } -} diff --git a/websocket-provider/types/add-route-params.ts b/websocket-provider/types/add-route-params.ts deleted file mode 100644 index fa07c52..0000000 --- a/websocket-provider/types/add-route-params.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ExpressMiddleware } from "./express-middleware"; -import { WSController } from "./ws-controller"; - -export type AddRouteParams = { - onConnect: ExpressMiddleware[], - onMessage: WSController[], - } \ No newline at end of file diff --git a/websocket-provider/types/express-middleware.ts b/websocket-provider/types/express-middleware.ts deleted file mode 100644 index ca8875a..0000000 --- a/websocket-provider/types/express-middleware.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Request, Response, NextFunction } from 'express'; - -export type ExpressMiddleware = (req: Request, res: Response, next: NextFunction) => any; \ No newline at end of file diff --git a/websocket-provider/types/ws-controller.ts b/websocket-provider/types/ws-controller.ts deleted file mode 100644 index 1b86c85..0000000 --- a/websocket-provider/types/ws-controller.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { WebSocket } from 'ws'; - -export type WSController = (message: any, socket: WebSocket) => any; \ No newline at end of file diff --git a/websocket-provider/utils/inject-http-request.ts b/websocket-provider/utils/inject-http-request.ts deleted file mode 100644 index 9f8944e..0000000 --- a/websocket-provider/utils/inject-http-request.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { IncomingMessage } from "http"; - -type HttpRequest = { - headers?: Record; - body?: unknown; -}; - -export function injectHttpRequest(request: IncomingMessage, httpRequest: HttpRequest) { - // Merge headers - if (httpRequest.headers) { - for (const [key, value] of Object.entries(httpRequest.headers)) { - request.headers[key.toLowerCase()] = value; - } - } - - // Attach body as a custom property - if (httpRequest.body) { - (request as any).body = httpRequest.body; - } - - return request; -} diff --git a/websocket-provider/utils/middleware-adapter.ts b/websocket-provider/utils/middleware-adapter.ts deleted file mode 100644 index 885756c..0000000 --- a/websocket-provider/utils/middleware-adapter.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { IncomingMessage } from 'http'; -import { WebSocket } from 'ws'; -import { MockResponse } from '../mocks/express-response'; - -export function runExpressMiddleware( - middleware: (req, res, next) => void, - request: IncomingMessage, - socket: WebSocket -): Promise<{ success: boolean; error?: string }> { - return new Promise((resolve) => { - const mockRes = new MockResponse(socket); - let nextCalled = false; - - const next = (error) => { - if (nextCalled) return; - nextCalled = true; - - if (error) { - resolve({ success: false, error: error.message || 'Middleware error' }); - } else { - resolve({ success: true }); - } - }; - - const originalSend = mockRes.send.bind(mockRes); - const originalSendStatus = mockRes.sendStatus.bind(mockRes); - - mockRes.send = (data) => { - if (!nextCalled) { - nextCalled = true; - resolve({ success: false, error: `HTTP ${mockRes.statusCode}` }); - } - return mockRes; - }; - - mockRes.sendStatus = (code: number) => { - if (!nextCalled) { - nextCalled = true; - resolve({ success: false, error: `HTTP ${code}` }); - } - return mockRes; - }; - - try { - middleware(request, mockRes, next); - } catch (error) { - console.error("Middleware exception:", error); - if (!nextCalled) { - nextCalled = true; - resolve({ success: false, error: error.message || 'Middleware exception' }); - } - } - }); -} \ No newline at end of file From 421f059b293f4698978ad4ad963a46918175ea8b Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Tue, 16 Sep 2025 16:08:54 +0530 Subject: [PATCH 13/49] refactor: websocket-provider -> secure-ws in GitHub Actions workflow --- ...socket-provider.yml => npm-publish-secure-ws.yml} | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename .github/workflows/{npm-publish-websocket-provider.yml => npm-publish-secure-ws.yml} (89%) diff --git a/.github/workflows/npm-publish-websocket-provider.yml b/.github/workflows/npm-publish-secure-ws.yml similarity index 89% rename from .github/workflows/npm-publish-websocket-provider.yml rename to .github/workflows/npm-publish-secure-ws.yml index 6bb8b98..65e9131 100644 --- a/.github/workflows/npm-publish-websocket-provider.yml +++ b/.github/workflows/npm-publish-secure-ws.yml @@ -1,4 +1,4 @@ -name: Release and Publish websocket-provider +name: Release and Publish secure-ws on: push: @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: "websocket-provider" + working-directory: "secure-ws" steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 @@ -25,12 +25,12 @@ jobs: publish_and_release: needs: setup - name: Publish websocket-provider package + name: Publish secure-ws package environment: "${{ github.ref_name == 'main' && 'Prod' || 'Dev' }}" runs-on: ubuntu-latest defaults: run: - working-directory: "websocket-provider" + working-directory: "secure-ws" steps: - name: Generate token if: ${{ github.ref_name == 'main'}} @@ -57,7 +57,7 @@ jobs: patch-wording: ${{ null }} rc-wording: ${{ null }} default: "${{ env.BRANCH == 'main' && 'patch' || 'prerelease' }}" - PACKAGEJSON_DIR: "websocket-provider" + PACKAGEJSON_DIR: "secure-ws" preid: "${{ env.BRANCH }}" skip-tag: "true" skip-push: "true" @@ -70,7 +70,7 @@ jobs: run: | git config user.email "fundabot@fundwave.com" git config user.name "fundabot" - git commit -a -m "CI: bumps websocket-provider to $VERSION" -m "[skip ci]" + git commit -a -m "CI: bumps secure-ws to $VERSION" -m "[skip ci]" - name: Publish package to npm run: | From 0958ebb98f0eaa9a9b9157b74d17a5ed94949456 Mon Sep 17 00:00:00 2001 From: fundabot Date: Tue, 16 Sep 2025 10:39:34 +0000 Subject: [PATCH 14/49] CI: bumps secure-ws to 0.0.2-websocket-provider.0 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index 5f1dc11..1f7cfac 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.1", + "version": "0.0.2-websocket-provider.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.1", + "version": "0.0.2-websocket-provider.0", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index 1c58ed2..f6c7c2c 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.1", + "version": "0.0.2-websocket-provider.0", "main": "dist/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", From 4a5939f2bde72318dc61cfe2e7a42586c9191a49 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Tue, 16 Sep 2025 16:20:31 +0530 Subject: [PATCH 15/49] fix: add build step before publishing secure-ws package --- .github/workflows/npm-publish-secure-ws.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/npm-publish-secure-ws.yml b/.github/workflows/npm-publish-secure-ws.yml index 65e9131..7a97fed 100644 --- a/.github/workflows/npm-publish-secure-ws.yml +++ b/.github/workflows/npm-publish-secure-ws.yml @@ -10,7 +10,7 @@ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: - setup: + build: runs-on: ubuntu-latest defaults: run: @@ -22,9 +22,11 @@ jobs: node-version: 18 - name: Install dependencies run: npm ci + - name: Build + run: npm run build publish_and_release: - needs: setup + needs: build name: Publish secure-ws package environment: "${{ github.ref_name == 'main' && 'Prod' || 'Dev' }}" runs-on: ubuntu-latest From 024f82a91066885370b2db00dd628cb43710d283 Mon Sep 17 00:00:00 2001 From: fundabot Date: Tue, 16 Sep 2025 10:51:36 +0000 Subject: [PATCH 16/49] CI: bumps secure-ws to 0.0.2-websocket-provider.1 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index 1f7cfac..417ee0a 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.0", + "version": "0.0.2-websocket-provider.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.0", + "version": "0.0.2-websocket-provider.1", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index f6c7c2c..bda5936 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.0", + "version": "0.0.2-websocket-provider.1", "main": "dist/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", From f0f16c7e40d1ffdacb03b63a048f9efeeaa43f4f Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Tue, 16 Sep 2025 16:32:00 +0530 Subject: [PATCH 17/49] fix: add missing files entry in package.json --- secure-ws/package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/secure-ws/package.json b/secure-ws/package.json index bda5936..3c7e7f3 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -16,5 +16,9 @@ "dependencies": { "@msgpack/msgpack": "^3.1.2", "ws": "^8.18.3" - } + }, + "files": [ + "dist", + "README.md" + ] } From ee8cf47871d88581f3ba60aa3a5225a5149c5c50 Mon Sep 17 00:00:00 2001 From: fundabot Date: Tue, 16 Sep 2025 11:03:03 +0000 Subject: [PATCH 18/49] CI: bumps secure-ws to 0.0.2-websocket-provider.2 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index 417ee0a..7873bcc 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.1", + "version": "0.0.2-websocket-provider.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.1", + "version": "0.0.2-websocket-provider.2", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index 3c7e7f3..e0882b5 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.1", + "version": "0.0.2-websocket-provider.2", "main": "dist/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", From f30b8c3a9b52232e23677d4024700818a596c28a Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Tue, 16 Sep 2025 16:50:39 +0530 Subject: [PATCH 19/49] Temp: log dir structure after build --- .github/workflows/npm-publish-secure-ws.yml | 28 ++------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/.github/workflows/npm-publish-secure-ws.yml b/.github/workflows/npm-publish-secure-ws.yml index 7a97fed..908ec35 100644 --- a/.github/workflows/npm-publish-secure-ws.yml +++ b/.github/workflows/npm-publish-secure-ws.yml @@ -66,33 +66,9 @@ jobs: skip-commit: "true" bump-policy: "ignore" - - name: Commit changes - env: - VERSION: ${{ steps.version.outputs.newTag }} - run: | - git config user.email "fundabot@fundwave.com" - git config user.name "fundabot" - git commit -a -m "CI: bumps secure-ws to $VERSION" -m "[skip ci]" - - name: Publish package to npm run: | - echo //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} > ~/.npmrc - echo registry=https://registry.npmjs.org/ >> ~/.npmrc - npm publish --tag $BRANCH_TAG --access public + ls -la + ls -la dist env: NODE_AUTH_TOKEN: ${{secrets.NPMJS_TOKEN}} - - - name: Push changes - uses: ad-m/github-push-action@master - with: - github_token: ${{ env.GITHUB_TOKEN }} - branch: ${{ github.ref }} - - - name: Release - if: ${{ github.ref_name == 'main'}} - env: - VERSION: ${{ steps.version.outputs.newTag }} - run: | - if [ "${BRANCH}" != "main" ]; then PRERELEASE="-p"; fi - echo "Releasing version ${VERSION} on branch ${BRANCH}" - gh release create ${VERSION} --target ${BRANCH} --generate-notes ${PRERELEASE} From 7bf514d2cd00dd0f2fa5626e8dd9ca21509cc723 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Tue, 16 Sep 2025 16:52:10 +0530 Subject: [PATCH 20/49] Revert "Temp: log dir structure after build" This reverts commit f30b8c3a9b52232e23677d4024700818a596c28a. --- .github/workflows/npm-publish-secure-ws.yml | 28 +++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/.github/workflows/npm-publish-secure-ws.yml b/.github/workflows/npm-publish-secure-ws.yml index 908ec35..7a97fed 100644 --- a/.github/workflows/npm-publish-secure-ws.yml +++ b/.github/workflows/npm-publish-secure-ws.yml @@ -66,9 +66,33 @@ jobs: skip-commit: "true" bump-policy: "ignore" + - name: Commit changes + env: + VERSION: ${{ steps.version.outputs.newTag }} + run: | + git config user.email "fundabot@fundwave.com" + git config user.name "fundabot" + git commit -a -m "CI: bumps secure-ws to $VERSION" -m "[skip ci]" + - name: Publish package to npm run: | - ls -la - ls -la dist + echo //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} > ~/.npmrc + echo registry=https://registry.npmjs.org/ >> ~/.npmrc + npm publish --tag $BRANCH_TAG --access public env: NODE_AUTH_TOKEN: ${{secrets.NPMJS_TOKEN}} + + - name: Push changes + uses: ad-m/github-push-action@master + with: + github_token: ${{ env.GITHUB_TOKEN }} + branch: ${{ github.ref }} + + - name: Release + if: ${{ github.ref_name == 'main'}} + env: + VERSION: ${{ steps.version.outputs.newTag }} + run: | + if [ "${BRANCH}" != "main" ]; then PRERELEASE="-p"; fi + echo "Releasing version ${VERSION} on branch ${BRANCH}" + gh release create ${VERSION} --target ${BRANCH} --generate-notes ${PRERELEASE} From c32a8793b5b602c57e3170ee732bccd1870bd199 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Tue, 16 Sep 2025 16:57:05 +0530 Subject: [PATCH 21/49] fix: remove build job and add it as a step in publish_and_release --- .github/workflows/npm-publish-secure-ws.yml | 24 ++++++--------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/.github/workflows/npm-publish-secure-ws.yml b/.github/workflows/npm-publish-secure-ws.yml index 7a97fed..6daf626 100644 --- a/.github/workflows/npm-publish-secure-ws.yml +++ b/.github/workflows/npm-publish-secure-ws.yml @@ -9,24 +9,8 @@ env: BRANCH: ${{ github.ref_name }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -jobs: - build: - runs-on: ubuntu-latest - defaults: - run: - working-directory: "secure-ws" - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Install dependencies - run: npm ci - - name: Build - run: npm run build - +jobs: publish_and_release: - needs: build name: Publish secure-ws package environment: "${{ github.ref_name == 'main' && 'Prod' || 'Dev' }}" runs-on: ubuntu-latest @@ -49,6 +33,12 @@ jobs: - uses: actions/checkout@v3 with: token: ${{ github.ref_name == 'main' && steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }} + + - name: Install dependencies + run: npm ci + + - name: Build + run: npm run build - name: Version bump id: version From 644d1389627aabb457298fe38594cfeec72dd43a Mon Sep 17 00:00:00 2001 From: fundabot Date: Tue, 16 Sep 2025 11:27:44 +0000 Subject: [PATCH 22/49] CI: bumps secure-ws to 0.0.2-websocket-provider.3 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index 7873bcc..cf7a5d4 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.2", + "version": "0.0.2-websocket-provider.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.2", + "version": "0.0.2-websocket-provider.3", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index e0882b5..4f0d9bd 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.2", + "version": "0.0.2-websocket-provider.3", "main": "dist/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", From 568f2a9dd891a24d7dfee3718a3d8c0c57084e00 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Tue, 16 Sep 2025 17:10:30 +0530 Subject: [PATCH 23/49] fix: add missing types and declaration options in package.json and tsconfig.json --- secure-ws/package.json | 1 + secure-ws/tsconfig.json | 1 + 2 files changed, 2 insertions(+) diff --git a/secure-ws/package.json b/secure-ws/package.json index 4f0d9bd..cf66ea4 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -2,6 +2,7 @@ "name": "secure-ws", "version": "0.0.2-websocket-provider.3", "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "tsc" diff --git a/secure-ws/tsconfig.json b/secure-ws/tsconfig.json index 17b7552..922c07a 100644 --- a/secure-ws/tsconfig.json +++ b/secure-ws/tsconfig.json @@ -5,6 +5,7 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, + "declaration": true, "outDir": "./dist", } } From 37d83d925d70cb7482f3dadc2bf5b78b4621b98e Mon Sep 17 00:00:00 2001 From: fundabot Date: Tue, 16 Sep 2025 11:41:14 +0000 Subject: [PATCH 24/49] CI: bumps secure-ws to 0.0.2-websocket-provider.4 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index cf7a5d4..867e387 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.3", + "version": "0.0.2-websocket-provider.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.3", + "version": "0.0.2-websocket-provider.4", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index cf66ea4..ada21e8 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.3", + "version": "0.0.2-websocket-provider.4", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From 585699258164484715625e9219f986ce55292546 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 11:18:05 +0530 Subject: [PATCH 25/49] fix: update workflow trigger to use paths instead of branches for secure-ws --- .github/workflows/npm-publish-secure-ws.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/npm-publish-secure-ws.yml b/.github/workflows/npm-publish-secure-ws.yml index 6daf626..b00a029 100644 --- a/.github/workflows/npm-publish-secure-ws.yml +++ b/.github/workflows/npm-publish-secure-ws.yml @@ -2,7 +2,8 @@ name: Release and Publish secure-ws on: push: - branches: [websocket-provider] + paths: + - "secure-ws/**" env: BRANCH_TAG: "${{ github.ref_name == 'main' && 'latest' || github.ref_name }}" From a5b60c5be2c93b799d8b4b0d2293003dcbfa4bec Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 11:18:24 +0530 Subject: [PATCH 26/49] add: README.md for secure-ws --- secure-ws/README.md | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 secure-ws/README.md diff --git a/secure-ws/README.md b/secure-ws/README.md new file mode 100644 index 0000000..91fca4e --- /dev/null +++ b/secure-ws/README.md @@ -0,0 +1,46 @@ +# secure-ws + +secure-ws is a TypeScript library for secure WebSocket servers that lets you run Express-style middleware during the upgrade handshake, ensuring unauthenticated connections are never left open. + +## Why use secure-ws + +- Run middleware during the WebSocket upgrade handshake +- Reuse Express Middlewares for authentication, validation and more +- Abstract away connection, upgrade, and messaging with Express-style routes, middleware, and controllers. + +## Installation + +``` +npm install --save secure-ws +``` + +## Usage + +```typescript +import express from "express"; +import { WebSocketProvider } from 'websocket-provider'; + +const wsApp = new WebSocketProvider(); +const app = express(); + +// app.get... +// app.post... + +wsApp.addRoute( + "/extract/metrics", + { + onConnect: [authMiddleware1, authMiddleware2], + onMessage: [controller] + } +); + +const httpServer = app.listen(PORT, () => { + console.info(`File service running at http://localhost:${PORT}`); +}); + +httpServer.on('upgrade', wsApp.handleUpgrade); +``` + +## License + +MIT From d26c68fe524ef4b29daf356d34d6b016cadecb22 Mon Sep 17 00:00:00 2001 From: fundabot Date: Wed, 17 Sep 2025 05:49:13 +0000 Subject: [PATCH 27/49] CI: bumps secure-ws to 0.0.2-websocket-provider.5 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index 867e387..f978b26 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.4", + "version": "0.0.2-websocket-provider.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.4", + "version": "0.0.2-websocket-provider.5", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index ada21e8..e6439a1 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.4", + "version": "0.0.2-websocket-provider.5", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From c8d6dbbbe574c09afaf3f77413fcd68dbedd1f8d Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 11:21:06 +0530 Subject: [PATCH 28/49] fix: correct import path for WebSocketProvider in README.md --- secure-ws/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/secure-ws/README.md b/secure-ws/README.md index 91fca4e..491b393 100644 --- a/secure-ws/README.md +++ b/secure-ws/README.md @@ -18,7 +18,7 @@ npm install --save secure-ws ```typescript import express from "express"; -import { WebSocketProvider } from 'websocket-provider'; +import { WebSocketProvider } from 'secure-ws'; const wsApp = new WebSocketProvider(); const app = express(); @@ -35,7 +35,7 @@ wsApp.addRoute( ); const httpServer = app.listen(PORT, () => { - console.info(`File service running at http://localhost:${PORT}`); + console.info(`Service running at port: ${PORT}`); }); httpServer.on('upgrade', wsApp.handleUpgrade); From ec03b63e37c46361495a971620195876703a7c61 Mon Sep 17 00:00:00 2001 From: fundabot Date: Wed, 17 Sep 2025 05:51:45 +0000 Subject: [PATCH 29/49] CI: bumps secure-ws to 0.0.2-websocket-provider.6 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index f978b26..b70c08b 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.5", + "version": "0.0.2-websocket-provider.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.5", + "version": "0.0.2-websocket-provider.6", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index e6439a1..3d80f13 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.5", + "version": "0.0.2-websocket-provider.6", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From e84a2010ac550720f07ec6d5bfef9288d5234e51 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 11:59:41 +0530 Subject: [PATCH 30/49] fix: replace btoa and atob with Buffer for base64 encoding and decoding --- secure-ws/core/ws-protocol-codec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/secure-ws/core/ws-protocol-codec.ts b/secure-ws/core/ws-protocol-codec.ts index c6e9dec..c710dcb 100644 --- a/secure-ws/core/ws-protocol-codec.ts +++ b/secure-ws/core/ws-protocol-codec.ts @@ -1,7 +1,7 @@ export class WSProtocolCodec { static encode(data: unknown): string { const json = JSON.stringify(data); - return btoa(json) + return Buffer.from(json).toString('base64') .replace(/\+/g, "-") .replace(/\//g, "_") .replace(/=+$/, ""); @@ -10,7 +10,7 @@ export class WSProtocolCodec { static decode(encoded: string): T { let str = encoded.replace(/-/g, "+").replace(/_/g, "/"); while (str.length % 4) str += "="; - const json = atob(str); + const json = Buffer.from(str, 'base64').toString(); return JSON.parse(json) as T; } } From 5f60b3317379db2a0a8012b11090ce52635b4aef Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 12:35:06 +0530 Subject: [PATCH 31/49] fix: implement MockResponse interface and update middleware type definitions --- secure-ws/mocks/express-response.ts | 3 ++- secure-ws/types/add-route-params.ts | 6 +++--- secure-ws/types/mock-response.ts | 6 ++++++ secure-ws/utils/middleware-adapter.ts | 27 +++++---------------------- 4 files changed, 16 insertions(+), 26 deletions(-) create mode 100644 secure-ws/types/mock-response.ts diff --git a/secure-ws/mocks/express-response.ts b/secure-ws/mocks/express-response.ts index 959f2f4..e7da8ea 100644 --- a/secure-ws/mocks/express-response.ts +++ b/secure-ws/mocks/express-response.ts @@ -1,6 +1,7 @@ import { WebSocket } from "ws"; +import { MockResponse as MockResponseType } from "../types/mock-response"; -export class MockResponse { +export class MockResponse implements MockResponseType { private socket: WebSocket; public statusCode: number = 200; diff --git a/secure-ws/types/add-route-params.ts b/secure-ws/types/add-route-params.ts index fa07c52..0359b8e 100644 --- a/secure-ws/types/add-route-params.ts +++ b/secure-ws/types/add-route-params.ts @@ -2,6 +2,6 @@ import { ExpressMiddleware } from "./express-middleware"; import { WSController } from "./ws-controller"; export type AddRouteParams = { - onConnect: ExpressMiddleware[], - onMessage: WSController[], - } \ No newline at end of file + onConnect: ExpressMiddleware[], + onMessage: WSController[], +} \ No newline at end of file diff --git a/secure-ws/types/mock-response.ts b/secure-ws/types/mock-response.ts new file mode 100644 index 0000000..22fbabc --- /dev/null +++ b/secure-ws/types/mock-response.ts @@ -0,0 +1,6 @@ +// types/mock-response.ts +export interface MockResponse { + status(code: number): this; + send(data: any): this; + sendStatus(code: number): this; +} diff --git a/secure-ws/utils/middleware-adapter.ts b/secure-ws/utils/middleware-adapter.ts index 885756c..fc627dd 100644 --- a/secure-ws/utils/middleware-adapter.ts +++ b/secure-ws/utils/middleware-adapter.ts @@ -1,9 +1,11 @@ import { IncomingMessage } from 'http'; import { WebSocket } from 'ws'; import { MockResponse } from '../mocks/express-response'; +import { MockResponse as MockResponseType } from '../types/mock-response'; +import { NextFunction, Request, Response } from 'express'; export function runExpressMiddleware( - middleware: (req, res, next) => void, + middleware: (req: Request, res: MockResponseType, next: NextFunction) => void, request: IncomingMessage, socket: WebSocket ): Promise<{ success: boolean; error?: string }> { @@ -11,7 +13,7 @@ export function runExpressMiddleware( const mockRes = new MockResponse(socket); let nextCalled = false; - const next = (error) => { + const next = (error?: any) => { if (nextCalled) return; nextCalled = true; @@ -22,27 +24,8 @@ export function runExpressMiddleware( } }; - const originalSend = mockRes.send.bind(mockRes); - const originalSendStatus = mockRes.sendStatus.bind(mockRes); - - mockRes.send = (data) => { - if (!nextCalled) { - nextCalled = true; - resolve({ success: false, error: `HTTP ${mockRes.statusCode}` }); - } - return mockRes; - }; - - mockRes.sendStatus = (code: number) => { - if (!nextCalled) { - nextCalled = true; - resolve({ success: false, error: `HTTP ${code}` }); - } - return mockRes; - }; - try { - middleware(request, mockRes, next); + middleware(request as Request, mockRes as MockResponseType, next); } catch (error) { console.error("Middleware exception:", error); if (!nextCalled) { From b7e47d492d899988014c491131e89999e7d49df2 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 12:36:09 +0530 Subject: [PATCH 32/49] fix: use IncomingMessageWithBody interface in injectHttpRequest --- secure-ws/utils/inject-http-request.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/secure-ws/utils/inject-http-request.ts b/secure-ws/utils/inject-http-request.ts index 9f8944e..64ec4c2 100644 --- a/secure-ws/utils/inject-http-request.ts +++ b/secure-ws/utils/inject-http-request.ts @@ -5,7 +5,11 @@ type HttpRequest = { body?: unknown; }; -export function injectHttpRequest(request: IncomingMessage, httpRequest: HttpRequest) { +interface IncomingMessageWithBody extends IncomingMessage { + body?: unknown; +} + +export function injectHttpRequest(request: IncomingMessageWithBody, httpRequest: HttpRequest) { // Merge headers if (httpRequest.headers) { for (const [key, value] of Object.entries(httpRequest.headers)) { @@ -15,7 +19,7 @@ export function injectHttpRequest(request: IncomingMessage, httpRequest: HttpReq // Attach body as a custom property if (httpRequest.body) { - (request as any).body = httpRequest.body; + request.body = httpRequest.body; } return request; From cf0c8fa128c3b8070416e60e31e63180dc7c6ab7 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 12:40:55 +0530 Subject: [PATCH 33/49] fix: ensure injectedRequest is only created when ws.protocol is valid --- secure-ws/core/web-socket-provider.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/secure-ws/core/web-socket-provider.ts b/secure-ws/core/web-socket-provider.ts index 985d457..55909d3 100644 --- a/secure-ws/core/web-socket-provider.ts +++ b/secure-ws/core/web-socket-provider.ts @@ -48,8 +48,12 @@ export class WebSocketProvider { private handleConnection = async (ws: WSWebSocket, request: IncomingMessage) => { const { pathname } = new URL(request.url!, 'wss://base.url'); - const httpRequest = WSProtocolCodec.decode(ws.protocol || ''); - const injectedRequest = injectHttpRequest(request, httpRequest); + let injectedRequest = {} as IncomingMessage; + + if (typeof ws.protocol === 'string' && ws.protocol.trim() !== '') { + const httpRequest = WSProtocolCodec.decode(ws.protocol); + injectedRequest = injectHttpRequest(request, httpRequest); + } if(!this.routes[pathname]) { ws.close(1000, 'Unknown path'); From f36634f36b5eafe58ed9251c5d9d6c1972a59e44 Mon Sep 17 00:00:00 2001 From: fundabot Date: Wed, 17 Sep 2025 07:11:47 +0000 Subject: [PATCH 34/49] CI: bumps secure-ws to 0.0.2-websocket-provider.7 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index b70c08b..7bfaf36 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.6", + "version": "0.0.2-websocket-provider.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.6", + "version": "0.0.2-websocket-provider.7", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index 3d80f13..929e482 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.6", + "version": "0.0.2-websocket-provider.7", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From c306e156c266ff969a565114330da84fb00d61f2 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 12:47:40 +0530 Subject: [PATCH 35/49] fix: remove trailing comma in tsconfig.json [skip ci] --- secure-ws/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secure-ws/tsconfig.json b/secure-ws/tsconfig.json index 922c07a..d57db00 100644 --- a/secure-ws/tsconfig.json +++ b/secure-ws/tsconfig.json @@ -6,6 +6,6 @@ "forceConsistentCasingInFileNames": true, "skipLibCheck": true, "declaration": true, - "outDir": "./dist", + "outDir": "./dist" } } From b0835856d4b790fc41dd0c15d12e973a67620a95 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 12:59:12 +0530 Subject: [PATCH 36/49] fix: update sendStatus method to send JSON response format --- secure-ws/mocks/express-response.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/secure-ws/mocks/express-response.ts b/secure-ws/mocks/express-response.ts index e7da8ea..0a106af 100644 --- a/secure-ws/mocks/express-response.ts +++ b/secure-ws/mocks/express-response.ts @@ -22,7 +22,10 @@ export class MockResponse implements MockResponseType { sendStatus(code: number) { this.statusCode = code; - this.socket.send(`HTTP/1.1 ${code} ${this.getStatusText()}\r\n\r\n`); + this.socket.send(JSON.stringify({ + status: code, + statusText: this.getStatusText() + })); this.socket.close(); return this; } From 48ee8a749fb1f708b127ec343ad3b7f03ed4a8dc Mon Sep 17 00:00:00 2001 From: fundabot Date: Wed, 17 Sep 2025 07:30:19 +0000 Subject: [PATCH 37/49] CI: bumps secure-ws to 0.0.2-websocket-provider.8 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index 7bfaf36..6b9eec1 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.7", + "version": "0.0.2-websocket-provider.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.7", + "version": "0.0.2-websocket-provider.8", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index 929e482..be5448c 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.7", + "version": "0.0.2-websocket-provider.8", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From ecb0ec79a1137e3934c74f7c715f17874108e1d9 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 13:02:52 +0530 Subject: [PATCH 38/49] fix: include response type in sendStatus method JSON response --- secure-ws/mocks/express-response.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/secure-ws/mocks/express-response.ts b/secure-ws/mocks/express-response.ts index 0a106af..2bb9c99 100644 --- a/secure-ws/mocks/express-response.ts +++ b/secure-ws/mocks/express-response.ts @@ -22,9 +22,11 @@ export class MockResponse implements MockResponseType { sendStatus(code: number) { this.statusCode = code; + const responseType = code >= 400 ? "error" : "success"; this.socket.send(JSON.stringify({ status: code, - statusText: this.getStatusText() + statusText: this.getStatusText(), + type: responseType })); this.socket.close(); return this; From 9016a12afc8f0068960358bb646880f63d904e0c Mon Sep 17 00:00:00 2001 From: fundabot Date: Wed, 17 Sep 2025 07:33:30 +0000 Subject: [PATCH 39/49] CI: bumps secure-ws to 0.0.2-websocket-provider.9 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index 6b9eec1..c1205da 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.8", + "version": "0.0.2-websocket-provider.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.8", + "version": "0.0.2-websocket-provider.9", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index be5448c..c4957fe 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.8", + "version": "0.0.2-websocket-provider.9", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From 348cf65d6ee6a6215d39242157d11a21d69a6bb4 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 17 Sep 2025 13:10:42 +0530 Subject: [PATCH 40/49] fix: update send method to send JSON response format --- secure-ws/mocks/express-response.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/secure-ws/mocks/express-response.ts b/secure-ws/mocks/express-response.ts index 2bb9c99..569f321 100644 --- a/secure-ws/mocks/express-response.ts +++ b/secure-ws/mocks/express-response.ts @@ -15,7 +15,12 @@ export class MockResponse implements MockResponseType { } send(data) { - this.socket.send(`HTTP/1.1 ${this.statusCode} ${this.getStatusText()}\r\n\r\n`); + const responseType = this.statusCode >= 400 ? "error" : "success"; + this.socket.send(JSON.stringify({ + type: responseType, + status: this.statusCode, + data: data + })); this.socket.close(); return this; } From 05eeb34d44c6f69ba60688142fa96d9d800bc940 Mon Sep 17 00:00:00 2001 From: fundabot Date: Wed, 17 Sep 2025 07:41:41 +0000 Subject: [PATCH 41/49] CI: bumps secure-ws to 0.0.2-websocket-provider.10 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index c1205da..0a301b4 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.9", + "version": "0.0.2-websocket-provider.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.9", + "version": "0.0.2-websocket-provider.10", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index c4957fe..07ee5c4 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.9", + "version": "0.0.2-websocket-provider.10", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From 35374775256e4b3aed685139c41008f611538a75 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Thu, 18 Sep 2025 15:24:21 +0530 Subject: [PATCH 42/49] fix: replace socket.write with console log for missing routes --- secure-ws/core/web-socket-provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secure-ws/core/web-socket-provider.ts b/secure-ws/core/web-socket-provider.ts index 55909d3..a6ced81 100644 --- a/secure-ws/core/web-socket-provider.ts +++ b/secure-ws/core/web-socket-provider.ts @@ -40,7 +40,7 @@ export class WebSocketProvider { this.server.emit('connection', ws, request); }); } else { - // socket.write('HTTP/1.1 404 Not Found\r\n\r\n'); + console.log('No route for path:', pathname); socket.end(); } }; From 6d02b62a4ca00ae51f3d8a3bc2d5faee5fdc001d Mon Sep 17 00:00:00 2001 From: fundabot Date: Thu, 18 Sep 2025 09:55:21 +0000 Subject: [PATCH 43/49] CI: bumps secure-ws to 0.0.2-websocket-provider.11 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index 0a301b4..c2036e0 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.10", + "version": "0.0.2-websocket-provider.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.10", + "version": "0.0.2-websocket-provider.11", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index 07ee5c4..ba6bbba 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.10", + "version": "0.0.2-websocket-provider.11", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From e13aebc144f80366b43776a3466a230755cccf0f Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 24 Sep 2025 11:04:47 +0530 Subject: [PATCH 44/49] add: unique ID to socket in handleUpgrade method --- secure-ws/core/web-socket-provider.ts | 10 ++++++---- secure-ws/types/client-socket.ts | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 secure-ws/types/client-socket.ts diff --git a/secure-ws/core/web-socket-provider.ts b/secure-ws/core/web-socket-provider.ts index a6ced81..644117f 100644 --- a/secure-ws/core/web-socket-provider.ts +++ b/secure-ws/core/web-socket-provider.ts @@ -1,7 +1,7 @@ import { WebSocketServer, WebSocket as WSWebSocket } from 'ws'; import { IncomingMessage } from 'http'; -import { Duplex } from 'stream'; import { decode } from "@msgpack/msgpack"; +import { randomUUID } from "crypto"; import { WSProtocolCodec } from './ws-protocol-codec'; import { runExpressMiddleware } from '../utils/middleware-adapter'; @@ -9,6 +9,7 @@ import { injectHttpRequest } from '../utils/inject-http-request'; import { WSController } from '../types/ws-controller'; import { AddRouteParams } from '../types/add-route-params'; +import { ClientSocket } from '../types/client-socket'; export class WebSocketProvider { public server: WebSocketServer; @@ -32,12 +33,13 @@ export class WebSocketProvider { onMessage } } - public handleUpgrade = (request: IncomingMessage, socket: Duplex, head: Buffer) => { + public handleUpgrade = (request: IncomingMessage, socket: ClientSocket, head: Buffer) => { const { pathname } = new URL(request.url!, 'wss://base.url'); if (this.routes[pathname]) { - this.server.handleUpgrade(request, socket, head, (ws: any) => { - this.server.emit('connection', ws, request); + socket.id = `${Date.now()}-${randomUUID()}`; + this.server.handleUpgrade(request, socket, head, (ws: WSWebSocket) => { + this.server.emit('connection', ws, request); }); } else { console.log('No route for path:', pathname); diff --git a/secure-ws/types/client-socket.ts b/secure-ws/types/client-socket.ts new file mode 100644 index 0000000..b2db5ce --- /dev/null +++ b/secure-ws/types/client-socket.ts @@ -0,0 +1,5 @@ +import { Duplex } from 'stream'; + +export interface ClientSocket extends Duplex { + id: string; +} \ No newline at end of file From 398e7d6ece2629fffda12d0a61d2f1e1bd9405b5 Mon Sep 17 00:00:00 2001 From: fundabot Date: Wed, 24 Sep 2025 05:35:35 +0000 Subject: [PATCH 45/49] CI: bumps secure-ws to 0.0.2-websocket-provider.12 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index c2036e0..c47b373 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.11", + "version": "0.0.2-websocket-provider.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.11", + "version": "0.0.2-websocket-provider.12", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index ba6bbba..651e2d4 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.11", + "version": "0.0.2-websocket-provider.12", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From 2ce2dd21605ec5a6ab2d96c6e2b50552b42d29d9 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Wed, 24 Sep 2025 11:31:24 +0530 Subject: [PATCH 46/49] fix: add socket id to ws object instead of raw socket duplex object --- secure-ws/core/web-socket-provider.ts | 13 +++++++------ secure-ws/types/client-socket.ts | 4 ++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/secure-ws/core/web-socket-provider.ts b/secure-ws/core/web-socket-provider.ts index 644117f..acbdbe0 100644 --- a/secure-ws/core/web-socket-provider.ts +++ b/secure-ws/core/web-socket-provider.ts @@ -1,4 +1,4 @@ -import { WebSocketServer, WebSocket as WSWebSocket } from 'ws'; +import { WebSocketServer } from 'ws'; import { IncomingMessage } from 'http'; import { decode } from "@msgpack/msgpack"; import { randomUUID } from "crypto"; @@ -10,6 +10,7 @@ import { injectHttpRequest } from '../utils/inject-http-request'; import { WSController } from '../types/ws-controller'; import { AddRouteParams } from '../types/add-route-params'; import { ClientSocket } from '../types/client-socket'; +import { Duplex } from 'stream'; export class WebSocketProvider { public server: WebSocketServer; @@ -33,12 +34,12 @@ export class WebSocketProvider { onMessage } } - public handleUpgrade = (request: IncomingMessage, socket: ClientSocket, head: Buffer) => { + public handleUpgrade = (request: IncomingMessage, socket: Duplex, head: Buffer) => { const { pathname } = new URL(request.url!, 'wss://base.url'); if (this.routes[pathname]) { - socket.id = `${Date.now()}-${randomUUID()}`; - this.server.handleUpgrade(request, socket, head, (ws: WSWebSocket) => { + this.server.handleUpgrade(request, socket, head, (ws: ClientSocket) => { + ws.id = `${Date.now()}-${randomUUID()}`; this.server.emit('connection', ws, request); }); } else { @@ -47,7 +48,7 @@ export class WebSocketProvider { } }; - private handleConnection = async (ws: WSWebSocket, request: IncomingMessage) => { + private handleConnection = async (ws: ClientSocket, request: IncomingMessage) => { const { pathname } = new URL(request.url!, 'wss://base.url'); let injectedRequest = {} as IncomingMessage; @@ -78,7 +79,7 @@ export class WebSocketProvider { ws.send(JSON.stringify({ type: "connection:ack" })); }; - private handleMessage = (socket: WSWebSocket, onMessage: WSController[]) => { + private handleMessage = (socket: ClientSocket, onMessage: WSController[]) => { return async (message) => { const request = decode(message) as IncomingMessage; diff --git a/secure-ws/types/client-socket.ts b/secure-ws/types/client-socket.ts index b2db5ce..a6d5169 100644 --- a/secure-ws/types/client-socket.ts +++ b/secure-ws/types/client-socket.ts @@ -1,5 +1,5 @@ -import { Duplex } from 'stream'; +import { WebSocket } from 'ws'; -export interface ClientSocket extends Duplex { +export interface ClientSocket extends WebSocket { id: string; } \ No newline at end of file From 5d003c052b53310b2e51ff354ea83137be036eda Mon Sep 17 00:00:00 2001 From: fundabot Date: Wed, 24 Sep 2025 06:02:42 +0000 Subject: [PATCH 47/49] CI: bumps secure-ws to 0.0.2-websocket-provider.13 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index c47b373..bdbd1b9 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.12", + "version": "0.0.2-websocket-provider.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.12", + "version": "0.0.2-websocket-provider.13", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index 651e2d4..4e0b863 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.12", + "version": "0.0.2-websocket-provider.13", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From fcb9da396c4c8b3944f4d293abd3f9bc00f7a430 Mon Sep 17 00:00:00 2001 From: Rahul Gorai Date: Thu, 25 Sep 2025 18:30:18 +0530 Subject: [PATCH 48/49] fix: manage client socket lifecycle by removing from clientSockets map on close event --- secure-ws/core/web-socket-provider.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/secure-ws/core/web-socket-provider.ts b/secure-ws/core/web-socket-provider.ts index acbdbe0..ac943ae 100644 --- a/secure-ws/core/web-socket-provider.ts +++ b/secure-ws/core/web-socket-provider.ts @@ -14,12 +14,14 @@ import { Duplex } from 'stream'; export class WebSocketProvider { public server: WebSocketServer; + public clientSockets: Map; private routes: Record; constructor() { this.server = new WebSocketServer({ noServer: true }); this.server.on('connection', this.handleConnection); this.routes = {}; + this.clientSockets = new Map(); } public addRoute = ( @@ -39,7 +41,13 @@ export class WebSocketProvider { if (this.routes[pathname]) { this.server.handleUpgrade(request, socket, head, (ws: ClientSocket) => { + ws.id = `${Date.now()}-${randomUUID()}`; + this.clientSockets.set(ws.id, ws); + ws.on('close', () => { + this.clientSockets.delete(ws.id); + }); + this.server.emit('connection', ws, request); }); } else { From f03b152a7c9ac5cfd8fd8c74bc1196b98dae61ec Mon Sep 17 00:00:00 2001 From: fundabot Date: Thu, 25 Sep 2025 13:01:03 +0000 Subject: [PATCH 49/49] CI: bumps secure-ws to 0.0.2-websocket-provider.14 [skip ci] --- secure-ws/package-lock.json | 4 ++-- secure-ws/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/secure-ws/package-lock.json b/secure-ws/package-lock.json index bdbd1b9..28f1b27 100644 --- a/secure-ws/package-lock.json +++ b/secure-ws/package-lock.json @@ -1,12 +1,12 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.13", + "version": "0.0.2-websocket-provider.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "secure-ws", - "version": "0.0.2-websocket-provider.13", + "version": "0.0.2-websocket-provider.14", "license": "ISC", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/secure-ws/package.json b/secure-ws/package.json index 4e0b863..be5c1e6 100644 --- a/secure-ws/package.json +++ b/secure-ws/package.json @@ -1,6 +1,6 @@ { "name": "secure-ws", - "version": "0.0.2-websocket-provider.13", + "version": "0.0.2-websocket-provider.14", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": {