@smoregg/sdk 2.0.0 → 2.2.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.
- package/dist/cjs/controller.cjs +260 -113
- package/dist/cjs/controller.cjs.map +1 -1
- package/dist/cjs/errors.cjs +1 -0
- package/dist/cjs/errors.cjs.map +1 -1
- package/dist/cjs/events.cjs +26 -3
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/index.cjs +2 -7
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/screen.cjs +244 -128
- package/dist/cjs/screen.cjs.map +1 -1
- package/dist/cjs/shared.cjs +34 -0
- package/dist/cjs/shared.cjs.map +1 -0
- package/dist/cjs/testing.cjs +181 -73
- package/dist/cjs/testing.cjs.map +1 -1
- package/dist/cjs/transport/PostMessageTransport.cjs +12 -0
- package/dist/cjs/transport/PostMessageTransport.cjs.map +1 -1
- package/dist/cjs/transport/protocol.cjs +2 -0
- package/dist/cjs/transport/protocol.cjs.map +1 -1
- package/dist/cjs/types.cjs +16 -0
- package/dist/cjs/types.cjs.map +1 -0
- package/dist/esm/controller.js +262 -115
- package/dist/esm/controller.js.map +1 -1
- package/dist/esm/errors.js +1 -0
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/events.js +25 -4
- package/dist/esm/events.js.map +1 -1
- package/dist/esm/index.js +1 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/screen.js +246 -130
- package/dist/esm/screen.js.map +1 -1
- package/dist/esm/shared.js +30 -0
- package/dist/esm/shared.js.map +1 -0
- package/dist/esm/testing.js +181 -73
- package/dist/esm/testing.js.map +1 -1
- package/dist/esm/transport/PostMessageTransport.js +12 -0
- package/dist/esm/transport/PostMessageTransport.js.map +1 -1
- package/dist/esm/transport/protocol.js +2 -1
- package/dist/esm/transport/protocol.js.map +1 -1
- package/dist/esm/types.js +14 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/types/controller.d.ts +1 -1
- package/dist/types/controller.d.ts.map +1 -1
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/events.d.ts +14 -1
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -8
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/screen.d.ts +3 -3
- package/dist/types/screen.d.ts.map +1 -1
- package/dist/types/shared.d.ts +21 -0
- package/dist/types/shared.d.ts.map +1 -0
- package/dist/types/testing.d.ts +65 -4
- package/dist/types/testing.d.ts.map +1 -1
- package/dist/types/transport/PostMessageTransport.d.ts +1 -0
- package/dist/types/transport/PostMessageTransport.d.ts.map +1 -1
- package/dist/types/transport/protocol.d.ts +5 -0
- package/dist/types/transport/protocol.d.ts.map +1 -1
- package/dist/types/types.d.ts +254 -345
- package/dist/types/types.d.ts.map +1 -1
- package/dist/umd/smore-sdk.umd.js +575 -784
- package/dist/umd/smore-sdk.umd.js.map +1 -1
- package/dist/umd/smore-sdk.umd.min.js +1 -1
- package/dist/umd/smore-sdk.umd.min.js.map +1 -1
- package/package.json +7 -1
- package/dist/cjs/config.cjs +0 -13
- package/dist/cjs/config.cjs.map +0 -1
- package/dist/esm/config.js +0 -10
- package/dist/esm/config.js.map +0 -1
- package/dist/types/config.d.ts +0 -35
- package/dist/types/config.d.ts.map +0 -1
package/dist/types/types.d.ts
CHANGED
|
@@ -26,6 +26,11 @@ export type RoomCode = string;
|
|
|
26
26
|
* is enforced by the server's genericRelay handler. Payloads exceeding this
|
|
27
27
|
* limit will be silently dropped by the server without error notification.
|
|
28
28
|
*
|
|
29
|
+
* **Reserved Fields:** The field names `playerIndex` and `targetPlayerIndex` are reserved
|
|
30
|
+
* by the SDK for internal routing. Using these as custom data field names will cause
|
|
31
|
+
* a compile-time error. The SDK automatically extracts `playerIndex` to identify the sender
|
|
32
|
+
* and uses `targetPlayerIndex` for targeted message delivery.
|
|
33
|
+
*
|
|
29
34
|
* **Type Safety Note:** Without providing an explicit generic type parameter,
|
|
30
35
|
* `createScreen()` and `createController()` default to the empty `EventMap`,
|
|
31
36
|
* which means `send()`, `broadcast()`, and `on()` accept any string as an event
|
|
@@ -46,7 +51,7 @@ export type RoomCode = string;
|
|
|
46
51
|
*
|
|
47
52
|
* // With explicit generic -- full type safety
|
|
48
53
|
* const screen = createScreen<MyGameEvents>({ debug: true });
|
|
49
|
-
* screen.on('tap', (
|
|
54
|
+
* screen.on('tap', (playerIndex, data) => { ... });
|
|
50
55
|
* await screen.ready;
|
|
51
56
|
*
|
|
52
57
|
* // Without generic -- no type safety (not recommended)
|
|
@@ -64,7 +69,10 @@ export type RoomCode = string;
|
|
|
64
69
|
* ```
|
|
65
70
|
*/
|
|
66
71
|
export interface EventMap {
|
|
67
|
-
[key: string]: unknown
|
|
72
|
+
[key: string]: Record<string, unknown> & {
|
|
73
|
+
playerIndex?: never;
|
|
74
|
+
targetPlayerIndex?: never;
|
|
75
|
+
};
|
|
68
76
|
}
|
|
69
77
|
/**
|
|
70
78
|
* Extract event names from an event map.
|
|
@@ -93,7 +101,7 @@ export interface CharacterAppearance {
|
|
|
93
101
|
/** Character style preset identifier */
|
|
94
102
|
style: string;
|
|
95
103
|
/** Additional character customization options */
|
|
96
|
-
options: Record<string,
|
|
104
|
+
options: Record<string, unknown>;
|
|
97
105
|
}
|
|
98
106
|
/**
|
|
99
107
|
* Information about a connected controller (player).
|
|
@@ -124,6 +132,100 @@ export interface ControllerInfo {
|
|
|
124
132
|
*/
|
|
125
133
|
readonly appearance?: CharacterAppearance | null;
|
|
126
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Transport interface for custom communication implementations.
|
|
137
|
+
* Implement this to use a custom transport instead of the default PostMessageTransport.
|
|
138
|
+
*/
|
|
139
|
+
export interface Transport {
|
|
140
|
+
emit(event: string, ...args: unknown[]): void;
|
|
141
|
+
on(event: string, handler: (...args: unknown[]) => void): void;
|
|
142
|
+
off(event: string, handler?: (...args: unknown[]) => void): void;
|
|
143
|
+
destroy(): void;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Error codes for SDK errors.
|
|
147
|
+
*/
|
|
148
|
+
export type SmoreErrorCode = 'TIMEOUT' | 'NOT_READY' | 'DESTROYED' | 'INVALID_EVENT' | 'INVALID_PLAYER' | 'CONNECTION_LOST' | 'INIT_FAILED' | 'RATE_LIMITED' | 'PAYLOAD_TOO_LARGE' | 'UNKNOWN';
|
|
149
|
+
/**
|
|
150
|
+
* Structured error type for SDK errors.
|
|
151
|
+
*/
|
|
152
|
+
export interface SmoreError {
|
|
153
|
+
/** Error code for programmatic handling */
|
|
154
|
+
code: SmoreErrorCode;
|
|
155
|
+
/** Human-readable error message */
|
|
156
|
+
message: string;
|
|
157
|
+
/** Original error if available */
|
|
158
|
+
cause?: Error;
|
|
159
|
+
/** Additional context */
|
|
160
|
+
details?: Record<string, unknown>;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Game results structure for gameOver().
|
|
164
|
+
* Flexible to accommodate different game types.
|
|
165
|
+
*/
|
|
166
|
+
export interface GameResults {
|
|
167
|
+
/** Player scores indexed by player index */
|
|
168
|
+
scores?: Record<PlayerIndex, number>;
|
|
169
|
+
/** Winner's player index (or -1 for no winner/tie) */
|
|
170
|
+
winner?: PlayerIndex;
|
|
171
|
+
/** Ranked player indices from first to last */
|
|
172
|
+
rankings?: PlayerIndex[];
|
|
173
|
+
/** Additional custom game-specific data */
|
|
174
|
+
custom?: Record<string, unknown>;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Lifecycle event names for subscribing via `on()`.
|
|
178
|
+
*
|
|
179
|
+
* These `$`-prefixed event names allow lifecycle events to be registered
|
|
180
|
+
* through the same `on()` method used for game events. The `$` prefix is
|
|
181
|
+
* reserved by the SDK and cannot be used for user-defined events.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* // These are equivalent:
|
|
186
|
+
* screen.onControllerJoin((pi, info) => { ... });
|
|
187
|
+
* screen.on(LifecycleEvent.CONTROLLER_JOIN, (pi, info) => { ... });
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
export declare const LifecycleEvent: {
|
|
191
|
+
readonly ALL_READY: "$all-ready";
|
|
192
|
+
readonly CONTROLLER_JOIN: "$controller-join";
|
|
193
|
+
readonly CONTROLLER_LEAVE: "$controller-leave";
|
|
194
|
+
readonly CONTROLLER_DISCONNECT: "$controller-disconnect";
|
|
195
|
+
readonly CONTROLLER_RECONNECT: "$controller-reconnect";
|
|
196
|
+
readonly CHARACTER_UPDATED: "$character-updated";
|
|
197
|
+
readonly ERROR: "$error";
|
|
198
|
+
readonly GAME_OVER: "$game-over";
|
|
199
|
+
readonly CONNECTION_CHANGE: "$connection-change";
|
|
200
|
+
};
|
|
201
|
+
/** Union of all lifecycle event name strings. */
|
|
202
|
+
export type LifecycleEventName = typeof LifecycleEvent[keyof typeof LifecycleEvent];
|
|
203
|
+
/**
|
|
204
|
+
* Handler signatures for Screen lifecycle events.
|
|
205
|
+
* Used by `on()` overloads to provide type-safe lifecycle event subscription.
|
|
206
|
+
*/
|
|
207
|
+
export interface ScreenLifecycleHandlers {
|
|
208
|
+
'$all-ready': () => void;
|
|
209
|
+
'$controller-join': (playerIndex: PlayerIndex, info: ControllerInfo) => void;
|
|
210
|
+
'$controller-leave': (playerIndex: PlayerIndex) => void;
|
|
211
|
+
'$controller-disconnect': (playerIndex: PlayerIndex) => void;
|
|
212
|
+
'$controller-reconnect': (playerIndex: PlayerIndex, info: ControllerInfo) => void;
|
|
213
|
+
'$character-updated': (playerIndex: PlayerIndex, appearance: CharacterAppearance | null) => void;
|
|
214
|
+
'$error': (error: SmoreError) => void;
|
|
215
|
+
'$connection-change': (connected: boolean) => void;
|
|
216
|
+
}
|
|
217
|
+
/** Screen lifecycle event name union. */
|
|
218
|
+
export type ScreenLifecycleEvent = keyof ScreenLifecycleHandlers;
|
|
219
|
+
/**
|
|
220
|
+
* Handler signatures for Controller lifecycle events.
|
|
221
|
+
* Extends Screen lifecycle events with Controller-specific events.
|
|
222
|
+
*/
|
|
223
|
+
export interface ControllerLifecycleHandlers extends ScreenLifecycleHandlers {
|
|
224
|
+
'$game-over': (results?: GameResults) => void;
|
|
225
|
+
'$state-recovery': (states: Record<number, Record<string, any>>) => void;
|
|
226
|
+
}
|
|
227
|
+
/** Controller lifecycle event name union. */
|
|
228
|
+
export type ControllerLifecycleEvent = keyof ControllerLifecycleHandlers;
|
|
127
229
|
/**
|
|
128
230
|
* Handler for events received from controllers.
|
|
129
231
|
* Receives the player index and event data.
|
|
@@ -144,12 +246,12 @@ export type ScreenEventHandler<TData = unknown> = (playerIndex: PlayerIndex, dat
|
|
|
144
246
|
*
|
|
145
247
|
* screen.on('tap', (playerIndex, data) => handleTap(playerIndex, data));
|
|
146
248
|
* screen.onAllReady(() => startCountdown());
|
|
147
|
-
* screen.onControllerJoin((
|
|
249
|
+
* screen.onControllerJoin((playerIndex, info) => console.log('Joined:', playerIndex));
|
|
148
250
|
*
|
|
149
251
|
* await screen.ready;
|
|
150
252
|
* ```
|
|
151
253
|
*/
|
|
152
|
-
export interface ScreenConfig
|
|
254
|
+
export interface ScreenConfig {
|
|
153
255
|
/**
|
|
154
256
|
* Enable debug mode for verbose logging.
|
|
155
257
|
* @default false
|
|
@@ -166,6 +268,19 @@ export interface ScreenConfig<_TEvents extends EventMap = EventMap> {
|
|
|
166
268
|
* @default 10000
|
|
167
269
|
*/
|
|
168
270
|
timeout?: number;
|
|
271
|
+
/**
|
|
272
|
+
* Automatically signal ready after initialization.
|
|
273
|
+
* When true (default), the SDK calls signalReady() automatically after init completes.
|
|
274
|
+
* Set to false if your game needs to load resources before signaling ready.
|
|
275
|
+
* @default true
|
|
276
|
+
*/
|
|
277
|
+
autoReady?: boolean;
|
|
278
|
+
/**
|
|
279
|
+
* Custom transport implementation.
|
|
280
|
+
* If provided, uses this instead of the default PostMessageTransport.
|
|
281
|
+
* The bridge handshake (_bridge:init) still occurs via postMessage.
|
|
282
|
+
*/
|
|
283
|
+
transport?: Transport;
|
|
169
284
|
}
|
|
170
285
|
/**
|
|
171
286
|
* Screen instance - the main interface for the host/TV side of your game.
|
|
@@ -179,9 +294,9 @@ export interface ScreenConfig<_TEvents extends EventMap = EventMap> {
|
|
|
179
294
|
* ```ts
|
|
180
295
|
* const screen = createScreen<MyEvents>({ debug: true });
|
|
181
296
|
*
|
|
182
|
-
* screen.on('tap', (
|
|
297
|
+
* screen.on('tap', (playerIndex, data) => handleTap(playerIndex, data));
|
|
183
298
|
* screen.onAllReady(() => startGame());
|
|
184
|
-
* screen.onControllerJoin((
|
|
299
|
+
* screen.onControllerJoin((playerIndex, info) => addPlayer(playerIndex, info));
|
|
185
300
|
*
|
|
186
301
|
* await screen.ready;
|
|
187
302
|
* screen.broadcast('phase-update', { phase: 'playing' });
|
|
@@ -203,6 +318,10 @@ export interface Screen<TEvents extends EventMap = EventMap> {
|
|
|
203
318
|
readonly isReady: boolean;
|
|
204
319
|
/** Whether the screen has been destroyed. */
|
|
205
320
|
readonly isDestroyed: boolean;
|
|
321
|
+
/** Whether the connection to the server is active. */
|
|
322
|
+
readonly isConnected: boolean;
|
|
323
|
+
/** Protocol version negotiated with the parent frame. */
|
|
324
|
+
readonly protocolVersion: number;
|
|
206
325
|
/**
|
|
207
326
|
* A Promise that resolves when the screen is initialized and ready.
|
|
208
327
|
* Use this to await readiness after creating a screen synchronously.
|
|
@@ -259,13 +378,6 @@ export interface Screen<TEvents extends EventMap = EventMap> {
|
|
|
259
378
|
* @returns Unsubscribe function to remove the callback
|
|
260
379
|
*/
|
|
261
380
|
onCharacterUpdated(callback: (playerIndex: PlayerIndex, appearance: CharacterAppearance | null) => void): () => void;
|
|
262
|
-
/**
|
|
263
|
-
* Register a callback for when the server rate-limits an event.
|
|
264
|
-
*
|
|
265
|
-
* @param callback - Called with the rate-limited event name
|
|
266
|
-
* @returns Unsubscribe function to remove the callback
|
|
267
|
-
*/
|
|
268
|
-
onRateLimited(callback: (event: string) => void): () => void;
|
|
269
381
|
/**
|
|
270
382
|
* Register a callback for when an error occurs.
|
|
271
383
|
* If no error callback is registered, errors are logged to console in debug mode.
|
|
@@ -274,6 +386,14 @@ export interface Screen<TEvents extends EventMap = EventMap> {
|
|
|
274
386
|
* @returns Unsubscribe function to remove the callback
|
|
275
387
|
*/
|
|
276
388
|
onError(callback: (error: SmoreError) => void): () => void;
|
|
389
|
+
/**
|
|
390
|
+
* Register a callback for when the connection status changes.
|
|
391
|
+
* Called when the connection to the server is lost or restored.
|
|
392
|
+
*
|
|
393
|
+
* @param callback - Called with true (connected) or false (disconnected)
|
|
394
|
+
* @returns Unsubscribe function to remove the callback
|
|
395
|
+
*/
|
|
396
|
+
onConnectionChange(callback: (connected: boolean) => void): () => void;
|
|
277
397
|
/**
|
|
278
398
|
* Broadcast an event to all connected controllers.
|
|
279
399
|
*
|
|
@@ -288,11 +408,6 @@ export interface Screen<TEvents extends EventMap = EventMap> {
|
|
|
288
408
|
* ```
|
|
289
409
|
*/
|
|
290
410
|
broadcast<K extends EventNames<TEvents>>(event: K, data: EventData<TEvents, K>): void;
|
|
291
|
-
/**
|
|
292
|
-
* Broadcast an event with any data (bypasses type checking).
|
|
293
|
-
* Use sparingly - prefer the typed broadcast() method.
|
|
294
|
-
*/
|
|
295
|
-
broadcastRaw(event: string, data?: unknown): void;
|
|
296
411
|
/**
|
|
297
412
|
* Send an event to a specific controller.
|
|
298
413
|
*
|
|
@@ -311,10 +426,24 @@ export interface Screen<TEvents extends EventMap = EventMap> {
|
|
|
311
426
|
*/
|
|
312
427
|
sendToController<K extends EventNames<TEvents>>(playerIndex: PlayerIndex, event: K, data: EventData<TEvents, K>): void;
|
|
313
428
|
/**
|
|
314
|
-
*
|
|
315
|
-
*
|
|
429
|
+
* Get a specific controller's cached custom state.
|
|
430
|
+
* Returns undefined if no state has been set for this controller.
|
|
431
|
+
*
|
|
432
|
+
* @param playerIndex - The controller's player index
|
|
316
433
|
*/
|
|
317
|
-
|
|
434
|
+
getControllerState(playerIndex: number): Record<string, any> | undefined;
|
|
435
|
+
/**
|
|
436
|
+
* Get all controllers' cached custom states.
|
|
437
|
+
* Returns a record mapping player index to state.
|
|
438
|
+
*/
|
|
439
|
+
getAllControllerStates(): Record<number, Record<string, any>>;
|
|
440
|
+
/**
|
|
441
|
+
* Register a listener for custom state changes from any controller.
|
|
442
|
+
*
|
|
443
|
+
* @param listener - Called with the player index and the new state
|
|
444
|
+
* @returns Unsubscribe function
|
|
445
|
+
*/
|
|
446
|
+
onCustomStateChange(listener: (playerIndex: number, state: Record<string, any>) => void): () => void;
|
|
318
447
|
/**
|
|
319
448
|
* Signal that the game is over and send results.
|
|
320
449
|
* This will broadcast a game-over event to all controllers.
|
|
@@ -345,6 +474,17 @@ export interface Screen<TEvents extends EventMap = EventMap> {
|
|
|
345
474
|
* ```
|
|
346
475
|
*/
|
|
347
476
|
signalReady(): void;
|
|
477
|
+
/**
|
|
478
|
+
* Subscribe to a lifecycle event or a user-defined game event.
|
|
479
|
+
*
|
|
480
|
+
* Lifecycle events use `$`-prefixed names. Use `LifecycleEvent` constants
|
|
481
|
+
* for type-safe subscription:
|
|
482
|
+
* ```ts
|
|
483
|
+
* screen.on(LifecycleEvent.CONTROLLER_JOIN, (pi, info) => { ... });
|
|
484
|
+
* screen.on('tap', (pi, data) => { ... }); // user event
|
|
485
|
+
* ```
|
|
486
|
+
*/
|
|
487
|
+
on<K extends ScreenLifecycleEvent>(event: K, handler: ScreenLifecycleHandlers[K]): () => void;
|
|
348
488
|
/**
|
|
349
489
|
* Add a listener for a specific event after construction.
|
|
350
490
|
* Can be called before the screen is ready -- handlers are queued
|
|
@@ -365,6 +505,7 @@ export interface Screen<TEvents extends EventMap = EventMap> {
|
|
|
365
505
|
* ```
|
|
366
506
|
*/
|
|
367
507
|
on<K extends EventNames<TEvents>>(event: K, handler: ScreenEventHandler<EventData<TEvents, K>>): () => void;
|
|
508
|
+
once<K extends ScreenLifecycleEvent>(event: K, handler: ScreenLifecycleHandlers[K]): () => void;
|
|
368
509
|
/**
|
|
369
510
|
* Add a one-time listener that auto-removes after first call.
|
|
370
511
|
*
|
|
@@ -372,10 +513,19 @@ export interface Screen<TEvents extends EventMap = EventMap> {
|
|
|
372
513
|
* `off(event, originalHandler)`. Use the returned unsubscribe function instead.
|
|
373
514
|
*/
|
|
374
515
|
once<K extends EventNames<TEvents>>(event: K, handler: ScreenEventHandler<EventData<TEvents, K>>): () => void;
|
|
516
|
+
off<K extends ScreenLifecycleEvent>(event: K, handler?: ScreenLifecycleHandlers[K]): void;
|
|
375
517
|
/**
|
|
376
518
|
* Remove a specific listener or all listeners for an event.
|
|
377
519
|
*/
|
|
378
520
|
off<K extends EventNames<TEvents>>(event: K, handler?: ScreenEventHandler<EventData<TEvents, K>>): void;
|
|
521
|
+
/**
|
|
522
|
+
* Remove all event listeners, or all listeners for a specific event.
|
|
523
|
+
* Only removes user event listeners registered via on()/once().
|
|
524
|
+
* Lifecycle callbacks (onControllerJoin, onAllReady, etc.) are not affected.
|
|
525
|
+
*
|
|
526
|
+
* @param event - Optional event name. If omitted, removes ALL user event listeners.
|
|
527
|
+
*/
|
|
528
|
+
removeAllListeners(event?: string): void;
|
|
379
529
|
/**
|
|
380
530
|
* Get a specific controller by player index.
|
|
381
531
|
* Returns undefined if not found.
|
|
@@ -385,14 +535,6 @@ export interface Screen<TEvents extends EventMap = EventMap> {
|
|
|
385
535
|
* Get the number of connected controllers.
|
|
386
536
|
*/
|
|
387
537
|
getControllerCount(): number;
|
|
388
|
-
/**
|
|
389
|
-
* Check if there is at least one connected controller.
|
|
390
|
-
* Useful for detecting when all players have disconnected
|
|
391
|
-
* (e.g., to pause the game or show a waiting screen).
|
|
392
|
-
*
|
|
393
|
-
* Screen-only method. Controller instances can check their own connection status directly.
|
|
394
|
-
*/
|
|
395
|
-
hasAnyConnectedControllers(): boolean;
|
|
396
538
|
/**
|
|
397
539
|
* Clean up all resources and disconnect.
|
|
398
540
|
* Call this when unmounting/destroying your game.
|
|
@@ -424,7 +566,7 @@ export type ControllerEventHandler<TData = unknown> = (data: TData) => void;
|
|
|
424
566
|
* controller.send('tap', { x: 100, y: 200 });
|
|
425
567
|
* ```
|
|
426
568
|
*/
|
|
427
|
-
export interface ControllerConfig
|
|
569
|
+
export interface ControllerConfig {
|
|
428
570
|
/**
|
|
429
571
|
* Enable debug mode for verbose logging.
|
|
430
572
|
* @default false
|
|
@@ -440,6 +582,19 @@ export interface ControllerConfig<_TEvents extends EventMap = EventMap> {
|
|
|
440
582
|
* @default 10000
|
|
441
583
|
*/
|
|
442
584
|
timeout?: number;
|
|
585
|
+
/**
|
|
586
|
+
* Automatically signal ready after initialization.
|
|
587
|
+
* When true (default), the SDK calls signalReady() automatically after init completes.
|
|
588
|
+
* Set to false if your game needs to load resources before signaling ready.
|
|
589
|
+
* @default true
|
|
590
|
+
*/
|
|
591
|
+
autoReady?: boolean;
|
|
592
|
+
/**
|
|
593
|
+
* Custom transport implementation.
|
|
594
|
+
* If provided, uses this instead of the default PostMessageTransport.
|
|
595
|
+
* The bridge handshake (_bridge:init) still occurs via postMessage.
|
|
596
|
+
*/
|
|
597
|
+
transport?: Transport;
|
|
443
598
|
}
|
|
444
599
|
/**
|
|
445
600
|
* Controller instance - the main interface for the player/phone side.
|
|
@@ -470,13 +625,19 @@ export interface ControllerConfig<_TEvents extends EventMap = EventMap> {
|
|
|
470
625
|
*/
|
|
471
626
|
export interface Controller<TEvents extends EventMap = EventMap> {
|
|
472
627
|
/** My player index (0, 1, 2, ...). */
|
|
473
|
-
readonly
|
|
628
|
+
readonly myPlayerIndex: PlayerIndex;
|
|
629
|
+
/** My own controller info. undefined before initialization. */
|
|
630
|
+
readonly me: ControllerInfo | undefined;
|
|
474
631
|
/** The room code for this game session. */
|
|
475
632
|
readonly roomCode: RoomCode;
|
|
476
633
|
/** Whether the controller is initialized and ready. */
|
|
477
634
|
readonly isReady: boolean;
|
|
478
635
|
/** Whether the controller has been destroyed. */
|
|
479
636
|
readonly isDestroyed: boolean;
|
|
637
|
+
/** Whether the connection to the server is active. */
|
|
638
|
+
readonly isConnected: boolean;
|
|
639
|
+
/** Protocol version negotiated with the parent frame. */
|
|
640
|
+
readonly protocolVersion: number;
|
|
480
641
|
/**
|
|
481
642
|
* Read-only list of all known controllers (players) in the room.
|
|
482
643
|
* Returns full ControllerInfo including playerIndex, nickname, connected status, and appearance.
|
|
@@ -542,13 +703,6 @@ export interface Controller<TEvents extends EventMap = EventMap> {
|
|
|
542
703
|
* @returns Unsubscribe function to remove the callback
|
|
543
704
|
*/
|
|
544
705
|
onCharacterUpdated(callback: (playerIndex: PlayerIndex, appearance: CharacterAppearance | null) => void): () => void;
|
|
545
|
-
/**
|
|
546
|
-
* Register a callback for when the server rate-limits an event.
|
|
547
|
-
*
|
|
548
|
-
* @param callback - Called with the rate-limited event name
|
|
549
|
-
* @returns Unsubscribe function to remove the callback
|
|
550
|
-
*/
|
|
551
|
-
onRateLimited(callback: (event: string) => void): () => void;
|
|
552
706
|
/**
|
|
553
707
|
* Register a callback for when an error occurs.
|
|
554
708
|
* If no error callback is registered, errors are logged to console in debug mode.
|
|
@@ -557,10 +711,50 @@ export interface Controller<TEvents extends EventMap = EventMap> {
|
|
|
557
711
|
* @returns Unsubscribe function to remove the callback
|
|
558
712
|
*/
|
|
559
713
|
onError(callback: (error: SmoreError) => void): () => void;
|
|
714
|
+
/**
|
|
715
|
+
* Register a callback for when the game ends.
|
|
716
|
+
* Called when the Screen calls gameOver().
|
|
717
|
+
*
|
|
718
|
+
* @param callback - Called with optional game results
|
|
719
|
+
* @returns Unsubscribe function to remove the callback
|
|
720
|
+
*/
|
|
721
|
+
onGameOver(callback: (results?: GameResults) => void): () => void;
|
|
722
|
+
/**
|
|
723
|
+
* Register a callback for when the connection status changes.
|
|
724
|
+
* Called when the connection to the server is lost or restored.
|
|
725
|
+
*
|
|
726
|
+
* @param callback - Called with true (connected) or false (disconnected)
|
|
727
|
+
* @returns Unsubscribe function to remove the callback
|
|
728
|
+
*/
|
|
729
|
+
onConnectionChange(callback: (connected: boolean) => void): () => void;
|
|
560
730
|
/**
|
|
561
731
|
* Returns the number of currently connected players.
|
|
562
732
|
*/
|
|
563
733
|
getControllerCount(): number;
|
|
734
|
+
/**
|
|
735
|
+
* Get a specific controller by player index.
|
|
736
|
+
* Returns undefined if not found.
|
|
737
|
+
*/
|
|
738
|
+
getController(playerIndex: PlayerIndex): ControllerInfo | undefined;
|
|
739
|
+
/**
|
|
740
|
+
* Set custom state for this controller. State is merged with existing state on the server.
|
|
741
|
+
* State persists only for the duration of the game session.
|
|
742
|
+
*
|
|
743
|
+
* @param state - Key-value state to merge
|
|
744
|
+
*/
|
|
745
|
+
setState(state: Record<string, any>): void;
|
|
746
|
+
/**
|
|
747
|
+
* Get this controller's cached custom state.
|
|
748
|
+
* Returns undefined if no state has been set.
|
|
749
|
+
*/
|
|
750
|
+
getMyState(): Record<string, any> | undefined;
|
|
751
|
+
/**
|
|
752
|
+
* Register a listener for custom state changes from any controller.
|
|
753
|
+
*
|
|
754
|
+
* @param listener - Called with the player index and the new state
|
|
755
|
+
* @returns Unsubscribe function
|
|
756
|
+
*/
|
|
757
|
+
onCustomStateChange(listener: (playerIndex: number, state: Record<string, any>) => void): () => void;
|
|
564
758
|
/**
|
|
565
759
|
* Send an event to the screen.
|
|
566
760
|
*
|
|
@@ -577,11 +771,6 @@ export interface Controller<TEvents extends EventMap = EventMap> {
|
|
|
577
771
|
* ```
|
|
578
772
|
*/
|
|
579
773
|
send<K extends EventNames<TEvents>>(event: K, data: EventData<TEvents, K>): void;
|
|
580
|
-
/**
|
|
581
|
-
* Send with any data (bypasses type checking).
|
|
582
|
-
* Use sparingly - prefer the typed send() method.
|
|
583
|
-
*/
|
|
584
|
-
sendRaw(event: string, data?: unknown): void;
|
|
585
774
|
/**
|
|
586
775
|
* Signal that this controller has finished loading resources and is ready to start.
|
|
587
776
|
*
|
|
@@ -596,6 +785,17 @@ export interface Controller<TEvents extends EventMap = EventMap> {
|
|
|
596
785
|
* ```
|
|
597
786
|
*/
|
|
598
787
|
signalReady(): void;
|
|
788
|
+
/**
|
|
789
|
+
* Subscribe to a lifecycle event or a user-defined game event.
|
|
790
|
+
*
|
|
791
|
+
* Lifecycle events use `$`-prefixed names. Use `LifecycleEvent` constants
|
|
792
|
+
* for type-safe subscription:
|
|
793
|
+
* ```ts
|
|
794
|
+
* controller.on(LifecycleEvent.CONTROLLER_JOIN, (pi, info) => { ... });
|
|
795
|
+
* controller.on('phase-update', (data) => { ... }); // user event
|
|
796
|
+
* ```
|
|
797
|
+
*/
|
|
798
|
+
on<K extends ControllerLifecycleEvent>(event: K, handler: ControllerLifecycleHandlers[K]): () => void;
|
|
599
799
|
/**
|
|
600
800
|
* Add a listener for a specific event after construction.
|
|
601
801
|
* Can be called before the controller is ready -- handlers are queued
|
|
@@ -621,6 +821,7 @@ export interface Controller<TEvents extends EventMap = EventMap> {
|
|
|
621
821
|
* ```
|
|
622
822
|
*/
|
|
623
823
|
on<K extends EventNames<TEvents>>(event: K, handler: ControllerEventHandler<EventData<TEvents, K>>): () => void;
|
|
824
|
+
once<K extends ControllerLifecycleEvent>(event: K, handler: ControllerLifecycleHandlers[K]): () => void;
|
|
624
825
|
/**
|
|
625
826
|
* Add a one-time listener that auto-removes after first call.
|
|
626
827
|
*
|
|
@@ -628,47 +829,25 @@ export interface Controller<TEvents extends EventMap = EventMap> {
|
|
|
628
829
|
* `off(event, originalHandler)`. Use the returned unsubscribe function instead.
|
|
629
830
|
*/
|
|
630
831
|
once<K extends EventNames<TEvents>>(event: K, handler: ControllerEventHandler<EventData<TEvents, K>>): () => void;
|
|
832
|
+
off<K extends ControllerLifecycleEvent>(event: K, handler?: ControllerLifecycleHandlers[K]): void;
|
|
631
833
|
/**
|
|
632
834
|
* Remove a specific listener or all listeners for an event.
|
|
633
835
|
*/
|
|
634
836
|
off<K extends EventNames<TEvents>>(event: K, handler?: ControllerEventHandler<EventData<TEvents, K>>): void;
|
|
837
|
+
/**
|
|
838
|
+
* Remove all event listeners, or all listeners for a specific event.
|
|
839
|
+
* Only removes user event listeners registered via on()/once().
|
|
840
|
+
* Lifecycle callbacks (onControllerJoin, onAllReady, etc.) are not affected.
|
|
841
|
+
*
|
|
842
|
+
* @param event - Optional event name. If omitted, removes ALL user event listeners.
|
|
843
|
+
*/
|
|
844
|
+
removeAllListeners(event?: string): void;
|
|
635
845
|
/**
|
|
636
846
|
* Clean up all resources and disconnect.
|
|
637
847
|
* Call this when unmounting/destroying your game.
|
|
638
848
|
*/
|
|
639
849
|
destroy(): void;
|
|
640
850
|
}
|
|
641
|
-
/**
|
|
642
|
-
* Game results structure for gameOver().
|
|
643
|
-
* Flexible to accommodate different game types.
|
|
644
|
-
*/
|
|
645
|
-
export interface GameResults {
|
|
646
|
-
/** Player scores indexed by player index */
|
|
647
|
-
scores?: Record<PlayerIndex, number>;
|
|
648
|
-
/** Winner's player index (or -1 for no winner/tie) */
|
|
649
|
-
winner?: PlayerIndex;
|
|
650
|
-
/** Ranked player indices from first to last */
|
|
651
|
-
rankings?: PlayerIndex[];
|
|
652
|
-
/** Additional custom data */
|
|
653
|
-
[key: string]: unknown;
|
|
654
|
-
}
|
|
655
|
-
/**
|
|
656
|
-
* Error codes for SDK errors.
|
|
657
|
-
*/
|
|
658
|
-
export type SmoreErrorCode = 'TIMEOUT' | 'NOT_READY' | 'DESTROYED' | 'INVALID_EVENT' | 'INVALID_PLAYER' | 'CONNECTION_LOST' | 'INIT_FAILED' | 'UNKNOWN';
|
|
659
|
-
/**
|
|
660
|
-
* Structured error type for SDK errors.
|
|
661
|
-
*/
|
|
662
|
-
export interface SmoreError {
|
|
663
|
-
/** Error code for programmatic handling */
|
|
664
|
-
code: SmoreErrorCode;
|
|
665
|
-
/** Human-readable error message */
|
|
666
|
-
message: string;
|
|
667
|
-
/** Original error if available */
|
|
668
|
-
cause?: Error;
|
|
669
|
-
/** Additional context */
|
|
670
|
-
details?: Record<string, unknown>;
|
|
671
|
-
}
|
|
672
851
|
/**
|
|
673
852
|
* Log levels for debug output.
|
|
674
853
|
*/
|
|
@@ -692,274 +871,4 @@ export interface DebugOptions {
|
|
|
692
871
|
/** Custom logger function */
|
|
693
872
|
logger?: (level: LogLevel, message: string, data?: unknown) => void;
|
|
694
873
|
}
|
|
695
|
-
/**
|
|
696
|
-
* Create a Screen instance for the host/TV side of your game.
|
|
697
|
-
*
|
|
698
|
-
* Returns a Screen instance synchronously. The screen begins listening
|
|
699
|
-
* for the bridge init message immediately. Use the `.ready` promise
|
|
700
|
-
* to await full initialization.
|
|
701
|
-
*
|
|
702
|
-
* @template TEvents - Event map type for type-safe events
|
|
703
|
-
* @param config - Screen configuration (debug, parentOrigin, timeout)
|
|
704
|
-
* @returns Screen instance (synchronous)
|
|
705
|
-
*
|
|
706
|
-
* @example
|
|
707
|
-
* ```ts
|
|
708
|
-
* const screen = createScreen<MyEvents>({ debug: true });
|
|
709
|
-
*
|
|
710
|
-
* screen.on('tap', (playerIndex, data) => {
|
|
711
|
-
* screen.broadcast('round-result', { ... });
|
|
712
|
-
* });
|
|
713
|
-
*
|
|
714
|
-
* screen.onAllReady(() => startGame());
|
|
715
|
-
* screen.onControllerJoin((pi, info) => addPlayer(pi, info));
|
|
716
|
-
*
|
|
717
|
-
* await screen.ready;
|
|
718
|
-
* ```
|
|
719
|
-
*/
|
|
720
|
-
export declare function createScreen<TEvents extends EventMap = EventMap>(config?: ScreenConfig<TEvents>): Screen<TEvents>;
|
|
721
|
-
/**
|
|
722
|
-
* Create a Controller instance for the player/phone side of your game.
|
|
723
|
-
*
|
|
724
|
-
* Returns a Controller instance synchronously. The controller begins listening
|
|
725
|
-
* for the bridge init message immediately. Use the `.ready` promise
|
|
726
|
-
* to await full initialization.
|
|
727
|
-
*
|
|
728
|
-
* @template TEvents - Event map type for type-safe events
|
|
729
|
-
* @param config - Controller configuration (debug, parentOrigin, timeout)
|
|
730
|
-
* @returns Controller instance (synchronous)
|
|
731
|
-
*
|
|
732
|
-
* @example
|
|
733
|
-
* ```ts
|
|
734
|
-
* const controller = createController<MyEvents>({ debug: true });
|
|
735
|
-
*
|
|
736
|
-
* controller.on('phase-update', (data) => setPhase(data.phase));
|
|
737
|
-
* controller.onAllReady(() => console.log('Ready!'));
|
|
738
|
-
*
|
|
739
|
-
* await controller.ready;
|
|
740
|
-
* controller.send('tap', { x: 100, y: 200 });
|
|
741
|
-
* ```
|
|
742
|
-
*/
|
|
743
|
-
export declare function createController<TEvents extends EventMap = EventMap>(config?: ControllerConfig<TEvents>): Controller<TEvents>;
|
|
744
|
-
/**
|
|
745
|
-
* Options for creating mock instances.
|
|
746
|
-
*/
|
|
747
|
-
export interface MockOptions {
|
|
748
|
-
/** Initial room code */
|
|
749
|
-
roomCode?: RoomCode;
|
|
750
|
-
/** Initial controllers for Screen mock */
|
|
751
|
-
controllers?: ControllerInfo[];
|
|
752
|
-
/** My index for Controller mock */
|
|
753
|
-
myIndex?: PlayerIndex;
|
|
754
|
-
/** Auto-trigger ready state */
|
|
755
|
-
autoReady?: boolean;
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* Mock Screen for testing.
|
|
759
|
-
* Extends Screen with additional test utilities.
|
|
760
|
-
*/
|
|
761
|
-
export interface MockScreen<TEvents extends EventMap = EventMap> extends Screen<TEvents> {
|
|
762
|
-
/**
|
|
763
|
-
* Simulate receiving an event from a controller.
|
|
764
|
-
* Triggers the corresponding listener.
|
|
765
|
-
*/
|
|
766
|
-
simulateEvent<K extends EventNames<TEvents>>(playerIndex: PlayerIndex, event: K, data: EventData<TEvents, K>): void;
|
|
767
|
-
/**
|
|
768
|
-
* Simulate a controller joining.
|
|
769
|
-
* Triggers onControllerJoin callbacks.
|
|
770
|
-
*/
|
|
771
|
-
simulateControllerJoin(info: ControllerInfo): void;
|
|
772
|
-
/**
|
|
773
|
-
* Simulate a controller leaving.
|
|
774
|
-
* Triggers onControllerLeave callbacks.
|
|
775
|
-
*/
|
|
776
|
-
simulateControllerLeave(playerIndex: PlayerIndex): void;
|
|
777
|
-
/**
|
|
778
|
-
* Simulate a controller disconnecting temporarily.
|
|
779
|
-
* Triggers onControllerDisconnect callbacks and marks player as disconnected.
|
|
780
|
-
*/
|
|
781
|
-
simulateControllerDisconnect(playerIndex: PlayerIndex): void;
|
|
782
|
-
/**
|
|
783
|
-
* Simulate a controller reconnecting after a disconnect.
|
|
784
|
-
* Triggers onControllerReconnect callbacks and marks player as connected.
|
|
785
|
-
*/
|
|
786
|
-
simulateControllerReconnect(playerIndex: PlayerIndex): void;
|
|
787
|
-
/**
|
|
788
|
-
* Get all events that were broadcast.
|
|
789
|
-
* Returns array of { event, data } objects.
|
|
790
|
-
*/
|
|
791
|
-
getBroadcasts(): Array<{
|
|
792
|
-
event: string;
|
|
793
|
-
data: unknown;
|
|
794
|
-
}>;
|
|
795
|
-
/**
|
|
796
|
-
* Get all events sent to a specific controller.
|
|
797
|
-
*/
|
|
798
|
-
getSentToController(playerIndex: PlayerIndex): Array<{
|
|
799
|
-
event: string;
|
|
800
|
-
data: unknown;
|
|
801
|
-
}>;
|
|
802
|
-
/**
|
|
803
|
-
* Clear recorded events.
|
|
804
|
-
*/
|
|
805
|
-
clearRecordedEvents(): void;
|
|
806
|
-
/**
|
|
807
|
-
* Manually trigger the ready state.
|
|
808
|
-
*/
|
|
809
|
-
triggerReady(): void;
|
|
810
|
-
/**
|
|
811
|
-
* Simulate a player's character appearance being updated.
|
|
812
|
-
* Triggers onCharacterUpdated callbacks and updates the controller's appearance.
|
|
813
|
-
*/
|
|
814
|
-
simulateCharacterUpdate(playerIndex: PlayerIndex, appearance: CharacterAppearance | null): void;
|
|
815
|
-
/**
|
|
816
|
-
* Simulate the server rate-limiting an event.
|
|
817
|
-
* Triggers onRateLimited callbacks.
|
|
818
|
-
*/
|
|
819
|
-
simulateRateLimited(event: string): void;
|
|
820
|
-
/**
|
|
821
|
-
* Simulate the all-ready event (all participants signaled ready).
|
|
822
|
-
* Triggers onAllReady callbacks.
|
|
823
|
-
*/
|
|
824
|
-
simulateAllReady(): void;
|
|
825
|
-
/** Simulate an error. Triggers onError callbacks. */
|
|
826
|
-
simulateError(error: any): void;
|
|
827
|
-
}
|
|
828
|
-
/**
|
|
829
|
-
* Mock Controller for testing.
|
|
830
|
-
* Extends Controller with additional test utilities.
|
|
831
|
-
*/
|
|
832
|
-
export interface MockController<TEvents extends EventMap = EventMap> extends Controller<TEvents> {
|
|
833
|
-
/**
|
|
834
|
-
* Simulate receiving an event from the screen.
|
|
835
|
-
* Triggers the corresponding listener.
|
|
836
|
-
*/
|
|
837
|
-
simulateEvent<K extends EventNames<TEvents>>(event: K, data: EventData<TEvents, K>): void;
|
|
838
|
-
/**
|
|
839
|
-
* Get all events that were sent to the screen.
|
|
840
|
-
* Returns array of { event, data } objects.
|
|
841
|
-
*/
|
|
842
|
-
getSentEvents(): Array<{
|
|
843
|
-
event: string;
|
|
844
|
-
data: unknown;
|
|
845
|
-
}>;
|
|
846
|
-
/**
|
|
847
|
-
* Clear recorded events.
|
|
848
|
-
*/
|
|
849
|
-
clearRecordedEvents(): void;
|
|
850
|
-
/**
|
|
851
|
-
* Manually trigger the ready state.
|
|
852
|
-
*/
|
|
853
|
-
triggerReady(): void;
|
|
854
|
-
/**
|
|
855
|
-
* Simulate another player joining the room.
|
|
856
|
-
* Triggers onControllerJoin callbacks.
|
|
857
|
-
*/
|
|
858
|
-
simulatePlayerJoin(playerIndex: PlayerIndex, info: ControllerInfo): void;
|
|
859
|
-
/**
|
|
860
|
-
* Simulate another player leaving the room.
|
|
861
|
-
* Triggers onControllerLeave callbacks.
|
|
862
|
-
*/
|
|
863
|
-
simulatePlayerLeave(playerIndex: PlayerIndex): void;
|
|
864
|
-
/**
|
|
865
|
-
* Simulate another player disconnecting temporarily.
|
|
866
|
-
* Triggers onControllerDisconnect callbacks.
|
|
867
|
-
*/
|
|
868
|
-
simulatePlayerDisconnect(playerIndex: PlayerIndex): void;
|
|
869
|
-
/**
|
|
870
|
-
* Simulate another player reconnecting after a disconnect.
|
|
871
|
-
* Triggers onControllerReconnect callbacks.
|
|
872
|
-
*/
|
|
873
|
-
simulatePlayerReconnect(playerIndex: PlayerIndex, info: ControllerInfo): void;
|
|
874
|
-
/**
|
|
875
|
-
* Simulate a player's character appearance being updated.
|
|
876
|
-
* Triggers onCharacterUpdated callbacks and updates the controller's appearance.
|
|
877
|
-
*/
|
|
878
|
-
simulateCharacterUpdate(playerIndex: PlayerIndex, appearance: CharacterAppearance | null): void;
|
|
879
|
-
/**
|
|
880
|
-
* Simulate the server rate-limiting an event.
|
|
881
|
-
* Triggers onRateLimited callbacks.
|
|
882
|
-
*/
|
|
883
|
-
simulateRateLimited(event: string): void;
|
|
884
|
-
/**
|
|
885
|
-
* Simulate the all-ready event (all participants signaled ready).
|
|
886
|
-
* Triggers onAllReady callbacks.
|
|
887
|
-
*/
|
|
888
|
-
simulateAllReady(): void;
|
|
889
|
-
/** Simulate an error. Triggers onError callbacks. */
|
|
890
|
-
simulateError(error: any): void;
|
|
891
|
-
}
|
|
892
|
-
/**
|
|
893
|
-
* Create a mock Screen for testing.
|
|
894
|
-
*
|
|
895
|
-
* @example
|
|
896
|
-
* ```ts
|
|
897
|
-
* const mockScreen = createMockScreen<MyEvents>({
|
|
898
|
-
* controllers: [
|
|
899
|
-
* { playerIndex: 0, nickname: 'Player 1', connected: true },
|
|
900
|
-
* { playerIndex: 1, nickname: 'Player 2', connected: true },
|
|
901
|
-
* ],
|
|
902
|
-
* });
|
|
903
|
-
*
|
|
904
|
-
* mockScreen.on('tap', (pi, data) => handleTap(pi, data));
|
|
905
|
-
* mockScreen.onAllReady(() => startGame());
|
|
906
|
-
*
|
|
907
|
-
* // Simulate player input
|
|
908
|
-
* mockScreen.simulateEvent(0, 'tap', { x: 100, y: 200 });
|
|
909
|
-
*
|
|
910
|
-
* // Check what was broadcast
|
|
911
|
-
* expect(mockScreen.getBroadcasts()).toContainEqual({
|
|
912
|
-
* event: 'score-update',
|
|
913
|
-
* data: { scores: { 0: 10 } },
|
|
914
|
-
* });
|
|
915
|
-
* ```
|
|
916
|
-
*/
|
|
917
|
-
export declare function createMockScreen<TEvents extends EventMap = EventMap>(options?: MockOptions): MockScreen<TEvents>;
|
|
918
|
-
/**
|
|
919
|
-
* Create a mock Controller for testing.
|
|
920
|
-
*
|
|
921
|
-
* @example
|
|
922
|
-
* ```ts
|
|
923
|
-
* const mockController = createMockController<MyEvents>({
|
|
924
|
-
* myIndex: 0,
|
|
925
|
-
* });
|
|
926
|
-
*
|
|
927
|
-
* mockController.on('your-turn', (data) => handleTurn(data));
|
|
928
|
-
* mockController.onAllReady(() => console.log('Ready!'));
|
|
929
|
-
*
|
|
930
|
-
* // Simulate receiving from screen
|
|
931
|
-
* mockController.simulateEvent('your-turn', { timeLimit: 30 });
|
|
932
|
-
*
|
|
933
|
-
* // Check what was sent
|
|
934
|
-
* expect(mockController.getSentEvents()).toContainEqual({
|
|
935
|
-
* event: 'answer',
|
|
936
|
-
* data: { choice: 2 },
|
|
937
|
-
* });
|
|
938
|
-
* ```
|
|
939
|
-
*/
|
|
940
|
-
export declare function createMockController<TEvents extends EventMap = EventMap>(options?: MockOptions): MockController<TEvents>;
|
|
941
|
-
/**
|
|
942
|
-
* Game metadata from game.json manifest.
|
|
943
|
-
* SYNC: Also defined in game-project/types/src/types.ts - keep in sync.
|
|
944
|
-
*/
|
|
945
|
-
export interface GameMetadata {
|
|
946
|
-
/** Unique game identifier */
|
|
947
|
-
id: string;
|
|
948
|
-
/** Display title */
|
|
949
|
-
title: string;
|
|
950
|
-
/** Game description */
|
|
951
|
-
description: string;
|
|
952
|
-
/** Minimum players required */
|
|
953
|
-
minPlayers: number;
|
|
954
|
-
/** Maximum players supported */
|
|
955
|
-
maxPlayers: number;
|
|
956
|
-
/** Game categories/tags */
|
|
957
|
-
categories: string[];
|
|
958
|
-
/** Thumbnail image URL */
|
|
959
|
-
thumbnail?: string;
|
|
960
|
-
/** Author/developer name */
|
|
961
|
-
author?: string;
|
|
962
|
-
/** Game version */
|
|
963
|
-
version?: string;
|
|
964
|
-
}
|
|
965
874
|
//# sourceMappingURL=types.d.ts.map
|