Compare commits

..

16 Commits

Author SHA1 Message Date
Damien Arrachequesne
2a2b44f20d test: add test 2025-12-22 10:24:29 +01:00
Suraj Rana
e1ad89a708 Drain queue before emitting connect event 2025-12-22 09:58:31 +01:00
Damien Arrachequesne
cdae01983a fix(sio-client): do not mangle the "_placeholder" attribute (bis)
The "_placeholder" attribute is used when sending binary data, and was
incorrectly mangled (converted to a random short property, like "it",
to reduce the bundle size).

Related:

- ca9e994815
- https://github.com/socketio/socket.io/issues/5215

[skip ci]
2025-12-19 15:48:28 +01:00
Damien Arrachequesne
39bb72039d docs: add release steps
[skip ci]
2025-12-19 15:43:14 +01:00
Valentin Rault
98741e15e9 refactor(sio-client): export DisconnectDescription type (#5392)
Related: https://github.com/socketio/socket.io/issues/4556
2025-12-19 14:51:39 +01:00
Damien Arrachequesne
8af70195bb refactor(sio): use URL constructor instead of url.parse()
Related: https://github.com/socketio/socket.io/issues/5377
2025-12-19 14:44:30 +01:00
Damien Arrachequesne
d88f3f4578 ci: use actions/checkout@v6 and actions/setup-node@v6
Release notes:

- https://github.com/actions/checkout/blob/main/CHANGELOG.md
- https://github.com/actions/setup-node/releases/tag/v6.0.0
2025-12-15 09:38:45 +01:00
Damien Arrachequesne
f5ee981ee8 ci(publish): use trusted publishing
Reference: https://docs.npmjs.com/trusted-publishers

[skip ci]
2025-12-15 08:57:17 +01:00
Damien Arrachequesne
76e3a72bba docs: add missing changelog links
[skip ci]
2025-12-15 08:55:26 +01:00
Damien Arrachequesne
a7b1938d06 test: regenerate SSL certs 2025-12-15 08:45:47 +01:00
Damien Arrachequesne
54743633ff chore(release): @socket.io/redis-streams-emitter@0.1.1
Diff: https://github.com/socketio/socket.io/compare/@socket.io/redis-streams-emitter@0.1.0...@socket.io/redis-streams-emitter@0.1.1
2025-11-07 10:33:07 +01:00
Damien Arrachequesne
7617707ed8 fix(redis-streams-emitter): remove dependency on socket.io-adapter
Related: https://github.com/socketio/socket.io/issues/5414
2025-11-07 10:28:27 +01:00
Damien Arrachequesne
599001d213 chore(release): @socket.io/redis-streams-emitter@0.1.0 2025-11-06 18:23:00 +01:00
Damien Arrachequesne
1c3e4711c1 feat: add emitter based on Redis streams
Related: https://github.com/socketio/socket.io-redis-streams-adapter/issues/8
2025-11-06 18:03:37 +01:00
Damien Arrachequesne
693080cac7 refactor(sio-adapter): add more debug logs 2025-10-20 15:11:21 +02:00
Damien Arrachequesne
5080c73e1e refactor: fix npm command 2025-10-17 09:41:39 +02:00
40 changed files with 1741 additions and 373 deletions

View File

@@ -49,10 +49,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}

View File

@@ -1,4 +1,4 @@
# reference: https://docs.npmjs.com/generating-provenance-statements
# reference: https://docs.npmjs.com/trusted-publishers#for-github-actions
name: Publish
@@ -32,6 +32,4 @@ jobs:
run: npm run compile --workspaces --if-present
- name: Publish package
run: npm publish --workspace=${GITHUB_REF_NAME%@*} --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --workspace=${GITHUB_REF_NAME%@*} --access public

View File

@@ -2,15 +2,17 @@
Here are the detailed changelogs for each package in this monorepo:
| Package | Changelog |
|--------------------------------|---------------------------------------------------------|
| `engine.io` | [link](packages/engine.io/CHANGELOG.md) |
| `engine.io-client` | [link](packages/engine.io-client/CHANGELOG.md) |
| `engine.io-parser` | [link](packages/engine.io-parser/CHANGELOG.md) |
| `socket.io` | [link](packages/socket.io/CHANGELOG.md) |
| `socket.io-adapter` | [link](packages/socket.io-adapter/CHANGELOG.md) |
| `socket.io-client` | [link](packages/socket.io-client/CHANGELOG.md) |
| `@socket.io/cluster-adapter` | [link](packages/socket.io-cluster-adapter/CHANGELOG.md) |
| `@socket.io/cluster-engine` | [link](packages/socket.io-cluster-engine/CHANGELOG.md) |
| `@socket.io/component-emitter` | [link](packages/socket.io-component-emitter/History.md) |
| `socket.io-parser` | [link](packages/socket.io-parser/CHANGELOG.md) |
| Package | Changelog |
|------------------------------------|----------------------------------------------------------------|
| `engine.io` | [link](packages/engine.io/CHANGELOG.md) |
| `engine.io-client` | [link](packages/engine.io-client/CHANGELOG.md) |
| `engine.io-parser` | [link](packages/engine.io-parser/CHANGELOG.md) |
| `socket.io` | [link](packages/socket.io/CHANGELOG.md) |
| `socket.io-adapter` | [link](packages/socket.io-adapter/CHANGELOG.md) |
| `socket.io-client` | [link](packages/socket.io-client/CHANGELOG.md) |
| `@socket.io/cluster-adapter` | [link](packages/socket.io-cluster-adapter/CHANGELOG.md) |
| `@socket.io/cluster-engine` | [link](packages/socket.io-cluster-engine/CHANGELOG.md) |
| `@socket.io/component-emitter` | [link](packages/socket.io-component-emitter/History.md) |
| `socket.io-parser` | [link](packages/socket.io-parser/CHANGELOG.md) |
| `@socket.io/postgres-emitter` | [link](packages/socket.io-postgres-emitter/CHANGELOG.md) |
| `@socket.io/redis-streams-emitter` | [link](/packages/socket.io-redis-streams-emitter/CHANGELOG.md) |

142
package-lock.json generated
View File

@@ -16,7 +16,8 @@
"packages/socket.io-parser",
"packages/socket.io-client",
"packages/socket.io",
"packages/socket.io-postgres-emitter"
"packages/socket.io-postgres-emitter",
"packages/socket.io-redis-streams-emitter"
],
"devDependencies": {
"@babel/core": "^7.24.7",
@@ -31,6 +32,7 @@
"@rollup/plugin-node-resolve": "^15.2.3",
"@sinonjs/fake-timers": "^11.2.2",
"@socket.io/postgres-adapter": "^0.1.0",
"@socket.io/redis-streams-adapter": "~0.2.2",
"@types/debug": "^4.1.12",
"@types/expect.js": "^0.3.32",
"@types/mocha": "^10.0.7",
@@ -121,6 +123,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz",
"integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==",
"dev": true,
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.24.7",
@@ -2809,6 +2812,7 @@
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.17.tgz",
"integrity": "sha512-IPvU9A31qRCZ7lds/x+ksuK/UMndd0EASveAvCvEtFFKIZjZ+m/a4a0L7S28KEWoR5ka8526hlSghDo4Hrc2Hg==",
"dev": true,
"peer": true,
"dependencies": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
@@ -3209,6 +3213,45 @@
"resolved": "packages/socket.io-postgres-emitter",
"link": true
},
"node_modules/@socket.io/redis-streams-adapter": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@socket.io/redis-streams-adapter/-/redis-streams-adapter-0.2.2.tgz",
"integrity": "sha512-BMPa6oGC0wFgpMXoGksbJ75zMBwk+79pxjHc2YusdoK+X0BxN4fTsqEBuFV7yeXi9ekbi87rwlsT61+WZGVW9g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@msgpack/msgpack": "~2.8.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"socket.io-adapter": "^2.5.4"
}
},
"node_modules/@socket.io/redis-streams-adapter/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/@socket.io/redis-streams-emitter": {
"resolved": "packages/socket.io-redis-streams-emitter",
"link": true
},
"node_modules/@szmarczak/http-timer": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
@@ -3306,7 +3349,6 @@
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
"dev": true,
"peer": true,
"dependencies": {
"@types/eslint": "*",
"@types/estree": "*"
@@ -3395,7 +3437,8 @@
"node_modules/@types/node": {
"version": "18.15.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.3.tgz",
"integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw=="
"integrity": "sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==",
"peer": true
},
"node_modules/@types/normalize-package-data": {
"version": "2.4.4",
@@ -4559,7 +4602,6 @@
"integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/helper-numbers": "1.13.2",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2"
@@ -4570,24 +4612,21 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
"integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-api-error": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
"integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-buffer": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
"integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-numbers": {
"version": "1.13.2",
@@ -4595,7 +4634,6 @@
"integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/floating-point-hex-parser": "1.13.2",
"@webassemblyjs/helper-api-error": "1.13.2",
@@ -4607,8 +4645,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
"integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-wasm-section": {
"version": "1.14.1",
@@ -4616,7 +4653,6 @@
"integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
@@ -4630,7 +4666,6 @@
"integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@xtuc/ieee754": "^1.2.0"
}
@@ -4641,7 +4676,6 @@
"integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@xtuc/long": "4.2.2"
}
@@ -4651,8 +4685,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
"integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/wasm-edit": {
"version": "1.14.1",
@@ -4660,7 +4693,6 @@
"integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
@@ -4678,7 +4710,6 @@
"integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
@@ -4693,7 +4724,6 @@
"integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
@@ -4707,7 +4737,6 @@
"integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-api-error": "1.13.2",
@@ -4723,7 +4752,6 @@
"integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@xtuc/long": "4.2.2"
@@ -4734,16 +4762,14 @@
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
"dev": true,
"license": "BSD-3-Clause",
"peer": true
"license": "BSD-3-Clause"
},
"node_modules/@xtuc/long": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"dev": true,
"license": "Apache-2.0",
"peer": true
"license": "Apache-2.0"
},
"node_modules/@zip.js/zip.js": {
"version": "2.7.45",
@@ -4786,6 +4812,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -4799,7 +4826,6 @@
"integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.13.0"
},
@@ -5914,6 +5940,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.9",
"caniuse-lite": "^1.0.30001746",
@@ -6313,7 +6340,6 @@
"integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"@types/node": "*",
"escape-string-regexp": "^4.0.0",
@@ -6333,7 +6359,6 @@
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=10"
},
@@ -6346,7 +6371,6 @@
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
"dev": true,
"peer": true,
"engines": {
"node": ">=6.0"
}
@@ -7236,7 +7260,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@types/node": "^22.2.0",
"@wdio/config": "8.46.0",
@@ -7262,7 +7285,8 @@
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1400418.tgz",
"integrity": "sha512-U8j75zDOXF8IP3o0Cgb7K4tFA9uUHEOru2Wx64+EUqL4LNOh9dRe1i8WKR1k3mSpjcCe3aIkTDvEwq0YkI4hfw==",
"dev": true,
"license": "BSD-3-Clause"
"license": "BSD-3-Clause",
"peer": true
},
"node_modules/devtools/node_modules/@types/node": {
"version": "22.18.9",
@@ -7271,7 +7295,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@@ -7283,7 +7306,6 @@
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@types/node": "^22.2.0"
},
@@ -7297,7 +7319,6 @@
"integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=16"
}
@@ -7308,8 +7329,7 @@
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true
"optional": true
},
"node_modules/devtools/node_modules/uuid": {
"version": "10.0.0",
@@ -7322,7 +7342,6 @@
],
"license": "MIT",
"optional": true,
"peer": true,
"bin": {
"uuid": "dist/bin/uuid"
}
@@ -7333,7 +7352,6 @@
"integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"isexe": "^3.1.1"
},
@@ -7721,8 +7739,7 @@
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
"integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
"dev": true,
"peer": true
"dev": true
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
@@ -7861,7 +7878,6 @@
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"dev": true,
"peer": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
@@ -7884,7 +7900,6 @@
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"peer": true,
"dependencies": {
"estraverse": "^5.2.0"
},
@@ -7897,7 +7912,6 @@
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
"peer": true,
"engines": {
"node": ">=4.0"
}
@@ -7907,7 +7921,6 @@
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"dev": true,
"peer": true,
"engines": {
"node": ">=4.0"
}
@@ -9053,8 +9066,7 @@
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true
"license": "BSD-2-Clause"
},
"node_modules/globals": {
"version": "11.12.0",
@@ -9748,7 +9760,6 @@
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
"dev": true,
"optional": true,
"peer": true,
"bin": {
"is-docker": "cli.js"
},
@@ -9904,7 +9915,6 @@
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"is-docker": "^2.0.0"
},
@@ -10356,7 +10366,6 @@
"integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"debug": "^2.6.9",
"marky": "^1.2.2"
@@ -10368,7 +10377,6 @@
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"ms": "2.0.0"
}
@@ -10378,8 +10386,7 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true,
"optional": true,
"peer": true
"optional": true
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
@@ -10399,7 +10406,6 @@
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
"integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
"dev": true,
"peer": true,
"engines": {
"node": ">=6.11.5"
}
@@ -10639,8 +10645,7 @@
"resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz",
"integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==",
"dev": true,
"optional": true,
"peer": true
"optional": true
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
@@ -11111,8 +11116,7 @@
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
"dev": true,
"peer": true
"dev": true
},
"node_modules/netmask": {
"version": "2.0.2",
@@ -11973,6 +11977,7 @@
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"pg-connection-string": "^2.9.1",
"pg-pool": "^3.10.1",
@@ -13209,6 +13214,7 @@
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"rollup": "dist/bin/rollup"
},
@@ -13362,6 +13368,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz",
"integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==",
"dev": true,
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"json-schema-traverse": "^1.0.0",
@@ -14480,7 +14487,6 @@
"integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.25",
"jest-worker": "^27.4.5",
@@ -14516,7 +14522,6 @@
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
@@ -14897,6 +14902,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz",
"integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==",
"dev": true,
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -14925,7 +14931,6 @@
}
],
"optional": true,
"peer": true,
"engines": {
"node": "*"
}
@@ -15213,7 +15218,6 @@
"integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
@@ -15669,7 +15673,6 @@
"integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.13.0"
}
@@ -16115,7 +16118,7 @@
},
"packages/socket.io-cluster-adapter": {
"name": "@socket.io/cluster-adapter",
"version": "0.2.2",
"version": "0.3.0",
"license": "MIT",
"dependencies": {
"debug": "~4.4.1"
@@ -16177,6 +16180,15 @@
"@msgpack/msgpack": "^2.7.0",
"debug": "~4.4.1"
}
},
"packages/socket.io-redis-streams-emitter": {
"name": "@socket.io/redis-streams-emitter",
"version": "0.0.1",
"license": "MIT",
"dependencies": {
"@msgpack/msgpack": "~2.8.0",
"debug": "~4.4.1"
}
}
}
}

View File

@@ -12,7 +12,8 @@
"packages/socket.io-parser",
"packages/socket.io-client",
"packages/socket.io",
"packages/socket.io-postgres-emitter"
"packages/socket.io-postgres-emitter",
"packages/socket.io-redis-streams-emitter"
],
"overrides": {
"@types/estree": "0.0.52",
@@ -32,6 +33,7 @@
"@rollup/plugin-node-resolve": "^15.2.3",
"@sinonjs/fake-timers": "^11.2.2",
"@socket.io/postgres-adapter": "^0.1.0",
"@socket.io/redis-streams-adapter": "~0.2.2",
"@types/debug": "^4.1.12",
"@types/expect.js": "^0.3.32",
"@types/mocha": "^10.0.7",

View File

@@ -1,33 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIFtTCCA52gAwIBAgIJAJKBPV3nMXjsMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTUxMTE4MTczODAwWhcNMjUxMTE1MTczODAwWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEAmNWKTumE1f+ptArhPTOcaUReoqBlri/ujIzm1N8Qr0hghS6B8eXGngAS
YM7ziTlLZmLKgZg7TYOs+qK+xNNjSMbkA4Tions7vX3FYAokfh1iSiQigAw3TAwg
brUaA0phucJBjvWI2mDuwzTLhQp1wmGrliAJhXag2ZQt817m6wrsFWuwiviMIHlq
mQhC+vwd2SvW4xGf5zxjzCM8m7pOiJCLjxXwvNphiTR3tb807W00mi5cMFwhmAUT
uSiVkVERubIYEKNSW2ynxzGFfb+GF/ddUxCKsnMDfM+SpMrsTBv9BzJzXU7Hc9jP
NPFtrZiVo9aKn8csTSvKifmfiNwl2YGuWlW++1+ew6Q9rqEqvKHnKU+Cuwt3y37U
ryqrBS47cz1xxFb3fCn+a72ytcHjI9lMqIQ0+IZ0/4cf0TK80ECEQ0CyrCk0E9Qz
eMEzIALRa/pI8uTXdoAtQIlOsfALWeni+QphZ1BVjwZRmr+F1Px2/R30+gAcZHKc
D+0Bm6owvpBWDe1s0DrkwtY3fyZ+OPS5/3eQtyhy9/3vnz9WBw0BGZyN2nzs5HsB
RB5qDBRx+NQz1QYp/Ba3WeVmZURe2NMnS4uEypkWahW1XNQ+g+JJhK1p01s0+v/B
f4DodYEcsw/3fRU0AKdsAkabQ68VIJAYyfQyinpNR9sHDKZ6Dx8CAwEAAaOBpzCB
pDAdBgNVHQ4EFgQUdwTc4idMFJo0xYmoLTJQeD7A59kwdQYDVR0jBG4wbIAUdwTc
4idMFJo0xYmoLTJQeD7A59mhSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpT
b21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCCQCS
gT1d5zF47DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQBRLzphOdJO
ekU+iwFLGXJiLfUQi3EORaA3mBtozvyRRUyxu0FqWdGGINcyq7xaZxkQ0P+eBMDv
V3F7FvidhaVe6TR7VJB2gyaWeLd1BSOi5gGBk5kuuqV3VbusNzY+WhJip98HEK+y
XP+Lt/LXJpPwOORF9TiR6IBFQn3fBVhPjsqQRzT468QuZ5DCGQ5UW+wWl43I8OxS
PDiUmHTlwLnLqqVFgSE+VnX4vSUZD8kDf0kkxssg1r56IzneSlRBegSVXIuRCbRf
QmWaxz+D6ffM1eNiE3nQxsgJy3dPL1Lfsaidgz39yAC099pjLyVH23cfmFmT/l5b
OdhRE5D75rL8eXAiI2/voz1M+v7XznHjZEhcVUlFsBXsk3zHb2vQQZRNPLnybTb8
biFpReSIWdpno+F5IrT7z0L8JI3LU0leEFV+Rf525Q+78Rffohxd51fUj0vLKoy9
un0IEkOcaJhHTPc2dMXb2qGcV4MaUEUsERrnanGZmdNd1aD3YAG3C+nJ8gxrEGHO
veD6Xbyf1K8e7H2sqhGCm8eyHgCFGQiul6yQ41ZwjKgoSCJvOJaYUFE18k0S9k/I
rWYvYWRYbDj4GYx+6LUTfyo30KK5jl4KAil92LrGlIfWK4IjUJyPlOJkb6gXkj0l
lfbUHTmnKthFwJS0958xBq7UM7+RzyFIOg==
MIIDBTCCAe2gAwIBAgIUPV8LcHEkiA3LPuNyt8kuDxRqjlQwDQYJKoZIhvcNAQEL
BQAwEjEQMA4GA1UEAwwHVGVzdCBDQTAeFw0yNTEyMTUwNzQ1MDdaFw0yNjEyMTUw
NzQ1MDdaMBIxEDAOBgNVBAMMB1Rlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQChKwRqFDrGgqMHjDUx5he6MDQ+BxlMqqpm0qu5pOCCPzSvYDFo
iU4n3lK6uCbemv9Gdk/U99ev8LAGg2SkZAZXBpDrdZepkA84ehUHu5u7PHlXNodE
KL7DLKsvoaYYiQ5rLyBYieDOYqtYJxtfLOeh+tmnNa+G4chpYzkll7OCeEQhbocQ
QLdP8novscoSibp6bPmoVsat8RRru0CK9ND1v+FvJ2R7Lz2isBIr+p9ZrkYkIXa3
OqN3wacZ+doYfAC/a4SK64Jgv+Lz6wuzsc7XVjBGEEaa1P1zd2rh70wNm8Lgmwr/
Oq1Lv7Lg3plXY7e/7V915p96/bxbIiVHiu1JAgMBAAGjUzBRMB0GA1UdDgQWBBRN
SIfG8SbjQTQCuymcNnQh4R5oxDAfBgNVHSMEGDAWgBRNSIfG8SbjQTQCuymcNnQh
4R5oxDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQADHV/KfXlN
ZBmjWWqQRCmJCUsFkn29C0RQQMILbxYkNl08DuSQw68+PsA2YeB4aUikmW5sRHYF
TgLXxgZ+aaGH4WtedumD4RGodcFbxI2WLIilKD4nH0FmB4I9bkULgMyyOZ0g+Vc7
ekynqzYtzQBgK+HLWtIWZRTM/BR5IAzt/SdAVoQwL3EHzlc57Q9rRqYeBiyse3lC
8Ojb9ZLhwv/hihWNd+mFKeWzLAGJIB439AUzKcg96YDKB3Nwosa16g0xslwxvAL/
cKJQ3mh7pIOX3iv9YV/uifRvdCiI/e2p00YjZiS3ggdravSGjLLypw6HFH3hFnw7
2ZzA88NgFQXi
-----END CERTIFICATE-----

View File

@@ -1,51 +1,28 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQChKwRqFDrGgqMH
jDUx5he6MDQ+BxlMqqpm0qu5pOCCPzSvYDFoiU4n3lK6uCbemv9Gdk/U99ev8LAG
g2SkZAZXBpDrdZepkA84ehUHu5u7PHlXNodEKL7DLKsvoaYYiQ5rLyBYieDOYqtY
JxtfLOeh+tmnNa+G4chpYzkll7OCeEQhbocQQLdP8novscoSibp6bPmoVsat8RRr
u0CK9ND1v+FvJ2R7Lz2isBIr+p9ZrkYkIXa3OqN3wacZ+doYfAC/a4SK64Jgv+Lz
6wuzsc7XVjBGEEaa1P1zd2rh70wNm8Lgmwr/Oq1Lv7Lg3plXY7e/7V915p96/bxb
IiVHiu1JAgMBAAECggEAALEu5oNDpERXNeRF5Me4tYkOHd1ye3ApRmeRLOkwxFEq
6dM04qe2PUEbF9/P3YybVpUG42V10jhyqNft+tCihbTlNkjZRC/R6zL09ZA9/ZTB
HhMQM6zU1XYqt83clO1zAecHfknYQ6lC9RVe8E6YiDq7ZQngT65rQWktdaJ0eOGS
awJiaEXhUsrcW7lSmeysvaTOqFm7RwkytH/hAoPWmPC6qvN+LR18aj5KXd3R4cRK
j+EWr2EXkKWx18hxI+5Y2icWO5lckzh4dfBoWrTgLGrXQdpnw8jWqTZ6431rqv6g
3Ao2NmRUUGz3eyY5CmXdl+vdbfZTC5xxSDhvB5NLrwKBgQC+QnqP0TZ6xO3Ov0gy
EAemCn8sEL+ByuJSJdBydLSRfghH1WfRdPzXWN7274zosNxUpPeft9Dq44YQYX6R
gUJ39QnmUVDwBVwFSw1ZgQjBvZJTr0sp4iBb9hEGhSLlpnrA4qZZQC28A+eKkmTu
QR0qMPjlqiacfFISBJwCSll26wKBgQDY2ziwueYuQuNy/jJ8+lFKvIMrv34+Htp/
ZNGxDN1Fthq9JRHUP4KL9UIVGlgIt6hwgOXIR0dw2pt7ffF1SiDST/PvBe5Allex
uvGfTeh0kTv6T/JAPnqBS5uM3fCnQaF/bbTllw4elKHB4liysh+Gq5svU7mV7Xop
1RmGKn6HmwKBgQC791u0uEH1mpdDOdFuvE2CKj6n30gER9e+xuMgINLAJt6xcVGn
KsgdTQzCs7nnrcuPyIdoASdi2DP7/QYZZLWxY6JLLC0lZHYcOKDQu11WYx6slLNS
hrfngrwhT+lBL295HrKv3GsSpFzdl3IlvKi+pTFRXP/WfDBs4qbq0F+AzwKBgDcB
5K9veGPjs65HrKbnGBfNGbjPKka3rNUDze0LRlWYi8/Ox2b/dS3rWIfh1tLfQ2rG
R4M2EXke+rGokMcftpOilE3dQ0I+4J/Eu+Wc7YokDQLBpMGHF6wUcbCZ26GRlFWu
jmRunLZFHYMA1178r+KJRSQMKNdPFd3moELYJKBhAoGBALAJg2x1B1TpLvJf3iI3
BeuASfYKpp3X3cyUy0ojxdYIEHHZ87TINojldHVd+t+80M8FG7YgQNTWtx0Wz587
EslppRo2r8qusax9KjaZ1uf04jWxR/v88dvpspSi3IV/J3rNhf3xz1gEFdRXvtQc
Ek+aWNHKp5nqpuY6HWUacI96
-----END PRIVATE KEY-----

View File

@@ -1,54 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,47A0291BAB679B36
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
-----END RSA PRIVATE KEY-----

View File

@@ -1,22 +1,17 @@
-----BEGIN CERTIFICATE-----
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
I3jNu1mm750TEWWMhPk=
-----END CERTIFICATE-----

View File

@@ -1,12 +1,15 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBrTCCARYCAQAwbTELMAkGA1UEBhMCRkkxEzARBgNVBAgTClNvbWUtU3RhdGUx
ETAPBgNVBAcTCEhlbHNpbmtpMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
eSBMdGQxEzARBgNVBAMTCkZvbyBDbGllbnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
MIGJAoGBAPrpGfw/w74wrXew/EggQwdcNFmF5EuoY2U2xfNoEtacpKVX5bGLU50K
Ka0CHhkBVG3UmQr2ZAQAZ3ELxNHAMxLTb4RQrUfXO+HvsSThlwdbynkJUSbncVOY
76OEv7sFBhdbXKL9dREG/bGbdD3kjvz3lqCmswUjweI678d2L+INAgMBAAGgADAN
BgkqhkiG9w0BAQUFAAOBgQDKGUqjkUxGOisFN70X7ZOW7H99veR9QlixKl5e0W+7
UtJ+GUtH2WQEb4F72+ruHrdDWQI1VaH9hPOvTRCjlgXiT0RHXpGPbJK/Nc+Eq5dm
kuk/tQeXv6+S1fgYOm0w09rE7pBjQtuAybB55lGZ7k84UE2xTc97Ru14nYFCsZ4z
RA==
MIICVjCCAT4CAQAwETEPMA0GA1UEAwwGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAt6j+z+Gsbq6QNmrHk2xjRT2r9tQSQKjD2s0m5K6Vh7UQ
5SnmOtlSdREepZNhcNbDEEZ8hEH01jVtsYvwbr/Z2yQii7qDw0CxaRypMAXP4LuD
ejvM1HHYZggUMUW3DQfAcFiMy7zIISKpXfBmU9EolnX3fzj/ta2VQluVlqrVdUdT
ttNiSh+shPwkULe9z93W37lwQw7OJI+QjNcTurBrHdhL/Yhz6yzX6/t5jmZxrHSM
SdaDJGcEplQqnGCfGhqtoLWyuZmSXaoxxvSsneC073BCEuVhJlZBIPRm2ZK2MOVK
XcgCEi9ipNF+o6WXLLAKApS53atSDsW/6WFJutN4yQIDAQABoAAwDQYJKoZIhvcN
AQELBQADggEBAK/qIcDwg0kFcriPBU9+LGbpedbtw0naT3PVXfYYq3TzjBtPW+4c
f5QmAhrIMkF0xQ1YdDsx9U/jQ93xL8OCo8+pbiQOYS0uVTqi/7UL9ggkD0aCGCZs
j1FEWbumouW9ZuQg6gsZ9XoZmXPTKZivIpalOTV460vQvhM4Fspx0i7LowiS9ijH
BGG8QEr1ZihhXQloJSnjwVMY8qqVwqvJDidkN7eSjZTL2yOBzgiigpk8IMe1bNrb
dIoJVEjzFooRa08MPt+BZJ7xiuCyKZe6aVmV0XZOcnHChSc8jmSRXZdNpikGdQRX
1BamYMxhR2x8QYX0DiJYZwpgUaG4EOHsqb8=
-----END CERTIFICATE REQUEST-----

View File

@@ -1,15 +1,28 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQD66Rn8P8O+MK13sPxIIEMHXDRZheRLqGNlNsXzaBLWnKSlV+Wx
i1OdCimtAh4ZAVRt1JkK9mQEAGdxC8TRwDMS02+EUK1H1zvh77Ek4ZcHW8p5CVEm
53FTmO+jhL+7BQYXW1yi/XURBv2xm3Q95I7895agprMFI8HiOu/Hdi/iDQIDAQAB
AoGBAOFHTXd4YO1wky82Dy1LGiOPm8kNOC7d33BOv2iN9uwN9J4nzymbqNUE/OpD
TnaxBPcfvNFk6+PT4QxUvsB8ytzDMZ3YC4xyJf5GPP/hfzyWCRjB557WZl1cx7nC
2gA93PBZE7WT1SySXmjsiC7o/2T/0cUaawXOBczHP8oXoEkBAkEA/c1MHs13ojxh
oOj/ibCpYpd2Zv5Hrc5tsh+otDdIrb79IAHnNw7WhMkLs6cLk1MY6jLeCvQtjlUY
H5C/6Ez84QJBAP0VZMgWPw3FVNXPrj833OA6XjyWO+TADpnlrahuDQqWnR3C29Uc
Iq/ApVX2pt2cNIZpiuJ4BYNc44cHjvu6vq0CQQChan1cJc9NhluNLELBfnLsOmpa
bKSH3P8VR19TZsm5fvub7Lnx4WT7xKXFl5scEsCIyts/WjbTDDmwca4r/zLhAkB4
wkeHbY4CnSDgsKr9AUPEPjWPBURo3vdYmY4mKvTQE5O+iqboZfdrEyoQ/ZMbdRhe
9mdNrmU7DAyI9qNUHAQ1AkAlq/vdkrcq5SRR9uti/1M0/Jaw7l3JutBaW93kdvXx
BX568ezO1PQtXwVSv+uJEkDoST1bkvhqt7hlMu/RkmfG
-----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3qP7P4axurpA2
aseTbGNFPav21BJAqMPazSbkrpWHtRDlKeY62VJ1ER6lk2Fw1sMQRnyEQfTWNW2x
i/Buv9nbJCKLuoPDQLFpHKkwBc/gu4N6O8zUcdhmCBQxRbcNB8BwWIzLvMghIqld
8GZT0SiWdfd/OP+1rZVCW5WWqtV1R1O202JKH6yE/CRQt73P3dbfuXBDDs4kj5CM
1xO6sGsd2Ev9iHPrLNfr+3mOZnGsdIxJ1oMkZwSmVCqcYJ8aGq2gtbK5mZJdqjHG
9Kyd4LTvcEIS5WEmVkEg9GbZkrYw5UpdyAISL2Kk0X6jpZcssAoClLndq1IOxb/p
YUm603jJAgMBAAECggEAHlPTr/QuCyDcQ4AicJ+nTNnAOcQPN4omvUy/LWf+3Sfz
IERo9jLIwPgQvXq2znFISLm6+gQCMBUmhfj7vO4FRYCUC8rC000tfpPzBDERgKS2
M0sIqdQazc5rty8x6P7ssiCNL19/FKmqmg6GdzTEpQPZ2LJK129QhGKnMvgGw5S5
TA1UUfiF3JoJLN9YY/EAvrWx6uML4JCsjkjzwG2rXG9S9IOIuULLYyK+d+383GUI
c/okVKILR8pUpFr+y5oor7Dcxa2ApkcRzTvFXvLoMyD7SHkmVLB6OdvgMvK+rVFH
eCqlxiKXAzy9FG1L/EL5pYJwUSKp4itv//WPbvAkYQKBgQC7raVpaYoQ9i+QiIR5
XQijEnZvPdJShqWtvLF65P8WQYdMvQFrO7HM9lSILNzL2291TssWBr5p9MuwbKmc
eKisYwzJWwyDsJiShYBBlAKZOgZ2l8U6m8SGgYUU7/OcVekwrIdm87xi7wsd52aW
ZhifzL7E/Zc5pEFdGKmYkRWoTQKBgQD6hOITk8dV461zrwS7Ev65psmWyx2SGUmq
EIBi0fgE5wov2CXT6jR8mjJgvDjefG4lw92rT8CLsyaguoi2fjktbtOfXLMKVCF4
K2r9KlD/44+WLKBYLKNCffvI+ZcdQqTvUJfZUH7k44fTP25ByqMyj6FNsC0xhL5W
h1k57W4QbQKBgQCO9LYKlVmVkfCpJ1PBHhx2GpocIfsS4X1R2WlXMxca3M8ypMVv
6QiGFxxMnd+RaJR9xobrQDfKfayptht8FGxm4wvaVIAzz1BoS0hmq1dPX+OMcg7J
ld0cl4vHZv8pFkeJy+FXilD1CyBsptZ9uUcIcezeIEwQnA0t3JtSmzDkAQKBgE63
zJYcPGmXphwQparm2BWb/AIfBsaunYALuVvT4FwiAQhxoclJ8X4psaTF4BTBApdp
SVEYOUdsXrnogybc2LiW93Y+2Z9oOjAZbH/qeRM+/RJSKXwrYo11KtXG3535H/x2
1ZAahBUGDdrqNooD024Cxcu0jS7fKDPmSbozCf+tAoGAZ3NwWzj3LpArnfOrDr7Z
rXiUvCmSjPUBF99vN080rU8fBILdQTdz5DdE3K0xWDEiwAk1NZbuwy4Fx02aHG9f
5CkmGEHOsLGT6n6BHrjuSCtvbNOAGLhSBbBJJkFOf3ktJXU64P38M7OP0j11Tzkv
VNurVfn19LNgoLisW5c9tEs=
-----END PRIVATE KEY-----

View File

@@ -1,18 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,081B123E7DBC9687
c8gE0LQMMtV7GhUcP7GHBotlNNAsbyG/gERB//BFlvRPjs43ALvm5xMGUkcsZkw9
H6ljvvgyRkud06x1mGxqlZ4fLlty0/mdXf6791R9gA/9bKLakHGlwnoVUrEPIeh3
Iu/3IF0Uz8o3uljSp9eehR8sW5V4o+Z1MszQ+GkcpCyYnDPykyN52QLTM3RcUJ0v
2iJrgxYEAyMA14iIpYM8IsFDYIBvwVfQxyBZnQ+8dDQgVOokz56g+/9emgOsVjWj
bdUKZ7+95RLxCq0hjJd8GnoDn7qtxIPOGVqYcdEwwNyzO43FnpjOFhNDWwsrNrgf
vUHKhZRHB99CkuCvGg4fjVbFd/1/n3eE5VmiQuqoHzPnXH3RDIx2rZSjFo/NkzYx
4XzZ4YOe6vOP7kR18CL+bl32WneMELoh+TPLmsSC3rIP48M8+oQINSZaBrl59Ocw
NW36xgDNSQoia2splVNo51vtZomq1Hb3co6hD43D4xnrc6Aqucm3BsW6UCc/PVKv
HAXLCb+3awIy5NJSYb0qRETE2rKB6LjmKfILtOrto6QYSlkJmQUxqoPXgRAWWNlw
1Ngws84+6UjmGWDBlpZHn0hcO/B7KJAAS/xNSFYDoSu6dAbabxTI/dZCWhw1aN5c
QeYPihCi66F6Vuq/QT89dHtZE4IMPH7R95Yp18tCcyVGxaEiphw3HJYepMxoJesQ
YH8tWQwvD5LaADzNJIKBxMjCOK23GuXWQLJJRf4QWiXaQar69qXULxBT3iqBp/rQ
VKsQByBwJlEo/YSEFjhhMgo0zSbqIRAY1XCDo+dgB2IB1KPAobhSCQ==
-----END RSA PRIVATE KEY-----

Binary file not shown.

View File

@@ -0,0 +1,22 @@
#!/bin/bash
# Generate CA private key and certificate
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -days 365 -out ca.crt -subj "/CN=Test CA"
# Generate server key and certificate request
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=localhost"
# Generate client key and certificate request
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr -subj "/CN=client"
# Sign server certificate with CA
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
# Sign client certificate with CA
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
# Generate client PFX files
openssl pkcs12 -export -passout pass: -out client.pfx -inkey client.key -in client.crt -certfile ca.crt

View File

@@ -1,22 +1,17 @@
-----BEGIN CERTIFICATE-----
MIIDtDCCAZwCFCt+tjtA9647yZp8eNZurQtNp4x/MA0GCSqGSIb3DQEBDQUAMEUx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjIxMTE4MjEyNDExWhcNMzIxMTE1MjEy
NDExWjBsMQswCQYDVQQGEwJGSTETMBEGA1UECBMKU29tZS1TdGF0ZTERMA8GA1UE
BxMISGVsc2lua2kxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDES
MBAGA1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA
QLNPDILqMIulvPga6ogci69xYaSp50U7Tv8Hww3m4D9w2ubyGqR7dDW20iGJI7tT
Ncv/UtLqgknEiCBXkq/MDr5gdXNI0V/j+qAOqfJSVxvxxHxLrt7ivjpZHbO7B3K7
bkWmCxAFzWAlE5U9FXX1b8VfetJv+cDEaXsYwuYfowIDAQABMA0GCSqGSIb3DQEB
DQUAA4ICAQCDSuFPJ++HY5WBhpnumbZ7+T0ReWKaerdNnQ2Xgrna5mZfB2xeRkvY
XeJ9VBCpGgEZKCKkhZCjomn/kLkYzRk4Sqr1ivN5NWl6G/9UTttHdRa3xiR1NhKI
AMYghpel30w5e+cWtsdR06P2FvZMuiMFCyqsbPf1xcEIAXN7HJDswq6g0ppTVZ4L
sXljG/J0vp+jAst4XKGLaGqnt8JaBnpNX9NO2Up3h5j7Pa4Nhm/LZ3Ku5ZVDmS1d
B98Bsgr6tQSSyPNfZW0tGXELsNX1I+wUFw9IXFadRTHkhjeT/GhFw3i12uY7rqzm
uJegTtWDkp1QOajhYhLD9WGXb9teldkAAgZawD6ax/uAzqx/4mBFvsUa3FMcua8k
HF9P2lLzKAcyaKt1cvlfUYmDVZ2Gh+9PgM8SqRpMIqK5jMRvFgemxJXS9BMBrQLp
TCvgRwQZD4mUloRlGNewKfJ0oQ1rY29vwdjTL8+BBS/GR8EuzYnqJG/D2nK0guIN
ze+cSDghA5N2pp/ffnpLWmkIDO+fsGAj3eApLhbPQ1xCXnEv6fOjgUmnxdt41m8d
+pEVBICohnvYgoEERDNAi1onJlBd/eyk0Jn37QiwqhQyrmfgwncvlt2SyzS1IZ7s
cEYreG6QHghBhgYiYo0FMuDCjT6g6Ga+T8nOp0xpZtGEWvHwjLjxvQ==
MIICrTCCAZUCFGdEcsibkaFr2RamsAlBpOyqm58fMA0GCSqGSIb3DQEBCwUAMBIx
EDAOBgNVBAMMB1Rlc3QgQ0EwHhcNMjUxMjE1MDc0NTA3WhcNMjYxMjE1MDc0NTA3
WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDJw97tTsSTtZrOVjd89NKW548SyaB14Ghuqpfc3KxGa5OMuaXQU9aY
nnoUCEU/YlS76t+ShZsQB9XR5UGy7T6ACJodm2tLsMmaNt3OX8JaXUeIY+UB9qPo
aG8dLBenHays+dud2O2QUF7QhvRvVO98NrGpVaYVpes5lEQhvzKjaiK+Nc51gndR
daAmvCPWINIBegUwRbbsAgNQaW8UEdxYWhVF8MDa//JPR7rTlHSFq6Or8SIvR1D/
xAtvEXyAqPlkedIjh6Or2YCEIR2Lx+9Ky0Yti5vmh3PqZG6g7lMDOhIg/fkO2NfT
9F+z6q7QL5+yOHzJgBepC7V5nQSQMQr9AgMBAAEwDQYJKoZIhvcNAQELBQADggEB
AJh7TfVR5lBVtWepx5ghWrWDrqEXw7nJp4ljaZ/tp+Ufb1LasMflbAnShvnhPAg4
A5/7GkCUjZOMc5QV2MYQGIPtyRdM1rdPG6EuR8SUA/+GxIbaLo7iDpAKpcvCdFfS
pd44wgDBbzbTtw3nRGy6RXm1vB2FyjvGWVXYL3XoE2r/xQPgaf93jeglbgo9C8Tj
MQ2NdR4GPBtjqZNDmer6p2Jr31pkS4exT7oNysnZfoXll8F4PHos7Wc5VYo/2qQy
uftfQqYIZLaZKzjR32Gsr6Z5yb8GlISWnRss5ebD6+wzh8sr4fat0SY/vy/3oq5V
0lwYgNPo/OuwNMA7Eo/iNPY=
-----END CERTIFICATE-----

View File

@@ -1,11 +1,15 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBrDCCARUCAQAwbDELMAkGA1UEBhMCRkkxEzARBgNVBAgTClNvbWUtU3RhdGUx
ETAPBgNVBAcTCEhlbHNpbmtpMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
eSBMdGQxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEAwECzTwyC6jCLpbz4GuqIHIuvcWGkqedFO07/B8MN5uA/cNrm8hqke3Q1
ttIhiSO7UzXL/1LS6oJJxIggV5KvzA6+YHVzSNFf4/qgDqnyUlcb8cR8S67e4r46
WR2zuwdyu25FpgsQBc1gJROVPRV19W/FX3rSb/nAxGl7GMLmH6MCAwEAAaAAMA0G
CSqGSIb3DQEBBQUAA4GBAClj/K2DAH5S64T6s7jervmk4N956Ho3aTLBgE+ReXLj
btcTdk3vFbQApAlG6MrSKys4HjpKpP/RENx3Js0HHeb8ELmWtIQNxRhwIpl0K5AD
xorKj+mwngLtVyARb/M7O3E8jYHzBPzpsolKWIY4AavYdmHu+Zhgm4hPKUcW+bAv
MIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAycPe7U7Ek7WazlY3fPTSluePEsmgdeBobqqX3Nys
RmuTjLml0FPWmJ56FAhFP2JUu+rfkoWbEAfV0eVBsu0+gAiaHZtrS7DJmjbdzl/C
Wl1HiGPlAfaj6GhvHSwXpx2srPnbndjtkFBe0Ib0b1TvfDaxqVWmFaXrOZREIb8y
o2oivjXOdYJ3UXWgJrwj1iDSAXoFMEW27AIDUGlvFBHcWFoVRfDA2v/yT0e605R0
haujq/EiL0dQ/8QLbxF8gKj5ZHnSI4ejq9mAhCEdi8fvSstGLYub5odz6mRuoO5T
AzoSIP35DtjX0/Rfs+qu0C+fsjh8yYAXqQu1eZ0EkDEK/QIDAQABoAAwDQYJKoZI
hvcNAQELBQADggEBAI9mZrnDPk8PaljHRTLYlYNtL0+gVpav+deUnAzbjA5bxdaw
t0xRptSDg3sFYFJWJ0HaqJltxSmdjj20MxmSCrexFOVXpISNsC/uZOs2CFWsDBdp
kL6pIDHmxJF2q3dA7kZMeElSqUohYlA5t5rHp6w8/Vb0HnHAlke4kPd+bbo0MyFt
mL2txXAz9AU8a5sG44x05VsSahtWSWeDNFbvaX27FhNDHxBMAFCj3niRQklMpCGG
uX+OWr42iNJLhjyR7zsJ26tf1gP6+kFoAz2kRNC9qyQyTAzXNEydg6Yff1TuZv2h
ktXz5unhsb91xO2iGT8PSWDHcVReSZRdyhwjYrI=
-----END CERTIFICATE REQUEST-----

View File

@@ -1,15 +1,28 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDAQLNPDILqMIulvPga6ogci69xYaSp50U7Tv8Hww3m4D9w2uby
GqR7dDW20iGJI7tTNcv/UtLqgknEiCBXkq/MDr5gdXNI0V/j+qAOqfJSVxvxxHxL
rt7ivjpZHbO7B3K7bkWmCxAFzWAlE5U9FXX1b8VfetJv+cDEaXsYwuYfowIDAQAB
AoGBAL7tQmXl2fmz/mu5kHhCpKwcuT6TpxEo4aN132aY+qxn1flBHAwiE2mbTmDi
rHViq/2GNrK5UUed3p60RdJSlgwIkyqtcGxWhUJGYCR/hU60qeeLp3MhhOoOFbiV
YTDsoC7V/SuWbX+1qG5FxnHSnTZhAIRkZXS4uTZ5WDcQm/7BAkEA+TlZ1IT9CeU/
FpHpqc8RgR8377Ehjy8o4Z4EGFnxQlAUWASnhs6dw4isr3+c7hA1OEmqmcRClPVZ
t1JbHAPC4QJBAMV60WSJzPUccCF47T9Ao2CeWFl/9dmgQQe9idpTNuKMXNtPJN44
0MQvnb+xS828woJOoRI+/UTVLLBc4xwMtwMCQQDZTadExTw4v5l1nX5GoJUbp9PG
/ARN64nSx0u8y9evwVErucs0oL0we+BOGZAEhz9QN/M3pceESDWUwYtNbv4hAkBB
Ku2MqvjK7k6GjTxlgjQn/zkSl+qOnZa4MjEarhlPm5hM+wokl0U1aK07BAwK4b6i
d8YpmkXEAEEWFiEQMZX3AkEA1SkdiFj1u7HnzO7onLJsnFzowX3pm1UFl0azOMlM
2GkjYxWeJ/4VL7Y6QkhHE0Nj3my2+MJQI9xpYgMbw/l11w==
-----END RSA PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJw97tTsSTtZrO
Vjd89NKW548SyaB14Ghuqpfc3KxGa5OMuaXQU9aYnnoUCEU/YlS76t+ShZsQB9XR
5UGy7T6ACJodm2tLsMmaNt3OX8JaXUeIY+UB9qPoaG8dLBenHays+dud2O2QUF7Q
hvRvVO98NrGpVaYVpes5lEQhvzKjaiK+Nc51gndRdaAmvCPWINIBegUwRbbsAgNQ
aW8UEdxYWhVF8MDa//JPR7rTlHSFq6Or8SIvR1D/xAtvEXyAqPlkedIjh6Or2YCE
IR2Lx+9Ky0Yti5vmh3PqZG6g7lMDOhIg/fkO2NfT9F+z6q7QL5+yOHzJgBepC7V5
nQSQMQr9AgMBAAECggEAHiOf8p98TltHrXBkGAqjRY8ACIytZ0ZXG0bo6gFdy6Qo
tZIK0qCfcwtjTYhBvdrksPCAJq1GEUI2XsUKCB4X4rzGNst/Xt5g8yQkhH459FEw
TQ+tBxrOd7pX9MngG6LbZzhopb7gl9jlnO036MSNhKbP6a1lYqD3DxIWjlr3B8Fg
JCK9T6tlkuij/METOKV0JCeQM1dwGzWTjYOXdtyci8+0/aUsLB08I72E61SP/6IK
zeFSaP2JkaUxSSA2vU369OODD/LE0EMdf21U2Dh7OGRZ55NbEoUztop0hdwI6smx
44nrmbKG23Y1LnLNFAAxopU6RAw44RG6PIwR9GrYIQKBgQDR/GuaNjfqz9livMi/
jO8EyGcLavqHQQykAT0ps1E+w+HL6Vdb+2auFTEcLMeDJIxb0iYvZyAsskvO3lgp
rH9sOcrsQrCluE+TA/tLvYmJyfAhFb42EansphO2oTDD/2aOexSGztGtuYAMBpFQ
3AkjppZN3qe4iB6gfys6fzCtXQKBgQD1+kh4Q+a1hv+Dh+Cn8wNnhgcTI3LvbU44
86G8iYmeTsEhy12PwGkz/RBLOX0DkxSPlpWgvDeF6kAgoQdA47c3ucaVnM1taf4h
cjAuS856FigM3E4C/rsEgvI7N4yV/rsKOnyqgHUwNalciAOgrhuGNDViazH9JpkK
pFaX7lhaIQKBgQCQKUyyPaDcC0BCIjtsDlSWIwNjellu/ACyo8sa0unnPlHJTXRV
SN5wi0oA/tkmNrRJ4ZenmZQkO3ACIPHEApIkefTPiOV/kG7JDsW6dPB08XdzL1s8
AZp4RnhoPHefR7tf/C3WcyzOqPi4yNWA/t8jY53y7faVoJXuOAA0k9eWXQKBgEvk
GI/igz/mktcGCS5IL/i0xWIGQePVGZlAsdn1pVwOeE/w6sD7YHoFzg0ng4aizmku
0KNy7r6Gc5qdlBtVJqYuzzJB2q+zUBEJpgvin6XTSDAPmJIb/Z96tznF/b4ZhaO2
P9hrIbzqEYLXBCeDEELrwLzIzfeI/RbndUAS7XeBAoGAa8WGdE7ndAtjCK4jCFiB
vIt4M6EZyZdmfTJ91SSEA303mp10cV6YGLOErROnBvnUlFSbRN8VNVA/LYq3M4Vm
da5jaFCjJhvH6qFhwsAkuGKsE1OPTs56iqZlSw9/8IJ6NW7/Igy6xR/Z5xRajAzl
FsyRRSHduI5HNgDo7riv46M=
-----END PRIVATE KEY-----

View File

@@ -1,18 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,8A14F3F31BF3CDF7
84UpLjX5GbfCoP/+ZRLwHZHqmgKyc2cjQOQKhp2YTk+4E0JSO7KsKwJax55r5VqE
ECGvbd8yvVZ3GRpU6bDCLelDN+Ob5ZSGhynI0f9is6Qle1/SbvaK+qL6MLf4H38l
Y91eZxjE8hLvOMHBlbobLmy9UUzl2osBDAM1nm5d1X7pF7mN4xgY8s2G7UPq3ZZS
NWwMsnwtb/9Ahm7WXfsJbebyKspkTSHYp/ozaOGW58fuKxkwRFd1UlyblZWU3ezP
JCpvJQ7HS6Dfy6+GUaxcC6pyxqnoJHYccB5usJ2h4QD4Es3sT7Vw7M80JKw3vAWm
TH7VkFX3yGfJ1p1jNzifN5687QqrjeI3/ecTs1rFhIC4TUPN9EDvw86Y6l6Mvo04
Hl2cVzCnCrZYq0ICD0op3+7f9kuKl7bz54S/iRG2qQdICohPs7ra2yaUy+NFVDs1
XdXyF5/xew+Rr2z7ygEd+OrvXxPV0zTFbicg9GXGeB/pIYAclmoSNXD5T3voN7y9
5MjSGL375N3z+kqPzMNawYCnZLwQ5jYTDUkDTATYpjcIDVDQkzbl8mFp4i+Z9GhL
H8FRAgmBbkgy3dxhFjxr/WzuaTkUCAbGhrtPd8WCPhBXJBzWdrBVR9SE8zT9n8lq
ZwaPwkPLBrLe/XZFEQJ5cdvMVNy4QQwsyxHnCgO3VUc68UYXb39MvyM6t8+S1rSm
SyvVAT+jB8T4VlE7tedQGuvyKMmeNIJe9znd3u4S+Aq2+vw6bOKeNYBMaupR5Gyl
bJrscuTG1aLUe+XH9BuFBUoIwdXuBv4Ko/pDL0MYPghDAEGkp4Acmg==
-----END RSA PRIVATE KEY-----

View File

@@ -199,6 +199,14 @@ export abstract class ClusterAdapter extends Adapter {
return debug("[%s] ignore message from self", this.uid);
}
if (message.nsp !== this.nsp.name) {
return debug(
"[%s] ignore message from another namespace (%s)",
this.uid,
message.nsp,
);
}
debug(
"[%s] new event of type %d from %s",
this.uid,
@@ -671,6 +679,8 @@ export abstract class ClusterAdapter extends Adapter {
protected publish(
message: DistributiveOmit<ClusterMessage, "nsp" | "uid">,
): void {
debug("[%s] sending message %s", this.uid, message.type);
this.publishAndReturnOffset(message).catch((err) => {
debug("[%s] error while publishing message: %s", this.uid, err);
});
@@ -699,6 +709,14 @@ export abstract class ClusterAdapter extends Adapter {
) {
(response as ClusterResponse).uid = this.uid;
(response as ClusterResponse).nsp = this.nsp.name;
debug(
"[%s] sending response %s to %s",
this.uid,
response.type,
requesterUid,
);
this.doPublishResponse(requesterUid, response as ClusterResponse).catch(
(err) => {
debug("[%s] error while publishing response: %s", this.uid, err);
@@ -790,17 +808,10 @@ export abstract class ClusterAdapterWithHeartbeat extends ClusterAdapter {
}
if (message.uid && message.uid !== EMITTER_UID) {
// we track the UID of each sender, in order to know how many servers there are in the cluster
// we track the UID of each sender to know how many servers there are in the cluster
this.nodesMap.set(message.uid, Date.now());
}
debug(
"[%s] new event of type %d from %s",
this.uid,
message.type,
message.uid,
);
switch (message.type) {
case MessageType.INITIAL_HEARTBEAT:
this.publish({

View File

@@ -67,11 +67,6 @@ describe("cluster adapter", () => {
serverSockets.push(socket);
servers.push(io);
if (servers.length === NODES_COUNT) {
// ensure all nodes know each other
servers[0].emit("ping");
servers[1].emit("ping");
servers[2].emit("ping");
done();
}
});

View File

@@ -0,0 +1,11 @@
# Releasing
1. Update the version in `package.json`
2. Update the version in `support/package.esm.json`
3. Update the changelog `CHANGELOG.md` with `conventional-changelog -p angular`
4. Compile the TypeScript sources with `npm run compile`
5. Generate the bundles with `npm run build`
6. Commit the changes in `package.json`, `support/package.esm.json`, `CHANGELOG.md` and `dist/`
7. Create the tag `socket.io-client@x.y.z` and push it to the GitHub repository. The workflow `.github/workflows/publish.yml` will safely publish the package to npm using trusted publishing.
8. Create a new release at https://github.com/socketio/socket.io/releases
9. Copy the bundles to the repository https://github.com/socketio/socket.io-cdn so that they are available at https://cdn.socket.io/

View File

@@ -1,6 +1,6 @@
import { url } from "./url.js";
import { Manager, ManagerOptions } from "./manager.js";
import { Socket, SocketOptions } from "./socket.js";
import { DisconnectDescription, Socket, SocketOptions } from "./socket.js";
import debugModule from "debug"; // debug()
const debug = debugModule("socket.io-client"); // debug()
@@ -91,6 +91,7 @@ export { protocol } from "socket.io-parser";
*/
export {
DisconnectDescription,
Manager,
ManagerOptions,
Socket,

View File

@@ -542,8 +542,7 @@ export class Socket<
args.push((err, ...responseArgs) => {
if (packet !== this._queue[0]) {
// the packet has already been acknowledged
return;
return debug("packet [%d] already acknowledged", packet.id);
}
const hasError = err !== null;
if (hasError) {
@@ -834,8 +833,8 @@ export class Socket<
this._pid = pid; // defined only if connection state recovery is enabled
this.connected = true;
this.emitBuffered();
this.emitReserved("connect");
this._drainQueue(true);
this.emitReserved("connect");
}
/**

View File

@@ -20,6 +20,7 @@ module.exports = {
mangle: {
properties: {
regex: /^_/,
reserved: ["_placeholder"],
},
},
}),

View File

@@ -110,4 +110,40 @@ describe("retry", () => {
}, 100);
});
});
it.only("should not emit a packet twice in the 'connect' handler", () => {
return wrap((done) => {
const socket = io(BASE_URL, {
forceNew: true,
retries: 3,
});
const received: string[] = [];
const sent: string[] = [];
socket.io.engine.on("packetCreate", ({ data }) => {
sent.push(data);
});
socket.io.engine.on("packet", ({ data }) => {
received.push(data);
});
socket.on("connect", () => {
socket.emit("echo", null);
});
setTimeout(() => {
expect(sent).to.eql(["0", '20["echo",null]']);
expect(received.length).to.eql(3);
// 1: engine.io OPEN packet
// 2: socket.io CONNECT packet
// 3: ack packet
expect(received[2]).to.eql("30[null]");
success(done, socket);
}, 100);
});
});
});

View File

@@ -19,7 +19,7 @@
"scripts": {
"compile": "rimraf ./dist && tsc",
"test": "npm run format:check && npm run compile && nyc mocha --import=tsx test/index.ts",
"format:check": "prettier --check \"lib/**/*.ts' \"test/**/*.ts\"",
"format:check": "prettier --check \"lib/**/*.ts\" \"test/**/*.ts\"",
"format:fix": "prettier --write \"lib/**/*.ts\" \"test/**/*.ts\"",
"prepack": "npm run compile"
},

View File

@@ -0,0 +1,19 @@
# Changelog
| Version | Release date |
|--------------------------|---------------|
| [0.1.1](#011-2025-11-07) | November 2025 |
| [0.1.0](#010-2025-11-06) | November 2025 |
## [0.1.1](https://github.com/socketio/socket.io/compare/@socket.io/redis-streams-emitter@0.1.0...@socket.io/redis-streams-emitter@0.1.1) (2025-11-07)
### Bug Fixes
* remove dependency on socket.io-adapter ([7617707](https://github.com/socketio/socket.io/commit/7617707ed8f0defd0e19cb7c6963504ce7b87f6b))
## 0.1.0 (2025-11-06)
Initial release!

View File

@@ -0,0 +1,7 @@
Copyright (c) 2025-present Guillermo Rauch and Socket.IO contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,220 @@
# Socket.IO Redis Streams emitter
The `@socket.io/redis-streams-emitter` package allows you to easily communicate with a group of Socket.IO servers from another Node.js process (server-side).
It must be used in conjunction with [`@socket.io/redis-streams-adapter`](https://github.com/socketio/socket.io-redis-streams-adapter).
**Table of contents**
<!-- TOC -->
* [Installation](#installation)
* [Usage](#usage)
* [With the `redis` package](#with-the-redis-package)
* [With the `redis` package and a Redis cluster](#with-the-redis-package-and-a-redis-cluster)
* [With the `ioredis` package](#with-the-ioredis-package)
* [With the `ioredis` package and a Redis cluster](#with-the-ioredis-package-and-a-redis-cluster)
* [Options](#options)
* [API](#api)
* [`Emitter(redisClient[, nsp][, opts])`](#emitterredisclient-nsp-opts)
* [`Emitter#to(room:string):BroadcastOperator`](#emittertoroomstringbroadcastoperator)
* [`Emitter#in(room:string):BroadcastOperator`](#emitterinroomstringbroadcastoperator)
* [`Emitter#except(room:string):BroadcastOperator`](#emitterexceptroomstringbroadcastoperator)
* [`Emitter#of(namespace:string):Emitter`](#emitterofnamespacestringemitter)
* [`Emitter#socketsJoin(rooms:string|string[])`](#emittersocketsjoinroomsstringstring)
* [`Emitter#socketsLeave(rooms:string|string[])`](#emittersocketsleaveroomsstringstring)
* [`Emitter#disconnectSockets(close:boolean)`](#emitterdisconnectsocketscloseboolean)
* [`Emitter#serverSideEmit(ev:string[,...args:any[]])`](#emitterserversideemitevstringargsany)
* [License](#license)
<!-- TOC -->
## Installation
```
npm install @socket.io/redis-streams-emitter redis
```
## Usage
### With the `redis` package
```js
import { createClient } from "redis";
import { Emitter } from "@socket.io/redis-streams-emitter";
const redisClient = createClient({
url: "redis://localhost:6379"
});
await redisClient.connect();
const io = new Emitter(redisClient);
setInterval(() => {
io.emit("ping", new Date());
}, 1000);
```
### With the `redis` package and a Redis cluster
```js
import { createCluster } from "redis";
import { Emitter } from "@socket.io/redis-streams-emitter";
const redisClient = createCluster({
rootNodes: [
{
url: "redis://localhost:7000",
},
{
url: "redis://localhost:7001",
},
{
url: "redis://localhost:7002",
},
],
});
await redisClient.connect();
const io = new Emitter(redisClient);
setInterval(() => {
io.emit("ping", new Date());
}, 1000);
```
### With the `ioredis` package
```js
import { Redis } from "ioredis";
import { Emitter } from "@socket.io/redis-streams-emitter";
const redisClient = new Redis();
const io = new Emitter(redisClient);
setInterval(() => {
io.emit("ping", new Date());
}, 1000);
```
### With the `ioredis` package and a Redis cluster
```js
import { Cluster } from "ioredis";
import { Emitter } from "@socket.io/redis-streams-emitter";
const redisClient = new Cluster([
{
host: "localhost",
port: 7000,
},
{
host: "localhost",
port: 7001,
},
{
host: "localhost",
port: 7002,
},
]);
const io = new Emitter(redisClient);
setInterval(() => {
io.emit("ping", new Date());
}, 1000);
```
## Options
| Name | Description | Default value |
|--------------|--------------------------------------------------------------------|---------------|
| `streamName` | The name of the Redis stream. | `socket.io` |
| `maxLen` | The maximum size of the stream. Almost exact trimming (~) is used. | `10_000` |
## API
### `Emitter(redisClient[, nsp][, opts])`
```js
const io = new Emitter(redisClient);
```
### `Emitter#to(room:string):BroadcastOperator`
### `Emitter#in(room:string):BroadcastOperator`
Specifies a specific `room` that you want to emit to.
```js
io.to("room1").emit("hello");
```
### `Emitter#except(room:string):BroadcastOperator`
Specifies a specific `room` that you want to exclude from broadcasting.
```js
io.except("room2").emit("hello");
```
### `Emitter#of(namespace:string):Emitter`
Specifies a specific namespace that you want to emit to.
```js
const customNamespace = io.of("/custom");
customNamespace.emit("hello");
```
### `Emitter#socketsJoin(rooms:string|string[])`
Makes the matching socket instances join the specified rooms:
```js
// make all Socket instances join the "room1" room
io.socketsJoin("room1");
// make all Socket instances of the "admin" namespace in the "room1" room join the "room2" room
io.of("/admin").in("room1").socketsJoin("room2");
```
### `Emitter#socketsLeave(rooms:string|string[])`
Makes the matching socket instances leave the specified rooms:
```js
// make all Socket instances leave the "room1" room
io.socketsLeave("room1");
// make all Socket instances of the "admin" namespace in the "room1" room leave the "room2" room
io.of("/admin").in("room1").socketsLeave("room2");
```
### `Emitter#disconnectSockets(close:boolean)`
Makes the matching socket instances disconnect:
```js
// make all Socket instances disconnect
io.disconnectSockets();
// make all Socket instances of the "admin" namespace in the "room1" room disconnect
io.of("/admin").in("room1").disconnectSockets();
// this also works with a single socket ID
io.of("/admin").in(theSocketId).disconnectSockets();
```
### `Emitter#serverSideEmit(ev:string[,...args:any[]])`
Emits an event that will be received by each Socket.IO server of the cluster.
```js
io.serverSideEmit("ping");
```
## License
[MIT](./LICENSE)

View File

@@ -0,0 +1,15 @@
services:
redis:
image: redis:5
ports:
- "6379:6379"
redis-cluster:
image: grokzen/redis-cluster:7.0.10
ports:
- "7000-7005:7000-7005"
valkey:
image: valkey/valkey:8
ports:
- "6389:6379"

View File

@@ -0,0 +1,75 @@
// imported from the 'socket.io-adapter' package
export enum MessageType {
INITIAL_HEARTBEAT = 1,
HEARTBEAT,
BROADCAST,
SOCKETS_JOIN,
SOCKETS_LEAVE,
DISCONNECT_SOCKETS,
FETCH_SOCKETS,
FETCH_SOCKETS_RESPONSE,
SERVER_SIDE_EMIT,
SERVER_SIDE_EMIT_RESPONSE,
BROADCAST_CLIENT_COUNT,
BROADCAST_ACK,
ADAPTER_CLOSE,
}
export type ServerId = string;
export type ClusterMessage = {
uid: ServerId;
nsp: string;
} & (
| {
type:
| MessageType.INITIAL_HEARTBEAT
| MessageType.HEARTBEAT
| MessageType.ADAPTER_CLOSE;
}
| {
type: MessageType.BROADCAST;
data: {
opts: { rooms: string[]; except: string[]; flags: BroadcastFlags };
packet: unknown;
requestId?: string;
};
}
| {
type: MessageType.SOCKETS_JOIN | MessageType.SOCKETS_LEAVE;
data: {
opts: { rooms: string[]; except: string[]; flags: BroadcastFlags };
rooms: string[];
};
}
| {
type: MessageType.DISCONNECT_SOCKETS;
data: {
opts: { rooms: string[]; except: string[]; flags: BroadcastFlags };
close?: boolean;
};
}
| {
type: MessageType.FETCH_SOCKETS;
data: {
opts: { rooms: string[]; except: string[]; flags: BroadcastFlags };
requestId: string;
};
}
| {
type: MessageType.SERVER_SIDE_EMIT;
data: {
requestId?: string;
packet: any[];
};
}
);
export interface BroadcastFlags {
volatile?: boolean;
compress?: boolean;
local?: boolean;
broadcast?: boolean;
binary?: boolean;
timeout?: number;
}

View File

@@ -0,0 +1,496 @@
import debugModule from "debug";
import type {
DefaultEventsMap,
EventNames,
EventParams,
EventsMap,
TypedEventBroadcaster,
} from "./typed-events";
import { encode } from "@msgpack/msgpack";
import { hasBinary, XADD } from "./util";
import { ClusterMessage, MessageType, BroadcastFlags } from "./adapter-types";
const debug = debugModule("socket.io-redis-streams-emitter");
const EMITTER_UID = "emitter";
type DistributiveOmit<T, K extends keyof any> = T extends any
? Omit<T, K>
: never;
// TODO move to the socket.io-adapter package
abstract class BaseEmitter<
EmitEvents extends EventsMap = DefaultEventsMap,
ServerSideEvents extends EventsMap = DefaultEventsMap,
> {
protected abstract publish(
message: DistributiveOmit<ClusterMessage, "uid" | "nsp">,
): void;
/**
* Emits to all clients.
*
* @return Always true
* @public
*/
public emit<Ev extends EventNames<EmitEvents>>(
ev: Ev,
...args: EventParams<EmitEvents, Ev>
): true {
return this.newBroadcastOperator().emit(ev, ...args);
}
/**
* Targets a room when emitting.
*
* @param room
* @return BroadcastOperator
* @public
*/
public to(
room: string | string[],
): BroadcastOperator<EmitEvents, ServerSideEvents> {
return this.newBroadcastOperator().to(room);
}
/**
* Targets a room when emitting.
*
* @param room
* @return BroadcastOperator
* @public
*/
public in(
room: string | string[],
): BroadcastOperator<EmitEvents, ServerSideEvents> {
return this.newBroadcastOperator().in(room);
}
/**
* Excludes a room when emitting.
*
* @param room
* @return BroadcastOperator
* @public
*/
public except(
room: string | string[],
): BroadcastOperator<EmitEvents, ServerSideEvents> {
return this.newBroadcastOperator().except(room);
}
/**
* Sets a modifier for a subsequent event emission that the event data may be lost if the client is not ready to
* receive messages (because of network slowness or other issues, or because theyre connected through long polling
* and is in the middle of a request-response cycle).
*
* @return BroadcastOperator
* @public
*/
public get volatile(): BroadcastOperator<EmitEvents, ServerSideEvents> {
return this.newBroadcastOperator().volatile;
}
/**
* Sets the compress flag.
*
* @param compress - if `true`, compresses the sending data
* @return BroadcastOperator
* @public
*/
public compress(
compress: boolean,
): BroadcastOperator<EmitEvents, ServerSideEvents> {
return this.newBroadcastOperator().compress(compress);
}
/**
* Makes the matching socket instances join the specified rooms
*
* @param rooms
* @public
*/
public socketsJoin(rooms: string | string[]): void {
return this.newBroadcastOperator().socketsJoin(rooms);
}
/**
* Makes the matching socket instances leave the specified rooms
*
* @param rooms
* @public
*/
public socketsLeave(rooms: string | string[]): void {
return this.newBroadcastOperator().socketsLeave(rooms);
}
/**
* Makes the matching socket instances disconnect
*
* @param close - whether to close the underlying connection
* @public
*/
public disconnectSockets(close: boolean = false): void {
return this.newBroadcastOperator().disconnectSockets(close);
}
/**
* Send a packet to the Socket.IO servers in the cluster
*
* @param ev - the event name
* @param args - any number of serializable arguments
*/
public serverSideEmit<Ev extends EventNames<ServerSideEvents>>(
ev: Ev,
...args: EventParams<ServerSideEvents, Ev>
): void {
return this.newBroadcastOperator().serverSideEmit(ev, ...args);
}
private newBroadcastOperator() {
return new BroadcastOperator<EmitEvents, ServerSideEvents>((msg) =>
this.publish(msg),
);
}
}
export const RESERVED_EVENTS: ReadonlySet<string | Symbol> = new Set(<const>[
"connect",
"connect_error",
"disconnect",
"disconnecting",
"newListener",
"removeListener",
]);
export class BroadcastOperator<
EmitEvents extends EventsMap,
ServerSideEvents extends EventsMap,
> implements TypedEventBroadcaster<EmitEvents>
{
constructor(
private readonly publish: (
message: DistributiveOmit<ClusterMessage, "uid" | "nsp">,
) => void,
private readonly rooms: Set<string> = new Set<string>(),
private readonly exceptRooms: Set<string> = new Set<string>(),
private readonly flags: BroadcastFlags = {},
) {}
/**
* Targets a room when emitting.
*
* @param room
* @return a new BroadcastOperator instance
* @public
*/
public to(
room: string | string[],
): BroadcastOperator<EmitEvents, ServerSideEvents> {
const rooms = new Set(this.rooms);
if (Array.isArray(room)) {
room.forEach((r) => rooms.add(r));
} else {
rooms.add(room);
}
return new BroadcastOperator(
this.publish,
rooms,
this.exceptRooms,
this.flags,
);
}
/**
* Targets a room when emitting.
*
* @param room
* @return a new BroadcastOperator instance
* @public
*/
public in(
room: string | string[],
): BroadcastOperator<EmitEvents, ServerSideEvents> {
return this.to(room);
}
/**
* Excludes a room when emitting.
*
* @param room
* @return a new BroadcastOperator instance
* @public
*/
public except(
room: string | string[],
): BroadcastOperator<EmitEvents, ServerSideEvents> {
const exceptRooms = new Set(this.exceptRooms);
if (Array.isArray(room)) {
room.forEach((r) => exceptRooms.add(r));
} else {
exceptRooms.add(room);
}
return new BroadcastOperator(
this.publish,
this.rooms,
exceptRooms,
this.flags,
);
}
/**
* Sets the compress flag.
*
* @param compress - if `true`, compresses the sending data
* @return a new BroadcastOperator instance
* @public
*/
public compress(
compress: boolean,
): BroadcastOperator<EmitEvents, ServerSideEvents> {
const flags = Object.assign({}, this.flags, { compress });
return new BroadcastOperator(
this.publish,
this.rooms,
this.exceptRooms,
flags,
);
}
/**
* Sets a modifier for a subsequent event emission that the event data may be lost if the client is not ready to
* receive messages (because of network slowness or other issues, or because theyre connected through long polling
* and is in the middle of a request-response cycle).
*
* @return a new BroadcastOperator instance
* @public
*/
public get volatile(): BroadcastOperator<EmitEvents, ServerSideEvents> {
const flags = Object.assign({}, this.flags, { volatile: true });
return new BroadcastOperator(
this.publish,
this.rooms,
this.exceptRooms,
flags,
);
}
/**
* Emits to all clients.
*
* @return Always true
* @public
*/
public emit<Ev extends EventNames<EmitEvents>>(
ev: Ev,
...args: EventParams<EmitEvents, Ev>
): true {
if (RESERVED_EVENTS.has(ev)) {
throw new Error(`"${String(ev)}" is a reserved event name`);
}
// set up packet object
const data = [ev, ...args];
const packet = {
type: 2, // EVENT
data: data,
};
const opts = {
rooms: [...this.rooms],
flags: this.flags,
except: [...this.exceptRooms],
};
this.publish({
type: MessageType.BROADCAST,
data: {
packet,
opts,
},
});
return true;
}
/**
* Makes the matching socket instances join the specified rooms
*
* @param rooms
* @public
*/
public socketsJoin(rooms: string | string[]): void {
this.publish({
type: MessageType.SOCKETS_JOIN,
data: {
opts: {
rooms: [...this.rooms],
except: [...this.exceptRooms],
flags: {},
},
rooms: Array.isArray(rooms) ? rooms : [rooms],
},
});
}
/**
* Makes the matching socket instances leave the specified rooms
*
* @param rooms
* @public
*/
public socketsLeave(rooms: string | string[]): void {
this.publish({
type: MessageType.SOCKETS_LEAVE,
data: {
opts: {
rooms: [...this.rooms],
except: [...this.exceptRooms],
flags: {},
},
rooms: Array.isArray(rooms) ? rooms : [rooms],
},
});
}
/**
* Makes the matching socket instances disconnect
*
* @param close - whether to close the underlying connection
* @public
*/
public disconnectSockets(close: boolean = false): void {
this.publish({
type: MessageType.DISCONNECT_SOCKETS,
data: {
opts: {
rooms: [...this.rooms],
except: [...this.exceptRooms],
flags: {},
},
close,
},
});
}
/**
* Send a packet to the Socket.IO servers in the cluster
*
* @param ev - the event name
* @param args - any number of serializable arguments
*/
public serverSideEmit<Ev extends EventNames<ServerSideEvents>>(
ev: Ev,
...args: EventParams<ServerSideEvents, Ev>
): void {
const withAck = args.length && typeof args[args.length - 1] === "function";
if (withAck) {
throw new Error("Acknowledgements are not supported");
}
this.publish({
type: MessageType.SERVER_SIDE_EMIT,
data: {
packet: [ev, ...args],
},
});
}
}
function flattenPayload(message: ClusterMessage) {
const rawMessage = {
uid: message.uid,
nsp: message.nsp,
type: message.type.toString(),
data: undefined as string | undefined,
};
// @ts-expect-error
const data = message.data;
if (data) {
const mayContainBinary = [
MessageType.BROADCAST,
MessageType.FETCH_SOCKETS_RESPONSE,
MessageType.SERVER_SIDE_EMIT,
MessageType.SERVER_SIDE_EMIT_RESPONSE,
MessageType.BROADCAST_ACK,
].includes(message.type);
if (mayContainBinary && hasBinary(data)) {
rawMessage.data = Buffer.from(encode(data)).toString("base64");
} else {
rawMessage.data = JSON.stringify(data);
}
}
return rawMessage;
}
export interface RedisStreamsEmitterOptions {
/**
* The name of the Redis stream.
* @default "socket.io"
*/
streamName?: string;
/**
* The maximum size of the stream. Almost exact trimming (~) is used.
* @default 10_000
*/
maxLen?: number;
}
export class Emitter<
EmitEvents extends EventsMap = DefaultEventsMap,
ServerSideEvents extends EventsMap = DefaultEventsMap,
> extends BaseEmitter<EmitEvents, ServerSideEvents> {
readonly #redisClient: any;
readonly #opts: Required<RedisStreamsEmitterOptions>;
readonly #nsp: string;
constructor(
redisClient: any,
opts: RedisStreamsEmitterOptions = {},
nsp = "/",
) {
super();
this.#redisClient = redisClient;
this.#opts = Object.assign(
{
streamName: "socket.io",
maxLen: 10_000,
},
opts,
);
this.#nsp = nsp;
}
public of(nsp: string) {
return new Emitter(this.#redisClient, this.#opts, nsp);
}
protected override publish(
message: DistributiveOmit<ClusterMessage, "uid" | "nsp">,
) {
(message as ClusterMessage).uid = EMITTER_UID;
(message as ClusterMessage).nsp = this.#nsp;
debug(
"publishing message %s to stream %s",
message.type,
this.#opts.streamName,
);
if (message.type === MessageType.BROADCAST) {
// @ts-expect-error FIXME untyped packet object
message.data.packet.nsp = this.#nsp;
}
return XADD(
this.#redisClient,
this.#opts.streamName,
flattenPayload(message as ClusterMessage),
this.#opts.maxLen,
);
}
}

View File

@@ -0,0 +1,37 @@
/**
* An events map is an interface that maps event names to their value, which
* represents the type of the `on` listener.
*/
export interface EventsMap {
[event: string]: any;
}
/**
* The default events map, used if no EventsMap is given. Using this EventsMap
* is equivalent to accepting all event names, and any data.
*/
export interface DefaultEventsMap {
[event: string]: (...args: any[]) => void;
}
/**
* Returns a union type containing all the keys of an event map.
*/
export type EventNames<Map extends EventsMap> = keyof Map & (string | symbol);
/** The tuple type representing the parameters of an event listener */
export type EventParams<
Map extends EventsMap,
Ev extends EventNames<Map>,
> = Parameters<Map[Ev]>;
/**
* Interface for classes that aren't `EventEmitter`s, but still expose a
* strictly typed `emit` method.
*/
export interface TypedEventBroadcaster<EmitEvents extends EventsMap> {
emit<Ev extends EventNames<EmitEvents>>(
ev: Ev,
...args: EventParams<EmitEvents, Ev>
): boolean;
}

View File

@@ -0,0 +1,68 @@
export function hasBinary(obj: any, toJSON?: boolean): boolean {
if (!obj || typeof obj !== "object") {
return false;
}
if (obj instanceof ArrayBuffer || ArrayBuffer.isView(obj)) {
return true;
}
if (Array.isArray(obj)) {
for (let i = 0, l = obj.length; i < l; i++) {
if (hasBinary(obj[i])) {
return true;
}
}
return false;
}
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key) && hasBinary(obj[key])) {
return true;
}
}
if (obj.toJSON && typeof obj.toJSON === "function" && !toJSON) {
return hasBinary(obj.toJSON(), true);
}
return false;
}
/**
* Whether the client comes from the `redis` package
*
* @param redisClient
*
* @see https://github.com/redis/node-redis
*/
function isRedisV4Client(redisClient: any) {
return typeof redisClient.sSubscribe === "function";
}
/**
* @see https://redis.io/commands/xadd/
*/
export function XADD(
redisClient: any,
streamName: string,
payload: any,
maxLenThreshold: number,
) {
if (isRedisV4Client(redisClient)) {
return redisClient.xAdd(streamName, "*", payload, {
TRIM: {
strategy: "MAXLEN",
strategyModifier: "~",
threshold: maxLenThreshold,
},
});
} else {
const args = [streamName, "MAXLEN", "~", maxLenThreshold, "*"];
Object.keys(payload).forEach((k) => {
args.push(k, payload[k]);
});
return redisClient.xadd.call(redisClient, args);
}
}

View File

@@ -0,0 +1,38 @@
{
"name": "@socket.io/redis-streams-emitter",
"version": "0.1.1",
"description": "The Socket.IO Redis streams emitter, allowing to communicate with a group of Socket.IO servers from another Node.js process",
"license": "MIT",
"homepage": "https://github.com/socketio/socket.io/tree/main/packages/socket.io-redis-streams-emitter#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/socketio/socket.io.git"
},
"files": [
"dist/"
],
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"compile": "rimraf ./dist && tsc",
"format:check": "prettier --parser typescript --check 'lib/**/*.ts' 'test/**/*.ts'",
"format:fix": "prettier --parser typescript --write 'lib/**/*.ts' 'test/**/*.ts'",
"prepack": "npm run compile",
"test": "npm run format:check && npm run compile && npm run test:redis-standalone && npm run test:ioredis-standalone",
"test:redis-standalone": "nyc mocha --import=tsx test/**/*.ts",
"test:redis-cluster": "REDIS_CLUSTER=1 mocha --import=tsx test/**/*.ts",
"test:ioredis-standalone": "REDIS_LIB=ioredis mocha --import=tsx test/**/*.ts",
"test:ioredis-cluster": "REDIS_LIB=ioredis REDIS_CLUSTER=1 mocha --import=tsx test/**/*.ts",
"test:valkey-standalone": "VALKEY=1 mocha --import=tsx test/**/*.ts"
},
"dependencies": {
"@msgpack/msgpack": "~2.8.0",
"debug": "~4.4.1"
},
"keywords": [
"socket.io",
"redis",
"redis-streams",
"emitter"
]
}

View File

@@ -0,0 +1,225 @@
import { type Server, type Socket as ServerSocket } from "socket.io";
import { type Socket as ClientSocket } from "socket.io-client";
import expect = require("expect.js");
import { times, sleep, setup, initRedisClient } from "./util";
import { Emitter } from "../lib";
const PROPAGATION_DELAY_IN_MS = 100;
describe("@socket.io/redis-streams-emitter", () => {
let servers: Server[],
serverSockets: ServerSocket[],
clientSockets: ClientSocket[],
cleanup: () => void,
emitter: Emitter;
beforeEach(async () => {
const testContext = await setup();
servers = testContext.servers;
serverSockets = testContext.serverSockets;
clientSockets = testContext.clientSockets;
const redisClient = await initRedisClient();
emitter = new Emitter(redisClient);
cleanup = () => {
testContext.cleanup();
redisClient.quit();
};
});
afterEach(() => cleanup());
describe("broadcast", function () {
it("broadcasts to all clients", (done) => {
const partialDone = times(3, done);
clientSockets.forEach((clientSocket) => {
clientSocket.on("test", (arg1, arg2, arg3) => {
expect(arg1).to.eql(1);
expect(arg2).to.eql("2");
expect(Buffer.isBuffer(arg3)).to.be(true);
partialDone();
});
});
emitter.emit("test", 1, "2", Buffer.from([3, 4]));
});
it("broadcasts to all clients in a namespace", (done) => {
const partialDone = times(3, () => {
servers.forEach((server) => server.of("/custom").adapter.close());
done();
});
servers.forEach((server) => server.of("/custom"));
const onConnect = times(3, async () => {
await sleep(PROPAGATION_DELAY_IN_MS);
emitter.of("/custom").emit("test");
});
clientSockets.forEach((clientSocket) => {
const socket = clientSocket.io.socket("/custom");
socket.on("connect", onConnect);
socket.on("test", () => {
socket.disconnect();
partialDone();
});
});
});
it("broadcasts to all clients in a room", (done) => {
serverSockets[1].join("room1");
clientSockets[0].on("test", () => {
done(new Error("should not happen"));
});
clientSockets[1].on("test", () => {
done();
});
clientSockets[2].on("test", () => {
done(new Error("should not happen"));
});
emitter.to("room1").emit("test");
});
it("broadcasts to all clients except in room", (done) => {
const partialDone = times(2, done);
serverSockets[1].join("room1");
clientSockets[0].on("test", () => {
partialDone();
});
clientSockets[1].on("test", () => {
done(new Error("should not happen"));
});
clientSockets[2].on("test", () => {
partialDone();
});
emitter.of("/").except("room1").emit("test");
});
});
describe("socketsJoin", () => {
it("makes all socket instances join the specified room", async () => {
emitter.socketsJoin("room1");
await sleep(PROPAGATION_DELAY_IN_MS);
expect(serverSockets[0].rooms.has("room1")).to.be(true);
expect(serverSockets[1].rooms.has("room1")).to.be(true);
expect(serverSockets[2].rooms.has("room1")).to.be(true);
});
it("makes the matching socket instances join the specified room", async () => {
serverSockets[0].join("room1");
serverSockets[2].join("room1");
emitter.in("room1").socketsJoin("room2");
await sleep(PROPAGATION_DELAY_IN_MS);
expect(serverSockets[0].rooms.has("room2")).to.be(true);
expect(serverSockets[1].rooms.has("room2")).to.be(false);
expect(serverSockets[2].rooms.has("room2")).to.be(true);
});
it("makes the given socket instance join the specified room", async () => {
emitter.in(serverSockets[1].id).socketsJoin("room3");
await sleep(PROPAGATION_DELAY_IN_MS);
expect(serverSockets[0].rooms.has("room3")).to.be(false);
expect(serverSockets[1].rooms.has("room3")).to.be(true);
expect(serverSockets[2].rooms.has("room3")).to.be(false);
});
});
describe("socketsLeave", () => {
it("makes all socket instances leave the specified room", async () => {
serverSockets[0].join("room1");
serverSockets[2].join("room1");
emitter.socketsLeave("room1");
await sleep(PROPAGATION_DELAY_IN_MS);
expect(serverSockets[0].rooms.has("room1")).to.be(false);
expect(serverSockets[1].rooms.has("room1")).to.be(false);
expect(serverSockets[2].rooms.has("room1")).to.be(false);
});
it("makes the matching socket instances leave the specified room", async () => {
serverSockets[0].join(["room1", "room2"]);
serverSockets[1].join(["room1", "room2"]);
serverSockets[2].join(["room2"]);
emitter.in("room1").socketsLeave("room2");
await sleep(PROPAGATION_DELAY_IN_MS);
expect(serverSockets[0].rooms.has("room2")).to.be(false);
expect(serverSockets[1].rooms.has("room2")).to.be(false);
expect(serverSockets[2].rooms.has("room2")).to.be(true);
});
it("makes the given socket instance leave the specified room", async () => {
serverSockets[0].join("room3");
serverSockets[1].join("room3");
serverSockets[2].join("room3");
emitter.in(serverSockets[1].id).socketsLeave("room3");
await sleep(PROPAGATION_DELAY_IN_MS);
expect(serverSockets[0].rooms.has("room3")).to.be(true);
expect(serverSockets[1].rooms.has("room3")).to.be(false);
expect(serverSockets[2].rooms.has("room3")).to.be(true);
});
});
describe("disconnectSockets", () => {
it("makes all socket instances disconnect", (done) => {
const partialDone = times(3, done);
clientSockets.forEach((clientSocket) => {
clientSocket.on("disconnect", (reason) => {
expect(reason).to.eql("io server disconnect");
partialDone();
});
});
emitter.disconnectSockets();
});
});
describe("serverSideEmit", () => {
it("sends an event to other server instances", (done) => {
const partialDone = times(3, done);
emitter.serverSideEmit("hello", "world", 1, "2");
servers[0].on("hello", (arg1, arg2, arg3) => {
expect(arg1).to.eql("world");
expect(arg2).to.eql(1);
expect(arg3).to.eql("2");
partialDone();
});
servers[1].on("hello", (arg1, arg2, arg3) => {
partialDone();
});
servers[2].of("/").on("hello", () => {
partialDone();
});
});
});
});

View File

@@ -0,0 +1,156 @@
import { createServer } from "node:http";
import { type AddressInfo } from "node:net";
import { createClient, createCluster } from "redis";
import { Redis, Cluster } from "ioredis";
import { Server, type Socket as ServerSocket } from "socket.io";
import { io as ioc, type Socket as ClientSocket } from "socket.io-client";
import { createAdapter } from "@socket.io/redis-streams-adapter";
export function times(count: number, fn: () => void) {
let i = 0;
return () => {
i++;
if (i === count) {
fn();
} else if (i > count) {
throw new Error(`too many calls: ${i} instead of ${count}`);
}
};
}
export function sleep(duration: number) {
return new Promise((resolve) => setTimeout(resolve, duration));
}
const mode = process.env.REDIS_CLUSTER === "1" ? "cluster" : "standalone";
const lib = process.env.REDIS_LIB || "redis";
console.log(`[INFO] testing in ${mode} mode with ${lib}`);
export async function initRedisClient() {
if (mode === "cluster") {
if (lib === "ioredis") {
return new Cluster([
{
host: "localhost",
port: 7000,
},
{
host: "localhost",
port: 7001,
},
{
host: "localhost",
port: 7002,
},
{
host: "localhost",
port: 7003,
},
{
host: "localhost",
port: 7004,
},
{
host: "localhost",
port: 7005,
},
]);
} else {
const redisClient = createCluster({
rootNodes: [
{
url: "redis://localhost:7000",
},
{
url: "redis://localhost:7001",
},
{
url: "redis://localhost:7002",
},
{
url: "redis://localhost:7003",
},
{
url: "redis://localhost:7004",
},
{
url: "redis://localhost:7005",
},
],
});
await redisClient.connect();
return redisClient;
}
} else {
if (lib === "ioredis") {
return new Redis();
} else {
const port = process.env.VALKEY === "1" ? 6389 : 6379;
const redisClient = createClient({
url: `redis://localhost:${port}`,
});
await redisClient.connect();
return redisClient;
}
}
}
async function init() {
const redisClient = await initRedisClient();
const httpServer = createServer();
const io = new Server(httpServer, {
adapter: createAdapter(redisClient, {
readCount: 1, // return as soon as possible
}),
});
return new Promise<{
io: Server;
socket: ServerSocket;
clientSocket: ClientSocket;
cleanup: () => void;
}>((resolve) => {
httpServer.listen(() => {
const port = (httpServer.address() as AddressInfo).port;
const clientSocket = ioc(`http://localhost:${port}`);
io.on("connection", async (socket) => {
resolve({
io,
socket,
clientSocket,
cleanup: () => {
io.close();
clientSocket.disconnect();
redisClient.quit();
},
});
});
});
});
}
export async function setup() {
const results = await Promise.all([init(), init(), init()]);
const servers = results.map(({ io }) => io);
const serverSockets = results.map(({ socket }) => socket);
const clientSockets = results.map(({ clientSocket }) => clientSocket);
const cleanupMethods = results.map(({ cleanup }) => cleanup);
return {
servers,
serverSockets,
clientSockets,
cleanup: () => {
for (const cleanup of cleanupMethods) {
cleanup();
}
},
};
}

View File

@@ -0,0 +1,13 @@
{
"compilerOptions": {
"outDir": "./dist",
"allowJs": false,
"target": "es2022",
"module": "commonjs",
"declaration": true,
"strict": true
},
"include": [
"./lib/**/*"
]
}

View File

@@ -0,0 +1,8 @@
# Releasing
1. Update the version in `package.json`
2. Update the changelog `CHANGELOG.md` with `conventional-changelog -p angular`
3. Copy the bundles from the client project to `client-dist/`
4. Commit the changes in `package.json`, `CHANGELOG.md` and `client-dist/`
5. Create the tag `socket.io@x.y.z` and push it to the GitHub repository. The workflow `.github/workflows/publish.yml` will safely publish the package to npm using trusted publishing.
6. Create a new release at https://github.com/socketio/socket.io/releases

View File

@@ -267,16 +267,7 @@ export class Client<
* @private
*/
private ondecoded(packet: Packet): void {
let namespace: string;
let authPayload: Record<string, unknown>;
if (this.conn.protocol === 3) {
const parsed = url.parse(packet.nsp, true);
namespace = parsed.pathname!;
authPayload = parsed.query;
} else {
namespace = packet.nsp;
authPayload = packet.data;
}
const { namespace, authPayload } = this._parseNamespace(packet);
const socket = this.nsps.get(namespace);
if (!socket && packet.type === PacketType.CONNECT) {
@@ -295,6 +286,20 @@ export class Client<
}
}
private _parseNamespace(packet: Packet) {
if (this.conn.protocol !== 3) {
return {
namespace: packet.nsp,
authPayload: packet.data,
};
}
const url = new URL(packet.nsp, "https://socket.io");
return {
namespace: url.pathname,
authPayload: Object.fromEntries(url.searchParams.entries()),
};
}
/**
* Handles an error.
*