@beta-gamer/react-native 0.1.19 → 0.1.22
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 +164 -70
- package/dist/index.d.mts +18 -9
- package/dist/index.d.ts +18 -9
- package/dist/index.js +1028 -47
- package/dist/index.mjs +1061 -52
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -5,134 +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
|
+
```
|
|
86
|
+
|
|
87
|
+
**3. Game screen — drop in `ChessBoard`**
|
|
64
88
|
|
|
65
|
-
|
|
66
|
-
|
|
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();
|
|
67
97
|
|
|
68
|
-
|
|
69
|
-
|
|
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
|
|
|
82
|
-
|
|
120
|
+
That's it. The board handles everything — no extra components needed.
|
|
83
121
|
|
|
84
|
-
|
|
122
|
+
---
|
|
85
123
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
|
89
|
-
|
|
90
|
-
| `
|
|
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
|
+
|
|
135
|
+
## Components
|
|
91
136
|
|
|
92
|
-
### Chess
|
|
137
|
+
### Chess, Checkers, Connect4, Tictactoe (fully native — no WebView)
|
|
93
138
|
|
|
94
139
|
| Component | Props | Description |
|
|
95
140
|
|-----------|-------|-------------|
|
|
96
|
-
| `ChessBoard` | `style?`, `showAfkWarning?` |
|
|
141
|
+
| `ChessBoard` | `style?`, `showAfkWarning?`, `onLeave?` | Full chess game — socket, board, clocks, AFK, promotion, game-over all built in |
|
|
97
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 |
|
|
98
146
|
|
|
99
|
-
###
|
|
147
|
+
### Subway Runner (WebView-based)
|
|
100
148
|
|
|
101
149
|
| Component | Props | Game |
|
|
102
150
|
|-----------|-------|------|
|
|
103
|
-
| `CheckersBoard` | `style?`, `showAfkWarning?` | checkers |
|
|
104
|
-
| `Connect4Board` | `style?`, `showAfkWarning?` | connect4 |
|
|
105
|
-
| `TictactoeBoard` | `style?`, `showAfkWarning?` | tictactoe |
|
|
106
151
|
| `SubwayRunnerGame`, `SubwayRunnerScore`, `SubwayRunnerLives` | `style?` | subway-runner |
|
|
107
152
|
|
|
108
|
-
|
|
153
|
+
### Shared
|
|
154
|
+
|
|
155
|
+
| Component | Props | Description |
|
|
156
|
+
|-----------|-------|-------------|
|
|
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
|
+
---
|
|
173
|
+
|
|
174
|
+
## `showAfkWarning` — custom AFK UI
|
|
175
|
+
|
|
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
|
+
---
|
|
109
206
|
|
|
110
207
|
## Hooks
|
|
111
208
|
|
|
209
|
+
Available when `connectSocket={true}` (default) and building a fully custom game UI:
|
|
210
|
+
|
|
112
211
|
```tsx
|
|
113
|
-
import { useGameState, useSession, useSocket
|
|
212
|
+
import { useGameState, useSession, useSocket } from '@beta-gamer/react-native';
|
|
114
213
|
|
|
115
214
|
const { status, winner, reason } = useGameState();
|
|
116
|
-
const { game,
|
|
117
|
-
const socket = useSocket(); // raw Socket.IO socket
|
|
118
|
-
const theme = useTheme(); // active theme tokens
|
|
215
|
+
const { game, matchType, players } = useSession();
|
|
216
|
+
const socket = useSocket(); // raw Socket.IO socket
|
|
119
217
|
```
|
|
120
218
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
| React | React Native |
|
|
124
|
-
|-------|-------------|
|
|
125
|
-
| `className` prop | `style` / `textStyle` / `rowStyle` props |
|
|
126
|
-
| CSS variables for theming | Theme injected via WebView script |
|
|
127
|
-
| `<div>`, `<span>` | `<View>`, `<Text>` |
|
|
128
|
-
| Move history scrolls via CSS | Wrapped in `<ScrollView>` |
|
|
219
|
+
---
|
|
129
220
|
|
|
130
221
|
## Supported games
|
|
131
222
|
|
|
132
223
|
`chess` · `checkers` · `connect4` · `tictactoe` · `subway-runner`
|
|
133
224
|
|
|
225
|
+
---
|
|
226
|
+
|
|
134
227
|
## Links
|
|
135
228
|
|
|
136
229
|
- [Documentation](https://beta-gamer.com/docs)
|
|
137
230
|
- [Dashboard](https://beta-gamer.com/dashboard)
|
|
138
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,10 +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;
|
|
88
|
-
|
|
89
|
+
onLeave?: () => void;
|
|
90
|
+
}
|
|
91
|
+
declare function ChessBoard({ style, showAfkWarning, onLeave }: Props$3): react_jsx_runtime.JSX.Element | null;
|
|
89
92
|
|
|
90
93
|
interface ChessMoveHistoryProps {
|
|
91
94
|
style?: ViewStyle;
|
|
@@ -94,20 +97,26 @@ interface ChessMoveHistoryProps {
|
|
|
94
97
|
}
|
|
95
98
|
declare function ChessMoveHistory({ style, rowStyle, textStyle }: ChessMoveHistoryProps): react_jsx_runtime.JSX.Element;
|
|
96
99
|
|
|
97
|
-
|
|
100
|
+
interface Props$2 {
|
|
98
101
|
style?: ViewStyle;
|
|
99
102
|
showAfkWarning?: boolean;
|
|
100
|
-
|
|
103
|
+
onLeave?: () => void;
|
|
104
|
+
}
|
|
105
|
+
declare function CheckersBoard({ style, showAfkWarning, onLeave }: Props$2): react_jsx_runtime.JSX.Element | null;
|
|
101
106
|
|
|
102
|
-
|
|
107
|
+
interface Props$1 {
|
|
103
108
|
style?: ViewStyle;
|
|
104
109
|
showAfkWarning?: boolean;
|
|
105
|
-
|
|
110
|
+
onLeave?: () => void;
|
|
111
|
+
}
|
|
112
|
+
declare function Connect4Board({ style, showAfkWarning, onLeave }: Props$1): react_jsx_runtime.JSX.Element | null;
|
|
106
113
|
|
|
107
|
-
|
|
114
|
+
interface Props {
|
|
108
115
|
style?: ViewStyle;
|
|
109
116
|
showAfkWarning?: boolean;
|
|
110
|
-
|
|
117
|
+
onLeave?: () => void;
|
|
118
|
+
}
|
|
119
|
+
declare function TictactoeBoard({ style, showAfkWarning, onLeave }: Props): react_jsx_runtime.JSX.Element | null;
|
|
111
120
|
|
|
112
121
|
declare function SubwayRunnerGame({ style }: {
|
|
113
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,10 +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;
|
|
88
|
-
|
|
89
|
+
onLeave?: () => void;
|
|
90
|
+
}
|
|
91
|
+
declare function ChessBoard({ style, showAfkWarning, onLeave }: Props$3): react_jsx_runtime.JSX.Element | null;
|
|
89
92
|
|
|
90
93
|
interface ChessMoveHistoryProps {
|
|
91
94
|
style?: ViewStyle;
|
|
@@ -94,20 +97,26 @@ interface ChessMoveHistoryProps {
|
|
|
94
97
|
}
|
|
95
98
|
declare function ChessMoveHistory({ style, rowStyle, textStyle }: ChessMoveHistoryProps): react_jsx_runtime.JSX.Element;
|
|
96
99
|
|
|
97
|
-
|
|
100
|
+
interface Props$2 {
|
|
98
101
|
style?: ViewStyle;
|
|
99
102
|
showAfkWarning?: boolean;
|
|
100
|
-
|
|
103
|
+
onLeave?: () => void;
|
|
104
|
+
}
|
|
105
|
+
declare function CheckersBoard({ style, showAfkWarning, onLeave }: Props$2): react_jsx_runtime.JSX.Element | null;
|
|
101
106
|
|
|
102
|
-
|
|
107
|
+
interface Props$1 {
|
|
103
108
|
style?: ViewStyle;
|
|
104
109
|
showAfkWarning?: boolean;
|
|
105
|
-
|
|
110
|
+
onLeave?: () => void;
|
|
111
|
+
}
|
|
112
|
+
declare function Connect4Board({ style, showAfkWarning, onLeave }: Props$1): react_jsx_runtime.JSX.Element | null;
|
|
106
113
|
|
|
107
|
-
|
|
114
|
+
interface Props {
|
|
108
115
|
style?: ViewStyle;
|
|
109
116
|
showAfkWarning?: boolean;
|
|
110
|
-
|
|
117
|
+
onLeave?: () => void;
|
|
118
|
+
}
|
|
119
|
+
declare function TictactoeBoard({ style, showAfkWarning, onLeave }: Props): react_jsx_runtime.JSX.Element | null;
|
|
111
120
|
|
|
112
121
|
declare function SubwayRunnerGame({ style }: {
|
|
113
122
|
style?: ViewStyle;
|