@smoregg/sdk 1.2.0 → 2.0.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/config.cjs.map +1 -1
- package/dist/cjs/controller.cjs +215 -145
- package/dist/cjs/controller.cjs.map +1 -1
- package/dist/cjs/screen.cjs +220 -178
- package/dist/cjs/screen.cjs.map +1 -1
- package/dist/cjs/testing.cjs +160 -151
- package/dist/cjs/testing.cjs.map +1 -1
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/controller.js +216 -146
- package/dist/esm/controller.js.map +1 -1
- package/dist/esm/screen.js +221 -179
- package/dist/esm/screen.js.map +1 -1
- package/dist/esm/testing.js +160 -151
- package/dist/esm/testing.js.map +1 -1
- package/dist/types/config.d.ts +1 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/controller.d.ts +22 -43
- package/dist/types/controller.d.ts.map +1 -1
- package/dist/types/index.d.ts +14 -14
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/screen.d.ts +26 -37
- package/dist/types/screen.d.ts.map +1 -1
- package/dist/types/testing.d.ts +16 -0
- package/dist/types/testing.d.ts.map +1 -1
- package/dist/types/types.d.ts +244 -338
- package/dist/types/types.d.ts.map +1 -1
- package/dist/umd/smore-sdk.umd.js +595 -474
- 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 +1 -1
- package/dist/cjs/SmoreHost.cjs +0 -306
- package/dist/cjs/SmoreHost.cjs.map +0 -1
- package/dist/cjs/SmorePlayer.cjs +0 -229
- package/dist/cjs/SmorePlayer.cjs.map +0 -1
- package/dist/cjs/components/DirectionPad.cjs +0 -68
- package/dist/cjs/components/DirectionPad.cjs.map +0 -1
- package/dist/cjs/components/DirectionPad.module.css.cjs +0 -12
- package/dist/cjs/components/DirectionPad.module.css.cjs.map +0 -1
- package/dist/cjs/components/HoldButton.cjs +0 -57
- package/dist/cjs/components/HoldButton.cjs.map +0 -1
- package/dist/cjs/components/HoldButton.module.css.cjs +0 -12
- package/dist/cjs/components/HoldButton.module.css.cjs.map +0 -1
- package/dist/cjs/components/IframeGameBridge.cjs +0 -115
- package/dist/cjs/components/IframeGameBridge.cjs.map +0 -1
- package/dist/cjs/components/SwipeArea.cjs +0 -58
- package/dist/cjs/components/SwipeArea.cjs.map +0 -1
- package/dist/cjs/components/SwipeArea.module.css.cjs +0 -12
- package/dist/cjs/components/SwipeArea.module.css.cjs.map +0 -1
- package/dist/cjs/components/TapButton.cjs +0 -58
- package/dist/cjs/components/TapButton.cjs.map +0 -1
- package/dist/cjs/components/TapButton.module.css.cjs +0 -12
- package/dist/cjs/components/TapButton.module.css.cjs.map +0 -1
- package/dist/cjs/context/RoomProvider.cjs +0 -118
- package/dist/cjs/context/RoomProvider.cjs.map +0 -1
- package/dist/cjs/hooks/useExternalGames.cjs +0 -49
- package/dist/cjs/hooks/useExternalGames.cjs.map +0 -1
- package/dist/cjs/hooks/useGameHost.cjs +0 -206
- package/dist/cjs/hooks/useGameHost.cjs.map +0 -1
- package/dist/cjs/hooks/useGamePlayer.cjs +0 -134
- package/dist/cjs/hooks/useGamePlayer.cjs.map +0 -1
- package/dist/cjs/iframe/index.cjs +0 -260
- package/dist/cjs/iframe/index.cjs.map +0 -1
- package/dist/cjs/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs +0 -33
- package/dist/cjs/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs.map +0 -1
- package/dist/cjs/server/index.cjs +0 -45
- package/dist/cjs/server/index.cjs.map +0 -1
- package/dist/cjs/transport/DirectTransport.cjs +0 -23
- package/dist/cjs/transport/DirectTransport.cjs.map +0 -1
- package/dist/cjs/utils/connectionMonitor.cjs +0 -77
- package/dist/cjs/utils/connectionMonitor.cjs.map +0 -1
- package/dist/cjs/utils/preloadAssets.cjs +0 -66
- package/dist/cjs/utils/preloadAssets.cjs.map +0 -1
- package/dist/cjs/utils/serverTime.cjs +0 -43
- package/dist/cjs/utils/serverTime.cjs.map +0 -1
- package/dist/esm/SmoreHost.js +0 -304
- package/dist/esm/SmoreHost.js.map +0 -1
- package/dist/esm/SmorePlayer.js +0 -227
- package/dist/esm/SmorePlayer.js.map +0 -1
- package/dist/esm/components/DirectionPad.js +0 -66
- package/dist/esm/components/DirectionPad.js.map +0 -1
- package/dist/esm/components/DirectionPad.module.css.js +0 -8
- package/dist/esm/components/DirectionPad.module.css.js.map +0 -1
- package/dist/esm/components/HoldButton.js +0 -55
- package/dist/esm/components/HoldButton.js.map +0 -1
- package/dist/esm/components/HoldButton.module.css.js +0 -8
- package/dist/esm/components/HoldButton.module.css.js.map +0 -1
- package/dist/esm/components/IframeGameBridge.js +0 -113
- package/dist/esm/components/IframeGameBridge.js.map +0 -1
- package/dist/esm/components/SwipeArea.js +0 -56
- package/dist/esm/components/SwipeArea.js.map +0 -1
- package/dist/esm/components/SwipeArea.module.css.js +0 -8
- package/dist/esm/components/SwipeArea.module.css.js.map +0 -1
- package/dist/esm/components/TapButton.js +0 -56
- package/dist/esm/components/TapButton.js.map +0 -1
- package/dist/esm/components/TapButton.module.css.js +0 -8
- package/dist/esm/components/TapButton.module.css.js.map +0 -1
- package/dist/esm/context/RoomProvider.js +0 -109
- package/dist/esm/context/RoomProvider.js.map +0 -1
- package/dist/esm/hooks/useExternalGames.js +0 -47
- package/dist/esm/hooks/useExternalGames.js.map +0 -1
- package/dist/esm/hooks/useGameHost.js +0 -204
- package/dist/esm/hooks/useGameHost.js.map +0 -1
- package/dist/esm/hooks/useGamePlayer.js +0 -132
- package/dist/esm/hooks/useGamePlayer.js.map +0 -1
- package/dist/esm/iframe/index.js +0 -257
- package/dist/esm/iframe/index.js.map +0 -1
- package/dist/esm/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js +0 -29
- package/dist/esm/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js.map +0 -1
- package/dist/esm/server/index.js +0 -43
- package/dist/esm/server/index.js.map +0 -1
- package/dist/esm/transport/DirectTransport.js +0 -21
- package/dist/esm/transport/DirectTransport.js.map +0 -1
- package/dist/esm/utils/connectionMonitor.js +0 -75
- package/dist/esm/utils/connectionMonitor.js.map +0 -1
- package/dist/esm/utils/preloadAssets.js +0 -63
- package/dist/esm/utils/preloadAssets.js.map +0 -1
- package/dist/esm/utils/serverTime.js +0 -41
- package/dist/esm/utils/serverTime.js.map +0 -1
- package/dist/types/SmoreHost.d.ts +0 -187
- package/dist/types/SmoreHost.d.ts.map +0 -1
- package/dist/types/SmorePlayer.d.ts +0 -146
- package/dist/types/SmorePlayer.d.ts.map +0 -1
- package/dist/types/components/DirectionPad.d.ts +0 -21
- package/dist/types/components/DirectionPad.d.ts.map +0 -1
- package/dist/types/components/HoldButton.d.ts +0 -22
- package/dist/types/components/HoldButton.d.ts.map +0 -1
- package/dist/types/components/IframeGameBridge.d.ts +0 -38
- package/dist/types/components/IframeGameBridge.d.ts.map +0 -1
- package/dist/types/components/SwipeArea.d.ts +0 -19
- package/dist/types/components/SwipeArea.d.ts.map +0 -1
- package/dist/types/components/TapButton.d.ts +0 -19
- package/dist/types/components/TapButton.d.ts.map +0 -1
- package/dist/types/components/index.d.ts +0 -6
- package/dist/types/components/index.d.ts.map +0 -1
- package/dist/types/context/RoomProvider.d.ts +0 -69
- package/dist/types/context/RoomProvider.d.ts.map +0 -1
- package/dist/types/context/index.d.ts +0 -3
- package/dist/types/context/index.d.ts.map +0 -1
- package/dist/types/dev/DevSimulator.d.ts +0 -31
- package/dist/types/dev/DevSimulator.d.ts.map +0 -1
- package/dist/types/dev/index.d.ts +0 -2
- package/dist/types/dev/index.d.ts.map +0 -1
- package/dist/types/hooks/index.d.ts +0 -7
- package/dist/types/hooks/index.d.ts.map +0 -1
- package/dist/types/hooks/useExternalGames.d.ts +0 -32
- package/dist/types/hooks/useExternalGames.d.ts.map +0 -1
- package/dist/types/hooks/useGameHost.d.ts +0 -67
- package/dist/types/hooks/useGameHost.d.ts.map +0 -1
- package/dist/types/hooks/useGamePlayer.d.ts +0 -55
- package/dist/types/hooks/useGamePlayer.d.ts.map +0 -1
- package/dist/types/iframe/IframeRoomProvider.d.ts +0 -31
- package/dist/types/iframe/IframeRoomProvider.d.ts.map +0 -1
- package/dist/types/iframe/index.d.ts +0 -18
- package/dist/types/iframe/index.d.ts.map +0 -1
- package/dist/types/iframe/vanilla-entry.d.ts +0 -7
- package/dist/types/iframe/vanilla-entry.d.ts.map +0 -1
- package/dist/types/iframe/vanilla.d.ts +0 -49
- package/dist/types/iframe/vanilla.d.ts.map +0 -1
- package/dist/types/server/createGameRelay.d.ts +0 -26
- package/dist/types/server/createGameRelay.d.ts.map +0 -1
- package/dist/types/server/index.d.ts +0 -3
- package/dist/types/server/index.d.ts.map +0 -1
- package/dist/types/utils/connectionMonitor.d.ts +0 -57
- package/dist/types/utils/connectionMonitor.d.ts.map +0 -1
- package/dist/types/utils/index.d.ts +0 -7
- package/dist/types/utils/index.d.ts.map +0 -1
- package/dist/types/utils/preloadAssets.d.ts +0 -29
- package/dist/types/utils/preloadAssets.d.ts.map +0 -1
- package/dist/types/utils/serverTime.d.ts +0 -28
- package/dist/types/utils/serverTime.d.ts.map +0 -1
- package/dist/umd/smore-sdk-iframe.umd.js +0 -266
- package/dist/umd/smore-sdk-iframe.umd.js.map +0 -1
- package/dist/umd/smore-sdk-iframe.umd.min.js +0 -2
- package/dist/umd/smore-sdk-iframe.umd.min.js.map +0 -1
- package/dist/umd/smore-sdk-vanilla.umd.js +0 -1275
- package/dist/umd/smore-sdk-vanilla.umd.js.map +0 -1
- package/dist/umd/smore-sdk-vanilla.umd.min.js +0 -2
- package/dist/umd/smore-sdk-vanilla.umd.min.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smore-sdk-vanilla.umd.js","sources":["../../src/transport/protocol.ts","../../src/transport/PostMessageTransport.ts","../../src/screen.ts","../../src/controller.ts","../../src/transport/DirectTransport.ts","../../src/events.ts","../../src/testing.ts"],"sourcesContent":["/**\n * postMessage protocol types for iframe ↔ parent communication.\n */\n\nexport const SMORE_MSG_PREFIX = 'smore:' as const;\n\nexport interface SmoreReadyMessage {\n type: 'smore:ready';\n}\n\nexport interface SmoreInitMessage {\n type: 'smore:init';\n payload: {\n side: 'host' | 'player';\n roomCode: string;\n players: any[];\n leaderId: string | null;\n myIndex?: number;\n isLeader?: boolean;\n };\n}\n\nexport interface SmoreEmitMessage {\n type: 'smore:emit';\n payload: {\n event: string;\n data?: any;\n ackId?: string;\n };\n}\n\nexport interface SmoreEventMessage {\n type: 'smore:event';\n payload: {\n event: string;\n data?: any;\n };\n}\n\nexport interface SmoreAckMessage {\n type: 'smore:ack';\n payload: {\n ackId: string;\n data?: any;\n };\n}\n\nexport interface SmoreUpdateMessage {\n type: 'smore:update';\n payload: {\n players?: any[];\n leaderId?: string | null;\n };\n}\n\n// DEPRECATED: SmoreLoadedMessage removed - no longer used in protocol\n// Previously: interface SmoreLoadedMessage { type: 'smore:loaded' }\n\nexport type SmoreMessage =\n | SmoreReadyMessage\n | SmoreInitMessage\n | SmoreEmitMessage\n | SmoreEventMessage\n | SmoreAckMessage\n | SmoreUpdateMessage;\n\nexport function isSmoreMessage(data: any): data is SmoreMessage {\n return data && typeof data === 'object' && typeof data.type === 'string' && data.type.startsWith(SMORE_MSG_PREFIX);\n}\n","/**\n * PostMessageTransport - Transport over window.postMessage for iframe-hosted games.\n *\n * Used inside an iframe. Sends `smore:emit` to parent and listens for `smore:event` from parent.\n */\n\nimport type { Transport, TransportEventHandler } from './types';\nimport type { SmoreEventMessage, SmoreAckMessage } from './protocol';\nimport { isSmoreMessage } from './protocol';\n\nexport class PostMessageTransport implements Transport {\n private handlers = new Map<string, Set<TransportEventHandler>>();\n private ackCallbacks = new Map<string, (...args: any[]) => void>();\n private ackCounter = 0;\n private parentOrigin: string;\n private boundMessageHandler: (e: MessageEvent) => void;\n\n constructor(parentOrigin: string = '*') {\n this.parentOrigin = parentOrigin;\n this.boundMessageHandler = this.handleMessage.bind(this);\n window.addEventListener('message', this.boundMessageHandler);\n }\n\n emit(event: string, ...args: any[]): void {\n // Detect if last arg is a callback (ack pattern)\n let data: any = args[0];\n let ackId: string | undefined;\n\n if (args.length >= 2 && typeof args[args.length - 1] === 'function') {\n data = args.length === 2 ? args[0] : args[0];\n const callback = args[args.length - 1];\n ackId = `ack_${++this.ackCounter}`;\n this.ackCallbacks.set(ackId, callback);\n }\n\n window.parent.postMessage(\n { type: 'smore:emit', payload: { event, data, ackId } },\n this.parentOrigin,\n );\n }\n\n on(event: string, handler: TransportEventHandler): void {\n let set = this.handlers.get(event);\n if (!set) {\n set = new Set();\n this.handlers.set(event, set);\n }\n set.add(handler);\n }\n\n off(event: string, handler?: TransportEventHandler): void {\n if (!handler) {\n this.handlers.delete(event);\n return;\n }\n this.handlers.get(event)?.delete(handler);\n }\n\n destroy(): void {\n window.removeEventListener('message', this.boundMessageHandler);\n this.handlers.clear();\n this.ackCallbacks.clear();\n }\n\n private handleMessage(e: MessageEvent): void {\n // Origin validation: only accept messages from the expected parent\n if (this.parentOrigin !== '*' && e.origin !== this.parentOrigin) return;\n\n const msg = e.data;\n if (!isSmoreMessage(msg)) return;\n\n if (msg.type === 'smore:event') {\n const { event, data } = (msg as SmoreEventMessage).payload;\n const set = this.handlers.get(event);\n if (set) {\n set.forEach((handler) => handler(data));\n }\n } else if (msg.type === 'smore:ack') {\n const { ackId, data } = (msg as SmoreAckMessage).payload;\n const cb = this.ackCallbacks.get(ackId);\n if (cb) {\n this.ackCallbacks.delete(ackId);\n cb(data);\n }\n }\n }\n}\n","/**\n * createScreen - Factory function for Screen instances (Host/TV side)\n *\n * Promise-based factory with type-safe event handling and comprehensive error management.\n *\n * @example Promise-based (recommended)\n * ```ts\n * interface MyEvents {\n * tap: { x: number; y: number };\n * 'phase-update': { phase: 'lobby' | 'playing' | 'results' };\n * }\n *\n * const screen = await createScreen<MyEvents>({\n * listeners: {\n * tap: (playerIndex, data) => console.log(`Player ${playerIndex} tapped at`, data.x, data.y),\n * },\n * });\n *\n * screen.broadcast('phase-update', { phase: 'playing' });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const screen = createScreen<MyEvents>({\n * onReady: () => screen.broadcast('ready', {}),\n * listeners: { ... },\n * });\n * // Use screen.instance for immediate access\n * ```\n */\n\nimport type {\n EventMap,\n EventNames,\n EventData,\n Screen,\n ScreenConfig,\n ScreenEventHandler,\n ControllerInfo,\n PlayerIndex,\n RoomCode,\n GameResults,\n SmoreError,\n SmoreErrorCode,\n DebugOptions,\n LogLevel,\n} from './types';\nimport type { Transport, TransportEventHandler } from './transport/types';\nimport { PostMessageTransport } from './transport/PostMessageTransport';\nimport { isSmoreMessage, type SmoreInitMessage, type SmoreUpdateMessage } from './transport/protocol';\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst SYSTEM_PREFIX = 'smore:';\n\nconst SYSTEM_EVENTS = {\n READY: `${SYSTEM_PREFIX}ready`,\n PLAYER_JOIN: `${SYSTEM_PREFIX}player-join`,\n PLAYER_LEAVE: `${SYSTEM_PREFIX}player-leave`,\n PLAYER_RECONNECT: `${SYSTEM_PREFIX}player-reconnect`,\n GAME_OVER: `${SYSTEM_PREFIX}game-over`,\n} as const;\n\nconst DEFAULT_TIMEOUT = 10000;\n\n// =============================================================================\n// ERROR CLASS\n// =============================================================================\n\n/**\n * Custom error class for SDK errors with structured error handling.\n */\nexport class SmoreSDKError extends Error {\n readonly code: SmoreErrorCode;\n readonly cause?: Error;\n readonly details?: Record<string, unknown>;\n\n constructor(\n code: SmoreErrorCode,\n message: string,\n options?: { cause?: Error; details?: Record<string, unknown> }\n ) {\n super(message);\n this.name = 'SmoreSDKError';\n this.code = code;\n this.cause = options?.cause;\n this.details = options?.details;\n\n // Maintain proper stack trace in V8 environments\n const ErrorWithCapture = Error as typeof Error & {\n captureStackTrace?: (target: object, constructor?: Function) => void;\n };\n if (typeof ErrorWithCapture.captureStackTrace === 'function') {\n ErrorWithCapture.captureStackTrace(this, SmoreSDKError);\n }\n }\n\n toSmoreError(): SmoreError {\n return {\n code: this.code,\n message: this.message,\n cause: this.cause,\n details: this.details,\n };\n }\n}\n\n// =============================================================================\n// VALIDATION\n// =============================================================================\n\nconst EVENT_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;\n\nfunction validateEventName(event: string): void {\n if (!event || typeof event !== 'string') {\n throw new SmoreSDKError('INVALID_EVENT', 'Event name must be a non-empty string');\n }\n if (!EVENT_NAME_REGEX.test(event)) {\n throw new SmoreSDKError(\n 'INVALID_EVENT',\n `Invalid event name \"${event}\". Event names must start with a letter, ` +\n `contain only letters, numbers, hyphens, or underscores, and end with a letter or number.`,\n { details: { event } }\n );\n }\n}\n\nfunction validatePlayerIndex(playerIndex: PlayerIndex, controllersCount: number): void {\n if (typeof playerIndex !== 'number' || !Number.isInteger(playerIndex)) {\n throw new SmoreSDKError('INVALID_PLAYER', 'Player index must be an integer');\n }\n if (playerIndex < 0 || playerIndex >= controllersCount) {\n throw new SmoreSDKError(\n 'INVALID_PLAYER',\n `Invalid player index ${playerIndex}. Valid range: 0-${controllersCount - 1}`,\n { details: { playerIndex, controllersCount } }\n );\n }\n}\n\n// =============================================================================\n// DEBUG LOGGER\n// =============================================================================\n\nclass DebugLogger {\n private enabled: boolean;\n private level: LogLevel;\n private prefix: string;\n private logSend: boolean;\n private logReceive: boolean;\n private logLifecycle: boolean;\n private customLogger?: (level: LogLevel, message: string, data?: unknown) => void;\n\n private static levelOrder: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n constructor(options?: boolean | DebugOptions) {\n if (typeof options === 'boolean') {\n this.enabled = options;\n this.level = 'debug';\n this.prefix = '[SmoreScreen]';\n this.logSend = true;\n this.logReceive = true;\n this.logLifecycle = true;\n } else if (options) {\n this.enabled = options.enabled ?? false;\n this.level = options.level ?? 'debug';\n this.prefix = options.prefix ?? '[SmoreScreen]';\n this.logSend = options.logSend ?? true;\n this.logReceive = options.logReceive ?? true;\n this.logLifecycle = options.logLifecycle ?? true;\n this.customLogger = options.logger;\n } else {\n this.enabled = false;\n this.level = 'debug';\n this.prefix = '[SmoreScreen]';\n this.logSend = true;\n this.logReceive = true;\n this.logLifecycle = true;\n }\n }\n\n private shouldLog(level: LogLevel): boolean {\n return this.enabled && DebugLogger.levelOrder[level] >= DebugLogger.levelOrder[this.level];\n }\n\n private log(level: LogLevel, message: string, data?: unknown): void {\n if (!this.shouldLog(level)) return;\n\n if (this.customLogger) {\n this.customLogger(level, `${this.prefix} ${message}`, data);\n return;\n }\n\n const consoleMethod = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log';\n if (data !== undefined) {\n console[consoleMethod](`${this.prefix} ${message}`, data);\n } else {\n console[consoleMethod](`${this.prefix} ${message}`);\n }\n }\n\n debug(message: string, data?: unknown): void {\n this.log('debug', message, data);\n }\n\n info(message: string, data?: unknown): void {\n this.log('info', message, data);\n }\n\n warn(message: string, data?: unknown): void {\n this.log('warn', message, data);\n }\n\n error(message: string, data?: unknown): void {\n this.log('error', message, data);\n }\n\n send(event: string, data?: unknown): void {\n if (this.logSend) {\n this.debug(`-> SEND: ${event}`, data);\n }\n }\n\n receive(event: string, data?: unknown): void {\n if (this.logReceive) {\n this.debug(`<- RECV: ${event}`, data);\n }\n }\n\n lifecycle(message: string, data?: unknown): void {\n if (this.logLifecycle) {\n this.info(`[Lifecycle] ${message}`, data);\n }\n }\n}\n\n// =============================================================================\n// SCREEN IMPLEMENTATION\n// =============================================================================\n\nclass ScreenImpl<TEvents extends EventMap> implements Screen<TEvents> {\n private transport: Transport | null = null;\n private config: ScreenConfig<TEvents>;\n private logger: DebugLogger;\n\n private _controllers: ControllerInfo[] = [];\n private _roomCode: RoomCode = '';\n private _leaderIndex: PlayerIndex = -1;\n private _isReady = false;\n private _isDestroyed = false;\n\n private eventHandlers = new Map<string, Set<ScreenEventHandler<unknown>>>();\n private registeredTransportHandlers: Array<{ event: string; handler: TransportEventHandler }> = [];\n private boundMessageHandler: ((e: MessageEvent) => void) | null = null;\n\n constructor(config: ScreenConfig<TEvents> = {}) {\n this.config = config;\n this.logger = new DebugLogger(config.debug);\n\n // Validate event names in initial listeners\n if (config.listeners) {\n for (const event of Object.keys(config.listeners)) {\n validateEventName(event);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Initialization (called by factory)\n // ---------------------------------------------------------------------------\n\n async initialize(): Promise<void> {\n this.logger.lifecycle('Initializing screen...');\n\n const parentOrigin = this.config.parentOrigin ?? '*';\n const timeout = this.config.timeout ?? DEFAULT_TIMEOUT;\n\n return new Promise<void>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.cleanup();\n const error = new SmoreSDKError(\n 'TIMEOUT',\n `Screen initialization timed out after ${timeout}ms. Make sure the parent frame sends smore:init.`,\n { details: { timeout } }\n );\n this.handleError(error);\n reject(error);\n }, timeout);\n\n this.boundMessageHandler = (e: MessageEvent) => {\n if (parentOrigin !== '*' && e.origin !== parentOrigin) return;\n\n const msg = e.data;\n if (!isSmoreMessage(msg)) return;\n\n if (msg.type === 'smore:init') {\n clearTimeout(timeoutId);\n const initData = (msg as SmoreInitMessage).payload;\n\n if (initData.side !== 'host') {\n const error = new SmoreSDKError(\n 'INIT_FAILED',\n `Received init for wrong side: ${initData.side}. Expected \"host\".`,\n { details: { side: initData.side } }\n );\n this.handleError(error);\n reject(error);\n return;\n }\n\n // Initialize transport\n this.transport = new PostMessageTransport(parentOrigin);\n this._roomCode = initData.roomCode;\n this._controllers = this.mapControllersFromInit(initData.players);\n this._leaderIndex = this.findLeaderIndex(initData.players, initData.leaderId);\n\n this.setupEventHandlers();\n this._isReady = true;\n\n this.logger.lifecycle('Screen ready', {\n roomCode: this._roomCode,\n controllers: this._controllers.length,\n leaderIndex: this._leaderIndex,\n });\n\n this.config.onReady?.();\n resolve();\n } else if (msg.type === 'smore:update') {\n const updateData = (msg as SmoreUpdateMessage).payload;\n\n if (updateData.players) {\n this._controllers = this.mapControllersFromInit(updateData.players);\n }\n if (updateData.leaderId !== undefined) {\n this._leaderIndex = this.findLeaderIndex(\n updateData.players ?? [],\n updateData.leaderId\n );\n }\n\n this.logger.lifecycle('Room updated', {\n controllers: this._controllers.length,\n leaderIndex: this._leaderIndex,\n });\n }\n };\n\n window.addEventListener('message', this.boundMessageHandler);\n\n // Signal ready to parent\n window.parent.postMessage({ type: 'smore:ready' }, parentOrigin);\n this.logger.lifecycle('Sent smore:ready to parent');\n });\n }\n\n private mapControllersFromInit(players: unknown[]): ControllerInfo[] {\n return (players as Record<string, unknown>[]).map((p, index) => ({\n playerIndex: (p.playerIndex as number) ?? index,\n nickname: (p.nickname as string) || `Player ${index + 1}`,\n connected: p.connected !== false,\n appearance: p.appearance as ControllerInfo['appearance'],\n }));\n }\n\n private findLeaderIndex(players: unknown[], leaderId: string | null): PlayerIndex {\n if (!leaderId) return -1;\n const idx = (players as Record<string, unknown>[]).findIndex(\n (p) => p.sessionId === leaderId\n );\n return idx >= 0 ? idx : -1;\n }\n\n private setupEventHandlers(): void {\n if (!this.transport) return;\n\n // System events: player join/leave/reconnect\n this.registerTransportHandler(SYSTEM_EVENTS.PLAYER_JOIN, (data: unknown) => {\n const payload = data as { player?: ControllerInfo };\n const player = payload?.player;\n if (player && typeof player.playerIndex === 'number') {\n this.logger.lifecycle('Controller joined', { playerIndex: player.playerIndex });\n this.config.onControllerJoin?.(player.playerIndex, player);\n }\n });\n\n this.registerTransportHandler(SYSTEM_EVENTS.PLAYER_LEAVE, (data: unknown) => {\n const payload = data as { playerIndex?: number };\n if (typeof payload?.playerIndex === 'number') {\n this.logger.lifecycle('Controller left', { playerIndex: payload.playerIndex });\n this.config.onControllerLeave?.(payload.playerIndex);\n }\n });\n\n this.registerTransportHandler(SYSTEM_EVENTS.PLAYER_RECONNECT, (data: unknown) => {\n const payload = data as { player?: ControllerInfo };\n const player = payload?.player;\n if (player && typeof player.playerIndex === 'number') {\n this.logger.lifecycle('Controller reconnected', { playerIndex: player.playerIndex });\n this.config.onControllerReconnect?.(player.playerIndex, player);\n }\n });\n\n // Legacy room events (backward compatibility)\n this.registerTransportHandler('room:player-joined', (data: unknown) => {\n const payload = data as { player?: { playerIndex?: number }; playerIndex?: number };\n const playerIndex = payload?.player?.playerIndex ?? payload?.playerIndex;\n if (typeof playerIndex === 'number') {\n this.config.onControllerJoin?.(playerIndex, {\n playerIndex,\n nickname: `Player ${playerIndex + 1}`,\n connected: true,\n });\n }\n });\n\n this.registerTransportHandler('room:player-left', (data: unknown) => {\n const payload = data as { playerIndex?: number; player?: { playerIndex?: number } };\n const playerIndex = payload?.playerIndex ?? payload?.player?.playerIndex;\n if (typeof playerIndex === 'number') {\n this.config.onControllerLeave?.(playerIndex);\n }\n });\n\n // User event listeners from config\n if (this.config.listeners) {\n for (const [event, handler] of Object.entries(this.config.listeners)) {\n if (!handler) continue;\n this.setupUserEventHandler(event, handler as ScreenEventHandler<unknown>);\n }\n }\n }\n\n private setupUserEventHandler(event: string, handler: ScreenEventHandler<unknown>): void {\n const wrappedHandler = (data: unknown) => {\n this.logger.receive(event, data);\n const payload = data as { playerIndex?: number };\n const { playerIndex, ...rest } = payload as { playerIndex?: number; [key: string]: unknown };\n if (typeof playerIndex === 'number') {\n try {\n handler(playerIndex, rest);\n } catch (err) {\n this.handleError(\n new SmoreSDKError('UNKNOWN', `Error in handler for event \"${event}\"`, {\n cause: err instanceof Error ? err : undefined,\n details: { event, playerIndex },\n })\n );\n }\n }\n };\n\n this.registerTransportHandler(event, wrappedHandler);\n\n // Also store in eventHandlers for on/off management\n let handlers = this.eventHandlers.get(event);\n if (!handlers) {\n handlers = new Set();\n this.eventHandlers.set(event, handlers);\n }\n handlers.add(handler);\n }\n\n private registerTransportHandler(event: string, handler: TransportEventHandler): void {\n if (!this.transport) return;\n this.transport.on(event, handler);\n this.registeredTransportHandlers.push({ event, handler });\n }\n\n // ---------------------------------------------------------------------------\n // Properties (readonly)\n // ---------------------------------------------------------------------------\n\n get controllers(): readonly ControllerInfo[] {\n return [...this._controllers];\n }\n\n get roomCode(): RoomCode {\n return this._roomCode;\n }\n\n get leaderIndex(): PlayerIndex {\n return this._leaderIndex;\n }\n\n get isReady(): boolean {\n return this._isReady;\n }\n\n get isDestroyed(): boolean {\n return this._isDestroyed;\n }\n\n // ---------------------------------------------------------------------------\n // Communication Methods\n // ---------------------------------------------------------------------------\n\n broadcast<K extends EventNames<TEvents>>(event: K, data: EventData<TEvents, K>): void {\n this.ensureReady('broadcast');\n validateEventName(event);\n this.logger.send(event, data);\n this.transport!.emit(event, data);\n }\n\n broadcastRaw(event: string, data?: unknown): void {\n this.ensureReady('broadcastRaw');\n validateEventName(event);\n this.logger.send(event, data);\n this.transport!.emit(event, data);\n }\n\n sendToController<K extends EventNames<TEvents>>(\n playerIndex: PlayerIndex,\n event: K,\n data: EventData<TEvents, K>\n ): void {\n this.ensureReady('sendToController');\n validateEventName(event);\n validatePlayerIndex(playerIndex, this._controllers.length);\n this.logger.send(`${event} -> Player ${playerIndex}`, data);\n this.transport!.emit(event, {\n targetPlayerIndex: playerIndex,\n ...(data && typeof data === 'object' ? data : { data }),\n });\n }\n\n sendToControllerRaw(playerIndex: PlayerIndex, event: string, data?: unknown): void {\n this.ensureReady('sendToControllerRaw');\n validateEventName(event);\n validatePlayerIndex(playerIndex, this._controllers.length);\n this.logger.send(`${event} -> Player ${playerIndex}`, data);\n this.transport!.emit(event, {\n targetPlayerIndex: playerIndex,\n ...(data && typeof data === 'object' ? data : { data }),\n });\n }\n\n // ---------------------------------------------------------------------------\n // Game Lifecycle\n // ---------------------------------------------------------------------------\n\n gameOver(results?: GameResults): void {\n this.ensureReady('gameOver');\n this.logger.lifecycle('Game over', results);\n this.transport!.emit(SYSTEM_EVENTS.GAME_OVER, { results });\n }\n\n // ---------------------------------------------------------------------------\n // Event Subscription\n // ---------------------------------------------------------------------------\n\n on<K extends EventNames<TEvents>>(\n event: K,\n handler: ScreenEventHandler<EventData<TEvents, K>>\n ): () => void {\n validateEventName(event);\n\n let handlers = this.eventHandlers.get(event);\n if (!handlers) {\n handlers = new Set();\n this.eventHandlers.set(event, handlers);\n }\n handlers.add(handler as ScreenEventHandler<unknown>);\n\n // Also register on transport if ready\n if (this.transport) {\n const wrappedHandler = (data: unknown) => {\n this.logger.receive(event, data);\n const payload = data as { playerIndex?: number };\n const { playerIndex, ...rest } = payload as { playerIndex?: number; [key: string]: unknown };\n if (typeof playerIndex === 'number') {\n try {\n handler(playerIndex, rest as EventData<TEvents, K>);\n } catch (err) {\n this.handleError(\n new SmoreSDKError('UNKNOWN', `Error in handler for event \"${event}\"`, {\n cause: err instanceof Error ? err : undefined,\n })\n );\n }\n }\n };\n this.registerTransportHandler(event, wrappedHandler);\n }\n\n // Return unsubscribe function\n return () => {\n handlers?.delete(handler as ScreenEventHandler<unknown>);\n if (handlers?.size === 0) {\n this.eventHandlers.delete(event);\n }\n };\n }\n\n once<K extends EventNames<TEvents>>(\n event: K,\n handler: ScreenEventHandler<EventData<TEvents, K>>\n ): () => void {\n const wrappedHandler: ScreenEventHandler<EventData<TEvents, K>> = (playerIndex, data) => {\n unsubscribe();\n handler(playerIndex, data);\n };\n const unsubscribe = this.on(event, wrappedHandler);\n return unsubscribe;\n }\n\n off<K extends EventNames<TEvents>>(\n event: K,\n handler?: ScreenEventHandler<EventData<TEvents, K>>\n ): void {\n if (!handler) {\n // Remove all handlers for this event\n this.eventHandlers.delete(event);\n this.transport?.off(event);\n } else {\n const handlers = this.eventHandlers.get(event);\n handlers?.delete(handler as ScreenEventHandler<unknown>);\n if (handlers?.size === 0) {\n this.eventHandlers.delete(event);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Utilities\n // ---------------------------------------------------------------------------\n\n getController(playerIndex: PlayerIndex): ControllerInfo | undefined {\n return this._controllers.find((c) => c.playerIndex === playerIndex);\n }\n\n isLeader(playerIndex: PlayerIndex): boolean {\n return playerIndex === this._leaderIndex;\n }\n\n getControllerCount(): number {\n return this._controllers.filter((c) => c.connected).length;\n }\n\n // ---------------------------------------------------------------------------\n // Cleanup\n // ---------------------------------------------------------------------------\n\n destroy(): void {\n if (this._isDestroyed) return;\n\n this.logger.lifecycle('Destroying screen...');\n this._isDestroyed = true;\n this._isReady = false;\n\n this.cleanup();\n this.logger.lifecycle('Screen destroyed');\n }\n\n private cleanup(): void {\n // Remove all registered transport handlers\n for (const { event, handler } of this.registeredTransportHandlers) {\n this.transport?.off(event, handler);\n }\n this.registeredTransportHandlers = [];\n\n // Clear event handlers\n this.eventHandlers.clear();\n\n // Destroy transport\n if (this.transport instanceof PostMessageTransport) {\n this.transport.destroy();\n }\n this.transport = null;\n\n // Remove message listener\n if (this.boundMessageHandler) {\n window.removeEventListener('message', this.boundMessageHandler);\n this.boundMessageHandler = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Error Handling\n // ---------------------------------------------------------------------------\n\n private handleError(error: SmoreSDKError): void {\n const smoreError = error.toSmoreError();\n if (this.config.onError) {\n this.config.onError(smoreError);\n } else {\n this.logger.error(error.message, error.details);\n }\n }\n\n private ensureReady(method: string): void {\n if (this._isDestroyed) {\n throw new SmoreSDKError(\n 'DESTROYED',\n `Cannot call ${method}() after destroy()`,\n { details: { method } }\n );\n }\n if (!this._isReady || !this.transport) {\n throw new SmoreSDKError(\n 'NOT_READY',\n `Cannot call ${method}() before screen is ready. Use await createScreen() or onReady callback.`,\n { details: { method } }\n );\n }\n }\n}\n\n// =============================================================================\n// FACTORY FUNCTION\n// =============================================================================\n\n/**\n * Create a Screen instance for the host/TV side of your game.\n *\n * Returns a Promise that resolves when the screen is ready.\n * The promise also has an `instance` property for immediate access (use with onReady callback).\n *\n * @template TEvents - Event map type for type-safe events\n * @param config - Screen configuration\n * @returns Promise that resolves to the Screen instance when ready\n *\n * @example Promise-based (recommended)\n * ```ts\n * const screen = await createScreen<MyEvents>({\n * listeners: {\n * tap: (playerIndex, data) => handleTap(playerIndex, data),\n * },\n * });\n *\n * screen.broadcast('game-start', { countdown: 3 });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const { instance: screen } = createScreen<MyEvents>({\n * onReady: () => {\n * screen.broadcast('game-start', { countdown: 3 });\n * },\n * listeners: { ... },\n * });\n * ```\n */\nexport function createScreen<TEvents extends EventMap = EventMap>(\n config?: ScreenConfig<TEvents>\n): Promise<Screen<TEvents>> & { instance: Screen<TEvents> } {\n const screen = new ScreenImpl<TEvents>(config);\n\n const promise = screen.initialize().then(() => screen as Screen<TEvents>);\n\n // Attach instance for callback-based usage\n (promise as Promise<Screen<TEvents>> & { instance: Screen<TEvents> }).instance =\n screen as Screen<TEvents>;\n\n return promise as Promise<Screen<TEvents>> & { instance: Screen<TEvents> };\n}\n","/**\n * createController - Factory function for creating a Controller instance.\n *\n * Returns a Promise that resolves when the controller is ready and initialized.\n * Uses PostMessageTransport for iframe communication with parent window.\n *\n * @example Promise-based (recommended)\n * ```ts\n * const controller = await createController<MyEvents>({\n * listeners: {\n * 'phase-update': (data) => setPhase(data.phase),\n * },\n * });\n *\n * console.log(`Ready! My index: ${controller.myIndex}`);\n * controller.send('tap', { x: 100, y: 200 });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const controller = createController<MyEvents>({\n * onReady: () => {\n * console.log('Ready!');\n * },\n * listeners: { ... },\n * });\n * // Use controller.instance for immediate access\n * ```\n */\n\nimport type {\n Controller,\n ControllerConfig,\n ControllerEventHandler,\n ControllerInfo,\n DebugOptions,\n EventData,\n EventMap,\n EventNames,\n LogLevel,\n PlayerIndex,\n RoomCode,\n SmoreError,\n SmoreErrorCode,\n} from './types';\nimport { PostMessageTransport } from './transport/PostMessageTransport';\nimport type { TransportEventHandler } from './transport/types';\nimport {\n isSmoreMessage,\n type SmoreInitMessage,\n type SmoreUpdateMessage,\n} from './transport/protocol';\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst SYSTEM_PREFIX = 'smore:';\n\nconst SYSTEM_EVENTS = {\n READY: `${SYSTEM_PREFIX}ready`,\n PLAYER_JOIN: `${SYSTEM_PREFIX}player-join`,\n PLAYER_LEAVE: `${SYSTEM_PREFIX}player-leave`,\n} as const;\n\nconst DEFAULT_TIMEOUT = 10000;\n\n// =============================================================================\n// ERROR CLASS\n// =============================================================================\n\n/**\n * Custom error class for SDK errors.\n */\nexport class SmoreSDKError extends Error {\n readonly code: SmoreErrorCode;\n readonly cause?: Error;\n readonly details?: Record<string, unknown>;\n\n constructor(\n code: SmoreErrorCode,\n message: string,\n options?: {\n cause?: Error;\n details?: Record<string, unknown>;\n },\n ) {\n super(message);\n this.name = 'SmoreSDKError';\n this.code = code;\n this.cause = options?.cause;\n this.details = options?.details;\n\n // Maintain proper stack trace in V8 engines\n const ErrorWithCapture = Error as typeof Error & {\n captureStackTrace?: (target: object, constructor?: Function) => void;\n };\n if (typeof ErrorWithCapture.captureStackTrace === 'function') {\n ErrorWithCapture.captureStackTrace(this, SmoreSDKError);\n }\n }\n\n toSmoreError(): SmoreError {\n return {\n code: this.code,\n message: this.message,\n cause: this.cause,\n details: this.details,\n };\n }\n}\n\n// =============================================================================\n// VALIDATION\n// =============================================================================\n\nconst EVENT_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;\n\nfunction validateEventName(event: string): void {\n if (!event || typeof event !== 'string') {\n throw new SmoreSDKError('INVALID_EVENT', 'Event name must be a non-empty string');\n }\n if (!EVENT_NAME_REGEX.test(event)) {\n throw new SmoreSDKError(\n 'INVALID_EVENT',\n `Invalid event name \"${event}\". Event names must:\\n` +\n ` - Start with a letter (a-z, A-Z)\\n` +\n ` - Only contain letters, numbers, hyphens (-), and underscores (_)\\n` +\n ` - End with a letter or number`,\n { details: { event } },\n );\n }\n}\n\n// =============================================================================\n// DEBUG LOGGER\n// =============================================================================\n\ninterface Logger {\n debug(message: string, data?: unknown): void;\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n}\n\nfunction createLogger(options: boolean | DebugOptions | undefined): Logger {\n const enabled = typeof options === 'boolean' ? options : options?.enabled ?? false;\n const level = (typeof options === 'object' ? options.level : undefined) ?? 'debug';\n const prefix = (typeof options === 'object' ? options.prefix : undefined) ?? '[SmoreController]';\n const customLogger = typeof options === 'object' ? options.logger : undefined;\n\n const levelPriority: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n const shouldLog = (msgLevel: LogLevel): boolean => {\n if (!enabled) return false;\n return levelPriority[msgLevel] >= levelPriority[level];\n };\n\n const log = (msgLevel: LogLevel, message: string, data?: unknown): void => {\n if (!shouldLog(msgLevel)) return;\n\n if (customLogger) {\n customLogger(msgLevel, message, data);\n return;\n }\n\n const fullMessage = `${prefix} ${message}`;\n const consoleFn = console[msgLevel] ?? console.log;\n\n if (data !== undefined) {\n consoleFn(fullMessage, data);\n } else {\n consoleFn(fullMessage);\n }\n };\n\n return {\n debug: (msg, data) => log('debug', msg, data),\n info: (msg, data) => log('info', msg, data),\n warn: (msg, data) => log('warn', msg, data),\n error: (msg, data) => log('error', msg, data),\n };\n}\n\n// =============================================================================\n// CONTROLLER IMPLEMENTATION\n// =============================================================================\n\nclass ControllerImpl<TEvents extends EventMap> implements Controller<TEvents> {\n private transport: PostMessageTransport | null = null;\n private config: ControllerConfig<TEvents>;\n private logger: Logger;\n private _roomCode: RoomCode = '';\n private _myIndex: PlayerIndex = -1;\n private _isLeader: boolean = false;\n private _isReady: boolean = false;\n private _isDestroyed: boolean = false;\n private boundMessageHandler: ((e: MessageEvent) => void) | null = null;\n private registeredHandlers: Array<{ event: string; handler: TransportEventHandler }> = [];\n private eventListeners = new Map<string, Set<ControllerEventHandler<unknown>>>();\n\n constructor(config: ControllerConfig<TEvents> = {}) {\n this.config = config;\n this.logger = createLogger(config.debug);\n\n // Validate event names in listeners\n if (config.listeners) {\n for (const event of Object.keys(config.listeners)) {\n validateEventName(event);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Properties (readonly)\n // ---------------------------------------------------------------------------\n\n get myIndex(): PlayerIndex {\n return this._myIndex;\n }\n\n get isLeader(): boolean {\n return this._isLeader;\n }\n\n get roomCode(): RoomCode {\n return this._roomCode;\n }\n\n get isReady(): boolean {\n return this._isReady;\n }\n\n get isDestroyed(): boolean {\n return this._isDestroyed;\n }\n\n // ---------------------------------------------------------------------------\n // Initialization\n // ---------------------------------------------------------------------------\n\n async initialize(): Promise<void> {\n const parentOrigin = this.config.parentOrigin ?? '*';\n const timeout = this.config.timeout ?? DEFAULT_TIMEOUT;\n\n this.logger.debug('Initializing controller...', { parentOrigin, timeout });\n\n return new Promise<void>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.cleanup();\n const error = new SmoreSDKError(\n 'TIMEOUT',\n `Controller initialization timed out after ${timeout}ms. ` +\n `Make sure the parent window sends smore:init message.`,\n { details: { timeout } },\n );\n this.handleError(error);\n reject(error);\n }, timeout);\n\n // Listen for init message from parent\n this.boundMessageHandler = (e: MessageEvent) => {\n if (parentOrigin !== '*' && e.origin !== parentOrigin) return;\n\n const msg = e.data;\n if (!isSmoreMessage(msg)) return;\n\n if (msg.type === 'smore:init') {\n clearTimeout(timeoutId);\n this.handleInit(msg as SmoreInitMessage, parentOrigin, resolve, reject);\n } else if (msg.type === 'smore:update') {\n this.handleUpdate(msg as SmoreUpdateMessage);\n }\n };\n\n window.addEventListener('message', this.boundMessageHandler);\n\n // Signal ready to parent\n this.logger.debug('Sending smore:ready to parent');\n window.parent.postMessage({ type: 'smore:ready' }, parentOrigin);\n });\n }\n\n private handleInit(\n msg: SmoreInitMessage,\n parentOrigin: string,\n resolve: () => void,\n reject: (err: Error) => void,\n ): void {\n const initData = msg.payload;\n\n this.logger.debug('Received smore:init', initData);\n\n if (initData.side !== 'player') {\n const error = new SmoreSDKError(\n 'INIT_FAILED',\n `Controller received init for wrong side: ${initData.side}`,\n { details: { side: initData.side } },\n );\n this.handleError(error);\n reject(error);\n return;\n }\n\n if (initData.myIndex === undefined) {\n const error = new SmoreSDKError(\n 'INIT_FAILED',\n 'Missing myIndex in init payload',\n { details: initData },\n );\n this.handleError(error);\n reject(error);\n return;\n }\n\n // Initialize transport\n this.transport = new PostMessageTransport(parentOrigin);\n this._roomCode = initData.roomCode;\n this._myIndex = initData.myIndex;\n this._isLeader = initData.isLeader ?? false;\n\n this.setupEventHandlers();\n\n this._isReady = true;\n this.logger.info('Controller ready', {\n roomCode: this._roomCode,\n myIndex: this._myIndex,\n isLeader: this._isLeader,\n });\n\n this.config.onReady?.();\n resolve();\n }\n\n private handleUpdate(msg: SmoreUpdateMessage): void {\n const updateData = msg.payload;\n this.logger.debug('Received smore:update', updateData);\n\n // Future: handle leader changes, player list updates, etc.\n }\n\n private setupEventHandlers(): void {\n if (!this.transport) return;\n\n // System events: player join/leave\n this.registerHandler(\n SYSTEM_EVENTS.PLAYER_JOIN,\n (data: { player?: ControllerInfo; playerIndex?: number }) => {\n const playerIndex = data.player?.playerIndex ?? data.playerIndex;\n if (playerIndex !== undefined) {\n this.logger.debug('Player joined', { playerIndex });\n this.config.onControllerJoin?.(playerIndex, data.player as ControllerInfo);\n }\n },\n );\n\n this.registerHandler(\n SYSTEM_EVENTS.PLAYER_LEAVE,\n (data: { player?: { playerIndex?: number }; playerIndex?: number }) => {\n const playerIndex = data.player?.playerIndex ?? data.playerIndex;\n if (playerIndex !== undefined) {\n this.logger.debug('Player left', { playerIndex });\n this.config.onControllerLeave?.(playerIndex);\n }\n },\n );\n\n // User event listeners from config\n if (this.config.listeners) {\n for (const [event, handler] of Object.entries(this.config.listeners)) {\n if (!handler) continue;\n\n this.registerHandler(event, (data: unknown) => {\n this.logReceive(event, data);\n (handler as ControllerEventHandler<unknown>)(data);\n });\n }\n }\n }\n\n private registerHandler(event: string, handler: TransportEventHandler): void {\n if (!this.transport) return;\n this.transport.on(event, handler);\n this.registeredHandlers.push({ event, handler });\n }\n\n // ---------------------------------------------------------------------------\n // Communication Methods\n // ---------------------------------------------------------------------------\n\n send<K extends EventNames<TEvents>>(event: K, data: EventData<TEvents, K>): void {\n this.ensureReady('send');\n validateEventName(event);\n\n this.logSend(event, data);\n this.transport!.emit(event, data);\n }\n\n sendRaw(event: string, data?: unknown): void {\n this.ensureReady('sendRaw');\n validateEventName(event);\n\n this.logSend(event, data);\n this.transport!.emit(event, data);\n }\n\n // ---------------------------------------------------------------------------\n // Event Subscription\n // ---------------------------------------------------------------------------\n\n on<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n validateEventName(event);\n\n // Add to local listeners map\n let listeners = this.eventListeners.get(event);\n if (!listeners) {\n listeners = new Set();\n this.eventListeners.set(event, listeners);\n }\n listeners.add(handler as ControllerEventHandler<unknown>);\n\n // Register with transport if ready\n const transportHandler: TransportEventHandler = (data: unknown) => {\n this.logReceive(event, data);\n (handler as ControllerEventHandler<unknown>)(data);\n };\n\n if (this.transport) {\n this.transport.on(event, transportHandler);\n this.registeredHandlers.push({ event, handler: transportHandler });\n }\n\n // Return unsubscribe function\n return () => {\n listeners?.delete(handler as ControllerEventHandler<unknown>);\n if (listeners?.size === 0) {\n this.eventListeners.delete(event);\n }\n this.transport?.off(event, transportHandler);\n this.registeredHandlers = this.registeredHandlers.filter(\n (h) => h.handler !== transportHandler,\n );\n };\n }\n\n once<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n const unsubscribe = this.on(event, ((data: EventData<TEvents, K>) => {\n unsubscribe();\n handler(data);\n }) as ControllerEventHandler<EventData<TEvents, K>>);\n return unsubscribe;\n }\n\n off<K extends EventNames<TEvents>>(\n event: K,\n handler?: ControllerEventHandler<EventData<TEvents, K>>,\n ): void {\n if (!handler) {\n // Remove all listeners for this event\n this.eventListeners.delete(event);\n this.transport?.off(event);\n this.registeredHandlers = this.registeredHandlers.filter((h) => h.event !== event);\n } else {\n // Remove specific handler\n const listeners = this.eventListeners.get(event);\n listeners?.delete(handler as ControllerEventHandler<unknown>);\n if (listeners?.size === 0) {\n this.eventListeners.delete(event);\n }\n // Note: Can't easily remove specific handler from transport without tracking\n // This is a limitation of the current transport interface\n }\n }\n\n // ---------------------------------------------------------------------------\n // Cleanup\n // ---------------------------------------------------------------------------\n\n destroy(): void {\n if (this._isDestroyed) return;\n\n this.logger.info('Destroying controller');\n this.cleanup();\n this._isDestroyed = true;\n }\n\n private cleanup(): void {\n this._isReady = false;\n\n // Remove all registered handlers\n for (const { event, handler } of this.registeredHandlers) {\n this.transport?.off(event, handler);\n }\n this.registeredHandlers = [];\n\n // Clear event listeners\n this.eventListeners.clear();\n\n // Destroy transport\n if (this.transport) {\n this.transport.destroy();\n this.transport = null;\n }\n\n // Remove message listener\n if (this.boundMessageHandler) {\n window.removeEventListener('message', this.boundMessageHandler);\n this.boundMessageHandler = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private Helpers\n // ---------------------------------------------------------------------------\n\n private ensureReady(method: string): void {\n if (this._isDestroyed) {\n throw new SmoreSDKError(\n 'DESTROYED',\n `Cannot call ${method}() after destroy()`,\n { details: { method } },\n );\n }\n if (!this._isReady || !this.transport) {\n throw new SmoreSDKError(\n 'NOT_READY',\n `Cannot call ${method}() before controller is ready. ` +\n `Use await createController() or wait for onReady callback.`,\n { details: { method, isReady: this._isReady } },\n );\n }\n }\n\n private handleError(error: SmoreSDKError): void {\n if (this.config.onError) {\n this.config.onError(error.toSmoreError());\n } else {\n this.logger.error(error.message, error.details);\n }\n }\n\n private logSend(event: string, data?: unknown): void {\n const options = this.config.debug;\n const shouldLog =\n typeof options === 'object' ? (options.logSend ?? true) : Boolean(options);\n if (shouldLog) {\n this.logger.debug(`→ SEND [${event}]`, data);\n }\n }\n\n private logReceive(event: string, data?: unknown): void {\n const options = this.config.debug;\n const shouldLog =\n typeof options === 'object' ? (options.logReceive ?? true) : Boolean(options);\n if (shouldLog) {\n this.logger.debug(`← RECV [${event}]`, data);\n }\n }\n}\n\n// =============================================================================\n// FACTORY FUNCTION\n// =============================================================================\n\n/**\n * Create a Controller instance for the player/phone side of your game.\n *\n * Returns a Promise that resolves when the controller is ready.\n * The returned object also has an `instance` property for immediate access.\n *\n * @template TEvents - Event map type for type-safe events\n * @param config - Controller configuration\n * @returns Promise that resolves to the Controller instance when ready\n *\n * @example Promise-based (recommended)\n * ```ts\n * const controller = await createController<MyEvents>({\n * listeners: {\n * 'phase-update': (data) => setPhase(data.phase),\n * },\n * });\n *\n * controller.send('tap', { x: 100, y: 200 });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const result = createController<MyEvents>({\n * onReady: () => {\n * result.instance.send('ready', {});\n * },\n * listeners: { ... },\n * });\n * ```\n */\nexport function createController<TEvents extends EventMap = EventMap>(\n config?: ControllerConfig<TEvents>,\n): Promise<Controller<TEvents>> & { instance: Controller<TEvents> } {\n const controller = new ControllerImpl<TEvents>(config ?? {});\n\n const promise = controller.initialize().then(() => controller as Controller<TEvents>);\n\n // Attach instance property for immediate access\n (promise as Promise<Controller<TEvents>> & { instance: Controller<TEvents> }).instance =\n controller;\n\n return promise as Promise<Controller<TEvents>> & { instance: Controller<TEvents> };\n}\n","/**\n * DirectTransport - Wraps a Socket.IO socket as a Transport.\n * Used by bundled (internal) games. Behaviour is identical to using socket directly.\n */\n\nimport type { Socket } from 'socket.io-client';\nimport type { Transport, TransportEventHandler } from './types';\n\nexport class DirectTransport implements Transport {\n constructor(private socket: Socket) {}\n\n emit(event: string, ...args: any[]): void {\n this.socket.emit(event, ...args);\n }\n\n on(event: string, handler: TransportEventHandler): void {\n this.socket.on(event, handler);\n }\n\n off(event: string, handler?: TransportEventHandler): void {\n if (handler) {\n this.socket.off(event, handler);\n } else {\n this.socket.off(event);\n }\n }\n}\n","/**\n * SDK 시스템 이벤트 상수\n * 모든 시스템 이벤트는 'smore:' prefix 사용\n * 유저 이벤트는 ':' 사용 불가\n */\n\nexport const SMORE_EVENTS = {\n // 게임 lifecycle\n READY: 'smore:ready',\n GAME_OVER: 'smore:game-over',\n RETURN_TO_LOBBY: 'smore:return-to-lobby',\n\n // 플레이어 관리\n PLAYER_JOIN: 'smore:player-join',\n PLAYER_LEAVE: 'smore:player-leave',\n\n // 특정 플레이어에게 전송 (내부용)\n SEND_TO_PLAYER: 'smore:send-to-player',\n\n // 초기화\n INIT: 'smore:init',\n UPDATE: 'smore:update',\n} as const;\n\nexport type SmoreEvent = typeof SMORE_EVENTS[keyof typeof SMORE_EVENTS];\n\n/**\n * 유저 이벤트명 검증\n * ':' 포함 시 에러, '_'와 '-'는 허용\n */\nexport function validateUserEvent(event: string): void {\n if (event.includes(':')) {\n throw new Error(\n `Invalid event name \"${event}\": User events cannot contain ':'. ` +\n `Use '_' or '-' instead. System events use 'smore:' prefix.`\n );\n }\n}\n\n/**\n * 시스템 이벤트인지 확인\n */\nexport function isSystemEvent(event: string): boolean {\n return event.startsWith('smore:');\n}\n","/**\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 * @packageDocumentation\n */\n\nimport type {\n EventMap,\n EventNames,\n EventData,\n ControllerInfo,\n PlayerIndex,\n GameResults,\n ScreenEventHandler,\n ControllerEventHandler,\n MockScreen,\n MockController,\n MockOptions,\n} from './types';\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 * @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 * // 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 let _leaderIndex: PlayerIndex = initialControllers[0]?.playerIndex ?? -1;\n\n // Event listeners\n const listeners = new Map<string, Set<ScreenEventHandler>>();\n\n // Lifecycle callbacks\n let onReadyCallback: (() => void) | undefined;\n let onControllerJoinCallback:\n | ((index: PlayerIndex, info: ControllerInfo) => void)\n | undefined;\n let onControllerLeaveCallback: ((index: PlayerIndex) => void) | undefined;\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 leaderIndex() {\n return _leaderIndex;\n },\n get isReady() {\n return _isReady;\n },\n get isDestroyed() {\n return _isDestroyed;\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 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 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 (!_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 (!_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 screen.broadcastRaw('game-over', results);\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 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 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 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 isLeader(playerIndex: PlayerIndex): boolean {\n return playerIndex === _leaderIndex;\n },\n\n getControllerCount(): number {\n return _controllers.length;\n },\n\n // === Cleanup ===\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 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 if (_leaderIndex === -1) {\n _leaderIndex = info.playerIndex;\n }\n if (onControllerJoinCallback) {\n onControllerJoinCallback(info.playerIndex, info);\n }\n },\n\n simulateControllerLeave(playerIndex: PlayerIndex): void {\n _controllers = _controllers.filter((c) => c.playerIndex !== playerIndex);\n if (_leaderIndex === playerIndex) {\n _leaderIndex = _controllers[0]?.playerIndex ?? -1;\n }\n if (onControllerLeaveCallback) {\n onControllerLeaveCallback(playerIndex);\n }\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 if (onReadyCallback) {\n onReadyCallback();\n }\n },\n };\n\n // Auto-trigger ready if enabled\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 * @example\n * ```ts\n * const controller = createMockController<MyEvents>({\n * myIndex: 0,\n * isLeader: true,\n * });\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 isLeader: initialIsLeader = false,\n autoReady = true,\n } = options;\n\n // Internal state\n let _isReady = false;\n let _isDestroyed = false;\n let _isLeader = initialIsLeader;\n\n // Event listeners\n const listeners = new Map<string, Set<ControllerEventHandler>>();\n\n // Lifecycle callbacks\n let onReadyCallback: (() => void) | undefined;\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 isLeader() {\n return _isLeader;\n },\n get roomCode() {\n return roomCode;\n },\n get isReady() {\n return _isReady;\n },\n get isDestroyed() {\n return _isDestroyed;\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 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 sentEvents.push({ event, data });\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 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 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 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 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 if (onReadyCallback) {\n onReadyCallback();\n }\n },\n\n setLeader(isLeader: boolean): void {\n _isLeader = isLeader;\n },\n };\n\n // Auto-trigger ready if enabled\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":["SYSTEM_PREFIX","SYSTEM_EVENTS","DEFAULT_TIMEOUT","EVENT_NAME_REGEX","validateEventName","SmoreSDKError"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).SmoreSDK={})}(this,function(e){"use strict";function t(e){return e&&"object"==typeof e&&"string"==typeof e.type&&e.type.startsWith("smore:")}class r{handlers=new Map;ackCallbacks=new Map;ackCounter=0;parentOrigin;boundMessageHandler;constructor(e="*"){this.parentOrigin=e,this.boundMessageHandler=this.handleMessage.bind(this),window.addEventListener("message",this.boundMessageHandler)}emit(e,...t){let r,n=t[0];if(t.length>=2&&"function"==typeof t[t.length-1]){t.length,n=t[0];const e=t[t.length-1];r="ack_"+ ++this.ackCounter,this.ackCallbacks.set(r,e)}window.parent.postMessage({type:"smore:emit",payload:{event:e,data:n,ackId:r}},this.parentOrigin)}on(e,t){let r=this.handlers.get(e);r||(r=new Set,this.handlers.set(e,r)),r.add(t)}off(e,t){t?this.handlers.get(e)?.delete(t):this.handlers.delete(e)}destroy(){window.removeEventListener("message",this.boundMessageHandler),this.handlers.clear(),this.ackCallbacks.clear()}handleMessage(e){if("*"!==this.parentOrigin&&e.origin!==this.parentOrigin)return;const r=e.data;if(t(r))if("smore:event"===r.type){const{event:e,data:t}=r.payload,n=this.handlers.get(e);n&&n.forEach(e=>e(t))}else if("smore:ack"===r.type){const{ackId:e,data:t}=r.payload,n=this.ackCallbacks.get(e);n&&(this.ackCallbacks.delete(e),n(t))}}}const n="smore:",s={PLAYER_JOIN:`${n}player-join`,PLAYER_LEAVE:`${n}player-leave`,PLAYER_RECONNECT:`${n}player-reconnect`,GAME_OVER:`${n}game-over`};let o=class e extends Error{code;cause;details;constructor(t,r,n){super(r),this.name="SmoreSDKError",this.code=t,this.cause=n?.cause,this.details=n?.details;const s=Error;"function"==typeof s.captureStackTrace&&s.captureStackTrace(this,e)}toSmoreError(){return{code:this.code,message:this.message,cause:this.cause,details:this.details}}};const i=/^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;function a(e){if(!e||"string"!=typeof e)throw new o("INVALID_EVENT","Event name must be a non-empty string");if(!i.test(e))throw new o("INVALID_EVENT",`Invalid event name "${e}". Event names must start with a letter, contain only letters, numbers, hyphens, or underscores, and end with a letter or number.`,{details:{event:e}})}function l(e,t){if("number"!=typeof e||!Number.isInteger(e))throw new o("INVALID_PLAYER","Player index must be an integer");if(e<0||e>=t)throw new o("INVALID_PLAYER",`Invalid player index ${e}. Valid range: 0-${t-1}`,{details:{playerIndex:e,controllersCount:t}})}class d{enabled;level;prefix;logSend;logReceive;logLifecycle;customLogger;static levelOrder={debug:0,info:1,warn:2,error:3};constructor(e){"boolean"==typeof e?(this.enabled=e,this.level="debug",this.prefix="[SmoreScreen]",this.logSend=!0,this.logReceive=!0,this.logLifecycle=!0):e?(this.enabled=e.enabled??!1,this.level=e.level??"debug",this.prefix=e.prefix??"[SmoreScreen]",this.logSend=e.logSend??!0,this.logReceive=e.logReceive??!0,this.logLifecycle=e.logLifecycle??!0,this.customLogger=e.logger):(this.enabled=!1,this.level="debug",this.prefix="[SmoreScreen]",this.logSend=!0,this.logReceive=!0,this.logLifecycle=!0)}shouldLog(e){return this.enabled&&d.levelOrder[e]>=d.levelOrder[this.level]}log(e,t,r){if(!this.shouldLog(e))return;if(this.customLogger)return void this.customLogger(e,`${this.prefix} ${t}`,r);const n="error"===e?"error":"warn"===e?"warn":"log";void 0!==r?console[n](`${this.prefix} ${t}`,r):console[n](`${this.prefix} ${t}`)}debug(e,t){this.log("debug",e,t)}info(e,t){this.log("info",e,t)}warn(e,t){this.log("warn",e,t)}error(e,t){this.log("error",e,t)}send(e,t){this.logSend&&this.debug(`-> SEND: ${e}`,t)}receive(e,t){this.logReceive&&this.debug(`<- RECV: ${e}`,t)}lifecycle(e,t){this.logLifecycle&&this.info(`[Lifecycle] ${e}`,t)}}class h{transport=null;config;logger;_controllers=[];_roomCode="";_leaderIndex=-1;_isReady=!1;_isDestroyed=!1;eventHandlers=new Map;registeredTransportHandlers=[];boundMessageHandler=null;constructor(e={}){if(this.config=e,this.logger=new d(e.debug),e.listeners)for(const t of Object.keys(e.listeners))a(t)}async initialize(){this.logger.lifecycle("Initializing screen...");const e=this.config.parentOrigin??"*",n=this.config.timeout??1e4;return new Promise((s,i)=>{const a=setTimeout(()=>{this.cleanup();const e=new o("TIMEOUT",`Screen initialization timed out after ${n}ms. Make sure the parent frame sends smore:init.`,{details:{timeout:n}});this.handleError(e),i(e)},n);this.boundMessageHandler=n=>{if("*"!==e&&n.origin!==e)return;const l=n.data;if(t(l))if("smore:init"===l.type){clearTimeout(a);const t=l.payload;if("host"!==t.side){const e=new o("INIT_FAILED",`Received init for wrong side: ${t.side}. Expected "host".`,{details:{side:t.side}});return this.handleError(e),void i(e)}this.transport=new r(e),this._roomCode=t.roomCode,this._controllers=this.mapControllersFromInit(t.players),this._leaderIndex=this.findLeaderIndex(t.players,t.leaderId),this.setupEventHandlers(),this._isReady=!0,this.logger.lifecycle("Screen ready",{roomCode:this._roomCode,controllers:this._controllers.length,leaderIndex:this._leaderIndex}),this.config.onReady?.(),s()}else if("smore:update"===l.type){const e=l.payload;e.players&&(this._controllers=this.mapControllersFromInit(e.players)),void 0!==e.leaderId&&(this._leaderIndex=this.findLeaderIndex(e.players??[],e.leaderId)),this.logger.lifecycle("Room updated",{controllers:this._controllers.length,leaderIndex:this._leaderIndex})}},window.addEventListener("message",this.boundMessageHandler),window.parent.postMessage({type:"smore:ready"},e),this.logger.lifecycle("Sent smore:ready to parent")})}mapControllersFromInit(e){return e.map((e,t)=>({playerIndex:e.playerIndex??t,nickname:e.nickname||`Player ${t+1}`,connected:!1!==e.connected,appearance:e.appearance}))}findLeaderIndex(e,t){if(!t)return-1;const r=e.findIndex(e=>e.sessionId===t);return r>=0?r:-1}setupEventHandlers(){if(this.transport&&(this.registerTransportHandler(s.PLAYER_JOIN,e=>{const t=e,r=t?.player;r&&"number"==typeof r.playerIndex&&(this.logger.lifecycle("Controller joined",{playerIndex:r.playerIndex}),this.config.onControllerJoin?.(r.playerIndex,r))}),this.registerTransportHandler(s.PLAYER_LEAVE,e=>{const t=e;"number"==typeof t?.playerIndex&&(this.logger.lifecycle("Controller left",{playerIndex:t.playerIndex}),this.config.onControllerLeave?.(t.playerIndex))}),this.registerTransportHandler(s.PLAYER_RECONNECT,e=>{const t=e,r=t?.player;r&&"number"==typeof r.playerIndex&&(this.logger.lifecycle("Controller reconnected",{playerIndex:r.playerIndex}),this.config.onControllerReconnect?.(r.playerIndex,r))}),this.registerTransportHandler("room:player-joined",e=>{const t=e,r=t?.player?.playerIndex??t?.playerIndex;"number"==typeof r&&this.config.onControllerJoin?.(r,{playerIndex:r,nickname:`Player ${r+1}`,connected:!0})}),this.registerTransportHandler("room:player-left",e=>{const t=e,r=t?.playerIndex??t?.player?.playerIndex;"number"==typeof r&&this.config.onControllerLeave?.(r)}),this.config.listeners))for(const[e,t]of Object.entries(this.config.listeners))t&&this.setupUserEventHandler(e,t)}setupUserEventHandler(e,t){this.registerTransportHandler(e,r=>{this.logger.receive(e,r);const n=r,{playerIndex:s,...i}=n;if("number"==typeof s)try{t(s,i)}catch(t){this.handleError(new o("UNKNOWN",`Error in handler for event "${e}"`,{cause:t instanceof Error?t:void 0,details:{event:e,playerIndex:s}}))}});let r=this.eventHandlers.get(e);r||(r=new Set,this.eventHandlers.set(e,r)),r.add(t)}registerTransportHandler(e,t){this.transport&&(this.transport.on(e,t),this.registeredTransportHandlers.push({event:e,handler:t}))}get controllers(){return[...this._controllers]}get roomCode(){return this._roomCode}get leaderIndex(){return this._leaderIndex}get isReady(){return this._isReady}get isDestroyed(){return this._isDestroyed}broadcast(e,t){this.ensureReady("broadcast"),a(e),this.logger.send(e,t),this.transport.emit(e,t)}broadcastRaw(e,t){this.ensureReady("broadcastRaw"),a(e),this.logger.send(e,t),this.transport.emit(e,t)}sendToController(e,t,r){this.ensureReady("sendToController"),a(t),l(e,this._controllers.length),this.logger.send(`${t} -> Player ${e}`,r),this.transport.emit(t,{targetPlayerIndex:e,...r&&"object"==typeof r?r:{data:r}})}sendToControllerRaw(e,t,r){this.ensureReady("sendToControllerRaw"),a(t),l(e,this._controllers.length),this.logger.send(`${t} -> Player ${e}`,r),this.transport.emit(t,{targetPlayerIndex:e,...r&&"object"==typeof r?r:{data:r}})}gameOver(e){this.ensureReady("gameOver"),this.logger.lifecycle("Game over",e),this.transport.emit(s.GAME_OVER,{results:e})}on(e,t){a(e);let r=this.eventHandlers.get(e);if(r||(r=new Set,this.eventHandlers.set(e,r)),r.add(t),this.transport){const r=r=>{this.logger.receive(e,r);const n=r,{playerIndex:s,...i}=n;if("number"==typeof s)try{t(s,i)}catch(t){this.handleError(new o("UNKNOWN",`Error in handler for event "${e}"`,{cause:t instanceof Error?t:void 0}))}};this.registerTransportHandler(e,r)}return()=>{r?.delete(t),0===r?.size&&this.eventHandlers.delete(e)}}once(e,t){const r=this.on(e,(e,n)=>{r(),t(e,n)});return r}off(e,t){if(t){const r=this.eventHandlers.get(e);r?.delete(t),0===r?.size&&this.eventHandlers.delete(e)}else this.eventHandlers.delete(e),this.transport?.off(e)}getController(e){return this._controllers.find(t=>t.playerIndex===e)}isLeader(e){return e===this._leaderIndex}getControllerCount(){return this._controllers.filter(e=>e.connected).length}destroy(){this._isDestroyed||(this.logger.lifecycle("Destroying screen..."),this._isDestroyed=!0,this._isReady=!1,this.cleanup(),this.logger.lifecycle("Screen destroyed"))}cleanup(){for(const{event:e,handler:t}of this.registeredTransportHandlers)this.transport?.off(e,t);this.registeredTransportHandlers=[],this.eventHandlers.clear(),this.transport instanceof r&&this.transport.destroy(),this.transport=null,this.boundMessageHandler&&(window.removeEventListener("message",this.boundMessageHandler),this.boundMessageHandler=null)}handleError(e){const t=e.toSmoreError();this.config.onError?this.config.onError(t):this.logger.error(e.message,e.details)}ensureReady(e){if(this._isDestroyed)throw new o("DESTROYED",`Cannot call ${e}() after destroy()`,{details:{method:e}});if(!this._isReady||!this.transport)throw new o("NOT_READY",`Cannot call ${e}() before screen is ready. Use await createScreen() or onReady callback.`,{details:{method:e}})}}const c="smore:",g={PLAYER_JOIN:`${c}player-join`,PLAYER_LEAVE:`${c}player-leave`};class p extends Error{code;cause;details;constructor(e,t,r){super(t),this.name="SmoreSDKError",this.code=e,this.cause=r?.cause,this.details=r?.details;const n=Error;"function"==typeof n.captureStackTrace&&n.captureStackTrace(this,p)}toSmoreError(){return{code:this.code,message:this.message,cause:this.cause,details:this.details}}}const u=/^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;function y(e){if(!e||"string"!=typeof e)throw new p("INVALID_EVENT","Event name must be a non-empty string");if(!u.test(e))throw new p("INVALID_EVENT",`Invalid event name "${e}". Event names must:\n - Start with a letter (a-z, A-Z)\n - Only contain letters, numbers, hyphens (-), and underscores (_)\n - End with a letter or number`,{details:{event:e}})}function f(e){const t="boolean"==typeof e?e:e?.enabled??!1,r=("object"==typeof e?e.level:void 0)??"debug",n=("object"==typeof e?e.prefix:void 0)??"[SmoreController]",s="object"==typeof e?e.logger:void 0,o={debug:0,info:1,warn:2,error:3},i=(e,i,a)=>{if(!(e=>!!t&&o[e]>=o[r])(e))return;if(s)return void s(e,i,a);const l=`${n} ${i}`,d=console[e]??console.log;void 0!==a?d(l,a):d(l)};return{debug:(e,t)=>i("debug",e,t),info:(e,t)=>i("info",e,t),warn:(e,t)=>i("warn",e,t),error:(e,t)=>i("error",e,t)}}class m{transport=null;config;logger;_roomCode="";_myIndex=-1;_isLeader=!1;_isReady=!1;_isDestroyed=!1;boundMessageHandler=null;registeredHandlers=[];eventListeners=new Map;constructor(e={}){if(this.config=e,this.logger=f(e.debug),e.listeners)for(const t of Object.keys(e.listeners))y(t)}get myIndex(){return this._myIndex}get isLeader(){return this._isLeader}get roomCode(){return this._roomCode}get isReady(){return this._isReady}get isDestroyed(){return this._isDestroyed}async initialize(){const e=this.config.parentOrigin??"*",r=this.config.timeout??1e4;return this.logger.debug("Initializing controller...",{parentOrigin:e,timeout:r}),new Promise((n,s)=>{const o=setTimeout(()=>{this.cleanup();const e=new p("TIMEOUT",`Controller initialization timed out after ${r}ms. Make sure the parent window sends smore:init message.`,{details:{timeout:r}});this.handleError(e),s(e)},r);this.boundMessageHandler=r=>{if("*"!==e&&r.origin!==e)return;const i=r.data;t(i)&&("smore:init"===i.type?(clearTimeout(o),this.handleInit(i,e,n,s)):"smore:update"===i.type&&this.handleUpdate(i))},window.addEventListener("message",this.boundMessageHandler),this.logger.debug("Sending smore:ready to parent"),window.parent.postMessage({type:"smore:ready"},e)})}handleInit(e,t,n,s){const o=e.payload;if(this.logger.debug("Received smore:init",o),"player"!==o.side){const e=new p("INIT_FAILED",`Controller received init for wrong side: ${o.side}`,{details:{side:o.side}});return this.handleError(e),void s(e)}if(void 0===o.myIndex){const e=new p("INIT_FAILED","Missing myIndex in init payload",{details:o});return this.handleError(e),void s(e)}this.transport=new r(t),this._roomCode=o.roomCode,this._myIndex=o.myIndex,this._isLeader=o.isLeader??!1,this.setupEventHandlers(),this._isReady=!0,this.logger.info("Controller ready",{roomCode:this._roomCode,myIndex:this._myIndex,isLeader:this._isLeader}),this.config.onReady?.(),n()}handleUpdate(e){const t=e.payload;this.logger.debug("Received smore:update",t)}setupEventHandlers(){if(this.transport&&(this.registerHandler(g.PLAYER_JOIN,e=>{const t=e.player?.playerIndex??e.playerIndex;void 0!==t&&(this.logger.debug("Player joined",{playerIndex:t}),this.config.onControllerJoin?.(t,e.player))}),this.registerHandler(g.PLAYER_LEAVE,e=>{const t=e.player?.playerIndex??e.playerIndex;void 0!==t&&(this.logger.debug("Player left",{playerIndex:t}),this.config.onControllerLeave?.(t))}),this.config.listeners))for(const[e,t]of Object.entries(this.config.listeners))t&&this.registerHandler(e,r=>{this.logReceive(e,r),t(r)})}registerHandler(e,t){this.transport&&(this.transport.on(e,t),this.registeredHandlers.push({event:e,handler:t}))}send(e,t){this.ensureReady("send"),y(e),this.logSend(e,t),this.transport.emit(e,t)}sendRaw(e,t){this.ensureReady("sendRaw"),y(e),this.logSend(e,t),this.transport.emit(e,t)}on(e,t){y(e);let r=this.eventListeners.get(e);r||(r=new Set,this.eventListeners.set(e,r)),r.add(t);const n=r=>{this.logReceive(e,r),t(r)};return this.transport&&(this.transport.on(e,n),this.registeredHandlers.push({event:e,handler:n})),()=>{r?.delete(t),0===r?.size&&this.eventListeners.delete(e),this.transport?.off(e,n),this.registeredHandlers=this.registeredHandlers.filter(e=>e.handler!==n)}}once(e,t){const r=this.on(e,e=>{r(),t(e)});return r}off(e,t){if(t){const r=this.eventListeners.get(e);r?.delete(t),0===r?.size&&this.eventListeners.delete(e)}else this.eventListeners.delete(e),this.transport?.off(e),this.registeredHandlers=this.registeredHandlers.filter(t=>t.event!==e)}destroy(){this._isDestroyed||(this.logger.info("Destroying controller"),this.cleanup(),this._isDestroyed=!0)}cleanup(){this._isReady=!1;for(const{event:e,handler:t}of this.registeredHandlers)this.transport?.off(e,t);this.registeredHandlers=[],this.eventListeners.clear(),this.transport&&(this.transport.destroy(),this.transport=null),this.boundMessageHandler&&(window.removeEventListener("message",this.boundMessageHandler),this.boundMessageHandler=null)}ensureReady(e){if(this._isDestroyed)throw new p("DESTROYED",`Cannot call ${e}() after destroy()`,{details:{method:e}});if(!this._isReady||!this.transport)throw new p("NOT_READY",`Cannot call ${e}() before controller is ready. Use await createController() or wait for onReady callback.`,{details:{method:e,isReady:this._isReady}})}handleError(e){this.config.onError?this.config.onError(e.toSmoreError()):this.logger.error(e.message,e.details)}logSend(e,t){const r=this.config.debug;("object"==typeof r?r.logSend??!0:Boolean(r))&&this.logger.debug(`→ SEND [${e}]`,t)}logReceive(e,t){const r=this.config.debug;("object"==typeof r?r.logReceive??!0:Boolean(r))&&this.logger.debug(`← RECV [${e}]`,t)}}e.DirectTransport=class{constructor(e){this.socket=e}emit(e,...t){this.socket.emit(e,...t)}on(e,t){this.socket.on(e,t)}off(e,t){t?this.socket.off(e,t):this.socket.off(e)}},e.PostMessageTransport=r,e.SMORE_EVENTS={READY:"smore:ready",GAME_OVER:"smore:game-over",RETURN_TO_LOBBY:"smore:return-to-lobby",PLAYER_JOIN:"smore:player-join",PLAYER_LEAVE:"smore:player-leave",SEND_TO_PLAYER:"smore:send-to-player",INIT:"smore:init",UPDATE:"smore:update"},e.SmoreSDKError=o,e.createController=function(e){const t=new m(e??{}),r=t.initialize().then(()=>t);return r.instance=t,r},e.createMockController=function(e={}){const{roomCode:t="TEST",myIndex:r=0,isLeader:n=!1,autoReady:s=!0}=e;let o=!1,i=!1,a=n;const l=new Map,d=[],h={get myIndex(){return r},get isLeader(){return a},get roomCode(){return t},get isReady(){return o},get isDestroyed(){return i},send(e,t){if(i)throw new Error("Cannot send: controller is destroyed");d.push({event:e,data:t})},sendRaw(e,t){if(i)throw new Error("Cannot send: controller is destroyed");d.push({event:e,data:t})},on(e,t){const r=e;return l.has(r)||l.set(r,new Set),l.get(r).add(t),()=>{l.get(r)?.delete(t)}},once(e,t){const r=n=>{t(n),h.off(e,r)};return h.on(e,r)},off(e,t){const r=e;t?l.get(r)?.delete(t):l.delete(r)},destroy(){i=!0,l.clear(),d.length=0},simulateEvent(e,t){const r=e,n=l.get(r);n&&n.forEach(e=>{e(t)})},getSentEvents:()=>[...d],clearRecordedEvents(){d.length=0},triggerReady(){o=!0},setLeader(e){a=e}};return s&&setTimeout(()=>h.triggerReady(),0),h},e.createMockScreen=function(e={}){const{roomCode:t="TEST",controllers:r=[],autoReady:n=!0}=e;let s=[...r],o=!1,i=!1,a=r[0]?.playerIndex??-1;const l=new Map,d=[],h=[],c={get controllers(){return[...s]},get roomCode(){return t},get leaderIndex(){return a},get isReady(){return o},get isDestroyed(){return i},broadcast(e,t){if(i)throw new Error("Cannot broadcast: screen is destroyed");d.push({event:e,data:t})},broadcastRaw(e,t){if(i)throw new Error("Cannot broadcast: screen is destroyed");d.push({event:e,data:t})},sendToController(e,t,r){if(i)throw new Error("Cannot send: screen is destroyed");if(!s.some(t=>t.playerIndex===e))throw new Error(`Invalid player index: ${e}`);h.push({playerIndex:e,event:t,data:r})},sendToControllerRaw(e,t,r){if(i)throw new Error("Cannot send: screen is destroyed");if(!s.some(t=>t.playerIndex===e))throw new Error(`Invalid player index: ${e}`);h.push({playerIndex:e,event:t,data:r})},gameOver(e){c.broadcastRaw("game-over",e)},on(e,t){const r=e;return l.has(r)||l.set(r,new Set),l.get(r).add(t),()=>{l.get(r)?.delete(t)}},once(e,t){const r=(n,s)=>{t(n,s),c.off(e,r)};return c.on(e,r)},off(e,t){const r=e;t?l.get(r)?.delete(t):l.delete(r)},getController:e=>s.find(t=>t.playerIndex===e),isLeader:e=>e===a,getControllerCount:()=>s.length,destroy(){i=!0,l.clear(),d.length=0,h.length=0},simulateEvent(e,t,r){const n=t,s=l.get(n);s&&s.forEach(t=>{t(e,r)})},simulateControllerJoin(e){s.push(e),-1===a&&(a=e.playerIndex)},simulateControllerLeave(e){s=s.filter(t=>t.playerIndex!==e),a===e&&(a=s[0]?.playerIndex??-1)},getBroadcasts:()=>[...d],getSentToController:e=>h.filter(t=>t.playerIndex===e).map(e=>({event:e.event,data:e.data})),clearRecordedEvents(){d.length=0,h.length=0},triggerReady(){o=!0}};return n&&setTimeout(()=>c.triggerReady(),0),c},e.createScreen=function(e){const t=new h(e),r=t.initialize().then(()=>t);return r.instance=t,r},e.isSystemEvent=function(e){return e.startsWith("smore:")},e.validateUserEvent=function(e){if(e.includes(":"))throw new Error(`Invalid event name "${e}": User events cannot contain ':'. Use '_' or '-' instead. System events use 'smore:' prefix.`)}});
|
|
2
|
-
//# sourceMappingURL=smore-sdk-vanilla.umd.min.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smore-sdk-vanilla.umd.min.js","sources":["../../src/transport/protocol.ts","../../src/transport/PostMessageTransport.ts","../../src/screen.ts","../../src/controller.ts","../../src/transport/DirectTransport.ts","../../src/events.ts","../../src/testing.ts"],"sourcesContent":["/**\n * postMessage protocol types for iframe ↔ parent communication.\n */\n\nexport const SMORE_MSG_PREFIX = 'smore:' as const;\n\nexport interface SmoreReadyMessage {\n type: 'smore:ready';\n}\n\nexport interface SmoreInitMessage {\n type: 'smore:init';\n payload: {\n side: 'host' | 'player';\n roomCode: string;\n players: any[];\n leaderId: string | null;\n myIndex?: number;\n isLeader?: boolean;\n };\n}\n\nexport interface SmoreEmitMessage {\n type: 'smore:emit';\n payload: {\n event: string;\n data?: any;\n ackId?: string;\n };\n}\n\nexport interface SmoreEventMessage {\n type: 'smore:event';\n payload: {\n event: string;\n data?: any;\n };\n}\n\nexport interface SmoreAckMessage {\n type: 'smore:ack';\n payload: {\n ackId: string;\n data?: any;\n };\n}\n\nexport interface SmoreUpdateMessage {\n type: 'smore:update';\n payload: {\n players?: any[];\n leaderId?: string | null;\n };\n}\n\n// DEPRECATED: SmoreLoadedMessage removed - no longer used in protocol\n// Previously: interface SmoreLoadedMessage { type: 'smore:loaded' }\n\nexport type SmoreMessage =\n | SmoreReadyMessage\n | SmoreInitMessage\n | SmoreEmitMessage\n | SmoreEventMessage\n | SmoreAckMessage\n | SmoreUpdateMessage;\n\nexport function isSmoreMessage(data: any): data is SmoreMessage {\n return data && typeof data === 'object' && typeof data.type === 'string' && data.type.startsWith(SMORE_MSG_PREFIX);\n}\n","/**\n * PostMessageTransport - Transport over window.postMessage for iframe-hosted games.\n *\n * Used inside an iframe. Sends `smore:emit` to parent and listens for `smore:event` from parent.\n */\n\nimport type { Transport, TransportEventHandler } from './types';\nimport type { SmoreEventMessage, SmoreAckMessage } from './protocol';\nimport { isSmoreMessage } from './protocol';\n\nexport class PostMessageTransport implements Transport {\n private handlers = new Map<string, Set<TransportEventHandler>>();\n private ackCallbacks = new Map<string, (...args: any[]) => void>();\n private ackCounter = 0;\n private parentOrigin: string;\n private boundMessageHandler: (e: MessageEvent) => void;\n\n constructor(parentOrigin: string = '*') {\n this.parentOrigin = parentOrigin;\n this.boundMessageHandler = this.handleMessage.bind(this);\n window.addEventListener('message', this.boundMessageHandler);\n }\n\n emit(event: string, ...args: any[]): void {\n // Detect if last arg is a callback (ack pattern)\n let data: any = args[0];\n let ackId: string | undefined;\n\n if (args.length >= 2 && typeof args[args.length - 1] === 'function') {\n data = args.length === 2 ? args[0] : args[0];\n const callback = args[args.length - 1];\n ackId = `ack_${++this.ackCounter}`;\n this.ackCallbacks.set(ackId, callback);\n }\n\n window.parent.postMessage(\n { type: 'smore:emit', payload: { event, data, ackId } },\n this.parentOrigin,\n );\n }\n\n on(event: string, handler: TransportEventHandler): void {\n let set = this.handlers.get(event);\n if (!set) {\n set = new Set();\n this.handlers.set(event, set);\n }\n set.add(handler);\n }\n\n off(event: string, handler?: TransportEventHandler): void {\n if (!handler) {\n this.handlers.delete(event);\n return;\n }\n this.handlers.get(event)?.delete(handler);\n }\n\n destroy(): void {\n window.removeEventListener('message', this.boundMessageHandler);\n this.handlers.clear();\n this.ackCallbacks.clear();\n }\n\n private handleMessage(e: MessageEvent): void {\n // Origin validation: only accept messages from the expected parent\n if (this.parentOrigin !== '*' && e.origin !== this.parentOrigin) return;\n\n const msg = e.data;\n if (!isSmoreMessage(msg)) return;\n\n if (msg.type === 'smore:event') {\n const { event, data } = (msg as SmoreEventMessage).payload;\n const set = this.handlers.get(event);\n if (set) {\n set.forEach((handler) => handler(data));\n }\n } else if (msg.type === 'smore:ack') {\n const { ackId, data } = (msg as SmoreAckMessage).payload;\n const cb = this.ackCallbacks.get(ackId);\n if (cb) {\n this.ackCallbacks.delete(ackId);\n cb(data);\n }\n }\n }\n}\n","/**\n * createScreen - Factory function for Screen instances (Host/TV side)\n *\n * Promise-based factory with type-safe event handling and comprehensive error management.\n *\n * @example Promise-based (recommended)\n * ```ts\n * interface MyEvents {\n * tap: { x: number; y: number };\n * 'phase-update': { phase: 'lobby' | 'playing' | 'results' };\n * }\n *\n * const screen = await createScreen<MyEvents>({\n * listeners: {\n * tap: (playerIndex, data) => console.log(`Player ${playerIndex} tapped at`, data.x, data.y),\n * },\n * });\n *\n * screen.broadcast('phase-update', { phase: 'playing' });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const screen = createScreen<MyEvents>({\n * onReady: () => screen.broadcast('ready', {}),\n * listeners: { ... },\n * });\n * // Use screen.instance for immediate access\n * ```\n */\n\nimport type {\n EventMap,\n EventNames,\n EventData,\n Screen,\n ScreenConfig,\n ScreenEventHandler,\n ControllerInfo,\n PlayerIndex,\n RoomCode,\n GameResults,\n SmoreError,\n SmoreErrorCode,\n DebugOptions,\n LogLevel,\n} from './types';\nimport type { Transport, TransportEventHandler } from './transport/types';\nimport { PostMessageTransport } from './transport/PostMessageTransport';\nimport { isSmoreMessage, type SmoreInitMessage, type SmoreUpdateMessage } from './transport/protocol';\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst SYSTEM_PREFIX = 'smore:';\n\nconst SYSTEM_EVENTS = {\n READY: `${SYSTEM_PREFIX}ready`,\n PLAYER_JOIN: `${SYSTEM_PREFIX}player-join`,\n PLAYER_LEAVE: `${SYSTEM_PREFIX}player-leave`,\n PLAYER_RECONNECT: `${SYSTEM_PREFIX}player-reconnect`,\n GAME_OVER: `${SYSTEM_PREFIX}game-over`,\n} as const;\n\nconst DEFAULT_TIMEOUT = 10000;\n\n// =============================================================================\n// ERROR CLASS\n// =============================================================================\n\n/**\n * Custom error class for SDK errors with structured error handling.\n */\nexport class SmoreSDKError extends Error {\n readonly code: SmoreErrorCode;\n readonly cause?: Error;\n readonly details?: Record<string, unknown>;\n\n constructor(\n code: SmoreErrorCode,\n message: string,\n options?: { cause?: Error; details?: Record<string, unknown> }\n ) {\n super(message);\n this.name = 'SmoreSDKError';\n this.code = code;\n this.cause = options?.cause;\n this.details = options?.details;\n\n // Maintain proper stack trace in V8 environments\n const ErrorWithCapture = Error as typeof Error & {\n captureStackTrace?: (target: object, constructor?: Function) => void;\n };\n if (typeof ErrorWithCapture.captureStackTrace === 'function') {\n ErrorWithCapture.captureStackTrace(this, SmoreSDKError);\n }\n }\n\n toSmoreError(): SmoreError {\n return {\n code: this.code,\n message: this.message,\n cause: this.cause,\n details: this.details,\n };\n }\n}\n\n// =============================================================================\n// VALIDATION\n// =============================================================================\n\nconst EVENT_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;\n\nfunction validateEventName(event: string): void {\n if (!event || typeof event !== 'string') {\n throw new SmoreSDKError('INVALID_EVENT', 'Event name must be a non-empty string');\n }\n if (!EVENT_NAME_REGEX.test(event)) {\n throw new SmoreSDKError(\n 'INVALID_EVENT',\n `Invalid event name \"${event}\". Event names must start with a letter, ` +\n `contain only letters, numbers, hyphens, or underscores, and end with a letter or number.`,\n { details: { event } }\n );\n }\n}\n\nfunction validatePlayerIndex(playerIndex: PlayerIndex, controllersCount: number): void {\n if (typeof playerIndex !== 'number' || !Number.isInteger(playerIndex)) {\n throw new SmoreSDKError('INVALID_PLAYER', 'Player index must be an integer');\n }\n if (playerIndex < 0 || playerIndex >= controllersCount) {\n throw new SmoreSDKError(\n 'INVALID_PLAYER',\n `Invalid player index ${playerIndex}. Valid range: 0-${controllersCount - 1}`,\n { details: { playerIndex, controllersCount } }\n );\n }\n}\n\n// =============================================================================\n// DEBUG LOGGER\n// =============================================================================\n\nclass DebugLogger {\n private enabled: boolean;\n private level: LogLevel;\n private prefix: string;\n private logSend: boolean;\n private logReceive: boolean;\n private logLifecycle: boolean;\n private customLogger?: (level: LogLevel, message: string, data?: unknown) => void;\n\n private static levelOrder: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n constructor(options?: boolean | DebugOptions) {\n if (typeof options === 'boolean') {\n this.enabled = options;\n this.level = 'debug';\n this.prefix = '[SmoreScreen]';\n this.logSend = true;\n this.logReceive = true;\n this.logLifecycle = true;\n } else if (options) {\n this.enabled = options.enabled ?? false;\n this.level = options.level ?? 'debug';\n this.prefix = options.prefix ?? '[SmoreScreen]';\n this.logSend = options.logSend ?? true;\n this.logReceive = options.logReceive ?? true;\n this.logLifecycle = options.logLifecycle ?? true;\n this.customLogger = options.logger;\n } else {\n this.enabled = false;\n this.level = 'debug';\n this.prefix = '[SmoreScreen]';\n this.logSend = true;\n this.logReceive = true;\n this.logLifecycle = true;\n }\n }\n\n private shouldLog(level: LogLevel): boolean {\n return this.enabled && DebugLogger.levelOrder[level] >= DebugLogger.levelOrder[this.level];\n }\n\n private log(level: LogLevel, message: string, data?: unknown): void {\n if (!this.shouldLog(level)) return;\n\n if (this.customLogger) {\n this.customLogger(level, `${this.prefix} ${message}`, data);\n return;\n }\n\n const consoleMethod = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log';\n if (data !== undefined) {\n console[consoleMethod](`${this.prefix} ${message}`, data);\n } else {\n console[consoleMethod](`${this.prefix} ${message}`);\n }\n }\n\n debug(message: string, data?: unknown): void {\n this.log('debug', message, data);\n }\n\n info(message: string, data?: unknown): void {\n this.log('info', message, data);\n }\n\n warn(message: string, data?: unknown): void {\n this.log('warn', message, data);\n }\n\n error(message: string, data?: unknown): void {\n this.log('error', message, data);\n }\n\n send(event: string, data?: unknown): void {\n if (this.logSend) {\n this.debug(`-> SEND: ${event}`, data);\n }\n }\n\n receive(event: string, data?: unknown): void {\n if (this.logReceive) {\n this.debug(`<- RECV: ${event}`, data);\n }\n }\n\n lifecycle(message: string, data?: unknown): void {\n if (this.logLifecycle) {\n this.info(`[Lifecycle] ${message}`, data);\n }\n }\n}\n\n// =============================================================================\n// SCREEN IMPLEMENTATION\n// =============================================================================\n\nclass ScreenImpl<TEvents extends EventMap> implements Screen<TEvents> {\n private transport: Transport | null = null;\n private config: ScreenConfig<TEvents>;\n private logger: DebugLogger;\n\n private _controllers: ControllerInfo[] = [];\n private _roomCode: RoomCode = '';\n private _leaderIndex: PlayerIndex = -1;\n private _isReady = false;\n private _isDestroyed = false;\n\n private eventHandlers = new Map<string, Set<ScreenEventHandler<unknown>>>();\n private registeredTransportHandlers: Array<{ event: string; handler: TransportEventHandler }> = [];\n private boundMessageHandler: ((e: MessageEvent) => void) | null = null;\n\n constructor(config: ScreenConfig<TEvents> = {}) {\n this.config = config;\n this.logger = new DebugLogger(config.debug);\n\n // Validate event names in initial listeners\n if (config.listeners) {\n for (const event of Object.keys(config.listeners)) {\n validateEventName(event);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Initialization (called by factory)\n // ---------------------------------------------------------------------------\n\n async initialize(): Promise<void> {\n this.logger.lifecycle('Initializing screen...');\n\n const parentOrigin = this.config.parentOrigin ?? '*';\n const timeout = this.config.timeout ?? DEFAULT_TIMEOUT;\n\n return new Promise<void>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.cleanup();\n const error = new SmoreSDKError(\n 'TIMEOUT',\n `Screen initialization timed out after ${timeout}ms. Make sure the parent frame sends smore:init.`,\n { details: { timeout } }\n );\n this.handleError(error);\n reject(error);\n }, timeout);\n\n this.boundMessageHandler = (e: MessageEvent) => {\n if (parentOrigin !== '*' && e.origin !== parentOrigin) return;\n\n const msg = e.data;\n if (!isSmoreMessage(msg)) return;\n\n if (msg.type === 'smore:init') {\n clearTimeout(timeoutId);\n const initData = (msg as SmoreInitMessage).payload;\n\n if (initData.side !== 'host') {\n const error = new SmoreSDKError(\n 'INIT_FAILED',\n `Received init for wrong side: ${initData.side}. Expected \"host\".`,\n { details: { side: initData.side } }\n );\n this.handleError(error);\n reject(error);\n return;\n }\n\n // Initialize transport\n this.transport = new PostMessageTransport(parentOrigin);\n this._roomCode = initData.roomCode;\n this._controllers = this.mapControllersFromInit(initData.players);\n this._leaderIndex = this.findLeaderIndex(initData.players, initData.leaderId);\n\n this.setupEventHandlers();\n this._isReady = true;\n\n this.logger.lifecycle('Screen ready', {\n roomCode: this._roomCode,\n controllers: this._controllers.length,\n leaderIndex: this._leaderIndex,\n });\n\n this.config.onReady?.();\n resolve();\n } else if (msg.type === 'smore:update') {\n const updateData = (msg as SmoreUpdateMessage).payload;\n\n if (updateData.players) {\n this._controllers = this.mapControllersFromInit(updateData.players);\n }\n if (updateData.leaderId !== undefined) {\n this._leaderIndex = this.findLeaderIndex(\n updateData.players ?? [],\n updateData.leaderId\n );\n }\n\n this.logger.lifecycle('Room updated', {\n controllers: this._controllers.length,\n leaderIndex: this._leaderIndex,\n });\n }\n };\n\n window.addEventListener('message', this.boundMessageHandler);\n\n // Signal ready to parent\n window.parent.postMessage({ type: 'smore:ready' }, parentOrigin);\n this.logger.lifecycle('Sent smore:ready to parent');\n });\n }\n\n private mapControllersFromInit(players: unknown[]): ControllerInfo[] {\n return (players as Record<string, unknown>[]).map((p, index) => ({\n playerIndex: (p.playerIndex as number) ?? index,\n nickname: (p.nickname as string) || `Player ${index + 1}`,\n connected: p.connected !== false,\n appearance: p.appearance as ControllerInfo['appearance'],\n }));\n }\n\n private findLeaderIndex(players: unknown[], leaderId: string | null): PlayerIndex {\n if (!leaderId) return -1;\n const idx = (players as Record<string, unknown>[]).findIndex(\n (p) => p.sessionId === leaderId\n );\n return idx >= 0 ? idx : -1;\n }\n\n private setupEventHandlers(): void {\n if (!this.transport) return;\n\n // System events: player join/leave/reconnect\n this.registerTransportHandler(SYSTEM_EVENTS.PLAYER_JOIN, (data: unknown) => {\n const payload = data as { player?: ControllerInfo };\n const player = payload?.player;\n if (player && typeof player.playerIndex === 'number') {\n this.logger.lifecycle('Controller joined', { playerIndex: player.playerIndex });\n this.config.onControllerJoin?.(player.playerIndex, player);\n }\n });\n\n this.registerTransportHandler(SYSTEM_EVENTS.PLAYER_LEAVE, (data: unknown) => {\n const payload = data as { playerIndex?: number };\n if (typeof payload?.playerIndex === 'number') {\n this.logger.lifecycle('Controller left', { playerIndex: payload.playerIndex });\n this.config.onControllerLeave?.(payload.playerIndex);\n }\n });\n\n this.registerTransportHandler(SYSTEM_EVENTS.PLAYER_RECONNECT, (data: unknown) => {\n const payload = data as { player?: ControllerInfo };\n const player = payload?.player;\n if (player && typeof player.playerIndex === 'number') {\n this.logger.lifecycle('Controller reconnected', { playerIndex: player.playerIndex });\n this.config.onControllerReconnect?.(player.playerIndex, player);\n }\n });\n\n // Legacy room events (backward compatibility)\n this.registerTransportHandler('room:player-joined', (data: unknown) => {\n const payload = data as { player?: { playerIndex?: number }; playerIndex?: number };\n const playerIndex = payload?.player?.playerIndex ?? payload?.playerIndex;\n if (typeof playerIndex === 'number') {\n this.config.onControllerJoin?.(playerIndex, {\n playerIndex,\n nickname: `Player ${playerIndex + 1}`,\n connected: true,\n });\n }\n });\n\n this.registerTransportHandler('room:player-left', (data: unknown) => {\n const payload = data as { playerIndex?: number; player?: { playerIndex?: number } };\n const playerIndex = payload?.playerIndex ?? payload?.player?.playerIndex;\n if (typeof playerIndex === 'number') {\n this.config.onControllerLeave?.(playerIndex);\n }\n });\n\n // User event listeners from config\n if (this.config.listeners) {\n for (const [event, handler] of Object.entries(this.config.listeners)) {\n if (!handler) continue;\n this.setupUserEventHandler(event, handler as ScreenEventHandler<unknown>);\n }\n }\n }\n\n private setupUserEventHandler(event: string, handler: ScreenEventHandler<unknown>): void {\n const wrappedHandler = (data: unknown) => {\n this.logger.receive(event, data);\n const payload = data as { playerIndex?: number };\n const { playerIndex, ...rest } = payload as { playerIndex?: number; [key: string]: unknown };\n if (typeof playerIndex === 'number') {\n try {\n handler(playerIndex, rest);\n } catch (err) {\n this.handleError(\n new SmoreSDKError('UNKNOWN', `Error in handler for event \"${event}\"`, {\n cause: err instanceof Error ? err : undefined,\n details: { event, playerIndex },\n })\n );\n }\n }\n };\n\n this.registerTransportHandler(event, wrappedHandler);\n\n // Also store in eventHandlers for on/off management\n let handlers = this.eventHandlers.get(event);\n if (!handlers) {\n handlers = new Set();\n this.eventHandlers.set(event, handlers);\n }\n handlers.add(handler);\n }\n\n private registerTransportHandler(event: string, handler: TransportEventHandler): void {\n if (!this.transport) return;\n this.transport.on(event, handler);\n this.registeredTransportHandlers.push({ event, handler });\n }\n\n // ---------------------------------------------------------------------------\n // Properties (readonly)\n // ---------------------------------------------------------------------------\n\n get controllers(): readonly ControllerInfo[] {\n return [...this._controllers];\n }\n\n get roomCode(): RoomCode {\n return this._roomCode;\n }\n\n get leaderIndex(): PlayerIndex {\n return this._leaderIndex;\n }\n\n get isReady(): boolean {\n return this._isReady;\n }\n\n get isDestroyed(): boolean {\n return this._isDestroyed;\n }\n\n // ---------------------------------------------------------------------------\n // Communication Methods\n // ---------------------------------------------------------------------------\n\n broadcast<K extends EventNames<TEvents>>(event: K, data: EventData<TEvents, K>): void {\n this.ensureReady('broadcast');\n validateEventName(event);\n this.logger.send(event, data);\n this.transport!.emit(event, data);\n }\n\n broadcastRaw(event: string, data?: unknown): void {\n this.ensureReady('broadcastRaw');\n validateEventName(event);\n this.logger.send(event, data);\n this.transport!.emit(event, data);\n }\n\n sendToController<K extends EventNames<TEvents>>(\n playerIndex: PlayerIndex,\n event: K,\n data: EventData<TEvents, K>\n ): void {\n this.ensureReady('sendToController');\n validateEventName(event);\n validatePlayerIndex(playerIndex, this._controllers.length);\n this.logger.send(`${event} -> Player ${playerIndex}`, data);\n this.transport!.emit(event, {\n targetPlayerIndex: playerIndex,\n ...(data && typeof data === 'object' ? data : { data }),\n });\n }\n\n sendToControllerRaw(playerIndex: PlayerIndex, event: string, data?: unknown): void {\n this.ensureReady('sendToControllerRaw');\n validateEventName(event);\n validatePlayerIndex(playerIndex, this._controllers.length);\n this.logger.send(`${event} -> Player ${playerIndex}`, data);\n this.transport!.emit(event, {\n targetPlayerIndex: playerIndex,\n ...(data && typeof data === 'object' ? data : { data }),\n });\n }\n\n // ---------------------------------------------------------------------------\n // Game Lifecycle\n // ---------------------------------------------------------------------------\n\n gameOver(results?: GameResults): void {\n this.ensureReady('gameOver');\n this.logger.lifecycle('Game over', results);\n this.transport!.emit(SYSTEM_EVENTS.GAME_OVER, { results });\n }\n\n // ---------------------------------------------------------------------------\n // Event Subscription\n // ---------------------------------------------------------------------------\n\n on<K extends EventNames<TEvents>>(\n event: K,\n handler: ScreenEventHandler<EventData<TEvents, K>>\n ): () => void {\n validateEventName(event);\n\n let handlers = this.eventHandlers.get(event);\n if (!handlers) {\n handlers = new Set();\n this.eventHandlers.set(event, handlers);\n }\n handlers.add(handler as ScreenEventHandler<unknown>);\n\n // Also register on transport if ready\n if (this.transport) {\n const wrappedHandler = (data: unknown) => {\n this.logger.receive(event, data);\n const payload = data as { playerIndex?: number };\n const { playerIndex, ...rest } = payload as { playerIndex?: number; [key: string]: unknown };\n if (typeof playerIndex === 'number') {\n try {\n handler(playerIndex, rest as EventData<TEvents, K>);\n } catch (err) {\n this.handleError(\n new SmoreSDKError('UNKNOWN', `Error in handler for event \"${event}\"`, {\n cause: err instanceof Error ? err : undefined,\n })\n );\n }\n }\n };\n this.registerTransportHandler(event, wrappedHandler);\n }\n\n // Return unsubscribe function\n return () => {\n handlers?.delete(handler as ScreenEventHandler<unknown>);\n if (handlers?.size === 0) {\n this.eventHandlers.delete(event);\n }\n };\n }\n\n once<K extends EventNames<TEvents>>(\n event: K,\n handler: ScreenEventHandler<EventData<TEvents, K>>\n ): () => void {\n const wrappedHandler: ScreenEventHandler<EventData<TEvents, K>> = (playerIndex, data) => {\n unsubscribe();\n handler(playerIndex, data);\n };\n const unsubscribe = this.on(event, wrappedHandler);\n return unsubscribe;\n }\n\n off<K extends EventNames<TEvents>>(\n event: K,\n handler?: ScreenEventHandler<EventData<TEvents, K>>\n ): void {\n if (!handler) {\n // Remove all handlers for this event\n this.eventHandlers.delete(event);\n this.transport?.off(event);\n } else {\n const handlers = this.eventHandlers.get(event);\n handlers?.delete(handler as ScreenEventHandler<unknown>);\n if (handlers?.size === 0) {\n this.eventHandlers.delete(event);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Utilities\n // ---------------------------------------------------------------------------\n\n getController(playerIndex: PlayerIndex): ControllerInfo | undefined {\n return this._controllers.find((c) => c.playerIndex === playerIndex);\n }\n\n isLeader(playerIndex: PlayerIndex): boolean {\n return playerIndex === this._leaderIndex;\n }\n\n getControllerCount(): number {\n return this._controllers.filter((c) => c.connected).length;\n }\n\n // ---------------------------------------------------------------------------\n // Cleanup\n // ---------------------------------------------------------------------------\n\n destroy(): void {\n if (this._isDestroyed) return;\n\n this.logger.lifecycle('Destroying screen...');\n this._isDestroyed = true;\n this._isReady = false;\n\n this.cleanup();\n this.logger.lifecycle('Screen destroyed');\n }\n\n private cleanup(): void {\n // Remove all registered transport handlers\n for (const { event, handler } of this.registeredTransportHandlers) {\n this.transport?.off(event, handler);\n }\n this.registeredTransportHandlers = [];\n\n // Clear event handlers\n this.eventHandlers.clear();\n\n // Destroy transport\n if (this.transport instanceof PostMessageTransport) {\n this.transport.destroy();\n }\n this.transport = null;\n\n // Remove message listener\n if (this.boundMessageHandler) {\n window.removeEventListener('message', this.boundMessageHandler);\n this.boundMessageHandler = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Error Handling\n // ---------------------------------------------------------------------------\n\n private handleError(error: SmoreSDKError): void {\n const smoreError = error.toSmoreError();\n if (this.config.onError) {\n this.config.onError(smoreError);\n } else {\n this.logger.error(error.message, error.details);\n }\n }\n\n private ensureReady(method: string): void {\n if (this._isDestroyed) {\n throw new SmoreSDKError(\n 'DESTROYED',\n `Cannot call ${method}() after destroy()`,\n { details: { method } }\n );\n }\n if (!this._isReady || !this.transport) {\n throw new SmoreSDKError(\n 'NOT_READY',\n `Cannot call ${method}() before screen is ready. Use await createScreen() or onReady callback.`,\n { details: { method } }\n );\n }\n }\n}\n\n// =============================================================================\n// FACTORY FUNCTION\n// =============================================================================\n\n/**\n * Create a Screen instance for the host/TV side of your game.\n *\n * Returns a Promise that resolves when the screen is ready.\n * The promise also has an `instance` property for immediate access (use with onReady callback).\n *\n * @template TEvents - Event map type for type-safe events\n * @param config - Screen configuration\n * @returns Promise that resolves to the Screen instance when ready\n *\n * @example Promise-based (recommended)\n * ```ts\n * const screen = await createScreen<MyEvents>({\n * listeners: {\n * tap: (playerIndex, data) => handleTap(playerIndex, data),\n * },\n * });\n *\n * screen.broadcast('game-start', { countdown: 3 });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const { instance: screen } = createScreen<MyEvents>({\n * onReady: () => {\n * screen.broadcast('game-start', { countdown: 3 });\n * },\n * listeners: { ... },\n * });\n * ```\n */\nexport function createScreen<TEvents extends EventMap = EventMap>(\n config?: ScreenConfig<TEvents>\n): Promise<Screen<TEvents>> & { instance: Screen<TEvents> } {\n const screen = new ScreenImpl<TEvents>(config);\n\n const promise = screen.initialize().then(() => screen as Screen<TEvents>);\n\n // Attach instance for callback-based usage\n (promise as Promise<Screen<TEvents>> & { instance: Screen<TEvents> }).instance =\n screen as Screen<TEvents>;\n\n return promise as Promise<Screen<TEvents>> & { instance: Screen<TEvents> };\n}\n","/**\n * createController - Factory function for creating a Controller instance.\n *\n * Returns a Promise that resolves when the controller is ready and initialized.\n * Uses PostMessageTransport for iframe communication with parent window.\n *\n * @example Promise-based (recommended)\n * ```ts\n * const controller = await createController<MyEvents>({\n * listeners: {\n * 'phase-update': (data) => setPhase(data.phase),\n * },\n * });\n *\n * console.log(`Ready! My index: ${controller.myIndex}`);\n * controller.send('tap', { x: 100, y: 200 });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const controller = createController<MyEvents>({\n * onReady: () => {\n * console.log('Ready!');\n * },\n * listeners: { ... },\n * });\n * // Use controller.instance for immediate access\n * ```\n */\n\nimport type {\n Controller,\n ControllerConfig,\n ControllerEventHandler,\n ControllerInfo,\n DebugOptions,\n EventData,\n EventMap,\n EventNames,\n LogLevel,\n PlayerIndex,\n RoomCode,\n SmoreError,\n SmoreErrorCode,\n} from './types';\nimport { PostMessageTransport } from './transport/PostMessageTransport';\nimport type { TransportEventHandler } from './transport/types';\nimport {\n isSmoreMessage,\n type SmoreInitMessage,\n type SmoreUpdateMessage,\n} from './transport/protocol';\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst SYSTEM_PREFIX = 'smore:';\n\nconst SYSTEM_EVENTS = {\n READY: `${SYSTEM_PREFIX}ready`,\n PLAYER_JOIN: `${SYSTEM_PREFIX}player-join`,\n PLAYER_LEAVE: `${SYSTEM_PREFIX}player-leave`,\n} as const;\n\nconst DEFAULT_TIMEOUT = 10000;\n\n// =============================================================================\n// ERROR CLASS\n// =============================================================================\n\n/**\n * Custom error class for SDK errors.\n */\nexport class SmoreSDKError extends Error {\n readonly code: SmoreErrorCode;\n readonly cause?: Error;\n readonly details?: Record<string, unknown>;\n\n constructor(\n code: SmoreErrorCode,\n message: string,\n options?: {\n cause?: Error;\n details?: Record<string, unknown>;\n },\n ) {\n super(message);\n this.name = 'SmoreSDKError';\n this.code = code;\n this.cause = options?.cause;\n this.details = options?.details;\n\n // Maintain proper stack trace in V8 engines\n const ErrorWithCapture = Error as typeof Error & {\n captureStackTrace?: (target: object, constructor?: Function) => void;\n };\n if (typeof ErrorWithCapture.captureStackTrace === 'function') {\n ErrorWithCapture.captureStackTrace(this, SmoreSDKError);\n }\n }\n\n toSmoreError(): SmoreError {\n return {\n code: this.code,\n message: this.message,\n cause: this.cause,\n details: this.details,\n };\n }\n}\n\n// =============================================================================\n// VALIDATION\n// =============================================================================\n\nconst EVENT_NAME_REGEX = /^[a-zA-Z]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;\n\nfunction validateEventName(event: string): void {\n if (!event || typeof event !== 'string') {\n throw new SmoreSDKError('INVALID_EVENT', 'Event name must be a non-empty string');\n }\n if (!EVENT_NAME_REGEX.test(event)) {\n throw new SmoreSDKError(\n 'INVALID_EVENT',\n `Invalid event name \"${event}\". Event names must:\\n` +\n ` - Start with a letter (a-z, A-Z)\\n` +\n ` - Only contain letters, numbers, hyphens (-), and underscores (_)\\n` +\n ` - End with a letter or number`,\n { details: { event } },\n );\n }\n}\n\n// =============================================================================\n// DEBUG LOGGER\n// =============================================================================\n\ninterface Logger {\n debug(message: string, data?: unknown): void;\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n}\n\nfunction createLogger(options: boolean | DebugOptions | undefined): Logger {\n const enabled = typeof options === 'boolean' ? options : options?.enabled ?? false;\n const level = (typeof options === 'object' ? options.level : undefined) ?? 'debug';\n const prefix = (typeof options === 'object' ? options.prefix : undefined) ?? '[SmoreController]';\n const customLogger = typeof options === 'object' ? options.logger : undefined;\n\n const levelPriority: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n const shouldLog = (msgLevel: LogLevel): boolean => {\n if (!enabled) return false;\n return levelPriority[msgLevel] >= levelPriority[level];\n };\n\n const log = (msgLevel: LogLevel, message: string, data?: unknown): void => {\n if (!shouldLog(msgLevel)) return;\n\n if (customLogger) {\n customLogger(msgLevel, message, data);\n return;\n }\n\n const fullMessage = `${prefix} ${message}`;\n const consoleFn = console[msgLevel] ?? console.log;\n\n if (data !== undefined) {\n consoleFn(fullMessage, data);\n } else {\n consoleFn(fullMessage);\n }\n };\n\n return {\n debug: (msg, data) => log('debug', msg, data),\n info: (msg, data) => log('info', msg, data),\n warn: (msg, data) => log('warn', msg, data),\n error: (msg, data) => log('error', msg, data),\n };\n}\n\n// =============================================================================\n// CONTROLLER IMPLEMENTATION\n// =============================================================================\n\nclass ControllerImpl<TEvents extends EventMap> implements Controller<TEvents> {\n private transport: PostMessageTransport | null = null;\n private config: ControllerConfig<TEvents>;\n private logger: Logger;\n private _roomCode: RoomCode = '';\n private _myIndex: PlayerIndex = -1;\n private _isLeader: boolean = false;\n private _isReady: boolean = false;\n private _isDestroyed: boolean = false;\n private boundMessageHandler: ((e: MessageEvent) => void) | null = null;\n private registeredHandlers: Array<{ event: string; handler: TransportEventHandler }> = [];\n private eventListeners = new Map<string, Set<ControllerEventHandler<unknown>>>();\n\n constructor(config: ControllerConfig<TEvents> = {}) {\n this.config = config;\n this.logger = createLogger(config.debug);\n\n // Validate event names in listeners\n if (config.listeners) {\n for (const event of Object.keys(config.listeners)) {\n validateEventName(event);\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Properties (readonly)\n // ---------------------------------------------------------------------------\n\n get myIndex(): PlayerIndex {\n return this._myIndex;\n }\n\n get isLeader(): boolean {\n return this._isLeader;\n }\n\n get roomCode(): RoomCode {\n return this._roomCode;\n }\n\n get isReady(): boolean {\n return this._isReady;\n }\n\n get isDestroyed(): boolean {\n return this._isDestroyed;\n }\n\n // ---------------------------------------------------------------------------\n // Initialization\n // ---------------------------------------------------------------------------\n\n async initialize(): Promise<void> {\n const parentOrigin = this.config.parentOrigin ?? '*';\n const timeout = this.config.timeout ?? DEFAULT_TIMEOUT;\n\n this.logger.debug('Initializing controller...', { parentOrigin, timeout });\n\n return new Promise<void>((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n this.cleanup();\n const error = new SmoreSDKError(\n 'TIMEOUT',\n `Controller initialization timed out after ${timeout}ms. ` +\n `Make sure the parent window sends smore:init message.`,\n { details: { timeout } },\n );\n this.handleError(error);\n reject(error);\n }, timeout);\n\n // Listen for init message from parent\n this.boundMessageHandler = (e: MessageEvent) => {\n if (parentOrigin !== '*' && e.origin !== parentOrigin) return;\n\n const msg = e.data;\n if (!isSmoreMessage(msg)) return;\n\n if (msg.type === 'smore:init') {\n clearTimeout(timeoutId);\n this.handleInit(msg as SmoreInitMessage, parentOrigin, resolve, reject);\n } else if (msg.type === 'smore:update') {\n this.handleUpdate(msg as SmoreUpdateMessage);\n }\n };\n\n window.addEventListener('message', this.boundMessageHandler);\n\n // Signal ready to parent\n this.logger.debug('Sending smore:ready to parent');\n window.parent.postMessage({ type: 'smore:ready' }, parentOrigin);\n });\n }\n\n private handleInit(\n msg: SmoreInitMessage,\n parentOrigin: string,\n resolve: () => void,\n reject: (err: Error) => void,\n ): void {\n const initData = msg.payload;\n\n this.logger.debug('Received smore:init', initData);\n\n if (initData.side !== 'player') {\n const error = new SmoreSDKError(\n 'INIT_FAILED',\n `Controller received init for wrong side: ${initData.side}`,\n { details: { side: initData.side } },\n );\n this.handleError(error);\n reject(error);\n return;\n }\n\n if (initData.myIndex === undefined) {\n const error = new SmoreSDKError(\n 'INIT_FAILED',\n 'Missing myIndex in init payload',\n { details: initData },\n );\n this.handleError(error);\n reject(error);\n return;\n }\n\n // Initialize transport\n this.transport = new PostMessageTransport(parentOrigin);\n this._roomCode = initData.roomCode;\n this._myIndex = initData.myIndex;\n this._isLeader = initData.isLeader ?? false;\n\n this.setupEventHandlers();\n\n this._isReady = true;\n this.logger.info('Controller ready', {\n roomCode: this._roomCode,\n myIndex: this._myIndex,\n isLeader: this._isLeader,\n });\n\n this.config.onReady?.();\n resolve();\n }\n\n private handleUpdate(msg: SmoreUpdateMessage): void {\n const updateData = msg.payload;\n this.logger.debug('Received smore:update', updateData);\n\n // Future: handle leader changes, player list updates, etc.\n }\n\n private setupEventHandlers(): void {\n if (!this.transport) return;\n\n // System events: player join/leave\n this.registerHandler(\n SYSTEM_EVENTS.PLAYER_JOIN,\n (data: { player?: ControllerInfo; playerIndex?: number }) => {\n const playerIndex = data.player?.playerIndex ?? data.playerIndex;\n if (playerIndex !== undefined) {\n this.logger.debug('Player joined', { playerIndex });\n this.config.onControllerJoin?.(playerIndex, data.player as ControllerInfo);\n }\n },\n );\n\n this.registerHandler(\n SYSTEM_EVENTS.PLAYER_LEAVE,\n (data: { player?: { playerIndex?: number }; playerIndex?: number }) => {\n const playerIndex = data.player?.playerIndex ?? data.playerIndex;\n if (playerIndex !== undefined) {\n this.logger.debug('Player left', { playerIndex });\n this.config.onControllerLeave?.(playerIndex);\n }\n },\n );\n\n // User event listeners from config\n if (this.config.listeners) {\n for (const [event, handler] of Object.entries(this.config.listeners)) {\n if (!handler) continue;\n\n this.registerHandler(event, (data: unknown) => {\n this.logReceive(event, data);\n (handler as ControllerEventHandler<unknown>)(data);\n });\n }\n }\n }\n\n private registerHandler(event: string, handler: TransportEventHandler): void {\n if (!this.transport) return;\n this.transport.on(event, handler);\n this.registeredHandlers.push({ event, handler });\n }\n\n // ---------------------------------------------------------------------------\n // Communication Methods\n // ---------------------------------------------------------------------------\n\n send<K extends EventNames<TEvents>>(event: K, data: EventData<TEvents, K>): void {\n this.ensureReady('send');\n validateEventName(event);\n\n this.logSend(event, data);\n this.transport!.emit(event, data);\n }\n\n sendRaw(event: string, data?: unknown): void {\n this.ensureReady('sendRaw');\n validateEventName(event);\n\n this.logSend(event, data);\n this.transport!.emit(event, data);\n }\n\n // ---------------------------------------------------------------------------\n // Event Subscription\n // ---------------------------------------------------------------------------\n\n on<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n validateEventName(event);\n\n // Add to local listeners map\n let listeners = this.eventListeners.get(event);\n if (!listeners) {\n listeners = new Set();\n this.eventListeners.set(event, listeners);\n }\n listeners.add(handler as ControllerEventHandler<unknown>);\n\n // Register with transport if ready\n const transportHandler: TransportEventHandler = (data: unknown) => {\n this.logReceive(event, data);\n (handler as ControllerEventHandler<unknown>)(data);\n };\n\n if (this.transport) {\n this.transport.on(event, transportHandler);\n this.registeredHandlers.push({ event, handler: transportHandler });\n }\n\n // Return unsubscribe function\n return () => {\n listeners?.delete(handler as ControllerEventHandler<unknown>);\n if (listeners?.size === 0) {\n this.eventListeners.delete(event);\n }\n this.transport?.off(event, transportHandler);\n this.registeredHandlers = this.registeredHandlers.filter(\n (h) => h.handler !== transportHandler,\n );\n };\n }\n\n once<K extends EventNames<TEvents>>(\n event: K,\n handler: ControllerEventHandler<EventData<TEvents, K>>,\n ): () => void {\n const unsubscribe = this.on(event, ((data: EventData<TEvents, K>) => {\n unsubscribe();\n handler(data);\n }) as ControllerEventHandler<EventData<TEvents, K>>);\n return unsubscribe;\n }\n\n off<K extends EventNames<TEvents>>(\n event: K,\n handler?: ControllerEventHandler<EventData<TEvents, K>>,\n ): void {\n if (!handler) {\n // Remove all listeners for this event\n this.eventListeners.delete(event);\n this.transport?.off(event);\n this.registeredHandlers = this.registeredHandlers.filter((h) => h.event !== event);\n } else {\n // Remove specific handler\n const listeners = this.eventListeners.get(event);\n listeners?.delete(handler as ControllerEventHandler<unknown>);\n if (listeners?.size === 0) {\n this.eventListeners.delete(event);\n }\n // Note: Can't easily remove specific handler from transport without tracking\n // This is a limitation of the current transport interface\n }\n }\n\n // ---------------------------------------------------------------------------\n // Cleanup\n // ---------------------------------------------------------------------------\n\n destroy(): void {\n if (this._isDestroyed) return;\n\n this.logger.info('Destroying controller');\n this.cleanup();\n this._isDestroyed = true;\n }\n\n private cleanup(): void {\n this._isReady = false;\n\n // Remove all registered handlers\n for (const { event, handler } of this.registeredHandlers) {\n this.transport?.off(event, handler);\n }\n this.registeredHandlers = [];\n\n // Clear event listeners\n this.eventListeners.clear();\n\n // Destroy transport\n if (this.transport) {\n this.transport.destroy();\n this.transport = null;\n }\n\n // Remove message listener\n if (this.boundMessageHandler) {\n window.removeEventListener('message', this.boundMessageHandler);\n this.boundMessageHandler = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Private Helpers\n // ---------------------------------------------------------------------------\n\n private ensureReady(method: string): void {\n if (this._isDestroyed) {\n throw new SmoreSDKError(\n 'DESTROYED',\n `Cannot call ${method}() after destroy()`,\n { details: { method } },\n );\n }\n if (!this._isReady || !this.transport) {\n throw new SmoreSDKError(\n 'NOT_READY',\n `Cannot call ${method}() before controller is ready. ` +\n `Use await createController() or wait for onReady callback.`,\n { details: { method, isReady: this._isReady } },\n );\n }\n }\n\n private handleError(error: SmoreSDKError): void {\n if (this.config.onError) {\n this.config.onError(error.toSmoreError());\n } else {\n this.logger.error(error.message, error.details);\n }\n }\n\n private logSend(event: string, data?: unknown): void {\n const options = this.config.debug;\n const shouldLog =\n typeof options === 'object' ? (options.logSend ?? true) : Boolean(options);\n if (shouldLog) {\n this.logger.debug(`→ SEND [${event}]`, data);\n }\n }\n\n private logReceive(event: string, data?: unknown): void {\n const options = this.config.debug;\n const shouldLog =\n typeof options === 'object' ? (options.logReceive ?? true) : Boolean(options);\n if (shouldLog) {\n this.logger.debug(`← RECV [${event}]`, data);\n }\n }\n}\n\n// =============================================================================\n// FACTORY FUNCTION\n// =============================================================================\n\n/**\n * Create a Controller instance for the player/phone side of your game.\n *\n * Returns a Promise that resolves when the controller is ready.\n * The returned object also has an `instance` property for immediate access.\n *\n * @template TEvents - Event map type for type-safe events\n * @param config - Controller configuration\n * @returns Promise that resolves to the Controller instance when ready\n *\n * @example Promise-based (recommended)\n * ```ts\n * const controller = await createController<MyEvents>({\n * listeners: {\n * 'phase-update': (data) => setPhase(data.phase),\n * },\n * });\n *\n * controller.send('tap', { x: 100, y: 200 });\n * ```\n *\n * @example Callback-based\n * ```ts\n * const result = createController<MyEvents>({\n * onReady: () => {\n * result.instance.send('ready', {});\n * },\n * listeners: { ... },\n * });\n * ```\n */\nexport function createController<TEvents extends EventMap = EventMap>(\n config?: ControllerConfig<TEvents>,\n): Promise<Controller<TEvents>> & { instance: Controller<TEvents> } {\n const controller = new ControllerImpl<TEvents>(config ?? {});\n\n const promise = controller.initialize().then(() => controller as Controller<TEvents>);\n\n // Attach instance property for immediate access\n (promise as Promise<Controller<TEvents>> & { instance: Controller<TEvents> }).instance =\n controller;\n\n return promise as Promise<Controller<TEvents>> & { instance: Controller<TEvents> };\n}\n","/**\n * DirectTransport - Wraps a Socket.IO socket as a Transport.\n * Used by bundled (internal) games. Behaviour is identical to using socket directly.\n */\n\nimport type { Socket } from 'socket.io-client';\nimport type { Transport, TransportEventHandler } from './types';\n\nexport class DirectTransport implements Transport {\n constructor(private socket: Socket) {}\n\n emit(event: string, ...args: any[]): void {\n this.socket.emit(event, ...args);\n }\n\n on(event: string, handler: TransportEventHandler): void {\n this.socket.on(event, handler);\n }\n\n off(event: string, handler?: TransportEventHandler): void {\n if (handler) {\n this.socket.off(event, handler);\n } else {\n this.socket.off(event);\n }\n }\n}\n","/**\n * SDK 시스템 이벤트 상수\n * 모든 시스템 이벤트는 'smore:' prefix 사용\n * 유저 이벤트는 ':' 사용 불가\n */\n\nexport const SMORE_EVENTS = {\n // 게임 lifecycle\n READY: 'smore:ready',\n GAME_OVER: 'smore:game-over',\n RETURN_TO_LOBBY: 'smore:return-to-lobby',\n\n // 플레이어 관리\n PLAYER_JOIN: 'smore:player-join',\n PLAYER_LEAVE: 'smore:player-leave',\n\n // 특정 플레이어에게 전송 (내부용)\n SEND_TO_PLAYER: 'smore:send-to-player',\n\n // 초기화\n INIT: 'smore:init',\n UPDATE: 'smore:update',\n} as const;\n\nexport type SmoreEvent = typeof SMORE_EVENTS[keyof typeof SMORE_EVENTS];\n\n/**\n * 유저 이벤트명 검증\n * ':' 포함 시 에러, '_'와 '-'는 허용\n */\nexport function validateUserEvent(event: string): void {\n if (event.includes(':')) {\n throw new Error(\n `Invalid event name \"${event}\": User events cannot contain ':'. ` +\n `Use '_' or '-' instead. System events use 'smore:' prefix.`\n );\n }\n}\n\n/**\n * 시스템 이벤트인지 확인\n */\nexport function isSystemEvent(event: string): boolean {\n return event.startsWith('smore:');\n}\n","/**\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 * @packageDocumentation\n */\n\nimport type {\n EventMap,\n EventNames,\n EventData,\n ControllerInfo,\n PlayerIndex,\n GameResults,\n ScreenEventHandler,\n ControllerEventHandler,\n MockScreen,\n MockController,\n MockOptions,\n} from './types';\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 * @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 * // 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 let _leaderIndex: PlayerIndex = initialControllers[0]?.playerIndex ?? -1;\n\n // Event listeners\n const listeners = new Map<string, Set<ScreenEventHandler>>();\n\n // Lifecycle callbacks\n let onReadyCallback: (() => void) | undefined;\n let onControllerJoinCallback:\n | ((index: PlayerIndex, info: ControllerInfo) => void)\n | undefined;\n let onControllerLeaveCallback: ((index: PlayerIndex) => void) | undefined;\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 leaderIndex() {\n return _leaderIndex;\n },\n get isReady() {\n return _isReady;\n },\n get isDestroyed() {\n return _isDestroyed;\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 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 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 (!_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 (!_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 screen.broadcastRaw('game-over', results);\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 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 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 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 isLeader(playerIndex: PlayerIndex): boolean {\n return playerIndex === _leaderIndex;\n },\n\n getControllerCount(): number {\n return _controllers.length;\n },\n\n // === Cleanup ===\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 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 if (_leaderIndex === -1) {\n _leaderIndex = info.playerIndex;\n }\n if (onControllerJoinCallback) {\n onControllerJoinCallback(info.playerIndex, info);\n }\n },\n\n simulateControllerLeave(playerIndex: PlayerIndex): void {\n _controllers = _controllers.filter((c) => c.playerIndex !== playerIndex);\n if (_leaderIndex === playerIndex) {\n _leaderIndex = _controllers[0]?.playerIndex ?? -1;\n }\n if (onControllerLeaveCallback) {\n onControllerLeaveCallback(playerIndex);\n }\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 if (onReadyCallback) {\n onReadyCallback();\n }\n },\n };\n\n // Auto-trigger ready if enabled\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 * @example\n * ```ts\n * const controller = createMockController<MyEvents>({\n * myIndex: 0,\n * isLeader: true,\n * });\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 isLeader: initialIsLeader = false,\n autoReady = true,\n } = options;\n\n // Internal state\n let _isReady = false;\n let _isDestroyed = false;\n let _isLeader = initialIsLeader;\n\n // Event listeners\n const listeners = new Map<string, Set<ControllerEventHandler>>();\n\n // Lifecycle callbacks\n let onReadyCallback: (() => void) | undefined;\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 isLeader() {\n return _isLeader;\n },\n get roomCode() {\n return roomCode;\n },\n get isReady() {\n return _isReady;\n },\n get isDestroyed() {\n return _isDestroyed;\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 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 sentEvents.push({ event, data });\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 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 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 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 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 if (onReadyCallback) {\n onReadyCallback();\n }\n },\n\n setLeader(isLeader: boolean): void {\n _isLeader = isLeader;\n },\n };\n\n // Auto-trigger ready if enabled\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":["isSmoreMessage","data","type","startsWith","PostMessageTransport","handlers","Map","ackCallbacks","ackCounter","parentOrigin","boundMessageHandler","constructor","this","handleMessage","bind","window","addEventListener","emit","event","args","ackId","length","callback","set","parent","postMessage","payload","on","handler","get","Set","add","off","delete","destroy","removeEventListener","clear","e","origin","msg","forEach","cb","SYSTEM_PREFIX","SYSTEM_EVENTS","PLAYER_JOIN","PLAYER_LEAVE","PLAYER_RECONNECT","GAME_OVER","SmoreSDKError","Error","code","cause","details","message","options","super","name","ErrorWithCapture","captureStackTrace","toSmoreError","EVENT_NAME_REGEX","validateEventName","test","validatePlayerIndex","playerIndex","controllersCount","Number","isInteger","DebugLogger","enabled","level","prefix","logSend","logReceive","logLifecycle","customLogger","static","debug","info","warn","error","logger","shouldLog","levelOrder","log","consoleMethod","console","send","receive","lifecycle","ScreenImpl","transport","config","_controllers","_roomCode","_leaderIndex","_isReady","_isDestroyed","eventHandlers","registeredTransportHandlers","listeners","Object","keys","initialize","timeout","Promise","resolve","reject","timeoutId","setTimeout","cleanup","handleError","clearTimeout","initData","side","roomCode","mapControllersFromInit","players","findLeaderIndex","leaderId","setupEventHandlers","controllers","leaderIndex","onReady","updateData","map","p","index","nickname","connected","appearance","idx","findIndex","sessionId","registerTransportHandler","player","onControllerJoin","onControllerLeave","onControllerReconnect","entries","setupUserEventHandler","rest","err","push","isReady","isDestroyed","broadcast","ensureReady","broadcastRaw","sendToController","targetPlayerIndex","sendToControllerRaw","gameOver","results","wrappedHandler","size","once","unsubscribe","getController","find","c","isLeader","getControllerCount","filter","smoreError","onError","method","createLogger","levelPriority","msgLevel","fullMessage","consoleFn","ControllerImpl","_myIndex","_isLeader","registeredHandlers","eventListeners","myIndex","handleInit","handleUpdate","registerHandler","sendRaw","transportHandler","h","Boolean","socket","READY","RETURN_TO_LOBBY","SEND_TO_PLAYER","INIT","UPDATE","controller","promise","then","instance","initialIsLeader","autoReady","sentEvents","eventStr","has","wrapper","simulateEvent","getSentEvents","clearRecordedEvents","triggerReady","setLeader","initialControllers","broadcasts","sends","screen","some","simulateControllerJoin","simulateControllerLeave","getBroadcasts","getSentToController","s","includes"],"mappings":"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"}
|