@gamealytics/web-sdk
Version:
GameAlytics SDK for Web/Node.js - Cross-platform analytics for game developers
284 lines (283 loc) • 9.86 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Environment = exports.UserConfig = exports.GameAlytics = exports.CustomEventBuilder = exports.SystemEventBuilder = exports.Ad = exports.Progression = exports.User = exports.IAP = exports.Gameplay = void 0;
// Core types
const DataValidator_1 = require("./validation/DataValidator");
const EventQueue_1 = require("./queue/EventQueue");
var Environment;
(function (Environment) {
Environment["DEVELOPMENT"] = "DEVELOPMENT";
Environment["PRODUCTION"] = "PRODUCTION";
})(Environment || (exports.Environment = Environment = {}));
class UserConfigBuilder {
setSessionId(sessionId) {
this.sessionId = sessionId;
return this;
}
setUserId(userId) {
this.userId = userId;
return this;
}
setAnonymous(anonymousId) {
this.anonymousId = anonymousId;
return this;
}
build() {
if (!this.sessionId) {
throw new Error('SessionId is required');
}
if (!this.userId && !this.anonymousId) {
throw new Error('Either userId or anonymousId must be provided');
}
return new UserConfig(this.sessionId, this.userId, this.anonymousId);
}
}
class UserConfig {
constructor(sessionId, userId, anonymousId) {
this.sessionId = sessionId;
if (userId !== undefined) {
this.userId = userId;
}
if (anonymousId !== undefined) {
this.anonymousId = anonymousId;
}
}
static builder() {
return new UserConfigBuilder();
}
}
exports.UserConfig = UserConfig;
class EventBuilderImpl {
constructor(eventType, eventCategory, isCustom) {
this.properties = {};
this.eventType = eventType;
this.eventCategory = eventCategory;
this.isCustom = isCustom;
}
setProperties(properties) {
this.properties = Object.assign(Object.assign({}, this.properties), properties);
return this;
}
async track() {
GameAlytics.getInstance().trackEvent(this.isCustom ? 'CUSTOM' : 'SYSTEM', this.eventType, this.eventCategory, this.properties);
}
}
class InitBuilder {
constructor(apiKey, environment) {
this.apiKey = apiKey;
this.environment = environment;
}
userConfig(userConfig) {
this.userConfigValue = userConfig;
return this;
}
create() {
if (!this.apiKey) {
throw new Error('API key is required');
}
if (!this.userConfigValue) {
throw new Error('UserConfig is required');
}
GameAlytics.instance = new GameAlytics(this.apiKey, this.environment, this.userConfigValue);
return GameAlytics.instance;
}
}
class GameAlytics {
constructor(apiKey, environment, userConfig) {
this.isInitialized = false;
this.apiKey = apiKey;
this.environment = environment;
this.userConfig = userConfig;
this.deviceInfo = this.autoFetchDeviceInfo();
this.baseUrl = environment === Environment.PRODUCTION
? 'https://client.gamealytics.click'
: 'https://client.dev.gamealytics.click';
// Initialize event queue with base URL and API key injection
this.eventQueue = new EventQueue_1.EventQueue();
window.__GA_BASE_URL__ = this.baseUrl;
window.__GA_API_KEY__ = this.apiKey;
this.isInitialized = true;
}
static init(apiKey, environment) {
return new InitBuilder(apiKey, environment);
}
static getInstance() {
if (!GameAlytics.instance) {
throw new Error('GameAlytics must be initialized first. Call GameAlytics.init(...).create()');
}
return GameAlytics.instance;
}
systemEvent() {
return new SystemEventBuilder();
}
customEvent() {
return new CustomEventBuilder();
}
autoFetchDeviceInfo() {
try {
const isBrowser = typeof window !== 'undefined';
return {
platform: isBrowser ? 'Web' : 'Node.js',
osVersion: this.getOSVersion(),
deviceModel: isBrowser ? window.navigator.platform : 'Node.js',
screenResolution: this.getScreenResolution(),
deviceManufacturer: isBrowser ? window.navigator.vendor || 'Unknown' : 'Node.js',
appVersion: '1.0.0'
};
}
catch (error) {
// Silent failure for performance
return {
platform: 'Unknown',
osVersion: 'Unknown',
deviceModel: 'Unknown',
screenResolution: 'Unknown',
deviceManufacturer: 'Unknown',
appVersion: '1.0.0'
};
}
}
trackEvent(type, eventType, category, properties) {
// Validate and sanitize properties
const validationResult = DataValidator_1.DataValidator.validateProperties(properties, {
maxLength: 100,
allowHtml: false,
allowedTypes: ['string', 'number', 'boolean']
});
// Log validation errors in development
if (validationResult.errors.length > 0 && this.environment === Environment.DEVELOPMENT) {
console.warn('GameAlytics validation warnings:', validationResult.errors);
}
const eventPayload = Object.assign(Object.assign({ type, value: eventType, category, properties: validationResult.sanitized }, this.deviceInfo), { timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, localDateTime: new Date().toISOString(), userId: this.userConfig.userId || '', anonymousId: this.userConfig.anonymousId || '', sessionId: this.userConfig.sessionId });
// Use event queue for reliable delivery
this.eventQueue.enqueue(eventPayload);
}
getOSVersion() {
if (typeof window === 'undefined')
return 'Node.js';
const userAgent = window.navigator.userAgent;
const platform = window.navigator.platform;
const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'];
const windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'];
const iosPlatforms = ['iPhone', 'iPad', 'iPod'];
if (macosPlatforms.indexOf(platform) !== -1)
return 'Mac OS';
if (iosPlatforms.indexOf(platform) !== -1)
return 'iOS';
if (windowsPlatforms.indexOf(platform) !== -1)
return 'Windows';
if (/Android/.test(userAgent))
return 'Android';
if (/Linux/.test(platform))
return 'Linux';
return 'Unknown';
}
getScreenResolution() {
if (typeof window !== 'undefined' && window.screen) {
return `${window.screen.width}x${window.screen.height}`;
}
return 'unknown';
}
ensureInitialized() {
if (!this.isInitialized) {
throw new Error('GameAlytics must be initialized first. Call GameAlytics.init()');
}
}
}
exports.GameAlytics = GameAlytics;
GameAlytics.instance = null;
// Event Category Classes
class Gameplay {
}
exports.Gameplay = Gameplay;
Gameplay.LEVEL_START = 'level_start';
Gameplay.LEVEL_END = 'level_end';
Gameplay.LEVEL_UP = 'level_up';
Gameplay.BOSS_FIGHT = 'boss_fight';
Gameplay.CHECKPOINT_REACHED = 'checkpoint_reached';
class IAP {
}
exports.IAP = IAP;
IAP.PURCHASE = 'purchase';
IAP.PURCHASE_FAILED = 'purchase_failed';
IAP.PURCHASE_RESTORED = 'purchase_restored';
IAP.SUBSCRIPTION_STARTED = 'subscription_started';
IAP.SUBSCRIPTION_CANCELLED = 'subscription_cancelled';
class User {
}
exports.User = User;
User.SESSION_START = 'session_start';
User.SESSION_END = 'session_end';
User.USER_LOGIN = 'user_login';
User.USER_LOGOUT = 'user_logout';
User.USER_REGISTER = 'user_register';
class Progression {
}
exports.Progression = Progression;
Progression.TUTORIAL_COMPLETE = 'tutorial_complete';
Progression.ACHIEVEMENT_UNLOCKED = 'achievement_unlocked';
Progression.MILESTONE_REACHED = 'milestone_reached';
Progression.QUEST_COMPLETED = 'quest_completed';
class Ad {
}
exports.Ad = Ad;
Ad.AD_VIEWED = 'ad_viewed';
Ad.AD_CLICKED = 'ad_clicked';
Ad.AD_REWARDED = 'ad_rewarded';
Ad.AD_FAILED = 'ad_failed';
// Event Builders
class SystemEventBuilder {
constructor() {
this.properties = {};
}
categoryClass(categoryClass) {
this.category = categoryClass.constructor.name.toLowerCase();
return this;
}
eventType(type) {
this.type = type;
return this;
}
setProperties(properties) {
this.properties = properties || {};
return this;
}
trigger() {
if (!GameAlytics.instance) {
throw new Error('GameAlytics must be initialized first');
}
if (!this.category || !this.type) {
throw new Error('Category and type are required');
}
GameAlytics.instance.trackEvent('SYSTEM', this.type, this.category, this.properties);
}
}
exports.SystemEventBuilder = SystemEventBuilder;
class CustomEventBuilder {
constructor() {
this.properties = {};
}
categoryName(category) {
this.category = category;
return this;
}
eventType(type) {
this.type = type;
return this;
}
setProperties(properties) {
this.properties = properties || {};
return this;
}
trigger() {
if (!GameAlytics.instance) {
throw new Error('GameAlytics must be initialized first');
}
if (!this.category || !this.type) {
throw new Error('Category and type are required');
}
GameAlytics.instance.trackEvent('CUSTOM', this.type, this.category, this.properties);
}
}
exports.CustomEventBuilder = CustomEventBuilder;
exports.default = GameAlytics;