@beta-gamer/react-native 0.1.8 → 0.1.12

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/dist/index.d.mts CHANGED
@@ -42,6 +42,7 @@ interface GameState {
42
42
 
43
43
  interface BetaGamerContextValue {
44
44
  token: string;
45
+ serverUrl: string;
45
46
  session: SessionTokenPayload;
46
47
  socket: Socket | null;
47
48
  gameState: GameState;
package/dist/index.d.ts CHANGED
@@ -42,6 +42,7 @@ interface GameState {
42
42
 
43
43
  interface BetaGamerContextValue {
44
44
  token: string;
45
+ serverUrl: string;
45
46
  session: SessionTokenPayload;
46
47
  socket: Socket | null;
47
48
  gameState: GameState;
package/dist/index.js CHANGED
@@ -41,6 +41,7 @@ module.exports = __toCommonJS(index_exports);
41
41
 
42
42
  // src/context/BetaGamerProvider.tsx
43
43
  var import_react = require("react");
44
+ var import_react_native = require("react-native");
44
45
  var import_socket = require("socket.io-client");
45
46
  var import_jsx_runtime = require("react/jsx-runtime");
46
47
  function base64Decode(str) {
@@ -101,6 +102,17 @@ function BetaGamerProvider({ token, serverUrl = "https://api.beta-gamer.com", so
101
102
  transports: ["websocket", "polling"]
102
103
  });
103
104
  setSocket(s);
105
+ s.on("connect_error", (err) => {
106
+ const msg = err.message?.toLowerCase() ?? "";
107
+ let reason = "Unable to connect to the game server.";
108
+ if (msg.includes("websocket") || msg.includes("transport")) reason = "Connection failed: server does not accept WebSocket connections.";
109
+ else if (msg.includes("timeout")) reason = "Connection timed out. Check your internet connection.";
110
+ else if (msg.includes("unauthorized") || msg.includes("401")) reason = "Connection refused: invalid or expired session token.";
111
+ else if (msg.includes("not found") || msg.includes("404")) reason = "Game server not found. Check your serverUrl.";
112
+ else if (msg.includes("cors")) reason = "Connection blocked by CORS policy.";
113
+ else if (err.message) reason = `Connection error: ${err.message}`;
114
+ import_react_native.Alert.alert("Connection Error", `[Beta Gamer] ${reason}`);
115
+ });
104
116
  s.on("game:state", (state) => {
105
117
  setGameState((prev) => ({ ...prev, ...state }));
106
118
  });
@@ -112,7 +124,7 @@ function BetaGamerProvider({ token, serverUrl = "https://api.beta-gamer.com", so
112
124
  setSocket(null);
113
125
  };
114
126
  }, [token, serverUrl, socketPath, session.game]);
115
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BetaGamerContext.Provider, { value: { token, session, socket, gameState, theme: session.theme ?? {} }, children });
127
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BetaGamerContext.Provider, { value: { token, serverUrl, session, socket, gameState, theme: session.theme ?? {} }, children });
116
128
  }
117
129
  function useBetaGamer() {
118
130
  const ctx = (0, import_react.useContext)(BetaGamerContext);
@@ -135,7 +147,7 @@ function useTheme() {
135
147
  }
136
148
 
137
149
  // src/components/PlayerCard.tsx
138
- var import_react_native = require("react-native");
150
+ var import_react_native2 = require("react-native");
139
151
  var import_jsx_runtime2 = require("react/jsx-runtime");
140
152
  function PlayerCard({ player, style, nameStyle, indicatorStyle }) {
141
153
  const { players } = useSession();
@@ -143,15 +155,15 @@ function PlayerCard({ player, style, nameStyle, indicatorStyle }) {
143
155
  const p = player === "self" ? players[0] : players[1];
144
156
  if (!p) return null;
145
157
  const isActive = currentTurn === p.id;
146
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native.View, { style, accessibilityRole: "text", children: [
147
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native.Text, { style: nameStyle, children: p.displayName }),
148
- isActive && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native.View, { style: indicatorStyle, accessibilityLabel: "Active turn" })
158
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style, accessibilityRole: "text", children: [
159
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: nameStyle, children: p.displayName }),
160
+ isActive && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: indicatorStyle, accessibilityLabel: "Active turn" })
149
161
  ] });
150
162
  }
151
163
 
152
164
  // src/components/Timer.tsx
153
165
  var import_react2 = require("react");
154
- var import_react_native2 = require("react-native");
166
+ var import_react_native3 = require("react-native");
155
167
  var import_jsx_runtime3 = require("react/jsx-runtime");
156
168
  function Timer({ player, initialSeconds = 600, style, textStyle }) {
157
169
  const socket = useSocket();
@@ -174,7 +186,7 @@ function Timer({ player, initialSeconds = 600, style, textStyle }) {
174
186
  }, [status]);
175
187
  const m = Math.floor(seconds / 60).toString().padStart(2, "0");
176
188
  const s = (seconds % 60).toString().padStart(2, "0");
177
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.View, { style, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native2.Text, { style: textStyle, children: [
189
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native3.Text, { style: textStyle, children: [
178
190
  m,
179
191
  ":",
180
192
  s
@@ -185,9 +197,8 @@ function Timer({ player, initialSeconds = 600, style, textStyle }) {
185
197
  var import_react3 = require("react");
186
198
  var import_react_native_webview = require("react-native-webview");
187
199
  var import_jsx_runtime4 = require("react/jsx-runtime");
188
- var BASE_URL = "https://api.beta-gamer.com";
189
200
  function GameWebView({ game, style }) {
190
- const { token, session } = useBetaGamer();
201
+ const { token, serverUrl, session } = useBetaGamer();
191
202
  const webViewRef = (0, import_react3.useRef)(null);
192
203
  if (session.game !== game) return null;
193
204
  const initScript = `
@@ -199,7 +210,7 @@ function GameWebView({ game, style }) {
199
210
  import_react_native_webview.WebView,
200
211
  {
201
212
  ref: webViewRef,
202
- source: { uri: `${BASE_URL}/embed/${game}` },
213
+ source: { uri: `${serverUrl}/embed/${game}` },
203
214
  injectedJavaScriptBeforeContentLoaded: initScript,
204
215
  style: [{ flex: 1 }, style],
205
216
  allowsInlineMediaPlayback: true,
@@ -216,7 +227,7 @@ function ChessBoard({ style }) {
216
227
 
217
228
  // src/components/chess/ChessMoveHistory.tsx
218
229
  var import_react4 = require("react");
219
- var import_react_native3 = require("react-native");
230
+ var import_react_native4 = require("react-native");
220
231
  var import_jsx_runtime6 = require("react/jsx-runtime");
221
232
  function ChessMoveHistory({ style, rowStyle, textStyle }) {
222
233
  const socket = useSocket();
@@ -242,7 +253,7 @@ function ChessMoveHistory({ style, rowStyle, textStyle }) {
242
253
  socket.off("chess:move", handler);
243
254
  };
244
255
  }, [socket]);
245
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native3.ScrollView, { style, children: moves.map(({ moveNumber, white, black }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native3.View, { style: rowStyle, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native3.Text, { style: textStyle, children: [
256
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native4.ScrollView, { style, children: moves.map(({ moveNumber, white, black }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native4.View, { style: rowStyle, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native4.Text, { style: textStyle, children: [
246
257
  moveNumber,
247
258
  ". ",
248
259
  white,
@@ -270,7 +281,7 @@ function TictactoeBoard({ style }) {
270
281
 
271
282
  // src/components/subway-runner/index.tsx
272
283
  var import_react5 = require("react");
273
- var import_react_native4 = require("react-native");
284
+ var import_react_native5 = require("react-native");
274
285
  var import_jsx_runtime10 = require("react/jsx-runtime");
275
286
  function SubwayRunnerGame({ style }) {
276
287
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(GameWebView, { game: "subway-runner", style });
@@ -285,7 +296,7 @@ function SubwayRunnerScore({ style, textStyle }) {
285
296
  socket.off("runner:score");
286
297
  };
287
298
  }, [socket]);
288
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native4.View, { style, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native4.Text, { style: textStyle, children: score }) });
299
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native5.View, { style, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native5.Text, { style: textStyle, children: score }) });
289
300
  }
290
301
  function SubwayRunnerLives({ style, lifeStyle }) {
291
302
  const socket = useSocket();
@@ -297,7 +308,7 @@ function SubwayRunnerLives({ style, lifeStyle }) {
297
308
  socket.off("runner:lives");
298
309
  };
299
310
  }, [socket]);
300
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native4.View, { style: [{ flexDirection: "row" }, style], children: Array.from({ length: lives }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native4.View, { style: lifeStyle, accessibilityLabel: "life" }, i)) });
311
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native5.View, { style: [{ flexDirection: "row" }, style], children: Array.from({ length: lives }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native5.View, { style: lifeStyle, accessibilityLabel: "life" }, i)) });
301
312
  }
302
313
  // Annotate the CommonJS export names for ESM import in node:
303
314
  0 && (module.exports = {
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/context/BetaGamerProvider.tsx
2
2
  import { createContext, useContext, useEffect, useState } from "react";
3
+ import { Alert } from "react-native";
3
4
  import { io } from "socket.io-client";
4
5
  import { jsx } from "react/jsx-runtime";
5
6
  function base64Decode(str) {
@@ -60,6 +61,17 @@ function BetaGamerProvider({ token, serverUrl = "https://api.beta-gamer.com", so
60
61
  transports: ["websocket", "polling"]
61
62
  });
62
63
  setSocket(s);
64
+ s.on("connect_error", (err) => {
65
+ const msg = err.message?.toLowerCase() ?? "";
66
+ let reason = "Unable to connect to the game server.";
67
+ if (msg.includes("websocket") || msg.includes("transport")) reason = "Connection failed: server does not accept WebSocket connections.";
68
+ else if (msg.includes("timeout")) reason = "Connection timed out. Check your internet connection.";
69
+ else if (msg.includes("unauthorized") || msg.includes("401")) reason = "Connection refused: invalid or expired session token.";
70
+ else if (msg.includes("not found") || msg.includes("404")) reason = "Game server not found. Check your serverUrl.";
71
+ else if (msg.includes("cors")) reason = "Connection blocked by CORS policy.";
72
+ else if (err.message) reason = `Connection error: ${err.message}`;
73
+ Alert.alert("Connection Error", `[Beta Gamer] ${reason}`);
74
+ });
63
75
  s.on("game:state", (state) => {
64
76
  setGameState((prev) => ({ ...prev, ...state }));
65
77
  });
@@ -71,7 +83,7 @@ function BetaGamerProvider({ token, serverUrl = "https://api.beta-gamer.com", so
71
83
  setSocket(null);
72
84
  };
73
85
  }, [token, serverUrl, socketPath, session.game]);
74
- return /* @__PURE__ */ jsx(BetaGamerContext.Provider, { value: { token, session, socket, gameState, theme: session.theme ?? {} }, children });
86
+ return /* @__PURE__ */ jsx(BetaGamerContext.Provider, { value: { token, serverUrl, session, socket, gameState, theme: session.theme ?? {} }, children });
75
87
  }
76
88
  function useBetaGamer() {
77
89
  const ctx = useContext(BetaGamerContext);
@@ -144,9 +156,8 @@ function Timer({ player, initialSeconds = 600, style, textStyle }) {
144
156
  import { useRef } from "react";
145
157
  import { WebView } from "react-native-webview";
146
158
  import { jsx as jsx4 } from "react/jsx-runtime";
147
- var BASE_URL = "https://api.beta-gamer.com";
148
159
  function GameWebView({ game, style }) {
149
- const { token, session } = useBetaGamer();
160
+ const { token, serverUrl, session } = useBetaGamer();
150
161
  const webViewRef = useRef(null);
151
162
  if (session.game !== game) return null;
152
163
  const initScript = `
@@ -158,7 +169,7 @@ function GameWebView({ game, style }) {
158
169
  WebView,
159
170
  {
160
171
  ref: webViewRef,
161
- source: { uri: `${BASE_URL}/embed/${game}` },
172
+ source: { uri: `${serverUrl}/embed/${game}` },
162
173
  injectedJavaScriptBeforeContentLoaded: initScript,
163
174
  style: [{ flex: 1 }, style],
164
175
  allowsInlineMediaPlayback: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beta-gamer/react-native",
3
- "version": "0.1.8",
3
+ "version": "0.1.12",
4
4
  "description": "React Native SDK for Beta Gamer GaaS — composable game components",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",