@couch-kit/host 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -5
- package/package.json +4 -4
- package/src/provider.tsx +35 -3
- package/src/server.ts +10 -0
package/README.md
CHANGED
|
@@ -50,14 +50,20 @@ Returns:
|
|
|
50
50
|
- `serverUrl`: HTTP URL phones should open (or `devServerUrl` in dev mode)
|
|
51
51
|
- `serverError`: static server error (if startup fails)
|
|
52
52
|
|
|
53
|
-
## System Actions
|
|
53
|
+
## System Actions
|
|
54
54
|
|
|
55
|
-
The host
|
|
55
|
+
The host automatically dispatches internal system actions (`__PLAYER_JOINED__`, `__PLAYER_LEFT__`, `__HYDRATE__`) into `createGameReducer`, which handles them for you. **You do not need to handle these in your reducer.**
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
- `PLAYER_LEFT`: payload `{ playerId: string }`
|
|
57
|
+
Player tracking (`state.players`) is managed automatically:
|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
- When a player joins, they are added to `state.players` with `connected: true`.
|
|
60
|
+
- When a player disconnects, they are marked as `connected: false`.
|
|
61
|
+
|
|
62
|
+
To react to player events outside of state (e.g., logging, analytics), use the callback config options:
|
|
63
|
+
|
|
64
|
+
- `onPlayerJoined?: (playerId: string, name: string) => void` -- called when a player successfully joins.
|
|
65
|
+
- `onPlayerLeft?: (playerId: string) => void` -- called when a player disconnects.
|
|
66
|
+
- `onError?: (error: Error) => void` -- called when a server error occurs.
|
|
61
67
|
|
|
62
68
|
### 1. Configure the Provider
|
|
63
69
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@couch-kit/host",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "React Native host for local multiplayer party games on Android TV — WebSocket server, state management, and static file serving",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"clean": "del-cli lib"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@couch-kit/core": "0.3.
|
|
54
|
+
"@couch-kit/core": "0.3.2",
|
|
55
55
|
"buffer": "^6.0.3",
|
|
56
56
|
"js-sha1": "^0.7.0",
|
|
57
57
|
"react-native-fs": "^2.20.0",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"react-native-tcp-socket": "^6.0.6"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@types/react": "
|
|
64
|
-
"@types/react-native": "0.
|
|
63
|
+
"@types/react": "^18.2.0",
|
|
64
|
+
"@types/react-native": "^0.72.0",
|
|
65
65
|
"react": "18.2.0",
|
|
66
66
|
"react-native": "0.72.6",
|
|
67
67
|
"del-cli": "^5.1.0",
|
package/src/provider.tsx
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
InternalActionTypes,
|
|
15
15
|
DEFAULT_HTTP_PORT,
|
|
16
16
|
DEFAULT_WS_PORT_OFFSET,
|
|
17
|
+
createGameReducer,
|
|
17
18
|
type IGameState,
|
|
18
19
|
type IAction,
|
|
19
20
|
type InternalAction,
|
|
@@ -22,7 +23,7 @@ import {
|
|
|
22
23
|
|
|
23
24
|
export interface GameHostConfig<S extends IGameState, A extends IAction> {
|
|
24
25
|
initialState: S;
|
|
25
|
-
reducer: (state: S, action: A
|
|
26
|
+
reducer: (state: S, action: A) => S;
|
|
26
27
|
port?: number; // Static server port (default 8080)
|
|
27
28
|
wsPort?: number; // WebSocket port (default: HTTP port + 2, i.e. 8082)
|
|
28
29
|
devMode?: boolean;
|
|
@@ -39,7 +40,7 @@ export interface GameHostConfig<S extends IGameState, A extends IAction> {
|
|
|
39
40
|
|
|
40
41
|
interface GameHostContextValue<S extends IGameState, A extends IAction> {
|
|
41
42
|
state: S;
|
|
42
|
-
dispatch: (action: A
|
|
43
|
+
dispatch: (action: A) => void;
|
|
43
44
|
serverUrl: string | null;
|
|
44
45
|
serverError: Error | null;
|
|
45
46
|
}
|
|
@@ -86,6 +87,22 @@ function isValidClientMessage(msg: unknown): msg is ClientMessage {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
/**
|
|
91
|
+
* React context provider that turns a React Native TV app into a local game server.
|
|
92
|
+
*
|
|
93
|
+
* Starts a static file server (for the web controller) and a WebSocket game server
|
|
94
|
+
* (for real-time state sync). Manages the canonical game state using the provided
|
|
95
|
+
* reducer and broadcasts state updates to all connected clients.
|
|
96
|
+
*
|
|
97
|
+
* @param config - Host configuration including reducer, initial state, ports, and callbacks.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* <GameHostProvider config={{ reducer: gameReducer, initialState }}>
|
|
102
|
+
* <GameScreen />
|
|
103
|
+
* </GameHostProvider>
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
89
106
|
export function GameHostProvider<S extends IGameState, A extends IAction>({
|
|
90
107
|
children,
|
|
91
108
|
config,
|
|
@@ -93,7 +110,12 @@ export function GameHostProvider<S extends IGameState, A extends IAction>({
|
|
|
93
110
|
children: React.ReactNode;
|
|
94
111
|
config: GameHostConfig<S, A>;
|
|
95
112
|
}) {
|
|
96
|
-
|
|
113
|
+
// Wrap the user's reducer with createGameReducer to handle internal actions
|
|
114
|
+
// (HYDRATE, PLAYER_JOINED, PLAYER_LEFT) automatically.
|
|
115
|
+
const [state, dispatch] = useReducer(
|
|
116
|
+
createGameReducer(config.reducer),
|
|
117
|
+
config.initialState,
|
|
118
|
+
);
|
|
97
119
|
|
|
98
120
|
// Keep a ref to state so we can access it inside callbacks/effects that don't depend on it
|
|
99
121
|
const stateRef = useRef(state);
|
|
@@ -312,6 +334,16 @@ export function GameHostProvider<S extends IGameState, A extends IAction>({
|
|
|
312
334
|
);
|
|
313
335
|
}
|
|
314
336
|
|
|
337
|
+
/**
|
|
338
|
+
* React hook to access the game host context.
|
|
339
|
+
*
|
|
340
|
+
* Must be used within a `<GameHostProvider>`. Returns the canonical game state,
|
|
341
|
+
* a dispatch function for actions, the server URL (for QR codes), and any
|
|
342
|
+
* server startup errors.
|
|
343
|
+
*
|
|
344
|
+
* @returns An object with `state`, `dispatch`, `serverUrl`, and `serverError`.
|
|
345
|
+
* @throws If used outside of a `<GameHostProvider>`.
|
|
346
|
+
*/
|
|
315
347
|
export function useGameHost<S extends IGameState, A extends IAction>() {
|
|
316
348
|
const context = useContext(GameHostContext);
|
|
317
349
|
if (!context) {
|
package/src/server.ts
CHANGED
|
@@ -11,6 +11,16 @@ export interface CouchKitHostConfig {
|
|
|
11
11
|
staticDir?: string; // Override the default www directory path (required on Android)
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* React hook that manages a static HTTP file server for serving the web controller.
|
|
16
|
+
*
|
|
17
|
+
* In production mode, starts a `StaticServer` bound to `0.0.0.0` on the configured port,
|
|
18
|
+
* serving files from `staticDir` (or `${RNFS.MainBundlePath}/www` by default).
|
|
19
|
+
* In dev mode, skips the server and returns `devServerUrl` directly.
|
|
20
|
+
*
|
|
21
|
+
* @param config - Server configuration including port, dev mode, and static directory.
|
|
22
|
+
* @returns An object with `url` (the server URL or null), `error`, and `loading`.
|
|
23
|
+
*/
|
|
14
24
|
export const useStaticServer = (config: CouchKitHostConfig) => {
|
|
15
25
|
const [url, setUrl] = useState<string | null>(null);
|
|
16
26
|
const [error, setError] = useState<Error | null>(null);
|