@smoregg/sdk 2.0.0 → 2.1.0

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 (70) hide show
  1. package/dist/cjs/controller.cjs +193 -115
  2. package/dist/cjs/controller.cjs.map +1 -1
  3. package/dist/cjs/errors.cjs +1 -0
  4. package/dist/cjs/errors.cjs.map +1 -1
  5. package/dist/cjs/events.cjs +19 -2
  6. package/dist/cjs/events.cjs.map +1 -1
  7. package/dist/cjs/index.cjs +2 -7
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs/screen.cjs +185 -130
  10. package/dist/cjs/screen.cjs.map +1 -1
  11. package/dist/cjs/shared.cjs +34 -0
  12. package/dist/cjs/shared.cjs.map +1 -0
  13. package/dist/cjs/testing.cjs +125 -74
  14. package/dist/cjs/testing.cjs.map +1 -1
  15. package/dist/cjs/transport/PostMessageTransport.cjs +12 -0
  16. package/dist/cjs/transport/PostMessageTransport.cjs.map +1 -1
  17. package/dist/cjs/transport/protocol.cjs +2 -0
  18. package/dist/cjs/transport/protocol.cjs.map +1 -1
  19. package/dist/cjs/types.cjs +16 -0
  20. package/dist/cjs/types.cjs.map +1 -0
  21. package/dist/esm/controller.js +195 -117
  22. package/dist/esm/controller.js.map +1 -1
  23. package/dist/esm/errors.js +1 -0
  24. package/dist/esm/errors.js.map +1 -1
  25. package/dist/esm/events.js +18 -3
  26. package/dist/esm/events.js.map +1 -1
  27. package/dist/esm/index.js +1 -3
  28. package/dist/esm/index.js.map +1 -1
  29. package/dist/esm/screen.js +187 -132
  30. package/dist/esm/screen.js.map +1 -1
  31. package/dist/esm/shared.js +30 -0
  32. package/dist/esm/shared.js.map +1 -0
  33. package/dist/esm/testing.js +125 -74
  34. package/dist/esm/testing.js.map +1 -1
  35. package/dist/esm/transport/PostMessageTransport.js +12 -0
  36. package/dist/esm/transport/PostMessageTransport.js.map +1 -1
  37. package/dist/esm/transport/protocol.js +2 -1
  38. package/dist/esm/transport/protocol.js.map +1 -1
  39. package/dist/esm/types.js +14 -0
  40. package/dist/esm/types.js.map +1 -0
  41. package/dist/types/controller.d.ts +1 -1
  42. package/dist/types/controller.d.ts.map +1 -1
  43. package/dist/types/errors.d.ts.map +1 -1
  44. package/dist/types/events.d.ts +10 -1
  45. package/dist/types/events.d.ts.map +1 -1
  46. package/dist/types/index.d.ts +4 -8
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/dist/types/screen.d.ts +3 -3
  49. package/dist/types/screen.d.ts.map +1 -1
  50. package/dist/types/shared.d.ts +21 -0
  51. package/dist/types/shared.d.ts.map +1 -0
  52. package/dist/types/testing.d.ts +63 -4
  53. package/dist/types/testing.d.ts.map +1 -1
  54. package/dist/types/transport/PostMessageTransport.d.ts +1 -0
  55. package/dist/types/transport/PostMessageTransport.d.ts.map +1 -1
  56. package/dist/types/transport/protocol.d.ts +4 -0
  57. package/dist/types/transport/protocol.d.ts.map +1 -1
  58. package/dist/types/types.d.ts +215 -347
  59. package/dist/types/types.d.ts.map +1 -1
  60. package/dist/umd/smore-sdk.umd.js +442 -787
  61. package/dist/umd/smore-sdk.umd.js.map +1 -1
  62. package/dist/umd/smore-sdk.umd.min.js +1 -1
  63. package/dist/umd/smore-sdk.umd.min.js.map +1 -1
  64. package/package.json +7 -1
  65. package/dist/cjs/config.cjs +0 -13
  66. package/dist/cjs/config.cjs.map +0 -1
  67. package/dist/esm/config.js +0 -10
  68. package/dist/esm/config.js.map +0 -1
  69. package/dist/types/config.d.ts +0 -35
  70. package/dist/types/config.d.ts.map +0 -1
@@ -1,4 +1,5 @@
1
1
  import { validateEventName } from './events.js';
2
+ import { SmoreSDKError } from './errors.js';
2
3
 
3
4
  function createMockScreen(options = {}) {
4
5
  const {
@@ -8,6 +9,7 @@ function createMockScreen(options = {}) {
8
9
  } = options;
9
10
  let _controllers = [...initialControllers];
10
11
  let _isReady = false;
12
+ let _isConnected = false;
11
13
  let _isDestroyed = false;
12
14
  const listeners = /* @__PURE__ */ new Map();
13
15
  const _onAllReadyCallbacks = /* @__PURE__ */ new Set();
@@ -16,8 +18,8 @@ function createMockScreen(options = {}) {
16
18
  const _onControllerDisconnectCallbacks = /* @__PURE__ */ new Set();
17
19
  const _onControllerReconnectCallbacks = /* @__PURE__ */ new Set();
18
20
  const _onCharacterUpdatedCallbacks = /* @__PURE__ */ new Set();
19
- const _onRateLimitedCallbacks = /* @__PURE__ */ new Set();
20
21
  const _onErrorCallbacks = /* @__PURE__ */ new Set();
22
+ const _onConnectionChangeCallbacks = /* @__PURE__ */ new Set();
21
23
  let _allReadyFired = false;
22
24
  let _readyResolve;
23
25
  const _readyPromise = new Promise((resolve) => {
@@ -39,6 +41,12 @@ function createMockScreen(options = {}) {
39
41
  get isDestroyed() {
40
42
  return _isDestroyed;
41
43
  },
44
+ get isConnected() {
45
+ return _isConnected;
46
+ },
47
+ get protocolVersion() {
48
+ return 1;
49
+ },
42
50
  get ready() {
43
51
  return _readyPromise;
44
52
  },
@@ -82,87 +90,82 @@ function createMockScreen(options = {}) {
82
90
  _onCharacterUpdatedCallbacks.delete(callback);
83
91
  };
84
92
  },
85
- onRateLimited(callback) {
86
- _onRateLimitedCallbacks.add(callback);
87
- return () => {
88
- _onRateLimitedCallbacks.delete(callback);
89
- };
90
- },
91
93
  onError(callback) {
92
94
  _onErrorCallbacks.add(callback);
93
95
  return () => {
94
96
  _onErrorCallbacks.delete(callback);
95
97
  };
96
98
  },
99
+ onConnectionChange(callback) {
100
+ _onConnectionChangeCallbacks.add(callback);
101
+ return () => {
102
+ _onConnectionChangeCallbacks.delete(callback);
103
+ };
104
+ },
97
105
  // === Communication Methods ===
98
106
  broadcast(event, data) {
99
107
  if (_isDestroyed) {
100
- throw new Error("Cannot broadcast: screen is destroyed");
108
+ throw new SmoreSDKError("DESTROYED", "Cannot call broadcast() after destroy()");
101
109
  }
102
110
  if (!_isReady) {
103
- throw new Error("Cannot broadcast: screen is not ready");
104
- }
105
- validateEventName(event);
106
- broadcasts.push({ event, data });
107
- },
108
- broadcastRaw(event, data) {
109
- if (_isDestroyed) {
110
- throw new Error("Cannot broadcast: screen is destroyed");
111
- }
112
- if (!_isReady) {
113
- throw new Error("Cannot broadcast: screen is not ready");
111
+ throw new SmoreSDKError("NOT_READY", "Cannot call broadcast() before screen is ready");
114
112
  }
115
113
  validateEventName(event);
116
114
  broadcasts.push({ event, data });
117
115
  },
118
116
  sendToController(playerIndex, event, data) {
119
117
  if (_isDestroyed) {
120
- throw new Error("Cannot send: screen is destroyed");
118
+ throw new SmoreSDKError("DESTROYED", "Cannot call sendToController() after destroy()");
121
119
  }
122
120
  if (!_isReady) {
123
- throw new Error("Cannot send: screen is not ready");
121
+ throw new SmoreSDKError("NOT_READY", "Cannot call sendToController() before screen is ready");
124
122
  }
125
123
  validateEventName(event);
126
124
  if (!_controllers.some((c) => c.playerIndex === playerIndex)) {
127
- throw new Error(`Invalid player index: ${playerIndex}`);
128
- }
129
- sends.push({ playerIndex, event, data });
130
- },
131
- sendToControllerRaw(playerIndex, event, data) {
132
- if (_isDestroyed) {
133
- throw new Error("Cannot send: screen is destroyed");
134
- }
135
- if (!_isReady) {
136
- throw new Error("Cannot send: screen is not ready");
137
- }
138
- validateEventName(event);
139
- if (!_controllers.some((c) => c.playerIndex === playerIndex)) {
140
- throw new Error(`Invalid player index: ${playerIndex}`);
125
+ throw new SmoreSDKError("INVALID_PLAYER", `No controller found with player index ${playerIndex}`);
141
126
  }
142
127
  sends.push({ playerIndex, event, data });
143
128
  },
144
129
  // === Game Lifecycle ===
145
130
  gameOver(results) {
146
131
  if (_isDestroyed) {
147
- throw new Error("Cannot call gameOver: screen is destroyed");
132
+ throw new SmoreSDKError("DESTROYED", "Cannot call gameOver() after destroy()");
148
133
  }
149
134
  if (!_isReady) {
150
- throw new Error("Cannot call gameOver: screen is not ready");
135
+ throw new SmoreSDKError("NOT_READY", "Cannot call gameOver() before screen is ready");
151
136
  }
152
137
  broadcasts.push({ event: "smore:game-over", data: { results } });
153
138
  },
154
139
  signalReady() {
155
140
  if (_isDestroyed) {
156
- throw new Error("Cannot call signalReady: screen is destroyed");
141
+ throw new SmoreSDKError("DESTROYED", "Cannot call signalReady() after destroy()");
157
142
  }
158
143
  if (!_isReady) {
159
- throw new Error("Cannot call signalReady: screen is not ready");
144
+ throw new SmoreSDKError("NOT_READY", "Cannot call signalReady() before screen is ready");
160
145
  }
161
146
  },
162
147
  // === Event Subscription ===
163
148
  on(event, handler) {
164
- validateEventName(event);
165
149
  const eventStr = event;
150
+ if (eventStr.startsWith("$")) {
151
+ switch (eventStr) {
152
+ case "$controller-join":
153
+ return screen.onControllerJoin(handler);
154
+ case "$controller-leave":
155
+ return screen.onControllerLeave(handler);
156
+ case "$controller-disconnect":
157
+ return screen.onControllerDisconnect(handler);
158
+ case "$controller-reconnect":
159
+ return screen.onControllerReconnect(handler);
160
+ case "$character-updated":
161
+ return screen.onCharacterUpdated(handler);
162
+ case "$all-ready":
163
+ return screen.onAllReady(handler);
164
+ case "$error":
165
+ return screen.onError(handler);
166
+ }
167
+ }
168
+ validateEventName(event);
166
169
  if (!listeners.has(eventStr)) {
167
170
  listeners.set(eventStr, /* @__PURE__ */ new Set());
168
171
  }
@@ -188,6 +191,13 @@ function createMockScreen(options = {}) {
188
191
  listeners.get(eventStr)?.delete(handler);
189
192
  }
190
193
  },
194
+ removeAllListeners(event) {
195
+ if (event) {
196
+ listeners.delete(event);
197
+ } else {
198
+ listeners.clear();
199
+ }
200
+ },
191
201
  // === Utilities ===
192
202
  getController(playerIndex) {
193
203
  return _controllers.find((c) => c.playerIndex === playerIndex);
@@ -195,9 +205,6 @@ function createMockScreen(options = {}) {
195
205
  getControllerCount() {
196
206
  return _controllers.filter((c) => c.connected).length;
197
207
  },
198
- hasAnyConnectedControllers() {
199
- return _controllers.some((c) => c.connected);
200
- },
201
208
  // === Cleanup ===
202
209
  /**
203
210
  * Note: destroy() clears recorded broadcast/event arrays. Call getBroadcasts() before destroy() if assertions are needed.
@@ -233,7 +240,7 @@ function createMockScreen(options = {}) {
233
240
  simulateControllerDisconnect(playerIndex) {
234
241
  const controller = _controllers.find((c) => c.playerIndex === playerIndex);
235
242
  if (!controller) {
236
- throw new Error(`Controller ${playerIndex} not found`);
243
+ throw new SmoreSDKError("INVALID_PLAYER", `Controller ${playerIndex} not found`);
237
244
  }
238
245
  _controllers = _controllers.map(
239
246
  (c) => c.playerIndex === playerIndex ? { ...c, connected: false } : c
@@ -246,7 +253,7 @@ function createMockScreen(options = {}) {
246
253
  simulateControllerReconnect(playerIndex) {
247
254
  const controller = _controllers.find((c) => c.playerIndex === playerIndex);
248
255
  if (!controller) {
249
- throw new Error(`Controller ${playerIndex} not found`);
256
+ throw new SmoreSDKError("INVALID_PLAYER", `Controller ${playerIndex} not found`);
250
257
  }
251
258
  const reconnectedController = { ...controller, connected: true };
252
259
  _controllers = _controllers.map(
@@ -257,16 +264,13 @@ function createMockScreen(options = {}) {
257
264
  simulateCharacterUpdate(playerIndex, appearance) {
258
265
  const controller = _controllers.find((c) => c.playerIndex === playerIndex);
259
266
  if (!controller) {
260
- throw new Error(`Controller ${playerIndex} not found`);
267
+ throw new SmoreSDKError("INVALID_PLAYER", `Controller ${playerIndex} not found`);
261
268
  }
262
269
  _controllers = _controllers.map(
263
270
  (c) => c.playerIndex === playerIndex ? { ...c, appearance } : c
264
271
  );
265
272
  _onCharacterUpdatedCallbacks.forEach((cb) => cb(playerIndex, appearance));
266
273
  },
267
- simulateRateLimited(event) {
268
- _onRateLimitedCallbacks.forEach((cb) => cb(event));
269
- },
270
274
  simulateAllReady() {
271
275
  _allReadyFired = true;
272
276
  _onAllReadyCallbacks.forEach((cb) => cb());
@@ -274,6 +278,10 @@ function createMockScreen(options = {}) {
274
278
  simulateError(error) {
275
279
  _onErrorCallbacks.forEach((cb) => cb(error));
276
280
  },
281
+ simulateConnectionChange(connected) {
282
+ _isConnected = connected;
283
+ _onConnectionChangeCallbacks.forEach((cb) => cb(connected));
284
+ },
277
285
  getBroadcasts() {
278
286
  return [...broadcasts];
279
287
  },
@@ -286,6 +294,7 @@ function createMockScreen(options = {}) {
286
294
  },
287
295
  triggerReady() {
288
296
  _isReady = true;
297
+ _isConnected = true;
289
298
  _readyResolve();
290
299
  }
291
300
  };
@@ -297,10 +306,11 @@ function createMockScreen(options = {}) {
297
306
  function createMockController(options = {}) {
298
307
  const {
299
308
  roomCode = "TEST",
300
- myIndex = 0,
309
+ myPlayerIndex = 0,
301
310
  autoReady = true
302
311
  } = options;
303
312
  let _isReady = false;
313
+ let _isConnected = false;
304
314
  let _isDestroyed = false;
305
315
  let _controllers = options.controllers ?? [];
306
316
  const listeners = /* @__PURE__ */ new Map();
@@ -310,8 +320,9 @@ function createMockController(options = {}) {
310
320
  const _onControllerDisconnectCallbacks = /* @__PURE__ */ new Set();
311
321
  const _onControllerReconnectCallbacks = /* @__PURE__ */ new Set();
312
322
  const _onCharacterUpdatedCallbacks = /* @__PURE__ */ new Set();
313
- const _onRateLimitedCallbacks = /* @__PURE__ */ new Set();
314
323
  const _onErrorCallbacks = /* @__PURE__ */ new Set();
324
+ const _onGameOverCallbacks = /* @__PURE__ */ new Set();
325
+ const _onConnectionChangeCallbacks = /* @__PURE__ */ new Set();
315
326
  let _allReadyFired = false;
316
327
  let _readyResolve;
317
328
  const _readyPromise = new Promise((resolve) => {
@@ -320,8 +331,8 @@ function createMockController(options = {}) {
320
331
  const sentEvents = [];
321
332
  const controller = {
322
333
  // === Properties ===
323
- get myIndex() {
324
- return myIndex;
334
+ get myPlayerIndex() {
335
+ return myPlayerIndex;
325
336
  },
326
337
  get roomCode() {
327
338
  return roomCode;
@@ -332,6 +343,12 @@ function createMockController(options = {}) {
332
343
  get isDestroyed() {
333
344
  return _isDestroyed;
334
345
  },
346
+ get isConnected() {
347
+ return _isConnected;
348
+ },
349
+ get protocolVersion() {
350
+ return 1;
351
+ },
335
352
  get controllers() {
336
353
  return [..._controllers];
337
354
  },
@@ -378,48 +395,70 @@ function createMockController(options = {}) {
378
395
  _onCharacterUpdatedCallbacks.delete(callback);
379
396
  };
380
397
  },
381
- onRateLimited(callback) {
382
- _onRateLimitedCallbacks.add(callback);
383
- return () => {
384
- _onRateLimitedCallbacks.delete(callback);
385
- };
386
- },
387
398
  onError(callback) {
388
399
  _onErrorCallbacks.add(callback);
389
400
  return () => {
390
401
  _onErrorCallbacks.delete(callback);
391
402
  };
392
403
  },
404
+ onConnectionChange(callback) {
405
+ _onConnectionChangeCallbacks.add(callback);
406
+ return () => {
407
+ _onConnectionChangeCallbacks.delete(callback);
408
+ };
409
+ },
410
+ onGameOver(callback) {
411
+ _onGameOverCallbacks.add(callback);
412
+ return () => {
413
+ _onGameOverCallbacks.delete(callback);
414
+ };
415
+ },
393
416
  getControllerCount() {
394
417
  return _controllers.filter((c) => c.connected).length;
395
418
  },
419
+ getController(playerIndex) {
420
+ return _controllers.find((c) => c.playerIndex === playerIndex);
421
+ },
396
422
  // === Communication Methods ===
397
423
  send(event, data) {
398
424
  if (_isDestroyed) {
399
- throw new Error("Cannot send: controller is destroyed");
400
- }
401
- validateEventName(event);
402
- sentEvents.push({ event, data });
403
- },
404
- sendRaw(event, data) {
405
- if (_isDestroyed) {
406
- throw new Error("Cannot send: controller is destroyed");
425
+ throw new SmoreSDKError("DESTROYED", "Cannot call send() after destroy()");
407
426
  }
408
427
  validateEventName(event);
409
428
  sentEvents.push({ event, data });
410
429
  },
411
430
  signalReady() {
412
431
  if (_isDestroyed) {
413
- throw new Error("Cannot call signalReady: controller is destroyed");
432
+ throw new SmoreSDKError("DESTROYED", "Cannot call signalReady() after destroy()");
414
433
  }
415
434
  if (!_isReady) {
416
- throw new Error("Cannot call signalReady: controller is not ready");
435
+ throw new SmoreSDKError("NOT_READY", "Cannot call signalReady() before controller is ready");
417
436
  }
418
437
  },
419
438
  // === Event Subscription ===
420
439
  on(event, handler) {
421
- validateEventName(event);
422
440
  const eventStr = event;
441
+ if (eventStr.startsWith("$")) {
442
+ switch (eventStr) {
443
+ case "$controller-join":
444
+ return controller.onControllerJoin(handler);
445
+ case "$controller-leave":
446
+ return controller.onControllerLeave(handler);
447
+ case "$controller-disconnect":
448
+ return controller.onControllerDisconnect(handler);
449
+ case "$controller-reconnect":
450
+ return controller.onControllerReconnect(handler);
451
+ case "$character-updated":
452
+ return controller.onCharacterUpdated(handler);
453
+ case "$all-ready":
454
+ return controller.onAllReady(handler);
455
+ case "$error":
456
+ return controller.onError(handler);
457
+ case "$game-over":
458
+ return controller.onGameOver(handler);
459
+ }
460
+ }
461
+ validateEventName(event);
423
462
  if (!listeners.has(eventStr)) {
424
463
  listeners.set(eventStr, /* @__PURE__ */ new Set());
425
464
  }
@@ -445,6 +484,13 @@ function createMockController(options = {}) {
445
484
  listeners.get(eventStr)?.delete(handler);
446
485
  }
447
486
  },
487
+ removeAllListeners(event) {
488
+ if (event) {
489
+ listeners.delete(event);
490
+ } else {
491
+ listeners.clear();
492
+ }
493
+ },
448
494
  // === Cleanup ===
449
495
  destroy() {
450
496
  _isDestroyed = true;
@@ -470,6 +516,7 @@ function createMockController(options = {}) {
470
516
  },
471
517
  triggerReady() {
472
518
  _isReady = true;
519
+ _isConnected = true;
473
520
  _readyResolve();
474
521
  },
475
522
  /**
@@ -510,22 +557,26 @@ function createMockController(options = {}) {
510
557
  simulateCharacterUpdate(playerIndex, appearance) {
511
558
  const ctrl = _controllers.find((c) => c.playerIndex === playerIndex);
512
559
  if (!ctrl) {
513
- throw new Error(`Controller ${playerIndex} not found`);
560
+ throw new SmoreSDKError("INVALID_PLAYER", `Controller ${playerIndex} not found`);
514
561
  }
515
562
  _controllers = _controllers.map(
516
563
  (c) => c.playerIndex === playerIndex ? { ...c, appearance } : c
517
564
  );
518
565
  _onCharacterUpdatedCallbacks.forEach((cb) => cb(playerIndex, appearance));
519
566
  },
520
- simulateRateLimited(event) {
521
- _onRateLimitedCallbacks.forEach((cb) => cb(event));
522
- },
523
567
  simulateAllReady() {
524
568
  _allReadyFired = true;
525
569
  _onAllReadyCallbacks.forEach((cb) => cb());
526
570
  },
527
571
  simulateError(error) {
528
572
  _onErrorCallbacks.forEach((cb) => cb(error));
573
+ },
574
+ simulateGameOver(results) {
575
+ _onGameOverCallbacks.forEach((cb) => cb(results));
576
+ },
577
+ simulateConnectionChange(connected) {
578
+ _isConnected = connected;
579
+ _onConnectionChangeCallbacks.forEach((cb) => cb(connected));
529
580
  }
530
581
  };
531
582
  if (autoReady) {
@@ -1 +1 @@
1
- {"version":3,"file":"testing.js","sources":["../../src/testing.ts"],"sourcesContent":["/**\n * @smoregg/sdk - Testing Utilities\n *\n * Mock implementations of Screen and Controller for unit testing.\n * All methods work synchronously for predictable test execution.\n *\n * Mocks use the same event emitter pattern as the real implementations:\n * lifecycle callbacks are registered via methods (onAllReady, onControllerJoin, etc.)\n * on the returned instance rather than via config options.\n *\n * @packageDocumentation\n */\n\nimport type {\n EventMap,\n EventNames,\n EventData,\n CharacterAppearance,\n ControllerInfo,\n PlayerIndex,\n GameResults,\n ScreenEventHandler,\n ControllerEventHandler,\n MockScreen,\n MockController,\n MockOptions,\n SmoreError,\n} from './types';\nimport { validateEventName } from './events';\n\n// =============================================================================\n// MOCK SCREEN IMPLEMENTATION\n// =============================================================================\n\ninterface RecordedBroadcast {\n event: string;\n data: unknown;\n}\n\ninterface RecordedSend {\n playerIndex: PlayerIndex;\n event: string;\n data: unknown;\n}\n\n/**\n * Create a mock Screen for testing game logic.\n *\n * All methods work synchronously. Events can be simulated and recorded\n * for assertions in unit tests.\n *\n * Uses the same event emitter pattern as real Screen: register lifecycle\n * callbacks via methods on the returned instance.\n *\n * @example\n * ```ts\n * const screen = createMockScreen<MyEvents>({\n * controllers: [\n * { playerIndex: 0, nickname: 'Player 1', connected: true },\n * { playerIndex: 1, nickname: 'Player 2', connected: true },\n * ],\n * });\n *\n * screen.on('tap', (pi, data) => handleTap(pi, data));\n * screen.onAllReady(() => startGame());\n *\n * // Simulate player input\n * screen.simulateEvent(0, 'tap', { x: 100, y: 200 });\n *\n * // Check what was broadcast\n * expect(screen.getBroadcasts()).toContainEqual({\n * event: 'score-update',\n * data: { scores: { 0: 10 } },\n * });\n * ```\n */\nexport function createMockScreen<TEvents extends EventMap = EventMap>(\n options: MockOptions = {},\n): MockScreen<TEvents> {\n const {\n roomCode = 'TEST',\n controllers: initialControllers = [],\n autoReady = true,\n } = options;\n\n // Internal state\n let _controllers: ControllerInfo[] = [...initialControllers];\n let _isReady = false;\n let _isDestroyed = false;\n\n // Event listeners\n const listeners = new Map<string, Set<ScreenEventHandler>>();\n\n // Lifecycle callback sets\n const _onAllReadyCallbacks = new Set<() => void>();\n const _onControllerJoinCallbacks = new Set<(index: PlayerIndex, info: ControllerInfo) => void>();\n const _onControllerLeaveCallbacks = new Set<(index: PlayerIndex) => void>();\n const _onControllerDisconnectCallbacks = new Set<(index: PlayerIndex) => void>();\n const _onControllerReconnectCallbacks = new Set<(index: PlayerIndex, info: ControllerInfo) => void>();\n const _onCharacterUpdatedCallbacks = new Set<(index: PlayerIndex, appearance: CharacterAppearance | null) => void>();\n const _onRateLimitedCallbacks = new Set<(event: string) => void>();\n const _onErrorCallbacks = new Set<(error: SmoreError) => void>();\n\n // Whether all-ready has fired\n let _allReadyFired = false;\n\n // Ready promise\n let _readyResolve: () => void;\n const _readyPromise = new Promise<void>((resolve) => {\n _readyResolve = resolve;\n });\n\n // Recorded events for testing\n const broadcasts: RecordedBroadcast[] = [];\n const sends: RecordedSend[] = [];\n\n // Screen implementation\n const screen: MockScreen<TEvents> = {\n // === Properties ===\n get controllers() {\n return [..._controllers];\n },\n get roomCode() {\n return roomCode;\n },\n get isReady() {\n return _isReady;\n },\n get isDestroyed() {\n return _isDestroyed;\n },\n get ready() {\n return _readyPromise;\n },\n\n // === Lifecycle Methods ===\n onAllReady(callback: () => void): () => void {\n if (_allReadyFired) {\n callback();\n }\n _onAllReadyCallbacks.add(callback);\n return () => { _onAllReadyCallbacks.delete(callback); };\n },\n\n onControllerJoin(callback: (playerIndex: PlayerIndex, info: ControllerInfo) => void): () => void {\n _onControllerJoinCallbacks.add(callback);\n return () => { _onControllerJoinCallbacks.delete(callback); };\n },\n\n onControllerLeave(callback: (playerIndex: PlayerIndex) => void): () => void {\n _onControllerLeaveCallbacks.add(callback);\n return () => { _onControllerLeaveCallbacks.delete(callback); };\n },\n\n onControllerDisconnect(callback: (playerIndex: PlayerIndex) => void): () => void {\n _onControllerDisconnectCallbacks.add(callback);\n return () => { _onControllerDisconnectCallbacks.delete(callback); };\n },\n\n onControllerReconnect(callback: (playerIndex: PlayerIndex, info: ControllerInfo) => void): () => void {\n _onControllerReconnectCallbacks.add(callback);\n return () => { _onControllerReconnectCallbacks.delete(callback); };\n },\n\n onCharacterUpdated(callback: (playerIndex: PlayerIndex, appearance: CharacterAppearance | null) => void): () => void {\n _onCharacterUpdatedCallbacks.add(callback);\n return () => { _onCharacterUpdatedCallbacks.delete(callback); };\n },\n\n onRateLimited(callback: (event: string) => void): () => void {\n _onRateLimitedCallbacks.add(callback);\n return () => { _onRateLimitedCallbacks.delete(callback); };\n },\n\n onError(callback: (error: SmoreError) => void): () => void {\n _onErrorCallbacks.add(callback);\n return () => { _onErrorCallbacks.delete(callback); };\n },\n\n // === Communication Methods ===\n broadcast<K extends EventNames<TEvents>>(\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n if (_isDestroyed) {\n throw new Error('Cannot broadcast: screen is destroyed');\n }\n if (!_isReady) {\n throw new Error('Cannot broadcast: screen is not ready');\n }\n validateEventName(event as string);\n broadcasts.push({ event: event as string, data });\n },\n\n broadcastRaw(event: string, data?: unknown): void {\n if (_isDestroyed) {\n throw new Error('Cannot broadcast: screen is destroyed');\n }\n if (!_isReady) {\n throw new Error('Cannot broadcast: screen is not ready');\n }\n validateEventName(event);\n broadcasts.push({ event, data });\n },\n\n sendToController<K extends EventNames<TEvents>>(\n playerIndex: PlayerIndex,\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n if (_isDestroyed) {\n throw new Error('Cannot send: screen is destroyed');\n }\n if (!_isReady) {\n throw new Error('Cannot send: screen is not ready');\n }\n validateEventName(event as string);\n if (!_controllers.some((c) => c.playerIndex === playerIndex)) {\n throw new Error(`Invalid player index: ${playerIndex}`);\n }\n sends.push({ playerIndex, event: event as string, data });\n },\n\n sendToControllerRaw(\n playerIndex: PlayerIndex,\n event: string,\n data?: unknown,\n ): void {\n if (_isDestroyed) {\n throw new Error('Cannot send: screen is destroyed');\n }\n if (!_isReady) {\n throw new Error('Cannot send: screen is not ready');\n }\n validateEventName(event);\n if (!_controllers.some((c) => c.playerIndex === playerIndex)) {\n throw new Error(`Invalid player index: ${playerIndex}`);\n }\n sends.push({ playerIndex, event, data });\n },\n\n // === Game Lifecycle ===\n gameOver(results?: GameResults): void {\n if (_isDestroyed) {\n throw new Error('Cannot call gameOver: screen is destroyed');\n }\n if (!_isReady) {\n throw new Error('Cannot call gameOver: screen is not ready');\n }\n broadcasts.push({ event: 'smore:game-over', data: { results } });\n },\n\n signalReady(): void {\n if (_isDestroyed) {\n throw new Error('Cannot call signalReady: screen is destroyed');\n }\n if (!_isReady) {\n throw new Error('Cannot call signalReady: screen is not ready');\n }\n // No-op in mock (real implementation emits to server)\n },\n\n // === Event Subscription ===\n on<K extends EventNames<TEvents>>(\n event: K,\n handler: ScreenEventHandler<EventData<TEvents, K>>,\n ): () => void {\n validateEventName(event as string);\n const eventStr = event as string;\n if (!listeners.has(eventStr)) {\n listeners.set(eventStr, new Set());\n }\n listeners.get(eventStr)!.add(handler as ScreenEventHandler);\n\n return () => {\n listeners.get(eventStr)?.delete(handler as ScreenEventHandler);\n };\n },\n\n once<K extends EventNames<TEvents>>(\n event: K,\n handler: ScreenEventHandler<EventData<TEvents, K>>,\n ): () => void {\n validateEventName(event as string);\n const wrapper: ScreenEventHandler<EventData<TEvents, K>> = (playerIndex, data) => {\n handler(playerIndex, data);\n screen.off(event, wrapper);\n };\n return screen.on(event, wrapper);\n },\n\n off<K extends EventNames<TEvents>>(\n event: K,\n handler?: ScreenEventHandler<EventData<TEvents, K>>,\n ): void {\n validateEventName(event as string);\n const eventStr = event as string;\n if (!handler) {\n listeners.delete(eventStr);\n } else {\n listeners.get(eventStr)?.delete(handler as ScreenEventHandler);\n }\n },\n\n // === Utilities ===\n getController(playerIndex: PlayerIndex): ControllerInfo | undefined {\n return _controllers.find((c) => c.playerIndex === playerIndex);\n },\n\n getControllerCount(): number {\n return _controllers.filter(c => c.connected).length;\n },\n\n hasAnyConnectedControllers(): boolean {\n return _controllers.some(c => c.connected);\n },\n\n // === Cleanup ===\n /**\n * Note: destroy() clears recorded broadcast/event arrays. Call getBroadcasts() before destroy() if assertions are needed.\n */\n destroy(): void {\n _isDestroyed = true;\n listeners.clear();\n broadcasts.length = 0;\n sends.length = 0;\n },\n\n // === Mock-specific methods ===\n simulateEvent<K extends EventNames<TEvents>>(\n playerIndex: PlayerIndex,\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n validateEventName(event as string);\n const eventStr = event as string;\n const handlers = listeners.get(eventStr);\n if (handlers) {\n handlers.forEach((handler) => {\n handler(playerIndex, data);\n });\n }\n },\n\n simulateControllerJoin(info: ControllerInfo): void {\n _controllers.push(info);\n _onControllerJoinCallbacks.forEach(cb => cb(info.playerIndex, info));\n },\n\n simulateControllerLeave(playerIndex: PlayerIndex): void {\n _controllers = _controllers.filter((c) => c.playerIndex !== playerIndex);\n _onControllerLeaveCallbacks.forEach(cb => cb(playerIndex));\n },\n\n /**\n * Simulate a controller network disconnect (player still in room but unreachable).\n */\n simulateControllerDisconnect(playerIndex: PlayerIndex): void {\n const controller = _controllers.find((c) => c.playerIndex === playerIndex);\n if (!controller) {\n throw new Error(`Controller ${playerIndex} not found`);\n }\n // Mark as disconnected (need to create new object since ControllerInfo is readonly)\n _controllers = _controllers.map((c) =>\n c.playerIndex === playerIndex\n ? { ...c, connected: false }\n : c\n );\n _onControllerDisconnectCallbacks.forEach(cb => cb(playerIndex));\n },\n\n /**\n * Simulate a controller network reconnect after disconnect.\n */\n simulateControllerReconnect(playerIndex: PlayerIndex): void {\n const controller = _controllers.find((c) => c.playerIndex === playerIndex);\n if (!controller) {\n throw new Error(`Controller ${playerIndex} not found`);\n }\n // Mark as connected (need to create new object since ControllerInfo is readonly)\n const reconnectedController = { ...controller, connected: true };\n _controllers = _controllers.map((c) =>\n c.playerIndex === playerIndex ? reconnectedController : c\n );\n _onControllerReconnectCallbacks.forEach(cb => cb(playerIndex, reconnectedController));\n },\n\n simulateCharacterUpdate(playerIndex: PlayerIndex, appearance: CharacterAppearance | null): void {\n const controller = _controllers.find((c) => c.playerIndex === playerIndex);\n if (!controller) {\n throw new Error(`Controller ${playerIndex} not found`);\n }\n _controllers = _controllers.map((c) =>\n c.playerIndex === playerIndex ? { ...c, appearance } : c\n );\n _onCharacterUpdatedCallbacks.forEach(cb => cb(playerIndex, appearance));\n },\n\n simulateRateLimited(event: string): void {\n _onRateLimitedCallbacks.forEach(cb => cb(event));\n },\n\n simulateAllReady(): void {\n _allReadyFired = true;\n _onAllReadyCallbacks.forEach(cb => cb());\n },\n\n simulateError(error: any): void {\n _onErrorCallbacks.forEach(cb => cb(error));\n },\n\n getBroadcasts(): Array<{ event: string; data: unknown }> {\n return [...broadcasts];\n },\n\n getSentToController(\n playerIndex: PlayerIndex,\n ): Array<{ event: string; data: unknown }> {\n return sends\n .filter((s) => s.playerIndex === playerIndex)\n .map((s) => ({ event: s.event, data: s.data }));\n },\n\n clearRecordedEvents(): void {\n broadcasts.length = 0;\n sends.length = 0;\n },\n\n triggerReady(): void {\n _isReady = true;\n _readyResolve();\n },\n };\n\n /**\n * Auto-trigger ready if enabled.\n *\n * **Note:** `autoReady` uses `setTimeout(0)` which fires asynchronously (next tick).\n * For synchronous test control, use `autoReady: false` and call `triggerReady()` manually.\n */\n if (autoReady) {\n setTimeout(() => screen.triggerReady(), 0);\n }\n\n return screen;\n}\n\n// =============================================================================\n// MOCK CONTROLLER IMPLEMENTATION\n// =============================================================================\n\ninterface RecordedEvent {\n event: string;\n data: unknown;\n}\n\n/**\n * Create a mock Controller for testing player input logic.\n *\n * All methods work synchronously. Events can be simulated and recorded\n * for assertions in unit tests.\n *\n * Uses the same event emitter pattern as real Controller: register lifecycle\n * callbacks via methods on the returned instance.\n *\n * @example\n * ```ts\n * const controller = createMockController<MyEvents>({\n * myIndex: 0,\n * });\n *\n * controller.on('your-turn', (data) => handleTurn(data));\n * controller.onAllReady(() => console.log('Ready!'));\n *\n * // Simulate receiving from screen\n * controller.simulateEvent('your-turn', { timeLimit: 30 });\n *\n * // Check what was sent\n * expect(controller.getSentEvents()).toContainEqual({\n * event: 'answer',\n * data: { choice: 2 },\n * });\n * ```\n */\nexport function createMockController<TEvents extends EventMap = EventMap>(\n options: MockOptions = {},\n): MockController<TEvents> {\n const {\n roomCode = 'TEST',\n myIndex = 0,\n autoReady = true,\n } = options;\n\n // Internal state -- uses a full ControllerInfo[] array (matching MockScreen pattern)\n // to preserve nickname/appearance data from simulatePlayerJoin()\n let _isReady = false;\n let _isDestroyed = false;\n let _controllers: ControllerInfo[] = options.controllers ?? [];\n\n // Event listeners\n const listeners = new Map<string, Set<ControllerEventHandler>>();\n\n // Lifecycle callback sets\n const _onAllReadyCallbacks = new Set<() => void>();\n const _onControllerJoinCallbacks = new Set<(index: PlayerIndex, info: ControllerInfo) => void>();\n const _onControllerLeaveCallbacks = new Set<(index: PlayerIndex) => void>();\n const _onControllerDisconnectCallbacks = new Set<(index: PlayerIndex) => void>();\n const _onControllerReconnectCallbacks = new Set<(index: PlayerIndex, info: ControllerInfo) => void>();\n const _onCharacterUpdatedCallbacks = new Set<(index: PlayerIndex, appearance: CharacterAppearance | null) => void>();\n const _onRateLimitedCallbacks = new Set<(event: string) => void>();\n const _onErrorCallbacks = new Set<(error: SmoreError) => void>();\n\n // Whether all-ready has fired\n let _allReadyFired = false;\n\n // Ready promise\n let _readyResolve: () => void;\n const _readyPromise = new Promise<void>((resolve) => {\n _readyResolve = resolve;\n });\n\n // Recorded events for testing\n const sentEvents: RecordedEvent[] = [];\n\n // Controller implementation\n const controller: MockController<TEvents> = {\n // === Properties ===\n get myIndex() {\n return myIndex;\n },\n get roomCode() {\n return roomCode;\n },\n get isReady() {\n return _isReady;\n },\n get isDestroyed() {\n return _isDestroyed;\n },\n\n get controllers(): readonly ControllerInfo[] {\n return [..._controllers];\n },\n\n get ready() {\n return _readyPromise;\n },\n\n // === Lifecycle Methods ===\n onAllReady(callback: () => void): () => void {\n if (_allReadyFired) {\n callback();\n }\n _onAllReadyCallbacks.add(callback);\n return () => { _onAllReadyCallbacks.delete(callback); };\n },\n\n onControllerJoin(callback: (playerIndex: PlayerIndex, info: ControllerInfo) => void): () => void {\n _onControllerJoinCallbacks.add(callback);\n return () => { _onControllerJoinCallbacks.delete(callback); };\n },\n\n onControllerLeave(callback: (playerIndex: PlayerIndex) => void): () => void {\n _onControllerLeaveCallbacks.add(callback);\n return () => { _onControllerLeaveCallbacks.delete(callback); };\n },\n\n onControllerDisconnect(callback: (playerIndex: PlayerIndex) => void): () => void {\n _onControllerDisconnectCallbacks.add(callback);\n return () => { _onControllerDisconnectCallbacks.delete(callback); };\n },\n\n onControllerReconnect(callback: (playerIndex: PlayerIndex, info: ControllerInfo) => void): () => void {\n _onControllerReconnectCallbacks.add(callback);\n return () => { _onControllerReconnectCallbacks.delete(callback); };\n },\n\n onCharacterUpdated(callback: (playerIndex: PlayerIndex, appearance: CharacterAppearance | null) => void): () => void {\n _onCharacterUpdatedCallbacks.add(callback);\n return () => { _onCharacterUpdatedCallbacks.delete(callback); };\n },\n\n onRateLimited(callback: (event: string) => void): () => void {\n _onRateLimitedCallbacks.add(callback);\n return () => { _onRateLimitedCallbacks.delete(callback); };\n },\n\n onError(callback: (error: SmoreError) => void): () => void {\n _onErrorCallbacks.add(callback);\n return () => { _onErrorCallbacks.delete(callback); };\n },\n\n getControllerCount(): number {\n return _controllers.filter(c => c.connected).length;\n },\n\n // === Communication Methods ===\n send<K extends EventNames<TEvents>>(\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n if (_isDestroyed) {\n throw new Error('Cannot send: controller is destroyed');\n }\n validateEventName(event as string);\n sentEvents.push({ event: event as string, data });\n },\n\n sendRaw(event: string, data?: unknown): void {\n if (_isDestroyed) {\n throw new Error('Cannot send: controller is destroyed');\n }\n validateEventName(event);\n sentEvents.push({ event, data });\n },\n\n signalReady(): void {\n if (_isDestroyed) {\n throw new Error('Cannot call signalReady: controller is destroyed');\n }\n if (!_isReady) {\n throw new Error('Cannot call signalReady: controller is not ready');\n }\n // No-op in mock (real implementation emits to server)\n },\n\n // === Event Subscription ===\n on<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n validateEventName(event as string);\n const eventStr = event as string;\n if (!listeners.has(eventStr)) {\n listeners.set(eventStr, new Set());\n }\n listeners.get(eventStr)!.add(handler as ControllerEventHandler);\n\n return () => {\n listeners.get(eventStr)?.delete(handler as ControllerEventHandler);\n };\n },\n\n once<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n validateEventName(event as string);\n const wrapper: ControllerEventHandler<EventData<TEvents, K>> = (data) => {\n handler(data);\n controller.off(event, wrapper);\n };\n return controller.on(event, wrapper);\n },\n\n off<K extends EventNames<TEvents>>(\n event: K,\n handler?: ControllerEventHandler<EventData<TEvents, K>>,\n ): void {\n validateEventName(event as string);\n const eventStr = event as string;\n if (!handler) {\n listeners.delete(eventStr);\n } else {\n listeners.get(eventStr)?.delete(handler as ControllerEventHandler);\n }\n },\n\n // === Cleanup ===\n destroy(): void {\n _isDestroyed = true;\n listeners.clear();\n sentEvents.length = 0;\n },\n\n // === Mock-specific methods ===\n simulateEvent<K extends EventNames<TEvents>>(\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n validateEventName(event as string);\n const eventStr = event as string;\n const handlers = listeners.get(eventStr);\n if (handlers) {\n handlers.forEach((handler) => {\n handler(data);\n });\n }\n },\n\n getSentEvents(): Array<{ event: string; data: unknown }> {\n return [...sentEvents];\n },\n\n clearRecordedEvents(): void {\n sentEvents.length = 0;\n },\n\n triggerReady(): void {\n _isReady = true;\n _readyResolve();\n },\n\n /**\n * Simulate a new player joining the room.\n * Stores full ControllerInfo (nickname, appearance, etc.) for later retrieval.\n */\n simulatePlayerJoin(playerIndex: PlayerIndex, info: ControllerInfo): void {\n if (!_controllers.some(c => c.playerIndex === playerIndex)) {\n _controllers = [..._controllers, { ...info, connected: info.connected ?? true }];\n }\n _onControllerJoinCallbacks.forEach(cb => cb(playerIndex, info));\n },\n\n /**\n * Simulate a player leaving the room (fully removed).\n */\n simulatePlayerLeave(playerIndex: PlayerIndex): void {\n _controllers = _controllers.filter(c => c.playerIndex !== playerIndex);\n _onControllerLeaveCallbacks.forEach(cb => cb(playerIndex));\n },\n\n /**\n * Simulate a player network disconnect (player still in room but unreachable).\n */\n simulatePlayerDisconnect(playerIndex: PlayerIndex): void {\n _controllers = _controllers.map(c =>\n c.playerIndex === playerIndex ? { ...c, connected: false } : c\n );\n _onControllerDisconnectCallbacks.forEach(cb => cb(playerIndex));\n },\n\n /**\n * Simulate a player network reconnect after disconnect.\n */\n simulatePlayerReconnect(playerIndex: PlayerIndex, info: ControllerInfo): void {\n _controllers = _controllers.map(c =>\n c.playerIndex === playerIndex ? { ...info, connected: true } : c\n );\n _onControllerReconnectCallbacks.forEach(cb => cb(playerIndex, info));\n },\n\n simulateCharacterUpdate(playerIndex: PlayerIndex, appearance: CharacterAppearance | null): void {\n const ctrl = _controllers.find((c) => c.playerIndex === playerIndex);\n if (!ctrl) {\n throw new Error(`Controller ${playerIndex} not found`);\n }\n _controllers = _controllers.map((c) =>\n c.playerIndex === playerIndex ? { ...c, appearance } : c\n );\n _onCharacterUpdatedCallbacks.forEach(cb => cb(playerIndex, appearance));\n },\n\n simulateRateLimited(event: string): void {\n _onRateLimitedCallbacks.forEach(cb => cb(event));\n },\n\n simulateAllReady(): void {\n _allReadyFired = true;\n _onAllReadyCallbacks.forEach(cb => cb());\n },\n\n simulateError(error: any): void {\n _onErrorCallbacks.forEach(cb => cb(error));\n },\n };\n\n /**\n * Auto-trigger ready if enabled.\n *\n * **Note:** `autoReady` uses `setTimeout(0)` which fires asynchronously (next tick).\n * For synchronous test control, use `autoReady: false` and call `triggerReady()` manually.\n */\n if (autoReady) {\n setTimeout(() => controller.triggerReady(), 0);\n }\n\n return controller;\n}\n\n// =============================================================================\n// EXPORTS\n// =============================================================================\n\nexport type { MockScreen, MockController, MockOptions };\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testing.js","sources":["../../src/testing.ts"],"sourcesContent":["/**\n * @smoregg/sdk - Testing Utilities\n *\n * Mock implementations of Screen and Controller for unit testing.\n * All methods work synchronously for predictable test execution.\n *\n * Mocks use the same event emitter pattern as the real implementations:\n * lifecycle callbacks are registered via methods (onAllReady, onControllerJoin, etc.)\n * on the returned instance rather than via config options.\n *\n * @packageDocumentation\n */\n\nimport type {\n EventMap,\n EventNames,\n EventData,\n CharacterAppearance,\n ControllerInfo,\n PlayerIndex,\n GameResults,\n ScreenEventHandler,\n ControllerEventHandler,\n SmoreError,\n Screen,\n Controller,\n RoomCode,\n} from './types';\nimport { validateEventName } from './events';\nimport { SmoreSDKError } from './errors';\n\n// =============================================================================\n// MOCK TYPES (internal — not part of public API)\n// =============================================================================\n\n/**\n * Options for creating mock instances.\n */\nexport interface MockOptions {\n /** Initial room code */\n roomCode?: RoomCode;\n /** Initial controllers for Screen mock */\n controllers?: ControllerInfo[];\n /** My index for Controller mock */\n myPlayerIndex?: PlayerIndex;\n /** Auto-trigger ready state */\n autoReady?: boolean;\n}\n\n/**\n * Mock Screen for testing.\n * Extends Screen with additional test utilities.\n */\nexport interface MockScreen<TEvents extends EventMap = EventMap>\n extends Screen<TEvents> {\n simulateEvent<K extends EventNames<TEvents>>(\n playerIndex: PlayerIndex,\n event: K,\n data: EventData<TEvents, K>,\n ): void;\n simulateControllerJoin(info: ControllerInfo): void;\n simulateControllerLeave(playerIndex: PlayerIndex): void;\n simulateControllerDisconnect(playerIndex: PlayerIndex): void;\n simulateControllerReconnect(playerIndex: PlayerIndex): void;\n getBroadcasts(): Array<{ event: string; data: unknown }>;\n getSentToController(playerIndex: PlayerIndex): Array<{ event: string; data: unknown }>;\n clearRecordedEvents(): void;\n triggerReady(): void;\n simulateCharacterUpdate(playerIndex: PlayerIndex, appearance: CharacterAppearance | null): void;\n simulateAllReady(): void;\n simulateError(error: any): void;\n simulateConnectionChange(connected: boolean): void;\n}\n\n/**\n * Mock Controller for testing.\n * Extends Controller with additional test utilities.\n */\nexport interface MockController<TEvents extends EventMap = EventMap>\n extends Controller<TEvents> {\n simulateEvent<K extends EventNames<TEvents>>(\n event: K,\n data: EventData<TEvents, K>,\n ): void;\n getSentEvents(): Array<{ event: string; data: unknown }>;\n clearRecordedEvents(): void;\n triggerReady(): void;\n simulatePlayerJoin(playerIndex: PlayerIndex, info: ControllerInfo): void;\n simulatePlayerLeave(playerIndex: PlayerIndex): void;\n simulatePlayerDisconnect(playerIndex: PlayerIndex): void;\n simulatePlayerReconnect(playerIndex: PlayerIndex, info: ControllerInfo): void;\n simulateCharacterUpdate(playerIndex: PlayerIndex, appearance: CharacterAppearance | null): void;\n simulateAllReady(): void;\n simulateError(error: any): void;\n simulateGameOver(results?: GameResults): void;\n simulateConnectionChange(connected: boolean): void;\n}\n\n// =============================================================================\n// MOCK SCREEN IMPLEMENTATION\n// =============================================================================\n\ninterface RecordedBroadcast {\n event: string;\n data: unknown;\n}\n\ninterface RecordedSend {\n playerIndex: PlayerIndex;\n event: string;\n data: unknown;\n}\n\n/**\n * Create a mock Screen for testing game logic.\n *\n * All methods work synchronously. Events can be simulated and recorded\n * for assertions in unit tests.\n *\n * Uses the same event emitter pattern as real Screen: register lifecycle\n * callbacks via methods on the returned instance.\n *\n * @example\n * ```ts\n * const screen = createMockScreen<MyEvents>({\n * controllers: [\n * { playerIndex: 0, nickname: 'Player 1', connected: true },\n * { playerIndex: 1, nickname: 'Player 2', connected: true },\n * ],\n * });\n *\n * screen.on('tap', (playerIndex, data) => handleTap(playerIndex, data));\n * screen.onAllReady(() => startGame());\n *\n * // Simulate player input\n * screen.simulateEvent(0, 'tap', { x: 100, y: 200 });\n *\n * // Check what was broadcast\n * expect(screen.getBroadcasts()).toContainEqual({\n * event: 'score-update',\n * data: { scores: { 0: 10 } },\n * });\n * ```\n */\nexport function createMockScreen<TEvents extends EventMap = EventMap>(\n options: MockOptions = {},\n): MockScreen<TEvents> {\n const {\n roomCode = 'TEST',\n controllers: initialControllers = [],\n autoReady = true,\n } = options;\n\n // Internal state\n let _controllers: ControllerInfo[] = [...initialControllers];\n let _isReady = false;\n let _isConnected = false;\n let _isDestroyed = false;\n\n // Event listeners\n const listeners = new Map<string, Set<ScreenEventHandler>>();\n\n // Lifecycle callback sets\n const _onAllReadyCallbacks = new Set<() => void>();\n const _onControllerJoinCallbacks = new Set<(index: PlayerIndex, info: ControllerInfo) => void>();\n const _onControllerLeaveCallbacks = new Set<(index: PlayerIndex) => void>();\n const _onControllerDisconnectCallbacks = new Set<(index: PlayerIndex) => void>();\n const _onControllerReconnectCallbacks = new Set<(index: PlayerIndex, info: ControllerInfo) => void>();\n const _onCharacterUpdatedCallbacks = new Set<(index: PlayerIndex, appearance: CharacterAppearance | null) => void>();\n const _onErrorCallbacks = new Set<(error: SmoreError) => void>();\n const _onConnectionChangeCallbacks = new Set<(connected: boolean) => void>();\n\n // Whether all-ready has fired\n let _allReadyFired = false;\n\n // Ready promise\n let _readyResolve: () => void;\n const _readyPromise = new Promise<void>((resolve) => {\n _readyResolve = resolve;\n });\n\n // Recorded events for testing\n const broadcasts: RecordedBroadcast[] = [];\n const sends: RecordedSend[] = [];\n\n // Screen implementation\n const screen: MockScreen<TEvents> = {\n // === Properties ===\n get controllers() {\n return [..._controllers];\n },\n get roomCode() {\n return roomCode;\n },\n get isReady() {\n return _isReady;\n },\n get isDestroyed() {\n return _isDestroyed;\n },\n get isConnected() {\n return _isConnected;\n },\n get protocolVersion() {\n return 1;\n },\n get ready() {\n return _readyPromise;\n },\n\n // === Lifecycle Methods ===\n onAllReady(callback: () => void): () => void {\n if (_allReadyFired) {\n callback();\n }\n _onAllReadyCallbacks.add(callback);\n return () => { _onAllReadyCallbacks.delete(callback); };\n },\n\n onControllerJoin(callback: (playerIndex: PlayerIndex, info: ControllerInfo) => void): () => void {\n _onControllerJoinCallbacks.add(callback);\n return () => { _onControllerJoinCallbacks.delete(callback); };\n },\n\n onControllerLeave(callback: (playerIndex: PlayerIndex) => void): () => void {\n _onControllerLeaveCallbacks.add(callback);\n return () => { _onControllerLeaveCallbacks.delete(callback); };\n },\n\n onControllerDisconnect(callback: (playerIndex: PlayerIndex) => void): () => void {\n _onControllerDisconnectCallbacks.add(callback);\n return () => { _onControllerDisconnectCallbacks.delete(callback); };\n },\n\n onControllerReconnect(callback: (playerIndex: PlayerIndex, info: ControllerInfo) => void): () => void {\n _onControllerReconnectCallbacks.add(callback);\n return () => { _onControllerReconnectCallbacks.delete(callback); };\n },\n\n onCharacterUpdated(callback: (playerIndex: PlayerIndex, appearance: CharacterAppearance | null) => void): () => void {\n _onCharacterUpdatedCallbacks.add(callback);\n return () => { _onCharacterUpdatedCallbacks.delete(callback); };\n },\n\n onError(callback: (error: SmoreError) => void): () => void {\n _onErrorCallbacks.add(callback);\n return () => { _onErrorCallbacks.delete(callback); };\n },\n\n onConnectionChange(callback: (connected: boolean) => void): () => void {\n _onConnectionChangeCallbacks.add(callback);\n return () => { _onConnectionChangeCallbacks.delete(callback); };\n },\n\n // === Communication Methods ===\n broadcast<K extends EventNames<TEvents>>(\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n if (_isDestroyed) {\n throw new SmoreSDKError('DESTROYED', 'Cannot call broadcast() after destroy()');\n }\n if (!_isReady) {\n throw new SmoreSDKError('NOT_READY', 'Cannot call broadcast() before screen is ready');\n }\n validateEventName(event as string);\n broadcasts.push({ event: event as string, data });\n },\n\n sendToController<K extends EventNames<TEvents>>(\n playerIndex: PlayerIndex,\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n if (_isDestroyed) {\n throw new SmoreSDKError('DESTROYED', 'Cannot call sendToController() after destroy()');\n }\n if (!_isReady) {\n throw new SmoreSDKError('NOT_READY', 'Cannot call sendToController() before screen is ready');\n }\n validateEventName(event as string);\n if (!_controllers.some((c) => c.playerIndex === playerIndex)) {\n throw new SmoreSDKError('INVALID_PLAYER', `No controller found with player index ${playerIndex}`);\n }\n sends.push({ playerIndex, event: event as string, data });\n },\n\n // === Game Lifecycle ===\n gameOver(results?: GameResults): void {\n if (_isDestroyed) {\n throw new SmoreSDKError('DESTROYED', 'Cannot call gameOver() after destroy()');\n }\n if (!_isReady) {\n throw new SmoreSDKError('NOT_READY', 'Cannot call gameOver() before screen is ready');\n }\n broadcasts.push({ event: 'smore:game-over', data: { results } });\n },\n\n signalReady(): void {\n if (_isDestroyed) {\n throw new SmoreSDKError('DESTROYED', 'Cannot call signalReady() after destroy()');\n }\n if (!_isReady) {\n throw new SmoreSDKError('NOT_READY', 'Cannot call signalReady() before screen is ready');\n }\n // No-op in mock (real implementation emits to server)\n },\n\n // === Event Subscription ===\n on<K extends EventNames<TEvents>>(\n event: K,\n handler: ScreenEventHandler<EventData<TEvents, K>>,\n ): () => void {\n const eventStr = event as string;\n\n // Handle $-prefixed lifecycle events by delegating to appropriate lifecycle method\n if (eventStr.startsWith('$')) {\n switch (eventStr) {\n case '$controller-join':\n return screen.onControllerJoin(handler as any);\n case '$controller-leave':\n return screen.onControllerLeave(handler as any);\n case '$controller-disconnect':\n return screen.onControllerDisconnect(handler as any);\n case '$controller-reconnect':\n return screen.onControllerReconnect(handler as any);\n case '$character-updated':\n return screen.onCharacterUpdated(handler as any);\n case '$all-ready':\n return screen.onAllReady(handler as any);\n case '$error':\n return screen.onError(handler as any);\n default:\n // Unknown lifecycle event, just treat as regular event\n break;\n }\n }\n\n validateEventName(event as string);\n\n if (!listeners.has(eventStr)) {\n listeners.set(eventStr, new Set());\n }\n listeners.get(eventStr)!.add(handler as ScreenEventHandler);\n\n return () => {\n listeners.get(eventStr)?.delete(handler as ScreenEventHandler);\n };\n },\n\n once<K extends EventNames<TEvents>>(\n event: K,\n handler: ScreenEventHandler<EventData<TEvents, K>>,\n ): () => void {\n validateEventName(event as string);\n const wrapper: ScreenEventHandler<EventData<TEvents, K>> = (playerIndex, data) => {\n handler(playerIndex, data);\n screen.off(event, wrapper);\n };\n return screen.on(event, wrapper);\n },\n\n off<K extends EventNames<TEvents>>(\n event: K,\n handler?: ScreenEventHandler<EventData<TEvents, K>>,\n ): void {\n validateEventName(event as string);\n const eventStr = event as string;\n if (!handler) {\n listeners.delete(eventStr);\n } else {\n listeners.get(eventStr)?.delete(handler as ScreenEventHandler);\n }\n },\n\n removeAllListeners(event?: string): void {\n if (event) {\n listeners.delete(event);\n } else {\n listeners.clear();\n }\n },\n\n // === Utilities ===\n getController(playerIndex: PlayerIndex): ControllerInfo | undefined {\n return _controllers.find((c) => c.playerIndex === playerIndex);\n },\n\n getControllerCount(): number {\n return _controllers.filter(c => c.connected).length;\n },\n\n // === Cleanup ===\n /**\n * Note: destroy() clears recorded broadcast/event arrays. Call getBroadcasts() before destroy() if assertions are needed.\n */\n destroy(): void {\n _isDestroyed = true;\n listeners.clear();\n broadcasts.length = 0;\n sends.length = 0;\n },\n\n // === Mock-specific methods ===\n simulateEvent<K extends EventNames<TEvents>>(\n playerIndex: PlayerIndex,\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n validateEventName(event as string);\n const eventStr = event as string;\n const handlers = listeners.get(eventStr);\n if (handlers) {\n handlers.forEach((handler) => {\n handler(playerIndex, data);\n });\n }\n },\n\n simulateControllerJoin(info: ControllerInfo): void {\n _controllers.push(info);\n _onControllerJoinCallbacks.forEach(cb => cb(info.playerIndex, info));\n },\n\n simulateControllerLeave(playerIndex: PlayerIndex): void {\n _controllers = _controllers.filter((c) => c.playerIndex !== playerIndex);\n _onControllerLeaveCallbacks.forEach(cb => cb(playerIndex));\n },\n\n /**\n * Simulate a controller network disconnect (player still in room but unreachable).\n */\n simulateControllerDisconnect(playerIndex: PlayerIndex): void {\n const controller = _controllers.find((c) => c.playerIndex === playerIndex);\n if (!controller) {\n throw new SmoreSDKError('INVALID_PLAYER', `Controller ${playerIndex} not found`);\n }\n // Mark as disconnected (need to create new object since ControllerInfo is readonly)\n _controllers = _controllers.map((c) =>\n c.playerIndex === playerIndex\n ? { ...c, connected: false }\n : c\n );\n _onControllerDisconnectCallbacks.forEach(cb => cb(playerIndex));\n },\n\n /**\n * Simulate a controller network reconnect after disconnect.\n */\n simulateControllerReconnect(playerIndex: PlayerIndex): void {\n const controller = _controllers.find((c) => c.playerIndex === playerIndex);\n if (!controller) {\n throw new SmoreSDKError('INVALID_PLAYER', `Controller ${playerIndex} not found`);\n }\n // Mark as connected (need to create new object since ControllerInfo is readonly)\n const reconnectedController = { ...controller, connected: true };\n _controllers = _controllers.map((c) =>\n c.playerIndex === playerIndex ? reconnectedController : c\n );\n _onControllerReconnectCallbacks.forEach(cb => cb(playerIndex, reconnectedController));\n },\n\n simulateCharacterUpdate(playerIndex: PlayerIndex, appearance: CharacterAppearance | null): void {\n const controller = _controllers.find((c) => c.playerIndex === playerIndex);\n if (!controller) {\n throw new SmoreSDKError('INVALID_PLAYER', `Controller ${playerIndex} not found`);\n }\n _controllers = _controllers.map((c) =>\n c.playerIndex === playerIndex ? { ...c, appearance } : c\n );\n _onCharacterUpdatedCallbacks.forEach(cb => cb(playerIndex, appearance));\n },\n\n simulateAllReady(): void {\n _allReadyFired = true;\n _onAllReadyCallbacks.forEach(cb => cb());\n },\n\n simulateError(error: any): void {\n _onErrorCallbacks.forEach(cb => cb(error));\n },\n\n simulateConnectionChange(connected: boolean): void {\n _isConnected = connected;\n _onConnectionChangeCallbacks.forEach(cb => cb(connected));\n },\n\n getBroadcasts(): Array<{ event: string; data: unknown }> {\n return [...broadcasts];\n },\n\n getSentToController(\n playerIndex: PlayerIndex,\n ): Array<{ event: string; data: unknown }> {\n return sends\n .filter((s) => s.playerIndex === playerIndex)\n .map((s) => ({ event: s.event, data: s.data }));\n },\n\n clearRecordedEvents(): void {\n broadcasts.length = 0;\n sends.length = 0;\n },\n\n triggerReady(): void {\n _isReady = true;\n _isConnected = true;\n _readyResolve();\n },\n };\n\n /**\n * Auto-trigger ready if enabled.\n *\n * **Note:** `autoReady` uses `setTimeout(0)` which fires asynchronously (next tick).\n * For synchronous test control, use `autoReady: false` and call `triggerReady()` manually.\n */\n if (autoReady) {\n setTimeout(() => screen.triggerReady(), 0);\n }\n\n return screen;\n}\n\n// =============================================================================\n// MOCK CONTROLLER IMPLEMENTATION\n// =============================================================================\n\ninterface RecordedEvent {\n event: string;\n data: unknown;\n}\n\n/**\n * Create a mock Controller for testing player input logic.\n *\n * All methods work synchronously. Events can be simulated and recorded\n * for assertions in unit tests.\n *\n * Uses the same event emitter pattern as real Controller: register lifecycle\n * callbacks via methods on the returned instance.\n *\n * @example\n * ```ts\n * const controller = createMockController<MyEvents>({\n * myPlayerIndex: 0,\n * });\n *\n * controller.on('your-turn', (data) => handleTurn(data));\n * controller.onAllReady(() => console.log('Ready!'));\n *\n * // Simulate receiving from screen\n * controller.simulateEvent('your-turn', { timeLimit: 30 });\n *\n * // Check what was sent\n * expect(controller.getSentEvents()).toContainEqual({\n * event: 'answer',\n * data: { choice: 2 },\n * });\n * ```\n */\nexport function createMockController<TEvents extends EventMap = EventMap>(\n options: MockOptions = {},\n): MockController<TEvents> {\n const {\n roomCode = 'TEST',\n myPlayerIndex = 0,\n autoReady = true,\n } = options;\n\n // Internal state -- uses a full ControllerInfo[] array (matching MockScreen pattern)\n // to preserve nickname/appearance data from simulatePlayerJoin()\n let _isReady = false;\n let _isConnected = false;\n let _isDestroyed = false;\n let _controllers: ControllerInfo[] = options.controllers ?? [];\n\n // Event listeners\n const listeners = new Map<string, Set<ControllerEventHandler>>();\n\n // Lifecycle callback sets\n const _onAllReadyCallbacks = new Set<() => void>();\n const _onControllerJoinCallbacks = new Set<(index: PlayerIndex, info: ControllerInfo) => void>();\n const _onControllerLeaveCallbacks = new Set<(index: PlayerIndex) => void>();\n const _onControllerDisconnectCallbacks = new Set<(index: PlayerIndex) => void>();\n const _onControllerReconnectCallbacks = new Set<(index: PlayerIndex, info: ControllerInfo) => void>();\n const _onCharacterUpdatedCallbacks = new Set<(index: PlayerIndex, appearance: CharacterAppearance | null) => void>();\n const _onErrorCallbacks = new Set<(error: SmoreError) => void>();\n const _onGameOverCallbacks = new Set<(results?: GameResults) => void>();\n const _onConnectionChangeCallbacks = new Set<(connected: boolean) => void>();\n\n // Whether all-ready has fired\n let _allReadyFired = false;\n\n // Ready promise\n let _readyResolve: () => void;\n const _readyPromise = new Promise<void>((resolve) => {\n _readyResolve = resolve;\n });\n\n // Recorded events for testing\n const sentEvents: RecordedEvent[] = [];\n\n // Controller implementation\n const controller: MockController<TEvents> = {\n // === Properties ===\n get myPlayerIndex() {\n return myPlayerIndex;\n },\n get roomCode() {\n return roomCode;\n },\n get isReady() {\n return _isReady;\n },\n get isDestroyed() {\n return _isDestroyed;\n },\n\n get isConnected() {\n return _isConnected;\n },\n\n get protocolVersion() {\n return 1;\n },\n\n get controllers(): readonly ControllerInfo[] {\n return [..._controllers];\n },\n\n get ready() {\n return _readyPromise;\n },\n\n // === Lifecycle Methods ===\n onAllReady(callback: () => void): () => void {\n if (_allReadyFired) {\n callback();\n }\n _onAllReadyCallbacks.add(callback);\n return () => { _onAllReadyCallbacks.delete(callback); };\n },\n\n onControllerJoin(callback: (playerIndex: PlayerIndex, info: ControllerInfo) => void): () => void {\n _onControllerJoinCallbacks.add(callback);\n return () => { _onControllerJoinCallbacks.delete(callback); };\n },\n\n onControllerLeave(callback: (playerIndex: PlayerIndex) => void): () => void {\n _onControllerLeaveCallbacks.add(callback);\n return () => { _onControllerLeaveCallbacks.delete(callback); };\n },\n\n onControllerDisconnect(callback: (playerIndex: PlayerIndex) => void): () => void {\n _onControllerDisconnectCallbacks.add(callback);\n return () => { _onControllerDisconnectCallbacks.delete(callback); };\n },\n\n onControllerReconnect(callback: (playerIndex: PlayerIndex, info: ControllerInfo) => void): () => void {\n _onControllerReconnectCallbacks.add(callback);\n return () => { _onControllerReconnectCallbacks.delete(callback); };\n },\n\n onCharacterUpdated(callback: (playerIndex: PlayerIndex, appearance: CharacterAppearance | null) => void): () => void {\n _onCharacterUpdatedCallbacks.add(callback);\n return () => { _onCharacterUpdatedCallbacks.delete(callback); };\n },\n\n onError(callback: (error: SmoreError) => void): () => void {\n _onErrorCallbacks.add(callback);\n return () => { _onErrorCallbacks.delete(callback); };\n },\n\n onConnectionChange(callback: (connected: boolean) => void): () => void {\n _onConnectionChangeCallbacks.add(callback);\n return () => { _onConnectionChangeCallbacks.delete(callback); };\n },\n\n onGameOver(callback: (results?: GameResults) => void): () => void {\n _onGameOverCallbacks.add(callback);\n return () => { _onGameOverCallbacks.delete(callback); };\n },\n\n getControllerCount(): number {\n return _controllers.filter(c => c.connected).length;\n },\n\n getController(playerIndex: PlayerIndex): ControllerInfo | undefined {\n return _controllers.find((c) => c.playerIndex === playerIndex);\n },\n\n // === Communication Methods ===\n send<K extends EventNames<TEvents>>(\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n if (_isDestroyed) {\n throw new SmoreSDKError('DESTROYED', 'Cannot call send() after destroy()');\n }\n validateEventName(event as string);\n sentEvents.push({ event: event as string, data });\n },\n\n signalReady(): void {\n if (_isDestroyed) {\n throw new SmoreSDKError('DESTROYED', 'Cannot call signalReady() after destroy()');\n }\n if (!_isReady) {\n throw new SmoreSDKError('NOT_READY', 'Cannot call signalReady() before controller is ready');\n }\n // No-op in mock (real implementation emits to server)\n },\n\n // === Event Subscription ===\n on<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n const eventStr = event as string;\n\n // Handle $-prefixed lifecycle events by delegating to appropriate lifecycle method\n if (eventStr.startsWith('$')) {\n switch (eventStr) {\n case '$controller-join':\n return controller.onControllerJoin(handler as any);\n case '$controller-leave':\n return controller.onControllerLeave(handler as any);\n case '$controller-disconnect':\n return controller.onControllerDisconnect(handler as any);\n case '$controller-reconnect':\n return controller.onControllerReconnect(handler as any);\n case '$character-updated':\n return controller.onCharacterUpdated(handler as any);\n case '$all-ready':\n return controller.onAllReady(handler as any);\n case '$error':\n return controller.onError(handler as any);\n case '$game-over':\n return controller.onGameOver(handler as any);\n default:\n // Unknown lifecycle event, just treat as regular event\n break;\n }\n }\n\n validateEventName(event as string);\n\n if (!listeners.has(eventStr)) {\n listeners.set(eventStr, new Set());\n }\n listeners.get(eventStr)!.add(handler as ControllerEventHandler);\n\n return () => {\n listeners.get(eventStr)?.delete(handler as ControllerEventHandler);\n };\n },\n\n once<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n validateEventName(event as string);\n const wrapper: ControllerEventHandler<EventData<TEvents, K>> = (data) => {\n handler(data);\n controller.off(event, wrapper);\n };\n return controller.on(event, wrapper);\n },\n\n off<K extends EventNames<TEvents>>(\n event: K,\n handler?: ControllerEventHandler<EventData<TEvents, K>>,\n ): void {\n validateEventName(event as string);\n const eventStr = event as string;\n if (!handler) {\n listeners.delete(eventStr);\n } else {\n listeners.get(eventStr)?.delete(handler as ControllerEventHandler);\n }\n },\n\n removeAllListeners(event?: string): void {\n if (event) {\n listeners.delete(event);\n } else {\n listeners.clear();\n }\n },\n\n // === Cleanup ===\n destroy(): void {\n _isDestroyed = true;\n listeners.clear();\n sentEvents.length = 0;\n },\n\n // === Mock-specific methods ===\n simulateEvent<K extends EventNames<TEvents>>(\n event: K,\n data: EventData<TEvents, K>,\n ): void {\n validateEventName(event as string);\n const eventStr = event as string;\n const handlers = listeners.get(eventStr);\n if (handlers) {\n handlers.forEach((handler) => {\n handler(data);\n });\n }\n },\n\n getSentEvents(): Array<{ event: string; data: unknown }> {\n return [...sentEvents];\n },\n\n clearRecordedEvents(): void {\n sentEvents.length = 0;\n },\n\n triggerReady(): void {\n _isReady = true;\n _isConnected = true;\n _readyResolve();\n },\n\n /**\n * Simulate a new player joining the room.\n * Stores full ControllerInfo (nickname, appearance, etc.) for later retrieval.\n */\n simulatePlayerJoin(playerIndex: PlayerIndex, info: ControllerInfo): void {\n if (!_controllers.some(c => c.playerIndex === playerIndex)) {\n _controllers = [..._controllers, { ...info, connected: info.connected ?? true }];\n }\n _onControllerJoinCallbacks.forEach(cb => cb(playerIndex, info));\n },\n\n /**\n * Simulate a player leaving the room (fully removed).\n */\n simulatePlayerLeave(playerIndex: PlayerIndex): void {\n _controllers = _controllers.filter(c => c.playerIndex !== playerIndex);\n _onControllerLeaveCallbacks.forEach(cb => cb(playerIndex));\n },\n\n /**\n * Simulate a player network disconnect (player still in room but unreachable).\n */\n simulatePlayerDisconnect(playerIndex: PlayerIndex): void {\n _controllers = _controllers.map(c =>\n c.playerIndex === playerIndex ? { ...c, connected: false } : c\n );\n _onControllerDisconnectCallbacks.forEach(cb => cb(playerIndex));\n },\n\n /**\n * Simulate a player network reconnect after disconnect.\n */\n simulatePlayerReconnect(playerIndex: PlayerIndex, info: ControllerInfo): void {\n _controllers = _controllers.map(c =>\n c.playerIndex === playerIndex ? { ...info, connected: true } : c\n );\n _onControllerReconnectCallbacks.forEach(cb => cb(playerIndex, info));\n },\n\n simulateCharacterUpdate(playerIndex: PlayerIndex, appearance: CharacterAppearance | null): void {\n const ctrl = _controllers.find((c) => c.playerIndex === playerIndex);\n if (!ctrl) {\n throw new SmoreSDKError('INVALID_PLAYER', `Controller ${playerIndex} not found`);\n }\n _controllers = _controllers.map((c) =>\n c.playerIndex === playerIndex ? { ...c, appearance } : c\n );\n _onCharacterUpdatedCallbacks.forEach(cb => cb(playerIndex, appearance));\n },\n\n simulateAllReady(): void {\n _allReadyFired = true;\n _onAllReadyCallbacks.forEach(cb => cb());\n },\n\n simulateError(error: any): void {\n _onErrorCallbacks.forEach(cb => cb(error));\n },\n\n simulateGameOver(results?: GameResults): void {\n _onGameOverCallbacks.forEach(cb => cb(results));\n },\n\n simulateConnectionChange(connected: boolean): void {\n _isConnected = connected;\n _onConnectionChangeCallbacks.forEach(cb => cb(connected));\n },\n };\n\n /**\n * Auto-trigger ready if enabled.\n *\n * **Note:** `autoReady` uses `setTimeout(0)` which fires asynchronously (next tick).\n * For synchronous test control, use `autoReady: false` and call `triggerReady()` manually.\n */\n if (autoReady) {\n setTimeout(() => controller.triggerReady(), 0);\n }\n\n return controller;\n}\n\n"],"names":[],"mappings":"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"}