up
All checks were successful
Deploy to Production / deploy (push) Successful in 8s

This commit is contained in:
lubukhu
2026-01-24 13:35:11 +07:00
parent 6c3e93636e
commit 65fd0158a3
145 changed files with 10262 additions and 0 deletions

View File

@@ -0,0 +1,247 @@
/**
* Game Iframe SDK - Core
* SDK chính - compose các layers: MessageHandler, MessageSender
*/
import { EventEmitter } from './EventEmitter';
import { MessageHandler } from './MessageHandler';
import { MessageSender } from './MessageSender';
import { DEFAULT_CONFIG, } from './types';
/**
* GameIframeSDK - Main SDK class
* Composes MessageHandler và MessageSender
*/
export class GameIframeSDK extends EventEmitter {
constructor(config) {
super();
this.pendingData = null;
this.isReady = false;
this.config = { ...DEFAULT_CONFIG, ...config };
// Initialize layers
this.messageHandler = new MessageHandler({
acceptedOrigin: this.config.iframeOrigin,
debug: this.config.debug,
});
this.messageSender = new MessageSender({
targetOrigin: this.config.iframeOrigin,
debug: this.config.debug,
});
// Setup event forwarding
this.setupEventForwarding();
// Start listening
this.messageHandler.start();
this.log('info', 'SDK initialized', { config: this.config });
}
// ==========================================================================
// PUBLIC API - Iframe Management
// ==========================================================================
/**
* Set iframe element reference
*/
setIframe(iframe) {
this.messageSender.setIframe(iframe);
this.isReady = false;
this.log('info', 'Iframe set', { hasIframe: !!iframe });
return this;
}
/**
* Get current iframe
*/
getIframe() {
return this.messageSender.getIframe();
}
/**
* Check if game is ready
*/
isGameReady() {
return this.isReady;
}
/**
* Check if sender is ready (iframe available)
*/
isSenderReady() {
return this.messageSender.isReady();
}
// ==========================================================================
// PUBLIC API - Send Data
// ==========================================================================
/**
* Send game data to iframe
*/
sendGameData(data) {
const result = this.messageSender.sendGameData(data);
if (!result.success) {
this.emit('error', {
message: 'Failed to send game data',
error: result.error,
});
}
return result.success;
}
/**
* Send leaderboard data to iframe
*/
sendLeaderboard(data) {
const result = this.messageSender.sendLeaderboard(data);
if (!result.success) {
this.emit('error', {
message: 'Failed to send leaderboard',
error: result.error,
});
}
return result.success;
}
// ==========================================================================
// PUBLIC API - Queue & Auto-send
// ==========================================================================
/**
* Queue data to be sent when game is ready
*/
queueGameData(data) {
this.pendingData = data;
this.log('info', 'Data queued for when game is ready');
// If already ready, send immediately
if (this.isReady) {
this.sendQueuedData();
}
return this;
}
/**
* Clear queued data
*/
clearQueuedData() {
this.pendingData = null;
return this;
}
// ==========================================================================
// PUBLIC API - Iframe Control
// ==========================================================================
/**
* Force reload iframe
*/
reloadIframe() {
this.isReady = false;
return this.messageSender.reloadIframe();
}
// ==========================================================================
// PUBLIC API - Lifecycle
// ==========================================================================
/**
* Cleanup and destroy SDK
*/
destroy() {
this.messageHandler.destroy();
this.removeAllListeners();
this.pendingData = null;
this.isReady = false;
this.log('info', 'SDK destroyed');
}
// ==========================================================================
// PUBLIC API - Direct Layer Access (Advanced)
// ==========================================================================
/**
* Get MessageHandler instance for advanced usage
*/
getMessageHandler() {
return this.messageHandler;
}
/**
* Get MessageSender instance for advanced usage
*/
getMessageSender() {
return this.messageSender;
}
// ==========================================================================
// PRIVATE METHODS
// ==========================================================================
/**
* Setup event forwarding from MessageHandler to SDK events
*/
setupEventForwarding() {
// Forward gameReady
this.messageHandler.on('gameReady', () => {
this.isReady = true;
this.emit('gameReady', undefined);
// Auto-send queued data if enabled
if (this.config.autoSendOnReady && this.pendingData) {
setTimeout(() => {
this.sendQueuedData();
}, this.config.readyDelay);
}
});
// Forward answerReport
this.messageHandler.on('answerReport', (data) => {
this.emit('answerReport', data);
});
// Forward finalResult
this.messageHandler.on('finalResult', (data) => {
this.emit('finalResult', data);
});
// Forward leaderboardRequest
this.messageHandler.on('leaderboardRequest', (data) => {
this.emit('leaderboardRequest', data);
});
// Forward errors
this.messageHandler.on('error', (error) => {
this.emit('error', error);
});
}
/**
* Send queued data
*/
sendQueuedData() {
if (this.pendingData) {
this.sendGameData(this.pendingData);
this.pendingData = null;
}
}
/**
* Internal logging
*/
log(level, message, data) {
if (this.config.debug) {
const prefix = '[GameIframeSDK]';
switch (level) {
case 'info':
console.log(prefix, message, data ?? '');
break;
case 'warn':
console.warn(prefix, message, data ?? '');
break;
case 'error':
console.error(prefix, message, data ?? '');
break;
}
}
this.emit('log', { level, message, data });
}
}
// ==========================================================================
// FACTORY / SINGLETON HELPERS
// ==========================================================================
let defaultInstance = null;
/**
* Create SDK instance
*/
export function createGameIframeSDK(config) {
return new GameIframeSDK(config);
}
/**
* Get or create default SDK instance
*/
export function getGameIframeSDK(config) {
if (!defaultInstance && config) {
defaultInstance = new GameIframeSDK(config);
}
if (!defaultInstance) {
throw new Error('GameIframeSDK not initialized. Call with config first.');
}
return defaultInstance;
}
/**
* Destroy default instance
*/
export function destroyGameIframeSDK() {
defaultInstance?.destroy();
defaultInstance = null;
}
//# sourceMappingURL=GameIframeSDK.js.map