@adstage/web-sdk
Version:
AdStage Web SDK - Production-ready marketing platform SDK with React Provider support for seamless integration
150 lines (128 loc) • 5.01 kB
text/typescript
import { DOMUtils } from '../utils/dom-utils';
import { getSDKVersion } from '../utils/version';
import { ConfigUtils } from '../utils/config-utils';
/**
* 디바이스 정보 수집 클래스
* - 브라우저 환경 정보 수집
* - 디바이스 ID 생성 및 관리
* - 세션 ID 생성 및 관리
*/
export class DeviceInfoCollector {
/**
* 디바이스 ID 생성 및 반환 (SSR 안전)
*/
static generateDeviceId(): string {
if (!DOMUtils.isBrowser()) return 'ssr_device_' + Date.now();
const stored = localStorage.getItem('adstage_device_id');
if (stored) return stored;
const deviceId = 'device_' + Math.random().toString(36).substr(2, 9) + '_' + Date.now();
localStorage.setItem('adstage_device_id', deviceId);
return deviceId;
}
/**
* 세션 ID 생성 및 반환 (SSR 안전)
*/
static generateSessionId(): string {
if (!DOMUtils.isBrowser()) return 'ssr_session_' + Date.now();
const stored = sessionStorage.getItem('adstage_session_id');
if (stored) return stored;
const sessionId = 'session_' + Math.random().toString(36).substr(2, 9) + '_' + Date.now();
sessionStorage.setItem('adstage_session_id', sessionId);
return sessionId;
}
/**
* 모바일 디바이스 여부 확인 (SSR 안전)
*/
static isMobile(): boolean {
if (!DOMUtils.isBrowser()) return false;
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
/**
* 플랫폼 타입 반환 (서버 enum에 맞춤, SSR 안전)
*/
static getPlatform(): 'ios' | 'android' | 'web' | 'desktop' {
if (!DOMUtils.isBrowser()) return 'web';
const userAgent = navigator.userAgent.toLowerCase();
if (/iphone|ipad|ipod/.test(userAgent)) {
return 'ios';
}
if (/android/.test(userAgent)) {
return 'android';
}
if (DeviceInfoCollector.isMobile()) {
return 'web'; // 모바일 웹
}
return 'desktop'; // 데스크톱 웹
}
/**
* 완전한 디바이스 정보 수집
*/
static collectDeviceInfo(): {
deviceId: string;
sessionId: string;
osVersion: string;
deviceModel: string;
appVersion: string;
sdkVersion: string;
language: string;
country: string;
ipAddress: string;
userAgent: string;
timezone: string;
viewportWidth: number;
viewportHeight: number;
screenWidth: number;
screenHeight: number;
colorDepth: number;
pixelRatio: number;
connectionType: string;
platform: 'ios' | 'android' | 'web' | 'desktop';
} {
const viewportInfo = DOMUtils.getViewportInfo();
return {
deviceId: DeviceInfoCollector.generateDeviceId(),
sessionId: DeviceInfoCollector.generateSessionId(),
osVersion: DOMUtils.isBrowser() ? navigator.platform : 'SSR',
deviceModel: DOMUtils.isBrowser() ? navigator.platform : 'SSR',
appVersion: '1.0.0', // 기본값 (사용자가 별도 설정 필요)
sdkVersion: getSDKVersion(), // package.json에서 동적 로드
language: DOMUtils.isBrowser() ? (navigator.language || 'ko') : 'ko',
country: 'KR', // 기본값
ipAddress: '', // 서버에서 자동으로 설정됨
userAgent: DOMUtils.isBrowser() ? navigator.userAgent : 'SSR',
timezone: DOMUtils.isBrowser() ? Intl.DateTimeFormat().resolvedOptions().timeZone : 'UTC',
viewportWidth: viewportInfo.width,
viewportHeight: viewportInfo.height,
screenWidth: DOMUtils.isBrowser() ? screen.width : 0,
screenHeight: DOMUtils.isBrowser() ? screen.height : 0,
colorDepth: DOMUtils.isBrowser() ? screen.colorDepth : 24,
pixelRatio: viewportInfo.pixelRatio,
connectionType: DOMUtils.isBrowser() ? ((navigator as any).connection?.effectiveType || 'unknown') : 'unknown',
platform: DeviceInfoCollector.getPlatform(),
};
}
/**
* 슬롯 위치 정보 가져오기 (SSR 안전)
* 슬라이더 내부 광고 요소도 지원
*/
static getSlotPosition(containerId: string): string {
// 1. 기본 컨테이너 ID로 먼저 찾기
let element = DOMUtils.safeGetElementById(containerId);
// 2. 컨테이너를 찾지 못한 경우, 슬라이더 래퍼 찾기
if (!element) {
// 슬라이더 래퍼는 일반적으로 원본 컨테이너 내부에 있음
const sliderWrapper = DOMUtils.safeQuerySelector(`#${containerId} .adstage-slider-wrapper`);
if (sliderWrapper) {
element = sliderWrapper as HTMLElement;
}
}
// 3. 여전히 찾지 못한 경우, data-adstage-slot-id 속성으로 찾기
if (!element) {
element = DOMUtils.safeQuerySelector(`[data-adstage-slot-id="${containerId}"]`);
}
if (!element) return 'unknown';
const rect = element.getBoundingClientRect();
const scrollInfo = DOMUtils.getScrollInfo();
return `x:${Math.round(rect.left)},y:${Math.round(rect.top + scrollInfo.scrollTop)}`;
}
}