@couch-kit/client 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +2 -2
- package/dist/index.js +7 -0
- package/lib/client.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/client.ts +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @couch-kit/client
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Fix player state not restored on page refresh
|
|
8
|
+
|
|
9
|
+
Players now maintain their identity across page refreshes and network reconnections. The library uses a stable player ID derived from a persistent session secret (stored in localStorage) instead of the ephemeral WebSocket socket ID.
|
|
10
|
+
|
|
11
|
+
**New features:**
|
|
12
|
+
- `__PLAYER_RECONNECTED__` internal action: dispatched when a returning player reconnects, preserving all game data (hand, score, turn, etc.)
|
|
13
|
+
- `__PLAYER_REMOVED__` internal action: dispatched when a disconnected player times out (default: 5 minutes), permanently removing them from state
|
|
14
|
+
- Race-safe disconnect handling: prevents marking a player as disconnected if they've already reconnected on a new socket
|
|
15
|
+
- Secret validation: malformed session secrets are rejected at the JOIN boundary
|
|
16
|
+
|
|
17
|
+
**Breaking changes:**
|
|
18
|
+
- `state.players` keys are now stable derived player IDs instead of ephemeral socket IDs
|
|
19
|
+
- `playerId` returned by `useGameClient()` and sent in `WELCOME` messages is now a stable identifier that persists across reconnections
|
|
20
|
+
- `secret` field in `JOIN` payload is now required (was optional)
|
|
21
|
+
|
|
22
|
+
**Security:**
|
|
23
|
+
- Raw session secret is never stored on `IPlayer` or broadcast to clients
|
|
24
|
+
- Only the derived public player ID is shared in game state
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Updated dependencies
|
|
29
|
+
- @couch-kit/core@0.5.0
|
|
30
|
+
|
|
3
31
|
## 0.5.1
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ Returns:
|
|
|
40
40
|
|
|
41
41
|
- `status`: `'connecting' | 'connected' | 'disconnected' | 'error'`
|
|
42
42
|
- `state`: current controller state (optimistic + hydrated)
|
|
43
|
-
- `playerId`:
|
|
43
|
+
- `playerId`: stable public identifier derived from the session secret. Persists across page refreshes and reconnections (the same player always gets the same `playerId`).
|
|
44
44
|
- `sendAction(action)`: optimistic dispatch + send to host
|
|
45
45
|
- `getServerTime()`: NTP-ish server time based on periodic ping/pong
|
|
46
46
|
- `rtt`: round-trip time (ms) to the server, updated periodically via PING/PONG
|
|
@@ -94,7 +94,7 @@ export default function Controller() {
|
|
|
94
94
|
const {
|
|
95
95
|
status, // 'connecting' | 'connected' | 'disconnected' | 'error'
|
|
96
96
|
state, // The current game state (synced with Host)
|
|
97
|
-
playerId, //
|
|
97
|
+
playerId, // Stable identifier, persists across reconnections
|
|
98
98
|
sendAction, // Function to send actions to Host
|
|
99
99
|
} = useGameClient({
|
|
100
100
|
reducer: gameReducer,
|
package/dist/index.js
CHANGED
|
@@ -156,6 +156,13 @@ function useGameClient(config) {
|
|
|
156
156
|
case MessageTypes2.PONG:
|
|
157
157
|
handlePongRef.current(msg.payload);
|
|
158
158
|
break;
|
|
159
|
+
case MessageTypes2.RECONNECTED:
|
|
160
|
+
setPlayerId(msg.payload.playerId);
|
|
161
|
+
dispatchLocal({
|
|
162
|
+
type: InternalActionTypes.HYDRATE,
|
|
163
|
+
payload: msg.payload.state
|
|
164
|
+
});
|
|
165
|
+
break;
|
|
159
166
|
}
|
|
160
167
|
} catch (e) {
|
|
161
168
|
console.error("Failed to parse message", e);
|
package/lib/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAUL,KAAK,UAAU,EACf,KAAK,OAAO,EAEb,MAAM,iBAAiB,CAAC;AAGzB,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,OAAO;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;IACpC,YAAY,EAAE,CAAC,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,OAAO,EACnE,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;;;;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAUL,KAAK,UAAU,EACf,KAAK,OAAO,EAEb,MAAM,iBAAiB,CAAC;AAGzB,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,OAAO;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC;IACpC,YAAY,EAAE,CAAC,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,OAAO,EACnE,MAAM,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;;;;yBAsNc,CAAC;;IAqBvC,8EAA8E;;IAE9E,0EAA0E;;IAE1E,+EAA+E;;EAGlF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@couch-kit/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "React hooks for phone controllers in Couch Kit party games — WebSocket client and action dispatch",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"clean": "rm -rf dist lib"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@couch-kit/core": "0.
|
|
46
|
+
"@couch-kit/core": "0.5.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"react": "^18.2.0",
|
package/src/client.ts
CHANGED
|
@@ -179,6 +179,14 @@ export function useGameClient<S extends IGameState, A extends IAction>(
|
|
|
179
179
|
case MessageTypes.PONG:
|
|
180
180
|
handlePongRef.current(msg.payload);
|
|
181
181
|
break;
|
|
182
|
+
|
|
183
|
+
case MessageTypes.RECONNECTED:
|
|
184
|
+
setPlayerId(msg.payload.playerId);
|
|
185
|
+
dispatchLocal({
|
|
186
|
+
type: InternalActionTypes.HYDRATE,
|
|
187
|
+
payload: msg.payload.state as S,
|
|
188
|
+
} as InternalAction<S>);
|
|
189
|
+
break;
|
|
182
190
|
}
|
|
183
191
|
} catch (e) {
|
|
184
192
|
console.error("Failed to parse message", e);
|