@mnbroatch/boardgame.io 0.0.1

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.
Files changed (296) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +102 -0
  3. package/ai/package.json +7 -0
  4. package/client/package.json +7 -0
  5. package/core/package.json +7 -0
  6. package/debug/package.json +7 -0
  7. package/dist/boardgameio.es.js +14238 -0
  8. package/dist/boardgameio.js +14277 -0
  9. package/dist/boardgameio.min.js +16 -0
  10. package/dist/cjs/Debug-9d141c06.js +9586 -0
  11. package/dist/cjs/ai-e0e8a768.js +377 -0
  12. package/dist/cjs/ai.js +20 -0
  13. package/dist/cjs/client-76dec77b.js +258 -0
  14. package/dist/cjs/client-a22d7500.js +524 -0
  15. package/dist/cjs/client.js +26 -0
  16. package/dist/cjs/core.js +52 -0
  17. package/dist/cjs/debug.js +18 -0
  18. package/dist/cjs/filter-player-view-bb02e2f6.js +89 -0
  19. package/dist/cjs/initialize-267fcd69.js +61 -0
  20. package/dist/cjs/internal.js +25 -0
  21. package/dist/cjs/master-2904879d.js +320 -0
  22. package/dist/cjs/master.js +18 -0
  23. package/dist/cjs/multiplayer.js +23 -0
  24. package/dist/cjs/plugin-random-7425844d.js +229 -0
  25. package/dist/cjs/plugins.js +59 -0
  26. package/dist/cjs/react-native.js +182 -0
  27. package/dist/cjs/react.js +727 -0
  28. package/dist/cjs/reducer-16eec232.js +1203 -0
  29. package/dist/cjs/server.js +4087 -0
  30. package/dist/cjs/socketio-7a0837eb.js +478 -0
  31. package/dist/cjs/testing.js +30 -0
  32. package/dist/cjs/transport-b1874dfa.js +37 -0
  33. package/dist/cjs/turn-order-b2ff8740.js +1136 -0
  34. package/dist/cjs/util-fcfd8fb8.js +140 -0
  35. package/dist/esm/Debug-0141fe2d.js +9577 -0
  36. package/dist/esm/ai-5c06e761.js +371 -0
  37. package/dist/esm/ai.js +8 -0
  38. package/dist/esm/client-2e653027.js +522 -0
  39. package/dist/esm/client-5f57c3f2.js +255 -0
  40. package/dist/esm/client.js +16 -0
  41. package/dist/esm/core.js +40 -0
  42. package/dist/esm/debug.js +10 -0
  43. package/dist/esm/filter-player-view-2c6cc96f.js +87 -0
  44. package/dist/esm/initialize-11d626ca.js +59 -0
  45. package/dist/esm/internal.js +10 -0
  46. package/dist/esm/master-fa8f2e43.js +318 -0
  47. package/dist/esm/master.js +10 -0
  48. package/dist/esm/multiplayer.js +14 -0
  49. package/dist/esm/plugin-random-087f861e.js +226 -0
  50. package/dist/esm/plugins.js +55 -0
  51. package/dist/esm/react-native.js +173 -0
  52. package/dist/esm/react.js +716 -0
  53. package/dist/esm/reducer-c46da7e5.js +1198 -0
  54. package/dist/esm/socketio-c22ffa65.js +455 -0
  55. package/dist/esm/testing.js +26 -0
  56. package/dist/esm/transport-ce07b771.js +35 -0
  57. package/dist/esm/turn-order-376d315e.js +1091 -0
  58. package/dist/esm/util-b6147cef.js +135 -0
  59. package/dist/types/packages/ai.d.ts +5 -0
  60. package/dist/types/packages/client.d.ts +3 -0
  61. package/dist/types/packages/core.d.ts +5 -0
  62. package/dist/types/packages/debug.d.ts +2 -0
  63. package/dist/types/packages/internal.d.ts +8 -0
  64. package/dist/types/packages/master.d.ts +2 -0
  65. package/dist/types/packages/multiplayer.d.ts +3 -0
  66. package/dist/types/packages/plugins.d.ts +3 -0
  67. package/dist/types/packages/react-native.d.ts +2 -0
  68. package/dist/types/packages/react.d.ts +3 -0
  69. package/dist/types/packages/server.d.ts +6 -0
  70. package/dist/types/packages/testing.d.ts +1 -0
  71. package/dist/types/src/ai/ai.d.ts +53 -0
  72. package/dist/types/src/ai/ai.test.d.ts +1 -0
  73. package/dist/types/src/ai/bot.d.ts +40 -0
  74. package/dist/types/src/ai/mcts-bot.d.ts +60 -0
  75. package/dist/types/src/ai/random-bot.d.ts +27 -0
  76. package/dist/types/src/client/client.d.ts +104 -0
  77. package/dist/types/src/client/client.test.d.ts +1 -0
  78. package/dist/types/src/client/debug/tests/debug.test.d.ts +1 -0
  79. package/dist/types/src/client/manager.d.ts +61 -0
  80. package/dist/types/src/client/react.d.ts +75 -0
  81. package/dist/types/src/client/react.ssr.test.d.ts +4 -0
  82. package/dist/types/src/client/react.test.d.ts +1 -0
  83. package/dist/types/src/client/transport/dummy.d.ts +18 -0
  84. package/dist/types/src/client/transport/local.d.ts +59 -0
  85. package/dist/types/src/client/transport/local.test.d.ts +1 -0
  86. package/dist/types/src/client/transport/socketio.d.ts +45 -0
  87. package/dist/types/src/client/transport/socketio.test.d.ts +1 -0
  88. package/dist/types/src/client/transport/transport.d.ts +50 -0
  89. package/dist/types/src/client/transport/transport.test.d.ts +1 -0
  90. package/dist/types/src/core/action-creators.d.ts +144 -0
  91. package/dist/types/src/core/action-types.d.ts +10 -0
  92. package/dist/types/src/core/backwards-compatibility.d.ts +12 -0
  93. package/dist/types/src/core/constants.d.ts +6 -0
  94. package/dist/types/src/core/errors.d.ts +15 -0
  95. package/dist/types/src/core/flow.d.ts +28 -0
  96. package/dist/types/src/core/flow.test.d.ts +1 -0
  97. package/dist/types/src/core/game-methods.d.ts +9 -0
  98. package/dist/types/src/core/game.d.ts +26 -0
  99. package/dist/types/src/core/game.test.d.ts +1 -0
  100. package/dist/types/src/core/initialize.d.ts +9 -0
  101. package/dist/types/src/core/logger.d.ts +2 -0
  102. package/dist/types/src/core/player-view.d.ts +7 -0
  103. package/dist/types/src/core/player-view.test.d.ts +1 -0
  104. package/dist/types/src/core/reducer.d.ts +155 -0
  105. package/dist/types/src/core/reducer.test.d.ts +1 -0
  106. package/dist/types/src/core/turn-order.d.ts +179 -0
  107. package/dist/types/src/core/turn-order.test.d.ts +8 -0
  108. package/dist/types/src/lobby/client.d.ts +194 -0
  109. package/dist/types/src/lobby/client.test.d.ts +1 -0
  110. package/dist/types/src/lobby/connection.d.ts +44 -0
  111. package/dist/types/src/lobby/connection.test.d.ts +1 -0
  112. package/dist/types/src/lobby/create-match-form.d.ts +26 -0
  113. package/dist/types/src/lobby/login-form.d.ts +23 -0
  114. package/dist/types/src/lobby/match-instance.d.ts +31 -0
  115. package/dist/types/src/lobby/react.d.ts +113 -0
  116. package/dist/types/src/lobby/react.ssr.test.d.ts +4 -0
  117. package/dist/types/src/lobby/react.test.d.ts +1 -0
  118. package/dist/types/src/master/filter-player-view.d.ts +96 -0
  119. package/dist/types/src/master/filter-player-view.test.d.ts +1 -0
  120. package/dist/types/src/master/master.d.ts +94 -0
  121. package/dist/types/src/master/master.test.d.ts +1 -0
  122. package/dist/types/src/plugins/events/events.d.ts +54 -0
  123. package/dist/types/src/plugins/events/events.test.d.ts +1 -0
  124. package/dist/types/src/plugins/main.d.ts +75 -0
  125. package/dist/types/src/plugins/main.test.d.ts +1 -0
  126. package/dist/types/src/plugins/plugin-events.d.ts +5 -0
  127. package/dist/types/src/plugins/plugin-immer.d.ts +7 -0
  128. package/dist/types/src/plugins/plugin-immer.test.d.ts +1 -0
  129. package/dist/types/src/plugins/plugin-log.d.ts +14 -0
  130. package/dist/types/src/plugins/plugin-log.test.d.ts +1 -0
  131. package/dist/types/src/plugins/plugin-player.d.ts +29 -0
  132. package/dist/types/src/plugins/plugin-player.test.d.ts +1 -0
  133. package/dist/types/src/plugins/plugin-random.d.ts +4 -0
  134. package/dist/types/src/plugins/plugin-serializable.d.ts +7 -0
  135. package/dist/types/src/plugins/plugin-serializable.test.d.ts +1 -0
  136. package/dist/types/src/plugins/random/random.alea.d.ts +19 -0
  137. package/dist/types/src/plugins/random/random.d.ts +54 -0
  138. package/dist/types/src/plugins/random/random.test.d.ts +1 -0
  139. package/dist/types/src/server/api.d.ts +13 -0
  140. package/dist/types/src/server/api.test.d.ts +1 -0
  141. package/dist/types/src/server/auth.d.ts +38 -0
  142. package/dist/types/src/server/auth.test.d.ts +1 -0
  143. package/dist/types/src/server/cors.d.ts +4 -0
  144. package/dist/types/src/server/cors.test.d.ts +1 -0
  145. package/dist/types/src/server/db/base.d.ts +192 -0
  146. package/dist/types/src/server/db/flatfile.d.ts +44 -0
  147. package/dist/types/src/server/db/flatfile.test.d.ts +1 -0
  148. package/dist/types/src/server/db/index.d.ts +4 -0
  149. package/dist/types/src/server/db/index.test.d.ts +1 -0
  150. package/dist/types/src/server/db/inmemory.d.ts +43 -0
  151. package/dist/types/src/server/db/inmemory.test.d.ts +1 -0
  152. package/dist/types/src/server/db/localstorage.d.ts +7 -0
  153. package/dist/types/src/server/db/localstorage.test.d.ts +1 -0
  154. package/dist/types/src/server/index.d.ts +68 -0
  155. package/dist/types/src/server/index.test.d.ts +1 -0
  156. package/dist/types/src/server/transport/pubsub/generic-pub-sub.d.ts +6 -0
  157. package/dist/types/src/server/transport/pubsub/in-memory-pub-sub.d.ts +7 -0
  158. package/dist/types/src/server/transport/pubsub/in-memory-pub-sub.test.d.ts +1 -0
  159. package/dist/types/src/server/transport/socketio-simultaneous.test.d.ts +1 -0
  160. package/dist/types/src/server/transport/socketio.d.ts +65 -0
  161. package/dist/types/src/server/transport/socketio.test.d.ts +1 -0
  162. package/dist/types/src/server/util.d.ts +35 -0
  163. package/dist/types/src/testing/mock-random.d.ts +15 -0
  164. package/dist/types/src/testing/mock-random.test.d.ts +1 -0
  165. package/dist/types/src/types.d.ts +387 -0
  166. package/internal/package.json +7 -0
  167. package/master/package.json +7 -0
  168. package/multiplayer/package.json +7 -0
  169. package/package.json +211 -0
  170. package/plugins/package.json +7 -0
  171. package/react/package.json +7 -0
  172. package/react-native/package.json +7 -0
  173. package/server/package.json +6 -0
  174. package/src/ai/ai.test.ts +433 -0
  175. package/src/ai/ai.ts +84 -0
  176. package/src/ai/bot.ts +122 -0
  177. package/src/ai/mcts-bot.ts +331 -0
  178. package/src/ai/random-bot.ts +20 -0
  179. package/src/client/client.test.ts +993 -0
  180. package/src/client/client.ts +588 -0
  181. package/src/client/debug/Debug.svelte +239 -0
  182. package/src/client/debug/Menu.svelte +65 -0
  183. package/src/client/debug/ai/AI.svelte +215 -0
  184. package/src/client/debug/ai/Options.svelte +48 -0
  185. package/src/client/debug/info/Info.svelte +22 -0
  186. package/src/client/debug/info/Item.svelte +24 -0
  187. package/src/client/debug/log/Log.svelte +157 -0
  188. package/src/client/debug/log/LogEvent.svelte +149 -0
  189. package/src/client/debug/log/LogMetadata.svelte +7 -0
  190. package/src/client/debug/log/PhaseMarker.svelte +27 -0
  191. package/src/client/debug/log/TurnMarker.svelte +23 -0
  192. package/src/client/debug/main/ClientSwitcher.svelte +59 -0
  193. package/src/client/debug/main/Controls.svelte +58 -0
  194. package/src/client/debug/main/Hotkey.svelte +84 -0
  195. package/src/client/debug/main/InteractiveFunction.svelte +85 -0
  196. package/src/client/debug/main/Main.svelte +121 -0
  197. package/src/client/debug/main/Move.svelte +68 -0
  198. package/src/client/debug/main/PlayerInfo.svelte +70 -0
  199. package/src/client/debug/mcts/Action.svelte +22 -0
  200. package/src/client/debug/mcts/MCTS.svelte +78 -0
  201. package/src/client/debug/mcts/Table.svelte +98 -0
  202. package/src/client/debug/tests/JSONTree.mock.svelte +3 -0
  203. package/src/client/debug/tests/debug.test.ts +183 -0
  204. package/src/client/debug/utils/shortcuts.js +50 -0
  205. package/src/client/debug/utils/shortcuts.test.js +49 -0
  206. package/src/client/manager.ts +177 -0
  207. package/src/client/react-native.js +136 -0
  208. package/src/client/react-native.test.js +229 -0
  209. package/src/client/react.ssr.test.tsx +24 -0
  210. package/src/client/react.test.tsx +213 -0
  211. package/src/client/react.tsx +192 -0
  212. package/src/client/transport/dummy.ts +19 -0
  213. package/src/client/transport/local.test.ts +353 -0
  214. package/src/client/transport/local.ts +230 -0
  215. package/src/client/transport/socketio.test.ts +328 -0
  216. package/src/client/transport/socketio.ts +210 -0
  217. package/src/client/transport/transport.test.ts +27 -0
  218. package/src/client/transport/transport.ts +95 -0
  219. package/src/core/action-creators.ts +159 -0
  220. package/src/core/action-types.ts +18 -0
  221. package/src/core/backwards-compatibility.ts +23 -0
  222. package/src/core/constants.ts +6 -0
  223. package/src/core/errors.ts +35 -0
  224. package/src/core/flow.test.ts +2433 -0
  225. package/src/core/flow.ts +897 -0
  226. package/src/core/game-methods.ts +9 -0
  227. package/src/core/game.test.ts +286 -0
  228. package/src/core/game.ts +114 -0
  229. package/src/core/initialize.ts +77 -0
  230. package/src/core/logger.test.js +90 -0
  231. package/src/core/logger.ts +18 -0
  232. package/src/core/player-view.test.ts +50 -0
  233. package/src/core/player-view.ts +39 -0
  234. package/src/core/reducer.test.ts +991 -0
  235. package/src/core/reducer.ts +532 -0
  236. package/src/core/turn-order.test.ts +1123 -0
  237. package/src/core/turn-order.ts +473 -0
  238. package/src/lobby/client.test.ts +385 -0
  239. package/src/lobby/client.ts +358 -0
  240. package/src/lobby/connection.test.ts +207 -0
  241. package/src/lobby/connection.ts +162 -0
  242. package/src/lobby/create-match-form.tsx +122 -0
  243. package/src/lobby/login-form.tsx +75 -0
  244. package/src/lobby/match-instance.tsx +135 -0
  245. package/src/lobby/react.ssr.test.tsx +22 -0
  246. package/src/lobby/react.test.tsx +594 -0
  247. package/src/lobby/react.tsx +402 -0
  248. package/src/master/filter-player-view.test.ts +381 -0
  249. package/src/master/filter-player-view.ts +102 -0
  250. package/src/master/master.test.ts +1068 -0
  251. package/src/master/master.ts +492 -0
  252. package/src/plugins/events/events.test.ts +108 -0
  253. package/src/plugins/events/events.ts +209 -0
  254. package/src/plugins/main.test.ts +411 -0
  255. package/src/plugins/main.ts +314 -0
  256. package/src/plugins/plugin-events.ts +40 -0
  257. package/src/plugins/plugin-immer.test.ts +86 -0
  258. package/src/plugins/plugin-immer.ts +37 -0
  259. package/src/plugins/plugin-log.test.ts +37 -0
  260. package/src/plugins/plugin-log.ts +40 -0
  261. package/src/plugins/plugin-player.test.ts +172 -0
  262. package/src/plugins/plugin-player.ts +100 -0
  263. package/src/plugins/plugin-random.ts +40 -0
  264. package/src/plugins/plugin-serializable.test.ts +40 -0
  265. package/src/plugins/plugin-serializable.ts +55 -0
  266. package/src/plugins/random/random.alea.ts +109 -0
  267. package/src/plugins/random/random.test.ts +167 -0
  268. package/src/plugins/random/random.ts +198 -0
  269. package/src/server/api.test.ts +1699 -0
  270. package/src/server/api.ts +527 -0
  271. package/src/server/auth.test.ts +275 -0
  272. package/src/server/auth.ts +89 -0
  273. package/src/server/cors.test.ts +121 -0
  274. package/src/server/cors.ts +7 -0
  275. package/src/server/db/base.ts +296 -0
  276. package/src/server/db/flatfile.test.ts +221 -0
  277. package/src/server/db/flatfile.ts +228 -0
  278. package/src/server/db/index.test.ts +8 -0
  279. package/src/server/db/index.ts +12 -0
  280. package/src/server/db/inmemory.test.ts +143 -0
  281. package/src/server/db/inmemory.ts +143 -0
  282. package/src/server/db/localstorage.test.ts +73 -0
  283. package/src/server/db/localstorage.ts +44 -0
  284. package/src/server/index.test.ts +265 -0
  285. package/src/server/index.ts +175 -0
  286. package/src/server/transport/pubsub/generic-pub-sub.ts +11 -0
  287. package/src/server/transport/pubsub/in-memory-pub-sub.test.ts +47 -0
  288. package/src/server/transport/pubsub/in-memory-pub-sub.ts +28 -0
  289. package/src/server/transport/socketio-simultaneous.test.ts +603 -0
  290. package/src/server/transport/socketio.test.ts +303 -0
  291. package/src/server/transport/socketio.ts +279 -0
  292. package/src/server/util.ts +85 -0
  293. package/src/testing/mock-random.test.ts +45 -0
  294. package/src/testing/mock-random.ts +27 -0
  295. package/src/types.ts +511 -0
  296. package/testing/package.json +7 -0
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Copyright 2017 The boardgame.io Authors
3
+ *
4
+ * Use of this source code is governed by a MIT-style
5
+ * license that can be found in the LICENSE file or at
6
+ * https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import { AssignShortcuts } from './shortcuts';
10
+
11
+ test('first char is used', () => {
12
+ const moves = {
13
+ clickCell: () => {},
14
+ playCard: () => {},
15
+ };
16
+
17
+ const shortcuts = AssignShortcuts(moves, '');
18
+
19
+ expect(shortcuts).toEqual({
20
+ clickCell: 'c',
21
+ playCard: 'p',
22
+ });
23
+ });
24
+
25
+ test('a-z if cannot use first char', () => {
26
+ const moves = {
27
+ takeCard: () => {},
28
+ takeToken: () => {},
29
+ };
30
+
31
+ const shortcuts = AssignShortcuts(moves, '');
32
+
33
+ expect(shortcuts).toEqual({
34
+ takeCard: 'a',
35
+ takeToken: 'b',
36
+ });
37
+ });
38
+
39
+ test('a-z if blacklist prevents using first char', () => {
40
+ const moves = {
41
+ clickCell: () => {},
42
+ };
43
+
44
+ const shortcuts = AssignShortcuts(moves, 'c');
45
+
46
+ expect(shortcuts).toEqual({
47
+ clickCell: 'a',
48
+ });
49
+ });
@@ -0,0 +1,177 @@
1
+ import Debug from './debug/Debug.svelte';
2
+ import type { _ClientImpl } from './client';
3
+
4
+ type SubscriptionState = {
5
+ client: _ClientImpl;
6
+ debuggableClients: _ClientImpl[];
7
+ };
8
+ type SubscribeCallback = (arg: SubscriptionState) => void;
9
+ type UnsubscribeCallback = () => void;
10
+
11
+ /**
12
+ * Class to manage boardgame.io clients and limit debug panel rendering.
13
+ */
14
+ export class ClientManager {
15
+ private debugPanel: Debug | null;
16
+ private currentClient: _ClientImpl | null;
17
+ private clients: Map<_ClientImpl, _ClientImpl>;
18
+ private subscribers: Map<symbol, SubscribeCallback>;
19
+
20
+ constructor() {
21
+ this.debugPanel = null;
22
+ this.currentClient = null;
23
+ this.clients = new Map();
24
+ this.subscribers = new Map();
25
+ }
26
+
27
+ /**
28
+ * Register a client with the client manager.
29
+ */
30
+ register(client: _ClientImpl): void {
31
+ // Add client to clients map.
32
+ this.clients.set(client, client);
33
+ // Mount debug for this client (no-op if another debug is already mounted).
34
+ this.mountDebug(client);
35
+ this.notifySubscribers();
36
+ }
37
+
38
+ /**
39
+ * Unregister a client from the client manager.
40
+ */
41
+ unregister(client: _ClientImpl): void {
42
+ // Remove client from clients map.
43
+ this.clients.delete(client);
44
+
45
+ if (this.currentClient === client) {
46
+ // If the removed client owned the debug panel, unmount it.
47
+ this.unmountDebug();
48
+ // Mount debug panel for next available client.
49
+ for (const [client] of this.clients) {
50
+ if (this.debugPanel) break;
51
+ this.mountDebug(client);
52
+ }
53
+ }
54
+
55
+ this.notifySubscribers();
56
+ }
57
+
58
+ /**
59
+ * Subscribe to the client manager state.
60
+ * Calls the passed callback each time the current client changes or a client
61
+ * registers/unregisters.
62
+ * Returns a function to unsubscribe from the state updates.
63
+ */
64
+ subscribe(callback: SubscribeCallback): UnsubscribeCallback {
65
+ const id = Symbol();
66
+ this.subscribers.set(id, callback);
67
+ callback(this.getState());
68
+ return () => {
69
+ this.subscribers.delete(id);
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Switch to a client with a matching playerID.
75
+ */
76
+ switchPlayerID(playerID: string): void {
77
+ // For multiplayer clients, try switching control to a different client
78
+ // that is using the same transport layer.
79
+ if (this.currentClient.multiplayer) {
80
+ for (const [client] of this.clients) {
81
+ if (
82
+ client.playerID === playerID &&
83
+ client.debugOpt !== false &&
84
+ client.multiplayer === this.currentClient.multiplayer
85
+ ) {
86
+ this.switchToClient(client);
87
+ return;
88
+ }
89
+ }
90
+ }
91
+
92
+ // If no client matches, update the playerID for the current client.
93
+ this.currentClient.updatePlayerID(playerID);
94
+ this.notifySubscribers();
95
+ }
96
+
97
+ /**
98
+ * Set the passed client as the active client for debugging.
99
+ */
100
+ switchToClient(client: _ClientImpl): void {
101
+ if (client === this.currentClient) return;
102
+ this.unmountDebug();
103
+ this.mountDebug(client);
104
+ this.notifySubscribers();
105
+ }
106
+
107
+ /**
108
+ * Notify all subscribers of changes to the client manager state.
109
+ */
110
+ private notifySubscribers(): void {
111
+ const arg = this.getState();
112
+ this.subscribers.forEach((cb) => {
113
+ cb(arg);
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Get the client manager state.
119
+ */
120
+ private getState(): SubscriptionState {
121
+ return {
122
+ client: this.currentClient,
123
+ debuggableClients: this.getDebuggableClients(),
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Get an array of the registered clients that haven’t disabled the debug panel.
129
+ */
130
+ private getDebuggableClients(): _ClientImpl[] {
131
+ return [...this.clients.values()].filter(
132
+ (client) => client.debugOpt !== false
133
+ );
134
+ }
135
+
136
+ /**
137
+ * Mount the debug panel using the passed client.
138
+ */
139
+ private mountDebug(client: _ClientImpl): void {
140
+ if (
141
+ client.debugOpt === false ||
142
+ this.debugPanel !== null ||
143
+ typeof document === 'undefined'
144
+ ) {
145
+ return;
146
+ }
147
+
148
+ let DebugImpl: typeof Debug | undefined;
149
+ let target = document.body;
150
+
151
+ if (process.env.NODE_ENV !== 'production') {
152
+ DebugImpl = Debug;
153
+ }
154
+
155
+ if (client.debugOpt && client.debugOpt !== true) {
156
+ DebugImpl = client.debugOpt.impl || DebugImpl;
157
+ target = client.debugOpt.target || target;
158
+ }
159
+
160
+ if (DebugImpl) {
161
+ this.currentClient = client;
162
+ this.debugPanel = new DebugImpl({
163
+ target,
164
+ props: { clientManager: this },
165
+ });
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Unmount the debug panel.
171
+ */
172
+ private unmountDebug(): void {
173
+ this.debugPanel.$destroy();
174
+ this.debugPanel = null;
175
+ this.currentClient = null;
176
+ }
177
+ }
@@ -0,0 +1,136 @@
1
+ /*
2
+ * Copyright 2017 The boardgame.io Authors
3
+ *
4
+ * Use of this source code is governed by a MIT-style
5
+ * license that can be found in the LICENSE file or at
6
+ * https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import React from 'react';
10
+ import PropTypes from 'prop-types';
11
+ import { Client as RawClient } from './client';
12
+
13
+ /**
14
+ * Client
15
+ *
16
+ * boardgame.io React Native client.
17
+ *
18
+ * @param {...object} game - The return value of `Game`.
19
+ * @param {...object} numPlayers - The number of players.
20
+ * @param {...object} board - The React component for the game.
21
+ * @param {...object} loading - (optional) The React component for the loading state.
22
+ * @param {...object} multiplayer - Set to a falsy value or a transportFactory, e.g., SocketIO()
23
+ * @param {...object} enhancer - Optional enhancer to send to the Redux store
24
+ *
25
+ * Returns:
26
+ * A React Native component that wraps board and provides an
27
+ * API through props for it to interact with the framework
28
+ * and dispatch actions such as MAKE_MOVE.
29
+ */
30
+ export function Client(opts) {
31
+ const { game, numPlayers, board, multiplayer, enhancer } = opts;
32
+ let { loading } = opts;
33
+
34
+ // Component that is displayed before the client has synced
35
+ // with the game master.
36
+ if (loading === undefined) {
37
+ const Loading = () => <></>;
38
+ loading = Loading;
39
+ }
40
+
41
+ /*
42
+ * WrappedBoard
43
+ *
44
+ * The main React component that wraps the passed in
45
+ * board component and adds the API to its props.
46
+ */
47
+ return class WrappedBoard extends React.Component {
48
+ static propTypes = {
49
+ // The ID of a game to connect to.
50
+ // Only relevant in multiplayer.
51
+ matchID: PropTypes.string,
52
+ // The ID of the player associated with this client.
53
+ // Only relevant in multiplayer.
54
+ playerID: PropTypes.string,
55
+ // This client's authentication credentials.
56
+ // Only relevant in multiplayer.
57
+ credentials: PropTypes.string,
58
+ };
59
+
60
+ static defaultProps = {
61
+ matchID: 'default',
62
+ playerID: null,
63
+ credentials: null,
64
+ };
65
+
66
+ constructor(props) {
67
+ super(props);
68
+
69
+ this.client = RawClient({
70
+ game,
71
+ numPlayers,
72
+ multiplayer,
73
+ matchID: props.matchID,
74
+ playerID: props.playerID,
75
+ credentials: props.credentials,
76
+ debug: false,
77
+ enhancer,
78
+ });
79
+ }
80
+
81
+ componentDidMount() {
82
+ this.unsubscribe = this.client.subscribe(() => this.forceUpdate());
83
+ this.client.start();
84
+ }
85
+
86
+ componentWillUnmount() {
87
+ this.client.stop();
88
+ this.unsubscribe();
89
+ }
90
+
91
+ componentDidUpdate(prevProps) {
92
+ if (prevProps.matchID != this.props.matchID) {
93
+ this.client.updateMatchID(this.props.matchID);
94
+ }
95
+ if (prevProps.playerID != this.props.playerID) {
96
+ this.client.updatePlayerID(this.props.playerID);
97
+ }
98
+ if (prevProps.credentials != this.props.credentials) {
99
+ this.client.updateCredentials(this.props.credentials);
100
+ }
101
+ }
102
+
103
+ render() {
104
+ let _board = null;
105
+
106
+ const state = this.client.getState();
107
+
108
+ if (state === null) {
109
+ return React.createElement(loading);
110
+ }
111
+
112
+ const { matchID, playerID, ...rest } = this.props;
113
+
114
+ if (board) {
115
+ _board = React.createElement(board, {
116
+ ...state,
117
+ ...rest,
118
+ matchID,
119
+ playerID,
120
+ isMultiplayer: !!multiplayer,
121
+ moves: this.client.moves,
122
+ events: this.client.events,
123
+ step: this.client.step,
124
+ reset: this.client.reset,
125
+ undo: this.client.undo,
126
+ redo: this.client.redo,
127
+ matchData: this.client.matchData,
128
+ sendChatMessage: this.client.sendChatMessage,
129
+ chatMessages: this.client.chatMessages,
130
+ });
131
+ }
132
+
133
+ return _board;
134
+ }
135
+ };
136
+ }
@@ -0,0 +1,229 @@
1
+ /*
2
+ * Copyright 2018 The boardgame.io Authors
3
+ *
4
+ * Use of this source code is governed by a MIT-style
5
+ * license that can be found in the LICENSE file or at
6
+ * https://opensource.org/licenses/MIT.
7
+ */
8
+ /* eslint-disable unicorn/no-array-callback-reference */
9
+
10
+ import React from 'react';
11
+ import { Client } from './react-native';
12
+ import Enzyme from 'enzyme';
13
+ import Adapter from 'enzyme-adapter-react-16';
14
+ import { Local } from './transport/local';
15
+ import { Transport } from './transport/transport';
16
+
17
+ class NoConnectionTransport extends Transport {
18
+ connect() {}
19
+ disconnect() {}
20
+ sendAction() {}
21
+ sendChatMessage() {}
22
+ requestSync() {}
23
+ updateMatchID() {}
24
+ updatePlayerID() {}
25
+ updateCredentials() {}
26
+ }
27
+
28
+ Enzyme.configure({ adapter: new Adapter() });
29
+
30
+ class TestBoard extends React.Component {
31
+ render() {
32
+ return <div id="board">Board</div>;
33
+ }
34
+ }
35
+
36
+ test('board is rendered', () => {
37
+ const Board = Client({
38
+ game: {},
39
+ board: TestBoard,
40
+ });
41
+
42
+ const game = Enzyme.mount(<Board />);
43
+ const board = game.find(TestBoard);
44
+
45
+ expect(board.props().isActive).toBe(true);
46
+ expect(board.text()).toBe('Board');
47
+
48
+ game.unmount();
49
+ });
50
+
51
+ test('board is rendered with custom loading', () => {
52
+ const Loading = () => <>connecting...</>;
53
+
54
+ const Board = Client({
55
+ game: {},
56
+ board: TestBoard,
57
+ loading: Loading,
58
+ multiplayer: (opts) => new NoConnectionTransport(opts),
59
+ });
60
+
61
+ const game = Enzyme.mount(<Board />);
62
+ const loadingComponent = game.find(Loading);
63
+
64
+ expect(loadingComponent.props()).toEqual({});
65
+ expect(loadingComponent.text()).toBe('connecting...');
66
+
67
+ game.unmount();
68
+ });
69
+
70
+ test('board props', () => {
71
+ const Board = Client({
72
+ game: {},
73
+ board: TestBoard,
74
+ });
75
+ const board = Enzyme.mount(<Board />).find(TestBoard);
76
+ expect(board.props().isMultiplayer).toEqual(false);
77
+ expect(board.props().isActive).toBe(true);
78
+ });
79
+
80
+ test('can pass extra props to Client', () => {
81
+ const Board = Client({
82
+ game: {},
83
+ board: TestBoard,
84
+ });
85
+ const board = Enzyme.mount(
86
+ <Board doStuff={() => true} extraValue={55} />
87
+ ).find(TestBoard);
88
+ expect(board.props().doStuff()).toBe(true);
89
+ expect(board.props().extraValue).toBe(55);
90
+ });
91
+
92
+ test('can pass empty board', () => {
93
+ const Board = Client({
94
+ game: {},
95
+ });
96
+
97
+ const game = Enzyme.mount(<Board />);
98
+ expect(game).not.toBe(undefined);
99
+ });
100
+
101
+ test('move api', () => {
102
+ const Board = Client({
103
+ game: {
104
+ moves: {
105
+ A: (_, arg) => ({ arg }),
106
+ },
107
+ },
108
+ board: TestBoard,
109
+ });
110
+
111
+ const game = Enzyme.mount(<Board />);
112
+ const board = game.find('TestBoard').instance();
113
+
114
+ expect(board.props.G).toEqual({});
115
+ board.props.moves.A(42);
116
+ expect(board.props.G).toEqual({ arg: 42 });
117
+ });
118
+
119
+ test('update matchID / playerID', () => {
120
+ let Board = null;
121
+ let game = null;
122
+
123
+ // No multiplayer.
124
+
125
+ Board = Client({
126
+ game: {
127
+ moves: {
128
+ A: (_, arg) => ({ arg }),
129
+ },
130
+ },
131
+ board: TestBoard,
132
+ });
133
+ game = Enzyme.mount(<Board />);
134
+ game.setProps({ matchID: 'a' });
135
+ game.setProps({ playerID: '3' });
136
+ expect(game.instance().transport).toBe(undefined);
137
+
138
+ // Multiplayer.
139
+
140
+ Board = Client({
141
+ game: {
142
+ moves: {
143
+ A: (_, arg) => ({ arg }),
144
+ },
145
+ },
146
+ board: TestBoard,
147
+ multiplayer: Local(),
148
+ });
149
+ game = Enzyme.mount(<Board matchID="a" playerID="1" credentials="foo" />);
150
+ const m = game.instance().client.transport;
151
+ const g = game.instance().client;
152
+
153
+ const spy1 = jest.spyOn(m, 'updateMatchID');
154
+ const spy2 = jest.spyOn(m, 'updatePlayerID');
155
+ const spy3 = jest.spyOn(g, 'updateCredentials');
156
+
157
+ expect(m.matchID).toBe('a');
158
+ expect(m.playerID).toBe('1');
159
+
160
+ game.setProps({ matchID: 'a' });
161
+ game.setProps({ playerID: '1' });
162
+ game.setProps({ credentials: 'foo' });
163
+
164
+ expect(m.matchID).toBe('a');
165
+ expect(m.playerID).toBe('1');
166
+ expect(spy1).not.toHaveBeenCalled();
167
+ expect(spy2).not.toHaveBeenCalled();
168
+ expect(spy3).not.toHaveBeenCalled();
169
+
170
+ game.setProps({ matchID: 'next' });
171
+ game.setProps({ playerID: 'next' });
172
+ game.setProps({ credentials: 'bar' });
173
+
174
+ expect(m.matchID).toBe('next');
175
+ expect(m.playerID).toBe('next');
176
+ expect(spy1).toHaveBeenCalled();
177
+ expect(spy2).toHaveBeenCalled();
178
+ expect(spy3).toHaveBeenCalled();
179
+ });
180
+
181
+ test('local playerView', () => {
182
+ const Board = Client({
183
+ game: {
184
+ setup: () => ({ secret: true }),
185
+ playerView: ({ playerID }) => ({ stripped: playerID }),
186
+ },
187
+ board: TestBoard,
188
+ numPlayers: 2,
189
+ });
190
+
191
+ const game = Enzyme.mount(<Board playerID="1" />);
192
+ const board = game.find('TestBoard').instance();
193
+ expect(board.props.G).toEqual({ stripped: '1' });
194
+ });
195
+
196
+ test('reset Game', () => {
197
+ const Board = Client({
198
+ game: {
199
+ moves: {
200
+ A: (_, arg) => ({ arg }),
201
+ },
202
+ },
203
+ board: TestBoard,
204
+ });
205
+
206
+ const game = Enzyme.mount(<Board />);
207
+ const board = game.find('TestBoard').instance();
208
+
209
+ const initial = { G: { ...board.props.G }, ctx: { ...board.props.ctx } };
210
+
211
+ expect(board.props.G).toEqual({});
212
+ board.props.moves.A(42);
213
+ expect(board.props.G).toEqual({ arg: 42 });
214
+ board.props.reset();
215
+ expect(board.props.G).toEqual(initial.G);
216
+ expect(board.props.ctx).toEqual(initial.ctx);
217
+ });
218
+
219
+ test('can receive enhancer', () => {
220
+ const enhancer = jest.fn().mockImplementation((next) => next);
221
+ const Board = Client({
222
+ game: {},
223
+ board: TestBoard,
224
+ enhancer,
225
+ });
226
+
227
+ Enzyme.mount(<Board />);
228
+ expect(enhancer).toBeCalled();
229
+ });
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @jest-environment node
3
+ */
4
+
5
+ import React from 'react';
6
+ import type { BoardProps } from './react';
7
+ import { Client } from './react';
8
+ import ReactDOMServer from 'react-dom/server';
9
+
10
+ class TestBoard extends React.Component<BoardProps> {
11
+ render() {
12
+ return <div id="my-board">Board</div>;
13
+ }
14
+ }
15
+
16
+ test('board is rendered - ssr', () => {
17
+ const Board = Client({
18
+ game: {},
19
+ board: TestBoard,
20
+ });
21
+ const ssrRender = ReactDOMServer.renderToString(<Board />);
22
+ expect(ssrRender).toContain('bgio-client');
23
+ expect(ssrRender).toContain('my-board');
24
+ });