@beta-gamer/react-native 0.1.18 → 0.1.21
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 +166 -70
- package/dist/index.d.mts +22 -9
- package/dist/index.d.ts +22 -9
- package/dist/index.js +1028 -46
- package/dist/index.mjs +1061 -51
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -5,132 +5,228 @@ React Native SDK for [Beta Gamer](https://beta-gamer.com) — embed multiplayer
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @beta-gamer/react-native
|
|
8
|
+
npm install @beta-gamer/react-native
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
> `react-native-webview` is only required for subway-runner. Chess, Checkers, Connect4, and Tictactoe are fully native.
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# Android — no extra steps needed
|
|
14
|
+
# Only if using subway-runner:
|
|
15
|
+
npx expo install react-native-webview # Expo
|
|
16
|
+
npm install react-native-webview && cd ios && pod install # Bare RN
|
|
18
17
|
```
|
|
19
18
|
|
|
20
19
|
## Requirements
|
|
21
20
|
|
|
22
|
-
- React Native 0.73+
|
|
23
|
-
-
|
|
24
|
-
|
|
21
|
+
- React Native 0.73+ or Expo SDK 50+
|
|
22
|
+
- A Beta Gamer account and API key → [beta-gamer.com](https://beta-gamer.com)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick start — Chess (fully native)
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
`ChessBoard` is a self-contained native component. It manages its own socket, renders with RN primitives, and handles matchmaking, clocks, AFK warnings, pawn promotion, and game-over automatically.
|
|
27
29
|
|
|
28
|
-
**1. Create a session
|
|
30
|
+
**1. Create a session on your backend** (never call the Beta Gamer API from the app)
|
|
29
31
|
|
|
30
32
|
```ts
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
// Your server — e.g. Express, Next.js API route, Cloudflare Worker
|
|
34
|
+
app.post('/api/game/start', async (req, res) => {
|
|
35
|
+
const { userId, userName, matchType } = req.body;
|
|
36
|
+
const response = await fetch('https://api.beta-gamer.com/v1/sessions', {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: {
|
|
39
|
+
'Authorization': 'Bearer bg_live_xxxx',
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
},
|
|
42
|
+
body: JSON.stringify({
|
|
43
|
+
game: 'chess',
|
|
44
|
+
matchType,
|
|
45
|
+
players: [{ id: userId, displayName: userName }],
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
const data = await response.json();
|
|
49
|
+
res.json({ sessionToken: data.sessionToken });
|
|
42
50
|
});
|
|
43
|
-
const { sessionToken } = await res.json();
|
|
44
51
|
```
|
|
45
52
|
|
|
46
|
-
**
|
|
53
|
+
> ⚠️ **Never call the Beta Gamer API from your app.** Your API key would be bundled into the binary and is trivially extractable from any APK or IPA.
|
|
47
54
|
|
|
48
|
-
|
|
49
|
-
import {
|
|
50
|
-
BetaGamerProvider,
|
|
51
|
-
ChessBoard,
|
|
52
|
-
ChessMoveHistory,
|
|
53
|
-
PlayerCard,
|
|
54
|
-
Timer,
|
|
55
|
-
} from '@beta-gamer/react-native';
|
|
56
|
-
import { View, StyleSheet } from 'react-native';
|
|
55
|
+
**2. Lobby screen — fetch the token**
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
```tsx
|
|
58
|
+
import { useState } from 'react';
|
|
59
|
+
import { View, Button, ActivityIndicator } from 'react-native';
|
|
60
|
+
import { useNavigation } from '@react-navigation/native';
|
|
61
|
+
|
|
62
|
+
export function ChessLobbyScreen() {
|
|
63
|
+
const navigation = useNavigation<any>();
|
|
64
|
+
const [loading, setLoading] = useState(false);
|
|
65
|
+
|
|
66
|
+
const startGame = async (matchType: 'matchmaking' | 'bot') => {
|
|
67
|
+
setLoading(true);
|
|
68
|
+
const res = await fetch('https://your-api.com/api/game/start', {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
headers: { 'Content-Type': 'application/json' },
|
|
71
|
+
body: JSON.stringify({ game: 'chess', matchType }),
|
|
72
|
+
});
|
|
73
|
+
const { sessionToken } = await res.json();
|
|
74
|
+
navigation.navigate('ChessGame', { sessionToken });
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
if (loading) return <ActivityIndicator />;
|
|
59
78
|
return (
|
|
60
|
-
<
|
|
61
|
-
<
|
|
62
|
-
|
|
63
|
-
|
|
79
|
+
<View>
|
|
80
|
+
<Button title="Find opponent" onPress={() => startGame('matchmaking')} />
|
|
81
|
+
<Button title="vs Bot" onPress={() => startGame('bot')} />
|
|
82
|
+
</View>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
64
86
|
|
|
65
|
-
|
|
66
|
-
<ChessMoveHistory style={styles.history} textStyle={styles.move} />
|
|
87
|
+
**3. Game screen — drop in `ChessBoard`**
|
|
67
88
|
|
|
68
|
-
|
|
69
|
-
|
|
89
|
+
```tsx
|
|
90
|
+
import { View, StyleSheet } from 'react-native';
|
|
91
|
+
import { useRoute, useNavigation } from '@react-navigation/native';
|
|
92
|
+
import { BetaGamerProvider, ChessBoard } from '@beta-gamer/react-native';
|
|
93
|
+
|
|
94
|
+
export function ChessGameScreen() {
|
|
95
|
+
const { sessionToken } = useRoute<any>().params;
|
|
96
|
+
const navigation = useNavigation();
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<BetaGamerProvider
|
|
100
|
+
token={sessionToken}
|
|
101
|
+
serverUrl="https://api.beta-gamer.com"
|
|
102
|
+
connectSocket={false} // ChessBoard manages its own socket
|
|
103
|
+
>
|
|
104
|
+
<View style={styles.screen}>
|
|
105
|
+
<ChessBoard
|
|
106
|
+
style={styles.board}
|
|
107
|
+
onLeave={() => navigation.goBack()}
|
|
108
|
+
/>
|
|
70
109
|
</View>
|
|
71
110
|
</BetaGamerProvider>
|
|
72
111
|
);
|
|
73
112
|
}
|
|
74
113
|
|
|
75
114
|
const styles = StyleSheet.create({
|
|
76
|
-
|
|
115
|
+
screen: { flex: 1, backgroundColor: '#0a0a0f' },
|
|
77
116
|
board: { flex: 1 },
|
|
78
|
-
// ... your styles
|
|
79
117
|
});
|
|
80
118
|
```
|
|
81
119
|
|
|
120
|
+
That's it. The board handles everything — no extra components needed.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## `BetaGamerProvider` props
|
|
125
|
+
|
|
126
|
+
| Prop | Type | Default | Description |
|
|
127
|
+
|------|------|---------|-------------|
|
|
128
|
+
| `token` | `string` | required | Session token from your backend |
|
|
129
|
+
| `serverUrl` | `string` | `'https://api.beta-gamer.com'` | Your Beta Gamer server URL |
|
|
130
|
+
| `socketPath` | `string` | `'/socket.io'` | Socket.IO path (change if self-hosting) |
|
|
131
|
+
| `connectSocket` | `boolean` | `true` | Set `false` when using board components — they manage their own socket. Using `true` with a board component creates a duplicate connection causing AFK and turn bugs. |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
82
135
|
## Components
|
|
83
136
|
|
|
84
|
-
###
|
|
137
|
+
### Chess, Checkers, Connect4, Tictactoe (fully native — no WebView)
|
|
85
138
|
|
|
86
139
|
| Component | Props | Description |
|
|
87
140
|
|-----------|-------|-------------|
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
141
|
+
| `ChessBoard` | `style?`, `showAfkWarning?`, `onLeave?` | Full chess game — socket, board, clocks, AFK, promotion, game-over all built in |
|
|
142
|
+
| `ChessMoveHistory` | `style?`, `textStyle?`, `rowStyle?` | Scrollable move list in algebraic notation |
|
|
143
|
+
| `CheckersBoard` | `style?`, `showAfkWarning?`, `onLeave?` | Full checkers game — piece selection, valid moves, captures, king promotion |
|
|
144
|
+
| `Connect4Board` | `style?`, `showAfkWarning?`, `onLeave?` | Full connect4 game — column drop, winning cell highlight |
|
|
145
|
+
| `TictactoeBoard` | `style?`, `showAfkWarning?`, `onLeave?` | Full tictactoe game — mark placement, winning line highlight |
|
|
146
|
+
|
|
147
|
+
### Subway Runner (WebView-based)
|
|
148
|
+
|
|
149
|
+
| Component | Props | Game |
|
|
150
|
+
|-----------|-------|------|
|
|
151
|
+
| `SubwayRunnerGame`, `SubwayRunnerScore`, `SubwayRunnerLives` | `style?` | subway-runner |
|
|
91
152
|
|
|
92
|
-
###
|
|
153
|
+
### Shared
|
|
93
154
|
|
|
94
155
|
| Component | Props | Description |
|
|
95
156
|
|-----------|-------|-------------|
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
157
|
+
| `PlayerCard` | `player` (`'self'`\|`'opponent'`), `style?`, `nameStyle?` | Player name + active-turn indicator |
|
|
158
|
+
| `Timer` | `player`, `initialSeconds?`, `style?`, `textStyle?` | Live countdown clock |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Board component props (all 4 games)
|
|
163
|
+
|
|
164
|
+
All native board components share the same props:
|
|
165
|
+
|
|
166
|
+
| Prop | Type | Default | Description |
|
|
167
|
+
|------|------|---------|-------------|
|
|
168
|
+
| `style` | `ViewStyle` | — | Style for the outer container |
|
|
169
|
+
| `showAfkWarning` | `boolean` | `true` | Show built-in AFK countdown banner. Set `false` to implement your own |
|
|
170
|
+
| `onLeave` | `() => void` | — | Called when player taps Leave or Play again after game over |
|
|
171
|
+
|
|
172
|
+
---
|
|
98
173
|
|
|
99
|
-
|
|
174
|
+
## `showAfkWarning` — custom AFK UI
|
|
100
175
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
176
|
+
If you want to render your own AFK banner, pass `showAfkWarning={false}` and listen to socket events manually:
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import { useEffect } from 'react';
|
|
180
|
+
import { useSocket } from '@beta-gamer/react-native';
|
|
181
|
+
|
|
182
|
+
function MyAfkBanner() {
|
|
183
|
+
const socket = useSocket();
|
|
184
|
+
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
if (!socket) return;
|
|
187
|
+
socket.on('chess:afk_warning', ({ playerId, secondsRemaining }) => {
|
|
188
|
+
// show your own banner
|
|
189
|
+
});
|
|
190
|
+
socket.on('chess:afk_warning_cleared', () => {
|
|
191
|
+
// hide banner
|
|
192
|
+
});
|
|
193
|
+
return () => {
|
|
194
|
+
socket.off('chess:afk_warning');
|
|
195
|
+
socket.off('chess:afk_warning_cleared');
|
|
196
|
+
};
|
|
197
|
+
}, [socket]);
|
|
198
|
+
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
> Note: custom AFK UI only works when using hooks (`useSocket`) with `connectSocket={true}`. `ChessBoard` manages its own internal socket — use `showAfkWarning={false}` on the component itself instead.
|
|
204
|
+
|
|
205
|
+
---
|
|
107
206
|
|
|
108
207
|
## Hooks
|
|
109
208
|
|
|
209
|
+
Available when `connectSocket={true}` (default) and building a fully custom game UI:
|
|
210
|
+
|
|
110
211
|
```tsx
|
|
111
|
-
import { useGameState, useSession, useSocket
|
|
212
|
+
import { useGameState, useSession, useSocket } from '@beta-gamer/react-native';
|
|
112
213
|
|
|
113
214
|
const { status, winner, reason } = useGameState();
|
|
114
|
-
const { game,
|
|
115
|
-
const socket = useSocket(); // raw Socket.IO socket
|
|
116
|
-
const theme = useTheme(); // active theme tokens
|
|
215
|
+
const { game, matchType, players } = useSession();
|
|
216
|
+
const socket = useSocket(); // raw Socket.IO socket
|
|
117
217
|
```
|
|
118
218
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
| React | React Native |
|
|
122
|
-
|-------|-------------|
|
|
123
|
-
| `className` prop | `style` / `textStyle` / `rowStyle` props |
|
|
124
|
-
| CSS variables for theming | Theme injected via WebView script |
|
|
125
|
-
| `<div>`, `<span>` | `<View>`, `<Text>` |
|
|
126
|
-
| Move history scrolls via CSS | Wrapped in `<ScrollView>` |
|
|
219
|
+
---
|
|
127
220
|
|
|
128
221
|
## Supported games
|
|
129
222
|
|
|
130
223
|
`chess` · `checkers` · `connect4` · `tictactoe` · `subway-runner`
|
|
131
224
|
|
|
225
|
+
---
|
|
226
|
+
|
|
132
227
|
## Links
|
|
133
228
|
|
|
134
229
|
- [Documentation](https://beta-gamer.com/docs)
|
|
135
230
|
- [Dashboard](https://beta-gamer.com/dashboard)
|
|
136
231
|
- [React SDK](https://www.npmjs.com/package/@beta-gamer/react)
|
|
232
|
+
- [Angular SDK](https://www.npmjs.com/package/@beta-gamer/angular)
|
package/dist/index.d.mts
CHANGED
|
@@ -52,9 +52,10 @@ interface BetaGamerProviderProps {
|
|
|
52
52
|
token: string;
|
|
53
53
|
serverUrl?: string;
|
|
54
54
|
socketPath?: string;
|
|
55
|
+
connectSocket?: boolean;
|
|
55
56
|
children: React.ReactNode;
|
|
56
57
|
}
|
|
57
|
-
declare function BetaGamerProvider({ token, serverUrl, socketPath, children }: BetaGamerProviderProps): react_jsx_runtime.JSX.Element;
|
|
58
|
+
declare function BetaGamerProvider({ token, serverUrl, socketPath, connectSocket, children }: BetaGamerProviderProps): react_jsx_runtime.JSX.Element;
|
|
58
59
|
declare function useBetaGamer(): BetaGamerContextValue;
|
|
59
60
|
|
|
60
61
|
/** Returns the current game state (status, players, winner, etc.) */
|
|
@@ -82,9 +83,12 @@ interface TimerProps {
|
|
|
82
83
|
}
|
|
83
84
|
declare function Timer({ player, initialSeconds, style, textStyle }: TimerProps): react_jsx_runtime.JSX.Element;
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
interface Props$3 {
|
|
86
87
|
style?: ViewStyle;
|
|
87
|
-
|
|
88
|
+
showAfkWarning?: boolean;
|
|
89
|
+
onLeave?: () => void;
|
|
90
|
+
}
|
|
91
|
+
declare function ChessBoard({ style, showAfkWarning, onLeave }: Props$3): react_jsx_runtime.JSX.Element | null;
|
|
88
92
|
|
|
89
93
|
interface ChessMoveHistoryProps {
|
|
90
94
|
style?: ViewStyle;
|
|
@@ -93,17 +97,26 @@ interface ChessMoveHistoryProps {
|
|
|
93
97
|
}
|
|
94
98
|
declare function ChessMoveHistory({ style, rowStyle, textStyle }: ChessMoveHistoryProps): react_jsx_runtime.JSX.Element;
|
|
95
99
|
|
|
96
|
-
|
|
100
|
+
interface Props$2 {
|
|
97
101
|
style?: ViewStyle;
|
|
98
|
-
|
|
102
|
+
showAfkWarning?: boolean;
|
|
103
|
+
onLeave?: () => void;
|
|
104
|
+
}
|
|
105
|
+
declare function CheckersBoard({ style, showAfkWarning, onLeave }: Props$2): react_jsx_runtime.JSX.Element | null;
|
|
99
106
|
|
|
100
|
-
|
|
107
|
+
interface Props$1 {
|
|
101
108
|
style?: ViewStyle;
|
|
102
|
-
|
|
109
|
+
showAfkWarning?: boolean;
|
|
110
|
+
onLeave?: () => void;
|
|
111
|
+
}
|
|
112
|
+
declare function Connect4Board({ style, showAfkWarning, onLeave }: Props$1): react_jsx_runtime.JSX.Element | null;
|
|
103
113
|
|
|
104
|
-
|
|
114
|
+
interface Props {
|
|
105
115
|
style?: ViewStyle;
|
|
106
|
-
|
|
116
|
+
showAfkWarning?: boolean;
|
|
117
|
+
onLeave?: () => void;
|
|
118
|
+
}
|
|
119
|
+
declare function TictactoeBoard({ style, showAfkWarning, onLeave }: Props): react_jsx_runtime.JSX.Element | null;
|
|
107
120
|
|
|
108
121
|
declare function SubwayRunnerGame({ style }: {
|
|
109
122
|
style?: ViewStyle;
|
package/dist/index.d.ts
CHANGED
|
@@ -52,9 +52,10 @@ interface BetaGamerProviderProps {
|
|
|
52
52
|
token: string;
|
|
53
53
|
serverUrl?: string;
|
|
54
54
|
socketPath?: string;
|
|
55
|
+
connectSocket?: boolean;
|
|
55
56
|
children: React.ReactNode;
|
|
56
57
|
}
|
|
57
|
-
declare function BetaGamerProvider({ token, serverUrl, socketPath, children }: BetaGamerProviderProps): react_jsx_runtime.JSX.Element;
|
|
58
|
+
declare function BetaGamerProvider({ token, serverUrl, socketPath, connectSocket, children }: BetaGamerProviderProps): react_jsx_runtime.JSX.Element;
|
|
58
59
|
declare function useBetaGamer(): BetaGamerContextValue;
|
|
59
60
|
|
|
60
61
|
/** Returns the current game state (status, players, winner, etc.) */
|
|
@@ -82,9 +83,12 @@ interface TimerProps {
|
|
|
82
83
|
}
|
|
83
84
|
declare function Timer({ player, initialSeconds, style, textStyle }: TimerProps): react_jsx_runtime.JSX.Element;
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
interface Props$3 {
|
|
86
87
|
style?: ViewStyle;
|
|
87
|
-
|
|
88
|
+
showAfkWarning?: boolean;
|
|
89
|
+
onLeave?: () => void;
|
|
90
|
+
}
|
|
91
|
+
declare function ChessBoard({ style, showAfkWarning, onLeave }: Props$3): react_jsx_runtime.JSX.Element | null;
|
|
88
92
|
|
|
89
93
|
interface ChessMoveHistoryProps {
|
|
90
94
|
style?: ViewStyle;
|
|
@@ -93,17 +97,26 @@ interface ChessMoveHistoryProps {
|
|
|
93
97
|
}
|
|
94
98
|
declare function ChessMoveHistory({ style, rowStyle, textStyle }: ChessMoveHistoryProps): react_jsx_runtime.JSX.Element;
|
|
95
99
|
|
|
96
|
-
|
|
100
|
+
interface Props$2 {
|
|
97
101
|
style?: ViewStyle;
|
|
98
|
-
|
|
102
|
+
showAfkWarning?: boolean;
|
|
103
|
+
onLeave?: () => void;
|
|
104
|
+
}
|
|
105
|
+
declare function CheckersBoard({ style, showAfkWarning, onLeave }: Props$2): react_jsx_runtime.JSX.Element | null;
|
|
99
106
|
|
|
100
|
-
|
|
107
|
+
interface Props$1 {
|
|
101
108
|
style?: ViewStyle;
|
|
102
|
-
|
|
109
|
+
showAfkWarning?: boolean;
|
|
110
|
+
onLeave?: () => void;
|
|
111
|
+
}
|
|
112
|
+
declare function Connect4Board({ style, showAfkWarning, onLeave }: Props$1): react_jsx_runtime.JSX.Element | null;
|
|
103
113
|
|
|
104
|
-
|
|
114
|
+
interface Props {
|
|
105
115
|
style?: ViewStyle;
|
|
106
|
-
|
|
116
|
+
showAfkWarning?: boolean;
|
|
117
|
+
onLeave?: () => void;
|
|
118
|
+
}
|
|
119
|
+
declare function TictactoeBoard({ style, showAfkWarning, onLeave }: Props): react_jsx_runtime.JSX.Element | null;
|
|
107
120
|
|
|
108
121
|
declare function SubwayRunnerGame({ style }: {
|
|
109
122
|
style?: ViewStyle;
|