Connect over polling first so the game still works when a proxy drops the
websocket upgrade.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-13 17:15:47 +02:00
co-authored by Claude Opus 5.5
parent 037b98f5e1
commit d1a9c7d0f7
7 changed files with 24 additions and 14 deletions
+1 -1
View File
@@ -186,7 +186,7 @@ restored on start. Players reconnect by themselves within a few seconds.
| `EACCES` during `npm ci`, build, or at start-up | Folder not owned by your user. Re-run the `chown` in step 2. |
| `EADDRINUSE` in `pm2 logs` | Port 3010 is taken. Change `PORT` in `ecosystem.config.cjs` and `localPort` in frpc, then `pm2 restart two-keys --update-env` and restart frpc. |
| Local `curl` works, domain gives frp's "page not found" | `customDomains` doesn't match the host name exactly, frpc wasn't restarted, or the front proxy rewrites `Host`. |
| Site loads but "Can't reach the server" toasts, or games feel laggy | Websocket upgrade headers missing on the central server's HTTPS proxy. |
| Site loads but games feel laggy, or `/socket.io` requests with `transport=websocket` fail in the browser's network tab | Websocket upgrade headers missing on the central server's HTTPS proxy. The game still works over polling. |
| Site loads but no games listed | `npm run build` or `validate-content` failed. Check `pm2 logs two-keys`. |
Do not run more than one instance (no pm2 cluster mode, no second copy behind a load balancer):
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@two-keys/client",
"version": "1.0.0",
"version": "1.0.1",
"private": true,
"type": "module",
"scripts": {
+3 -1
View File
@@ -2,7 +2,9 @@ import { io } from 'socket.io-client';
import type { JoinAck } from '@two-keys/shared';
import { pushToast } from './toasts';
export const socket = io({ transports: ['websocket', 'polling'] });
// Polling first, then upgrade: a websocket-first client never falls back, so a proxy that
// drops the Upgrade header would leave it unable to connect at all.
export const socket = io();
socket.on('toast', ({ message }: { message: string }) => pushToast(message));
socket.on('error', ({ message }: { message: string }) => pushToast(message, 'error'));
+5 -5
View File
@@ -1,12 +1,12 @@
{
"name": "two-keys",
"version": "1.0.0",
"version": "1.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "two-keys",
"version": "1.0.0",
"version": "1.0.1",
"workspaces": [
"shared",
"server",
@@ -23,7 +23,7 @@
},
"client": {
"name": "@two-keys/client",
"version": "1.0.0",
"version": "1.0.1",
"dependencies": {
"@two-keys/shared": "*",
"framer-motion": "^11.11.0",
@@ -6847,7 +6847,7 @@
},
"server": {
"name": "@two-keys/server",
"version": "1.0.0",
"version": "1.0.1",
"dependencies": {
"@two-keys/shared": "*",
"express": "^4.21.0",
@@ -7332,7 +7332,7 @@
},
"shared": {
"name": "@two-keys/shared",
"version": "1.0.0",
"version": "1.0.1",
"devDependencies": {
"vitest": "^2.1.0"
}
+9 -3
View File
@@ -1,10 +1,16 @@
{
"name": "two-keys",
"private": true,
"version": "1.0.0",
"version": "1.0.1",
"description": "Co-op mystery games for couples",
"workspaces": ["shared", "server", "client"],
"engines": { "node": ">=20" },
"workspaces": [
"shared",
"server",
"client"
],
"engines": {
"node": ">=20"
},
"scripts": {
"dev": "npm run validate-content && concurrently -n server,client \"npm -w server run dev\" \"npm -w client run dev\"",
"build": "npm -w shared run build && npm -w client run build && npm -w server run build",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@two-keys/server",
"version": "1.0.0",
"version": "1.0.1",
"private": true,
"type": "module",
"scripts": {
+4 -2
View File
@@ -1,11 +1,13 @@
{
"name": "@two-keys/shared",
"version": "1.0.0",
"version": "1.0.1",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": { ".": "./src/index.ts" },
"exports": {
".": "./src/index.ts"
},
"scripts": {
"build": "tsc --noEmit -p tsconfig.json",
"test": "vitest run"