@adstage/web-sdk 2.4.0 → 2.4.2
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/index.cjs.js +84 -8
- package/dist/index.d.ts +22 -11
- package/dist/index.esm.js +83 -9
- package/dist/index.standalone.js +155 -9
- package/package.json +1 -1
- package/src/index.ts +3 -0
- package/src/react/AdStageProvider.tsx +117 -0
- package/src/react/index.ts +11 -0
- package/src/renderers/base-renderer.ts +2 -0
- package/src/types/advertisement.ts +4 -17
- package/src/types/api.ts +1 -5
package/dist/index.cjs.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
|
|
3
6
|
// 광고 타입 정의
|
|
4
7
|
var AdType;
|
|
5
8
|
(function (AdType) {
|
|
@@ -19,15 +22,8 @@ var Platform;
|
|
|
19
22
|
// 광고 이벤트 타입
|
|
20
23
|
var AdEventType;
|
|
21
24
|
(function (AdEventType) {
|
|
22
|
-
AdEventType["IMPRESSION"] = "IMPRESSION";
|
|
23
|
-
AdEventType["CLICK"] = "CLICK";
|
|
24
|
-
AdEventType["HOVER"] = "HOVER";
|
|
25
25
|
AdEventType["VIEWABLE"] = "VIEWABLE";
|
|
26
|
-
AdEventType["
|
|
27
|
-
AdEventType["COMPLETED"] = "COMPLETED";
|
|
28
|
-
AdEventType["VIDEO_START"] = "VIDEO_START";
|
|
29
|
-
AdEventType["VIDEO_COMPLETE"] = "VIDEO_COMPLETE";
|
|
30
|
-
AdEventType["ERROR"] = "ERROR";
|
|
26
|
+
AdEventType["CLICK"] = "CLICK";
|
|
31
27
|
})(AdEventType || (AdEventType = {}));
|
|
32
28
|
// 디바이스 타입
|
|
33
29
|
var DeviceType;
|
|
@@ -1085,6 +1081,7 @@ class BaseAdRenderer {
|
|
|
1085
1081
|
display: 'block',
|
|
1086
1082
|
'max-width': '100%',
|
|
1087
1083
|
height: 'auto',
|
|
1084
|
+
'object-position': 'center', // 🎯 이미지 항상 중앙 정렬
|
|
1088
1085
|
};
|
|
1089
1086
|
// 사용자가 컨테이너 크기를 지정한 경우에만 크기 제한
|
|
1090
1087
|
const parsedWidth = this.parseSizeValue(slot?.width);
|
|
@@ -1093,6 +1090,7 @@ class BaseAdRenderer {
|
|
|
1093
1090
|
styles.width = '100%';
|
|
1094
1091
|
styles.height = '100%';
|
|
1095
1092
|
styles['object-fit'] = 'cover';
|
|
1093
|
+
styles['object-position'] = 'center'; // 🎯 크기 조정 시에도 중앙 정렬
|
|
1096
1094
|
}
|
|
1097
1095
|
return styles;
|
|
1098
1096
|
}
|
|
@@ -3316,6 +3314,82 @@ class AdStage {
|
|
|
3316
3314
|
}
|
|
3317
3315
|
}
|
|
3318
3316
|
|
|
3317
|
+
const AdStageContext = react.createContext(null);
|
|
3318
|
+
function AdStageProvider({ children, config }) {
|
|
3319
|
+
const [isInitialized, setIsInitialized] = react.useState(false);
|
|
3320
|
+
const [currentConfig, setCurrentConfig] = react.useState(null);
|
|
3321
|
+
const [error, setError] = react.useState(null);
|
|
3322
|
+
const initialize = (newConfig) => {
|
|
3323
|
+
try {
|
|
3324
|
+
setError(null);
|
|
3325
|
+
// 기존 인스턴스가 있으면 리셋
|
|
3326
|
+
if (isInitialized) {
|
|
3327
|
+
AdStage.reset();
|
|
3328
|
+
}
|
|
3329
|
+
AdStage.init(newConfig);
|
|
3330
|
+
setCurrentConfig(newConfig);
|
|
3331
|
+
setIsInitialized(true);
|
|
3332
|
+
if (newConfig.debug) {
|
|
3333
|
+
console.log('✅ AdStage SDK initialized successfully via React Provider');
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
catch (err) {
|
|
3337
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
3338
|
+
setError(errorMessage);
|
|
3339
|
+
console.error('❌ AdStage SDK initialization failed:', err);
|
|
3340
|
+
setIsInitialized(false);
|
|
3341
|
+
setCurrentConfig(null);
|
|
3342
|
+
}
|
|
3343
|
+
};
|
|
3344
|
+
const reset = () => {
|
|
3345
|
+
try {
|
|
3346
|
+
AdStage.reset();
|
|
3347
|
+
setIsInitialized(false);
|
|
3348
|
+
setCurrentConfig(null);
|
|
3349
|
+
setError(null);
|
|
3350
|
+
}
|
|
3351
|
+
catch (err) {
|
|
3352
|
+
console.error('❌ AdStage SDK reset failed:', err);
|
|
3353
|
+
}
|
|
3354
|
+
};
|
|
3355
|
+
// 자동 초기화
|
|
3356
|
+
react.useEffect(() => {
|
|
3357
|
+
if (config && !isInitialized) {
|
|
3358
|
+
initialize(config);
|
|
3359
|
+
}
|
|
3360
|
+
}, [config, isInitialized]);
|
|
3361
|
+
const contextValue = {
|
|
3362
|
+
isInitialized,
|
|
3363
|
+
config: currentConfig,
|
|
3364
|
+
initialize,
|
|
3365
|
+
reset,
|
|
3366
|
+
error
|
|
3367
|
+
};
|
|
3368
|
+
return (jsxRuntime.jsx(AdStageContext.Provider, { value: contextValue, children: children }));
|
|
3369
|
+
}
|
|
3370
|
+
/**
|
|
3371
|
+
* AdStage Context Hook
|
|
3372
|
+
* AdStageProvider 내에서 SDK 상태에 접근할 수 있습니다.
|
|
3373
|
+
*/
|
|
3374
|
+
function useAdStage() {
|
|
3375
|
+
const context = react.useContext(AdStageContext);
|
|
3376
|
+
if (!context) {
|
|
3377
|
+
throw new Error('useAdStage must be used within an AdStageProvider');
|
|
3378
|
+
}
|
|
3379
|
+
return context;
|
|
3380
|
+
}
|
|
3381
|
+
/**
|
|
3382
|
+
* AdStage SDK Hook
|
|
3383
|
+
* 초기화된 AdStage 인스턴스에 직접 접근할 수 있습니다.
|
|
3384
|
+
*/
|
|
3385
|
+
function useAdStageSDK() {
|
|
3386
|
+
const { isInitialized } = useAdStage();
|
|
3387
|
+
if (!isInitialized) {
|
|
3388
|
+
throw new Error('AdStage SDK is not initialized. Please call initialize() first or provide config to AdStageProvider.');
|
|
3389
|
+
}
|
|
3390
|
+
return AdStage;
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3319
3393
|
/**
|
|
3320
3394
|
* AdStage Web SDK
|
|
3321
3395
|
* 네임스페이스 아키텍처 기반 SDK
|
|
@@ -3326,5 +3400,7 @@ const SDK_VERSION = '2.0.0';
|
|
|
3326
3400
|
const SUPPORTED_MODULES = ['ads', 'events', 'config'];
|
|
3327
3401
|
|
|
3328
3402
|
exports.AdStage = AdStage;
|
|
3403
|
+
exports.AdStageProvider = AdStageProvider;
|
|
3329
3404
|
exports.SDK_VERSION = SDK_VERSION;
|
|
3330
3405
|
exports.SUPPORTED_MODULES = SUPPORTED_MODULES;
|
|
3406
|
+
exports.useAdStage = useAdStageSDK;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* AdStage SDK 모듈 타입
|
|
3
6
|
*/
|
|
@@ -68,15 +71,8 @@ declare enum Platform {
|
|
|
68
71
|
MOBILE = "MOBILE"
|
|
69
72
|
}
|
|
70
73
|
declare enum AdEventType {
|
|
71
|
-
IMPRESSION = "IMPRESSION",
|
|
72
|
-
CLICK = "CLICK",
|
|
73
|
-
HOVER = "HOVER",
|
|
74
74
|
VIEWABLE = "VIEWABLE",
|
|
75
|
-
|
|
76
|
-
COMPLETED = "COMPLETED",
|
|
77
|
-
VIDEO_START = "VIDEO_START",
|
|
78
|
-
VIDEO_COMPLETE = "VIDEO_COMPLETE",
|
|
79
|
-
ERROR = "ERROR"
|
|
75
|
+
CLICK = "CLICK"
|
|
80
76
|
}
|
|
81
77
|
declare enum DeviceType {
|
|
82
78
|
DESKTOP = "DESKTOP",
|
|
@@ -123,7 +119,7 @@ interface ViewabilityMetrics {
|
|
|
123
119
|
isViewable: boolean;
|
|
124
120
|
visibilityRatio: number;
|
|
125
121
|
duration: number;
|
|
126
|
-
|
|
122
|
+
viewables: number;
|
|
127
123
|
attentionTime: number;
|
|
128
124
|
scrollDepth: number;
|
|
129
125
|
completionRate: number;
|
|
@@ -199,7 +195,7 @@ interface AdSlot {
|
|
|
199
195
|
config?: AdSlotConfig;
|
|
200
196
|
advertisement?: Advertisement;
|
|
201
197
|
isViewable?: boolean;
|
|
202
|
-
|
|
198
|
+
viewableSent?: boolean;
|
|
203
199
|
loadTime?: number;
|
|
204
200
|
renderTime?: number;
|
|
205
201
|
events?: AdEvent[];
|
|
@@ -490,6 +486,21 @@ declare class AdStage {
|
|
|
490
486
|
static reset(): void;
|
|
491
487
|
}
|
|
492
488
|
|
|
489
|
+
interface AdStageProviderProps {
|
|
490
|
+
children: ReactNode;
|
|
491
|
+
/**
|
|
492
|
+
* 자동 초기화를 위한 설정 (선택사항)
|
|
493
|
+
* 제공되면 Provider 마운트 시 자동으로 초기화됩니다.
|
|
494
|
+
*/
|
|
495
|
+
config?: AdStageConfig;
|
|
496
|
+
}
|
|
497
|
+
declare function AdStageProvider({ children, config }: AdStageProviderProps): react_jsx_runtime.JSX.Element;
|
|
498
|
+
/**
|
|
499
|
+
* AdStage SDK Hook
|
|
500
|
+
* 초기화된 AdStage 인스턴스에 직접 접근할 수 있습니다.
|
|
501
|
+
*/
|
|
502
|
+
declare function useAdStageSDK(): typeof AdStage;
|
|
503
|
+
|
|
493
504
|
/**
|
|
494
505
|
* AdStage Web SDK
|
|
495
506
|
* 네임스페이스 아키텍처 기반 SDK
|
|
@@ -498,4 +509,4 @@ declare class AdStage {
|
|
|
498
509
|
declare const SDK_VERSION = "2.0.0";
|
|
499
510
|
declare const SUPPORTED_MODULES: readonly ["ads", "events", "config"];
|
|
500
511
|
|
|
501
|
-
export { AdEventType, AdOptions, AdSlot, AdStage, AdStageConfig, AdType, Advertisement, ApiResponse, BaseModule, EventProperties, ModuleName, OrganizationInfo, PageData, SDK_VERSION, SUPPORTED_MODULES };
|
|
512
|
+
export { AdEventType, AdOptions, AdSlot, AdStage, AdStageConfig, AdStageProvider, AdType, Advertisement, ApiResponse, BaseModule, EventProperties, ModuleName, OrganizationInfo, PageData, SDK_VERSION, SUPPORTED_MODULES, useAdStageSDK as useAdStage };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { createContext, useState, useEffect, useContext } from 'react';
|
|
3
|
+
|
|
1
4
|
// 광고 타입 정의
|
|
2
5
|
var AdType;
|
|
3
6
|
(function (AdType) {
|
|
@@ -17,15 +20,8 @@ var Platform;
|
|
|
17
20
|
// 광고 이벤트 타입
|
|
18
21
|
var AdEventType;
|
|
19
22
|
(function (AdEventType) {
|
|
20
|
-
AdEventType["IMPRESSION"] = "IMPRESSION";
|
|
21
|
-
AdEventType["CLICK"] = "CLICK";
|
|
22
|
-
AdEventType["HOVER"] = "HOVER";
|
|
23
23
|
AdEventType["VIEWABLE"] = "VIEWABLE";
|
|
24
|
-
AdEventType["
|
|
25
|
-
AdEventType["COMPLETED"] = "COMPLETED";
|
|
26
|
-
AdEventType["VIDEO_START"] = "VIDEO_START";
|
|
27
|
-
AdEventType["VIDEO_COMPLETE"] = "VIDEO_COMPLETE";
|
|
28
|
-
AdEventType["ERROR"] = "ERROR";
|
|
24
|
+
AdEventType["CLICK"] = "CLICK";
|
|
29
25
|
})(AdEventType || (AdEventType = {}));
|
|
30
26
|
// 디바이스 타입
|
|
31
27
|
var DeviceType;
|
|
@@ -1083,6 +1079,7 @@ class BaseAdRenderer {
|
|
|
1083
1079
|
display: 'block',
|
|
1084
1080
|
'max-width': '100%',
|
|
1085
1081
|
height: 'auto',
|
|
1082
|
+
'object-position': 'center', // 🎯 이미지 항상 중앙 정렬
|
|
1086
1083
|
};
|
|
1087
1084
|
// 사용자가 컨테이너 크기를 지정한 경우에만 크기 제한
|
|
1088
1085
|
const parsedWidth = this.parseSizeValue(slot?.width);
|
|
@@ -1091,6 +1088,7 @@ class BaseAdRenderer {
|
|
|
1091
1088
|
styles.width = '100%';
|
|
1092
1089
|
styles.height = '100%';
|
|
1093
1090
|
styles['object-fit'] = 'cover';
|
|
1091
|
+
styles['object-position'] = 'center'; // 🎯 크기 조정 시에도 중앙 정렬
|
|
1094
1092
|
}
|
|
1095
1093
|
return styles;
|
|
1096
1094
|
}
|
|
@@ -3314,6 +3312,82 @@ class AdStage {
|
|
|
3314
3312
|
}
|
|
3315
3313
|
}
|
|
3316
3314
|
|
|
3315
|
+
const AdStageContext = createContext(null);
|
|
3316
|
+
function AdStageProvider({ children, config }) {
|
|
3317
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
3318
|
+
const [currentConfig, setCurrentConfig] = useState(null);
|
|
3319
|
+
const [error, setError] = useState(null);
|
|
3320
|
+
const initialize = (newConfig) => {
|
|
3321
|
+
try {
|
|
3322
|
+
setError(null);
|
|
3323
|
+
// 기존 인스턴스가 있으면 리셋
|
|
3324
|
+
if (isInitialized) {
|
|
3325
|
+
AdStage.reset();
|
|
3326
|
+
}
|
|
3327
|
+
AdStage.init(newConfig);
|
|
3328
|
+
setCurrentConfig(newConfig);
|
|
3329
|
+
setIsInitialized(true);
|
|
3330
|
+
if (newConfig.debug) {
|
|
3331
|
+
console.log('✅ AdStage SDK initialized successfully via React Provider');
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
catch (err) {
|
|
3335
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
3336
|
+
setError(errorMessage);
|
|
3337
|
+
console.error('❌ AdStage SDK initialization failed:', err);
|
|
3338
|
+
setIsInitialized(false);
|
|
3339
|
+
setCurrentConfig(null);
|
|
3340
|
+
}
|
|
3341
|
+
};
|
|
3342
|
+
const reset = () => {
|
|
3343
|
+
try {
|
|
3344
|
+
AdStage.reset();
|
|
3345
|
+
setIsInitialized(false);
|
|
3346
|
+
setCurrentConfig(null);
|
|
3347
|
+
setError(null);
|
|
3348
|
+
}
|
|
3349
|
+
catch (err) {
|
|
3350
|
+
console.error('❌ AdStage SDK reset failed:', err);
|
|
3351
|
+
}
|
|
3352
|
+
};
|
|
3353
|
+
// 자동 초기화
|
|
3354
|
+
useEffect(() => {
|
|
3355
|
+
if (config && !isInitialized) {
|
|
3356
|
+
initialize(config);
|
|
3357
|
+
}
|
|
3358
|
+
}, [config, isInitialized]);
|
|
3359
|
+
const contextValue = {
|
|
3360
|
+
isInitialized,
|
|
3361
|
+
config: currentConfig,
|
|
3362
|
+
initialize,
|
|
3363
|
+
reset,
|
|
3364
|
+
error
|
|
3365
|
+
};
|
|
3366
|
+
return (jsx(AdStageContext.Provider, { value: contextValue, children: children }));
|
|
3367
|
+
}
|
|
3368
|
+
/**
|
|
3369
|
+
* AdStage Context Hook
|
|
3370
|
+
* AdStageProvider 내에서 SDK 상태에 접근할 수 있습니다.
|
|
3371
|
+
*/
|
|
3372
|
+
function useAdStage() {
|
|
3373
|
+
const context = useContext(AdStageContext);
|
|
3374
|
+
if (!context) {
|
|
3375
|
+
throw new Error('useAdStage must be used within an AdStageProvider');
|
|
3376
|
+
}
|
|
3377
|
+
return context;
|
|
3378
|
+
}
|
|
3379
|
+
/**
|
|
3380
|
+
* AdStage SDK Hook
|
|
3381
|
+
* 초기화된 AdStage 인스턴스에 직접 접근할 수 있습니다.
|
|
3382
|
+
*/
|
|
3383
|
+
function useAdStageSDK() {
|
|
3384
|
+
const { isInitialized } = useAdStage();
|
|
3385
|
+
if (!isInitialized) {
|
|
3386
|
+
throw new Error('AdStage SDK is not initialized. Please call initialize() first or provide config to AdStageProvider.');
|
|
3387
|
+
}
|
|
3388
|
+
return AdStage;
|
|
3389
|
+
}
|
|
3390
|
+
|
|
3317
3391
|
/**
|
|
3318
3392
|
* AdStage Web SDK
|
|
3319
3393
|
* 네임스페이스 아키텍처 기반 SDK
|
|
@@ -3323,4 +3397,4 @@ class AdStage {
|
|
|
3323
3397
|
const SDK_VERSION = '2.0.0';
|
|
3324
3398
|
const SUPPORTED_MODULES = ['ads', 'events', 'config'];
|
|
3325
3399
|
|
|
3326
|
-
export { AdStage, SDK_VERSION, SUPPORTED_MODULES };
|
|
3400
|
+
export { AdStage, AdStageProvider, SDK_VERSION, SUPPORTED_MODULES, useAdStageSDK as useAdStage };
|
package/dist/index.standalone.js
CHANGED
|
@@ -17,15 +17,8 @@ var Platform;
|
|
|
17
17
|
// 광고 이벤트 타입
|
|
18
18
|
var AdEventType;
|
|
19
19
|
(function (AdEventType) {
|
|
20
|
-
AdEventType["IMPRESSION"] = "IMPRESSION";
|
|
21
|
-
AdEventType["CLICK"] = "CLICK";
|
|
22
|
-
AdEventType["HOVER"] = "HOVER";
|
|
23
20
|
AdEventType["VIEWABLE"] = "VIEWABLE";
|
|
24
|
-
AdEventType["
|
|
25
|
-
AdEventType["COMPLETED"] = "COMPLETED";
|
|
26
|
-
AdEventType["VIDEO_START"] = "VIDEO_START";
|
|
27
|
-
AdEventType["VIDEO_COMPLETE"] = "VIDEO_COMPLETE";
|
|
28
|
-
AdEventType["ERROR"] = "ERROR";
|
|
21
|
+
AdEventType["CLICK"] = "CLICK";
|
|
29
22
|
})(AdEventType || (AdEventType = {}));
|
|
30
23
|
// 디바이스 타입
|
|
31
24
|
var DeviceType;
|
|
@@ -1083,6 +1076,7 @@ class BaseAdRenderer {
|
|
|
1083
1076
|
display: 'block',
|
|
1084
1077
|
'max-width': '100%',
|
|
1085
1078
|
height: 'auto',
|
|
1079
|
+
'object-position': 'center', // 🎯 이미지 항상 중앙 정렬
|
|
1086
1080
|
};
|
|
1087
1081
|
// 사용자가 컨테이너 크기를 지정한 경우에만 크기 제한
|
|
1088
1082
|
const parsedWidth = this.parseSizeValue(slot?.width);
|
|
@@ -1091,6 +1085,7 @@ class BaseAdRenderer {
|
|
|
1091
1085
|
styles.width = '100%';
|
|
1092
1086
|
styles.height = '100%';
|
|
1093
1087
|
styles['object-fit'] = 'cover';
|
|
1088
|
+
styles['object-position'] = 'center'; // 🎯 크기 조정 시에도 중앙 정렬
|
|
1094
1089
|
}
|
|
1095
1090
|
return styles;
|
|
1096
1091
|
}
|
|
@@ -3314,6 +3309,157 @@ class AdStage {
|
|
|
3314
3309
|
}
|
|
3315
3310
|
}
|
|
3316
3311
|
|
|
3312
|
+
var jsxRuntime = {exports: {}};
|
|
3313
|
+
|
|
3314
|
+
var reactJsxRuntime_production_min = {};
|
|
3315
|
+
|
|
3316
|
+
var react = {exports: {}};
|
|
3317
|
+
|
|
3318
|
+
var react_production_min = {};
|
|
3319
|
+
|
|
3320
|
+
/**
|
|
3321
|
+
* @license React
|
|
3322
|
+
* react.production.min.js
|
|
3323
|
+
*
|
|
3324
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3325
|
+
*
|
|
3326
|
+
* This source code is licensed under the MIT license found in the
|
|
3327
|
+
* LICENSE file in the root directory of this source tree.
|
|
3328
|
+
*/
|
|
3329
|
+
|
|
3330
|
+
var hasRequiredReact_production_min;
|
|
3331
|
+
|
|
3332
|
+
function requireReact_production_min () {
|
|
3333
|
+
if (hasRequiredReact_production_min) return react_production_min;
|
|
3334
|
+
hasRequiredReact_production_min = 1;
|
|
3335
|
+
var l=Symbol.for("react.element"),n=Symbol.for("react.portal"),p=Symbol.for("react.fragment"),q=Symbol.for("react.strict_mode"),r=Symbol.for("react.profiler"),t=Symbol.for("react.provider"),u=Symbol.for("react.context"),v=Symbol.for("react.forward_ref"),w=Symbol.for("react.suspense"),x=Symbol.for("react.memo"),y=Symbol.for("react.lazy"),z=Symbol.iterator;function A(a){if(null===a||"object"!==typeof a)return null;a=z&&a[z]||a["@@iterator"];return "function"===typeof a?a:null}
|
|
3336
|
+
var B={isMounted:function(){return !1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},C=Object.assign,D={};function E(a,b,e){this.props=a;this.context=b;this.refs=D;this.updater=e||B;}E.prototype.isReactComponent={};
|
|
3337
|
+
E.prototype.setState=function(a,b){if("object"!==typeof a&&"function"!==typeof a&&null!=a)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,a,b,"setState");};E.prototype.forceUpdate=function(a){this.updater.enqueueForceUpdate(this,a,"forceUpdate");};function F(){}F.prototype=E.prototype;function G(a,b,e){this.props=a;this.context=b;this.refs=D;this.updater=e||B;}var H=G.prototype=new F;
|
|
3338
|
+
H.constructor=G;C(H,E.prototype);H.isPureReactComponent=!0;var I=Array.isArray,J=Object.prototype.hasOwnProperty,K={current:null},L={key:!0,ref:!0,__self:!0,__source:!0};
|
|
3339
|
+
function M(a,b,e){var d,c={},k=null,h=null;if(null!=b)for(d in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(k=""+b.key),b)J.call(b,d)&&!L.hasOwnProperty(d)&&(c[d]=b[d]);var g=arguments.length-2;if(1===g)c.children=e;else if(1<g){for(var f=Array(g),m=0;m<g;m++)f[m]=arguments[m+2];c.children=f;}if(a&&a.defaultProps)for(d in g=a.defaultProps,g)void 0===c[d]&&(c[d]=g[d]);return {$$typeof:l,type:a,key:k,ref:h,props:c,_owner:K.current}}
|
|
3340
|
+
function N(a,b){return {$$typeof:l,type:a.type,key:b,ref:a.ref,props:a.props,_owner:a._owner}}function O(a){return "object"===typeof a&&null!==a&&a.$$typeof===l}function escape(a){var b={"=":"=0",":":"=2"};return "$"+a.replace(/[=:]/g,function(a){return b[a]})}var P=/\/+/g;function Q(a,b){return "object"===typeof a&&null!==a&&null!=a.key?escape(""+a.key):b.toString(36)}
|
|
3341
|
+
function R(a,b,e,d,c){var k=typeof a;if("undefined"===k||"boolean"===k)a=null;var h=!1;if(null===a)h=!0;else switch(k){case "string":case "number":h=!0;break;case "object":switch(a.$$typeof){case l:case n:h=!0;}}if(h)return h=a,c=c(h),a=""===d?"."+Q(h,0):d,I(c)?(e="",null!=a&&(e=a.replace(P,"$&/")+"/"),R(c,b,e,"",function(a){return a})):null!=c&&(O(c)&&(c=N(c,e+(!c.key||h&&h.key===c.key?"":(""+c.key).replace(P,"$&/")+"/")+a)),b.push(c)),1;h=0;d=""===d?".":d+":";if(I(a))for(var g=0;g<a.length;g++){k=
|
|
3342
|
+
a[g];var f=d+Q(k,g);h+=R(k,b,e,f,c);}else if(f=A(a),"function"===typeof f)for(a=f.call(a),g=0;!(k=a.next()).done;)k=k.value,f=d+Q(k,g++),h+=R(k,b,e,f,c);else if("object"===k)throw b=String(a),Error("Objects are not valid as a React child (found: "+("[object Object]"===b?"object with keys {"+Object.keys(a).join(", ")+"}":b)+"). If you meant to render a collection of children, use an array instead.");return h}
|
|
3343
|
+
function S(a,b,e){if(null==a)return a;var d=[],c=0;R(a,d,"","",function(a){return b.call(e,a,c++)});return d}function T(a){if(-1===a._status){var b=a._result;b=b();b.then(function(b){if(0===a._status||-1===a._status)a._status=1,a._result=b;},function(b){if(0===a._status||-1===a._status)a._status=2,a._result=b;});-1===a._status&&(a._status=0,a._result=b);}if(1===a._status)return a._result.default;throw a._result;}
|
|
3344
|
+
var U={current:null},V={transition:null},W={ReactCurrentDispatcher:U,ReactCurrentBatchConfig:V,ReactCurrentOwner:K};function X(){throw Error("act(...) is not supported in production builds of React.");}
|
|
3345
|
+
react_production_min.Children={map:S,forEach:function(a,b,e){S(a,function(){b.apply(this,arguments);},e);},count:function(a){var b=0;S(a,function(){b++;});return b},toArray:function(a){return S(a,function(a){return a})||[]},only:function(a){if(!O(a))throw Error("React.Children.only expected to receive a single React element child.");return a}};react_production_min.Component=E;react_production_min.Fragment=p;react_production_min.Profiler=r;react_production_min.PureComponent=G;react_production_min.StrictMode=q;react_production_min.Suspense=w;
|
|
3346
|
+
react_production_min.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=W;react_production_min.act=X;
|
|
3347
|
+
react_production_min.cloneElement=function(a,b,e){if(null===a||void 0===a)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+a+".");var d=C({},a.props),c=a.key,k=a.ref,h=a._owner;if(null!=b){void 0!==b.ref&&(k=b.ref,h=K.current);void 0!==b.key&&(c=""+b.key);if(a.type&&a.type.defaultProps)var g=a.type.defaultProps;for(f in b)J.call(b,f)&&!L.hasOwnProperty(f)&&(d[f]=void 0===b[f]&&void 0!==g?g[f]:b[f]);}var f=arguments.length-2;if(1===f)d.children=e;else if(1<f){g=Array(f);
|
|
3348
|
+
for(var m=0;m<f;m++)g[m]=arguments[m+2];d.children=g;}return {$$typeof:l,type:a.type,key:c,ref:k,props:d,_owner:h}};react_production_min.createContext=function(a){a={$$typeof:u,_currentValue:a,_currentValue2:a,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null};a.Provider={$$typeof:t,_context:a};return a.Consumer=a};react_production_min.createElement=M;react_production_min.createFactory=function(a){var b=M.bind(null,a);b.type=a;return b};react_production_min.createRef=function(){return {current:null}};
|
|
3349
|
+
react_production_min.forwardRef=function(a){return {$$typeof:v,render:a}};react_production_min.isValidElement=O;react_production_min.lazy=function(a){return {$$typeof:y,_payload:{_status:-1,_result:a},_init:T}};react_production_min.memo=function(a,b){return {$$typeof:x,type:a,compare:void 0===b?null:b}};react_production_min.startTransition=function(a){var b=V.transition;V.transition={};try{a();}finally{V.transition=b;}};react_production_min.unstable_act=X;react_production_min.useCallback=function(a,b){return U.current.useCallback(a,b)};react_production_min.useContext=function(a){return U.current.useContext(a)};
|
|
3350
|
+
react_production_min.useDebugValue=function(){};react_production_min.useDeferredValue=function(a){return U.current.useDeferredValue(a)};react_production_min.useEffect=function(a,b){return U.current.useEffect(a,b)};react_production_min.useId=function(){return U.current.useId()};react_production_min.useImperativeHandle=function(a,b,e){return U.current.useImperativeHandle(a,b,e)};react_production_min.useInsertionEffect=function(a,b){return U.current.useInsertionEffect(a,b)};react_production_min.useLayoutEffect=function(a,b){return U.current.useLayoutEffect(a,b)};
|
|
3351
|
+
react_production_min.useMemo=function(a,b){return U.current.useMemo(a,b)};react_production_min.useReducer=function(a,b,e){return U.current.useReducer(a,b,e)};react_production_min.useRef=function(a){return U.current.useRef(a)};react_production_min.useState=function(a){return U.current.useState(a)};react_production_min.useSyncExternalStore=function(a,b,e){return U.current.useSyncExternalStore(a,b,e)};react_production_min.useTransition=function(){return U.current.useTransition()};react_production_min.version="18.3.1";
|
|
3352
|
+
return react_production_min;
|
|
3353
|
+
}
|
|
3354
|
+
|
|
3355
|
+
{
|
|
3356
|
+
react.exports = requireReact_production_min();
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
var reactExports = react.exports;
|
|
3360
|
+
|
|
3361
|
+
/**
|
|
3362
|
+
* @license React
|
|
3363
|
+
* react-jsx-runtime.production.min.js
|
|
3364
|
+
*
|
|
3365
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3366
|
+
*
|
|
3367
|
+
* This source code is licensed under the MIT license found in the
|
|
3368
|
+
* LICENSE file in the root directory of this source tree.
|
|
3369
|
+
*/
|
|
3370
|
+
|
|
3371
|
+
var hasRequiredReactJsxRuntime_production_min;
|
|
3372
|
+
|
|
3373
|
+
function requireReactJsxRuntime_production_min () {
|
|
3374
|
+
if (hasRequiredReactJsxRuntime_production_min) return reactJsxRuntime_production_min;
|
|
3375
|
+
hasRequiredReactJsxRuntime_production_min = 1;
|
|
3376
|
+
var f=reactExports,k=Symbol.for("react.element"),l=Symbol.for("react.fragment"),m=Object.prototype.hasOwnProperty,n=f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0};
|
|
3377
|
+
function q(c,a,g){var b,d={},e=null,h=null;void 0!==g&&(e=""+g);void 0!==a.key&&(e=""+a.key);void 0!==a.ref&&(h=a.ref);for(b in a)m.call(a,b)&&!p.hasOwnProperty(b)&&(d[b]=a[b]);if(c&&c.defaultProps)for(b in a=c.defaultProps,a)void 0===d[b]&&(d[b]=a[b]);return {$$typeof:k,type:c,key:e,ref:h,props:d,_owner:n.current}}reactJsxRuntime_production_min.Fragment=l;reactJsxRuntime_production_min.jsx=q;reactJsxRuntime_production_min.jsxs=q;
|
|
3378
|
+
return reactJsxRuntime_production_min;
|
|
3379
|
+
}
|
|
3380
|
+
|
|
3381
|
+
{
|
|
3382
|
+
jsxRuntime.exports = requireReactJsxRuntime_production_min();
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
var jsxRuntimeExports = jsxRuntime.exports;
|
|
3386
|
+
|
|
3387
|
+
const AdStageContext = reactExports.createContext(null);
|
|
3388
|
+
function AdStageProvider({ children, config }) {
|
|
3389
|
+
const [isInitialized, setIsInitialized] = reactExports.useState(false);
|
|
3390
|
+
const [currentConfig, setCurrentConfig] = reactExports.useState(null);
|
|
3391
|
+
const [error, setError] = reactExports.useState(null);
|
|
3392
|
+
const initialize = (newConfig) => {
|
|
3393
|
+
try {
|
|
3394
|
+
setError(null);
|
|
3395
|
+
// 기존 인스턴스가 있으면 리셋
|
|
3396
|
+
if (isInitialized) {
|
|
3397
|
+
AdStage.reset();
|
|
3398
|
+
}
|
|
3399
|
+
AdStage.init(newConfig);
|
|
3400
|
+
setCurrentConfig(newConfig);
|
|
3401
|
+
setIsInitialized(true);
|
|
3402
|
+
if (newConfig.debug) {
|
|
3403
|
+
console.log('✅ AdStage SDK initialized successfully via React Provider');
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
catch (err) {
|
|
3407
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
3408
|
+
setError(errorMessage);
|
|
3409
|
+
console.error('❌ AdStage SDK initialization failed:', err);
|
|
3410
|
+
setIsInitialized(false);
|
|
3411
|
+
setCurrentConfig(null);
|
|
3412
|
+
}
|
|
3413
|
+
};
|
|
3414
|
+
const reset = () => {
|
|
3415
|
+
try {
|
|
3416
|
+
AdStage.reset();
|
|
3417
|
+
setIsInitialized(false);
|
|
3418
|
+
setCurrentConfig(null);
|
|
3419
|
+
setError(null);
|
|
3420
|
+
}
|
|
3421
|
+
catch (err) {
|
|
3422
|
+
console.error('❌ AdStage SDK reset failed:', err);
|
|
3423
|
+
}
|
|
3424
|
+
};
|
|
3425
|
+
// 자동 초기화
|
|
3426
|
+
reactExports.useEffect(() => {
|
|
3427
|
+
if (config && !isInitialized) {
|
|
3428
|
+
initialize(config);
|
|
3429
|
+
}
|
|
3430
|
+
}, [config, isInitialized]);
|
|
3431
|
+
const contextValue = {
|
|
3432
|
+
isInitialized,
|
|
3433
|
+
config: currentConfig,
|
|
3434
|
+
initialize,
|
|
3435
|
+
reset,
|
|
3436
|
+
error
|
|
3437
|
+
};
|
|
3438
|
+
return (jsxRuntimeExports.jsx(AdStageContext.Provider, { value: contextValue, children: children }));
|
|
3439
|
+
}
|
|
3440
|
+
/**
|
|
3441
|
+
* AdStage Context Hook
|
|
3442
|
+
* AdStageProvider 내에서 SDK 상태에 접근할 수 있습니다.
|
|
3443
|
+
*/
|
|
3444
|
+
function useAdStage() {
|
|
3445
|
+
const context = reactExports.useContext(AdStageContext);
|
|
3446
|
+
if (!context) {
|
|
3447
|
+
throw new Error('useAdStage must be used within an AdStageProvider');
|
|
3448
|
+
}
|
|
3449
|
+
return context;
|
|
3450
|
+
}
|
|
3451
|
+
/**
|
|
3452
|
+
* AdStage SDK Hook
|
|
3453
|
+
* 초기화된 AdStage 인스턴스에 직접 접근할 수 있습니다.
|
|
3454
|
+
*/
|
|
3455
|
+
function useAdStageSDK() {
|
|
3456
|
+
const { isInitialized } = useAdStage();
|
|
3457
|
+
if (!isInitialized) {
|
|
3458
|
+
throw new Error('AdStage SDK is not initialized. Please call initialize() first or provide config to AdStageProvider.');
|
|
3459
|
+
}
|
|
3460
|
+
return AdStage;
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3317
3463
|
/**
|
|
3318
3464
|
* AdStage Web SDK
|
|
3319
3465
|
* 네임스페이스 아키텍처 기반 SDK
|
|
@@ -3323,4 +3469,4 @@ class AdStage {
|
|
|
3323
3469
|
const SDK_VERSION = '2.0.0';
|
|
3324
3470
|
const SUPPORTED_MODULES = ['ads', 'events', 'config'];
|
|
3325
3471
|
|
|
3326
|
-
export { AdStage, SDK_VERSION, SUPPORTED_MODULES };
|
|
3472
|
+
export { AdStage, AdStageProvider, SDK_VERSION, SUPPORTED_MODULES, useAdStageSDK as useAdStage };
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
// 메인 네임스페이스 클래스
|
|
7
7
|
export { default as AdStage } from './core/AdStage';
|
|
8
8
|
|
|
9
|
+
// React 통합
|
|
10
|
+
export { AdStageProvider, useAdStage } from './react';
|
|
11
|
+
|
|
9
12
|
// 설정 및 타입
|
|
10
13
|
export type { AdStageConfig, ModuleName, BaseModule, ApiResponse, OrganizationInfo } from './types/config';
|
|
11
14
|
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdStage SDK - React Provider
|
|
3
|
+
* React 애플리케이션에서 AdStage SDK를 쉽게 사용할 수 있도록 하는 Provider 컴포넌트
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';
|
|
7
|
+
import AdStage from '../core/AdStage';
|
|
8
|
+
import { AdStageConfig } from '../types/config';
|
|
9
|
+
|
|
10
|
+
interface AdStageContextType {
|
|
11
|
+
isInitialized: boolean;
|
|
12
|
+
config: AdStageConfig | null;
|
|
13
|
+
initialize: (config: AdStageConfig) => void;
|
|
14
|
+
reset: () => void;
|
|
15
|
+
error: string | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const AdStageContext = createContext<AdStageContextType | null>(null);
|
|
19
|
+
|
|
20
|
+
interface AdStageProviderProps {
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* 자동 초기화를 위한 설정 (선택사항)
|
|
24
|
+
* 제공되면 Provider 마운트 시 자동으로 초기화됩니다.
|
|
25
|
+
*/
|
|
26
|
+
config?: AdStageConfig;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function AdStageProvider({ children, config }: AdStageProviderProps) {
|
|
30
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
31
|
+
const [currentConfig, setCurrentConfig] = useState<AdStageConfig | null>(null);
|
|
32
|
+
const [error, setError] = useState<string | null>(null);
|
|
33
|
+
|
|
34
|
+
const initialize = (newConfig: AdStageConfig) => {
|
|
35
|
+
try {
|
|
36
|
+
setError(null);
|
|
37
|
+
|
|
38
|
+
// 기존 인스턴스가 있으면 리셋
|
|
39
|
+
if (isInitialized) {
|
|
40
|
+
AdStage.reset();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
AdStage.init(newConfig);
|
|
44
|
+
|
|
45
|
+
setCurrentConfig(newConfig);
|
|
46
|
+
setIsInitialized(true);
|
|
47
|
+
|
|
48
|
+
if (newConfig.debug) {
|
|
49
|
+
console.log('✅ AdStage SDK initialized successfully via React Provider');
|
|
50
|
+
}
|
|
51
|
+
} catch (err) {
|
|
52
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
53
|
+
setError(errorMessage);
|
|
54
|
+
console.error('❌ AdStage SDK initialization failed:', err);
|
|
55
|
+
setIsInitialized(false);
|
|
56
|
+
setCurrentConfig(null);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const reset = () => {
|
|
61
|
+
try {
|
|
62
|
+
AdStage.reset();
|
|
63
|
+
setIsInitialized(false);
|
|
64
|
+
setCurrentConfig(null);
|
|
65
|
+
setError(null);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
console.error('❌ AdStage SDK reset failed:', err);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// 자동 초기화
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (config && !isInitialized) {
|
|
74
|
+
initialize(config);
|
|
75
|
+
}
|
|
76
|
+
}, [config, isInitialized]);
|
|
77
|
+
|
|
78
|
+
const contextValue: AdStageContextType = {
|
|
79
|
+
isInitialized,
|
|
80
|
+
config: currentConfig,
|
|
81
|
+
initialize,
|
|
82
|
+
reset,
|
|
83
|
+
error
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<AdStageContext.Provider value={contextValue}>
|
|
88
|
+
{children}
|
|
89
|
+
</AdStageContext.Provider>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* AdStage Context Hook
|
|
95
|
+
* AdStageProvider 내에서 SDK 상태에 접근할 수 있습니다.
|
|
96
|
+
*/
|
|
97
|
+
export function useAdStage(): AdStageContextType {
|
|
98
|
+
const context = useContext(AdStageContext);
|
|
99
|
+
if (!context) {
|
|
100
|
+
throw new Error('useAdStage must be used within an AdStageProvider');
|
|
101
|
+
}
|
|
102
|
+
return context;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* AdStage SDK Hook
|
|
107
|
+
* 초기화된 AdStage 인스턴스에 직접 접근할 수 있습니다.
|
|
108
|
+
*/
|
|
109
|
+
export function useAdStageSDK() {
|
|
110
|
+
const { isInitialized } = useAdStage();
|
|
111
|
+
|
|
112
|
+
if (!isInitialized) {
|
|
113
|
+
throw new Error('AdStage SDK is not initialized. Please call initialize() first or provide config to AdStageProvider.');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return AdStage;
|
|
117
|
+
}
|
package/src/react/index.ts
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AdStage Web SDK - React Integration
|
|
3
|
+
* React 애플리케이션을 위한 컴포넌트와 훅들
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { AdStageProvider, useAdStage as useAdStageContext, useAdStageSDK as useAdStage } from './AdStageProvider';
|
|
7
|
+
|
|
8
|
+
// 타입들도 재export
|
|
9
|
+
export type { AdStageConfig, ModuleName, BaseModule } from '../types/config';
|
|
10
|
+
export type { AdOptions } from '../modules/ads/AdsModule';
|
|
11
|
+
export type { AdType, AdEventType, Advertisement, AdSlot } from '../types/advertisement';
|
|
@@ -110,6 +110,7 @@ export abstract class BaseAdRenderer implements AdRenderer {
|
|
|
110
110
|
display: 'block',
|
|
111
111
|
'max-width': '100%',
|
|
112
112
|
height: 'auto',
|
|
113
|
+
'object-position': 'center', // 🎯 이미지 항상 중앙 정렬
|
|
113
114
|
};
|
|
114
115
|
|
|
115
116
|
// 사용자가 컨테이너 크기를 지정한 경우에만 크기 제한
|
|
@@ -120,6 +121,7 @@ export abstract class BaseAdRenderer implements AdRenderer {
|
|
|
120
121
|
styles.width = '100%';
|
|
121
122
|
styles.height = '100%';
|
|
122
123
|
styles['object-fit'] = 'cover';
|
|
124
|
+
styles['object-position'] = 'center'; // 🎯 크기 조정 시에도 중앙 정렬
|
|
123
125
|
}
|
|
124
126
|
|
|
125
127
|
return styles;
|
|
@@ -16,15 +16,8 @@ export enum Platform {
|
|
|
16
16
|
|
|
17
17
|
// 광고 이벤트 타입
|
|
18
18
|
export enum AdEventType {
|
|
19
|
-
IMPRESSION = 'IMPRESSION',
|
|
20
|
-
CLICK = 'CLICK',
|
|
21
|
-
HOVER = 'HOVER',
|
|
22
19
|
VIEWABLE = 'VIEWABLE',
|
|
23
|
-
|
|
24
|
-
COMPLETED = 'COMPLETED',
|
|
25
|
-
VIDEO_START = 'VIDEO_START',
|
|
26
|
-
VIDEO_COMPLETE = 'VIDEO_COMPLETE',
|
|
27
|
-
ERROR = 'ERROR',
|
|
20
|
+
CLICK = 'CLICK',
|
|
28
21
|
}
|
|
29
22
|
|
|
30
23
|
// 디바이스 타입
|
|
@@ -79,7 +72,7 @@ export interface ViewabilityMetrics {
|
|
|
79
72
|
isViewable: boolean;
|
|
80
73
|
visibilityRatio: number;
|
|
81
74
|
duration: number;
|
|
82
|
-
|
|
75
|
+
viewables: number;
|
|
83
76
|
attentionTime: number;
|
|
84
77
|
scrollDepth: number;
|
|
85
78
|
completionRate: number;
|
|
@@ -171,7 +164,7 @@ export interface AdSlot {
|
|
|
171
164
|
config?: AdSlotConfig;
|
|
172
165
|
advertisement?: Advertisement;
|
|
173
166
|
isViewable?: boolean;
|
|
174
|
-
|
|
167
|
+
viewableSent?: boolean;
|
|
175
168
|
loadTime?: number;
|
|
176
169
|
renderTime?: number;
|
|
177
170
|
events?: AdEvent[];
|
|
@@ -185,13 +178,7 @@ export interface AdSlot {
|
|
|
185
178
|
|
|
186
179
|
// 광고 성과 지표
|
|
187
180
|
export interface AdAnalytics {
|
|
188
|
-
|
|
181
|
+
viewables: number;
|
|
189
182
|
clicks: number;
|
|
190
|
-
hovers: number;
|
|
191
|
-
viewableImpressions: number;
|
|
192
|
-
errors: number;
|
|
193
183
|
ctr: number; // Click Through Rate
|
|
194
|
-
viewabilityRate: number;
|
|
195
|
-
averageViewTime: number;
|
|
196
|
-
totalViewTime: number;
|
|
197
184
|
}
|
package/src/types/api.ts
CHANGED
|
@@ -76,13 +76,9 @@ export interface AnalyticsRequest {
|
|
|
76
76
|
|
|
77
77
|
// 광고 분석 응답
|
|
78
78
|
export interface AnalyticsResponse {
|
|
79
|
-
|
|
79
|
+
viewables: number;
|
|
80
80
|
clicks: number;
|
|
81
|
-
hovers: number;
|
|
82
|
-
viewableImpressions: number;
|
|
83
|
-
errors: number;
|
|
84
81
|
ctr: number;
|
|
85
|
-
viewabilityRate: number;
|
|
86
82
|
breakdown?: Record<string, AdAnalytics>;
|
|
87
83
|
}
|
|
88
84
|
|