@adstage/web-sdk 2.4.5 → 2.4.7
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
CHANGED
|
@@ -47,11 +47,15 @@ class ViewableEventTracker {
|
|
|
47
47
|
static isDuplicateViewable(adId, slotId, debug = false) {
|
|
48
48
|
const key = `${adId}_${slotId}`;
|
|
49
49
|
const now = Date.now();
|
|
50
|
+
// 디버그 모드에 따른 쿨다운 시간 결정
|
|
51
|
+
const cooldownTime = debug ?
|
|
52
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_DEBUG :
|
|
53
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION;
|
|
50
54
|
// 메모리 기반 중복 확인 (새로고침 시 초기화됨)
|
|
51
55
|
const lastViewable = ViewableEventTracker.viewableTracker.get(key);
|
|
52
|
-
if (lastViewable && (now - lastViewable) <
|
|
56
|
+
if (lastViewable && (now - lastViewable) < cooldownTime) {
|
|
53
57
|
if (debug) {
|
|
54
|
-
console.log(`Duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((
|
|
58
|
+
console.log(`Duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((cooldownTime - (now - lastViewable)) / 1000)}s remaining (${debug ? 'debug' : 'production'} mode)`);
|
|
55
59
|
}
|
|
56
60
|
return true;
|
|
57
61
|
}
|
|
@@ -60,9 +64,9 @@ class ViewableEventTracker {
|
|
|
60
64
|
const sessionViewable = sessionStorage.getItem(sessionKey);
|
|
61
65
|
if (sessionViewable) {
|
|
62
66
|
const sessionTime = parseInt(sessionViewable, 10);
|
|
63
|
-
if (!isNaN(sessionTime) && (now - sessionTime) <
|
|
67
|
+
if (!isNaN(sessionTime) && (now - sessionTime) < cooldownTime) {
|
|
64
68
|
if (debug) {
|
|
65
|
-
console.log(`Session-based duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((
|
|
69
|
+
console.log(`Session-based duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((cooldownTime - (now - sessionTime)) / 1000)}s remaining (${debug ? 'debug' : 'production'} mode)`);
|
|
66
70
|
}
|
|
67
71
|
// 메모리에도 기록하여 이후 요청 최적화
|
|
68
72
|
ViewableEventTracker.viewableTracker.set(key, sessionTime);
|
|
@@ -74,6 +78,9 @@ class ViewableEventTracker {
|
|
|
74
78
|
sessionStorage.setItem(sessionKey, now.toString());
|
|
75
79
|
// 오래된 세션 스토리지 데이터 정리 (선택적)
|
|
76
80
|
ViewableEventTracker.cleanupOldViewables();
|
|
81
|
+
if (debug) {
|
|
82
|
+
console.log(`✅ New viewable recorded for ad ${adId} in slot ${slotId} (${debug ? 'debug' : 'production'} mode)`);
|
|
83
|
+
}
|
|
77
84
|
return false;
|
|
78
85
|
}
|
|
79
86
|
/**
|
|
@@ -81,7 +88,8 @@ class ViewableEventTracker {
|
|
|
81
88
|
*/
|
|
82
89
|
static cleanupOldViewables() {
|
|
83
90
|
const now = Date.now();
|
|
84
|
-
|
|
91
|
+
// 프로덕션 쿨다운의 2배 시간이 지난 데이터 정리
|
|
92
|
+
const cleanupThreshold = ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION * 2;
|
|
85
93
|
// 세션 스토리지 정리
|
|
86
94
|
for (let i = 0; i < sessionStorage.length; i++) {
|
|
87
95
|
const key = sessionStorage.key(i);
|
|
@@ -104,14 +112,33 @@ class ViewableEventTracker {
|
|
|
104
112
|
}
|
|
105
113
|
}
|
|
106
114
|
/**
|
|
107
|
-
* 모든 추적 데이터 정리
|
|
115
|
+
* 모든 추적 데이터 정리 (디버그용)
|
|
108
116
|
*/
|
|
109
117
|
static clear() {
|
|
110
118
|
ViewableEventTracker.viewableTracker.clear();
|
|
119
|
+
// 세션 스토리지에서도 adstage_viewable_ 키들 제거
|
|
120
|
+
const keysToRemove = [];
|
|
121
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
122
|
+
const key = sessionStorage.key(i);
|
|
123
|
+
if (key && key.startsWith('adstage_viewable_')) {
|
|
124
|
+
keysToRemove.push(key);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
keysToRemove.forEach(key => sessionStorage.removeItem(key));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 특정 광고의 viewable 추적 초기화 (디버그용)
|
|
131
|
+
*/
|
|
132
|
+
static clearAdViewable(adId, slotId) {
|
|
133
|
+
const key = `${adId}_${slotId}`;
|
|
134
|
+
ViewableEventTracker.viewableTracker.delete(key);
|
|
135
|
+
const sessionKey = `adstage_viewable_${key}`;
|
|
136
|
+
sessionStorage.removeItem(sessionKey);
|
|
111
137
|
}
|
|
112
138
|
}
|
|
113
139
|
ViewableEventTracker.viewableTracker = new Map();
|
|
114
|
-
ViewableEventTracker.
|
|
140
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION = 300000; // 5분 쿨다운 (프로덕션)
|
|
141
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_DEBUG = 30000; // 30초 쿨다운 (디버그)
|
|
115
142
|
|
|
116
143
|
/**
|
|
117
144
|
* SSR 안전한 DOM API 래퍼 클래스
|
|
@@ -2229,6 +2256,9 @@ class AdRenderer {
|
|
|
2229
2256
|
}
|
|
2230
2257
|
if (this.advertisementEventTracker) {
|
|
2231
2258
|
try {
|
|
2259
|
+
if (this.debug) {
|
|
2260
|
+
console.log(`🔄 Starting advertisement event tracking: ${eventType} for ad ${adId} in slot ${slotId}`);
|
|
2261
|
+
}
|
|
2232
2262
|
await this.advertisementEventTracker.trackAdvertisementEvent(adId, slotId, eventType, {});
|
|
2233
2263
|
if (this.debug) {
|
|
2234
2264
|
console.log(`📊 Advertisement event tracked: ${eventType} for ad ${adId} in slot ${slotId}`);
|
|
@@ -2240,6 +2270,11 @@ class AdRenderer {
|
|
|
2240
2270
|
}
|
|
2241
2271
|
}
|
|
2242
2272
|
}
|
|
2273
|
+
else {
|
|
2274
|
+
if (this.debug) {
|
|
2275
|
+
console.warn(`⚠️ AdvertisementEventTracker not available for ${eventType} event`);
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2243
2278
|
};
|
|
2244
2279
|
let sliderElement;
|
|
2245
2280
|
const optimizedSliderOptions = {
|
package/dist/index.esm.js
CHANGED
|
@@ -45,11 +45,15 @@ class ViewableEventTracker {
|
|
|
45
45
|
static isDuplicateViewable(adId, slotId, debug = false) {
|
|
46
46
|
const key = `${adId}_${slotId}`;
|
|
47
47
|
const now = Date.now();
|
|
48
|
+
// 디버그 모드에 따른 쿨다운 시간 결정
|
|
49
|
+
const cooldownTime = debug ?
|
|
50
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_DEBUG :
|
|
51
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION;
|
|
48
52
|
// 메모리 기반 중복 확인 (새로고침 시 초기화됨)
|
|
49
53
|
const lastViewable = ViewableEventTracker.viewableTracker.get(key);
|
|
50
|
-
if (lastViewable && (now - lastViewable) <
|
|
54
|
+
if (lastViewable && (now - lastViewable) < cooldownTime) {
|
|
51
55
|
if (debug) {
|
|
52
|
-
console.log(`Duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((
|
|
56
|
+
console.log(`Duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((cooldownTime - (now - lastViewable)) / 1000)}s remaining (${debug ? 'debug' : 'production'} mode)`);
|
|
53
57
|
}
|
|
54
58
|
return true;
|
|
55
59
|
}
|
|
@@ -58,9 +62,9 @@ class ViewableEventTracker {
|
|
|
58
62
|
const sessionViewable = sessionStorage.getItem(sessionKey);
|
|
59
63
|
if (sessionViewable) {
|
|
60
64
|
const sessionTime = parseInt(sessionViewable, 10);
|
|
61
|
-
if (!isNaN(sessionTime) && (now - sessionTime) <
|
|
65
|
+
if (!isNaN(sessionTime) && (now - sessionTime) < cooldownTime) {
|
|
62
66
|
if (debug) {
|
|
63
|
-
console.log(`Session-based duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((
|
|
67
|
+
console.log(`Session-based duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((cooldownTime - (now - sessionTime)) / 1000)}s remaining (${debug ? 'debug' : 'production'} mode)`);
|
|
64
68
|
}
|
|
65
69
|
// 메모리에도 기록하여 이후 요청 최적화
|
|
66
70
|
ViewableEventTracker.viewableTracker.set(key, sessionTime);
|
|
@@ -72,6 +76,9 @@ class ViewableEventTracker {
|
|
|
72
76
|
sessionStorage.setItem(sessionKey, now.toString());
|
|
73
77
|
// 오래된 세션 스토리지 데이터 정리 (선택적)
|
|
74
78
|
ViewableEventTracker.cleanupOldViewables();
|
|
79
|
+
if (debug) {
|
|
80
|
+
console.log(`✅ New viewable recorded for ad ${adId} in slot ${slotId} (${debug ? 'debug' : 'production'} mode)`);
|
|
81
|
+
}
|
|
75
82
|
return false;
|
|
76
83
|
}
|
|
77
84
|
/**
|
|
@@ -79,7 +86,8 @@ class ViewableEventTracker {
|
|
|
79
86
|
*/
|
|
80
87
|
static cleanupOldViewables() {
|
|
81
88
|
const now = Date.now();
|
|
82
|
-
|
|
89
|
+
// 프로덕션 쿨다운의 2배 시간이 지난 데이터 정리
|
|
90
|
+
const cleanupThreshold = ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION * 2;
|
|
83
91
|
// 세션 스토리지 정리
|
|
84
92
|
for (let i = 0; i < sessionStorage.length; i++) {
|
|
85
93
|
const key = sessionStorage.key(i);
|
|
@@ -102,14 +110,33 @@ class ViewableEventTracker {
|
|
|
102
110
|
}
|
|
103
111
|
}
|
|
104
112
|
/**
|
|
105
|
-
* 모든 추적 데이터 정리
|
|
113
|
+
* 모든 추적 데이터 정리 (디버그용)
|
|
106
114
|
*/
|
|
107
115
|
static clear() {
|
|
108
116
|
ViewableEventTracker.viewableTracker.clear();
|
|
117
|
+
// 세션 스토리지에서도 adstage_viewable_ 키들 제거
|
|
118
|
+
const keysToRemove = [];
|
|
119
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
120
|
+
const key = sessionStorage.key(i);
|
|
121
|
+
if (key && key.startsWith('adstage_viewable_')) {
|
|
122
|
+
keysToRemove.push(key);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
keysToRemove.forEach(key => sessionStorage.removeItem(key));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 특정 광고의 viewable 추적 초기화 (디버그용)
|
|
129
|
+
*/
|
|
130
|
+
static clearAdViewable(adId, slotId) {
|
|
131
|
+
const key = `${adId}_${slotId}`;
|
|
132
|
+
ViewableEventTracker.viewableTracker.delete(key);
|
|
133
|
+
const sessionKey = `adstage_viewable_${key}`;
|
|
134
|
+
sessionStorage.removeItem(sessionKey);
|
|
109
135
|
}
|
|
110
136
|
}
|
|
111
137
|
ViewableEventTracker.viewableTracker = new Map();
|
|
112
|
-
ViewableEventTracker.
|
|
138
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION = 300000; // 5분 쿨다운 (프로덕션)
|
|
139
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_DEBUG = 30000; // 30초 쿨다운 (디버그)
|
|
113
140
|
|
|
114
141
|
/**
|
|
115
142
|
* SSR 안전한 DOM API 래퍼 클래스
|
|
@@ -2227,6 +2254,9 @@ class AdRenderer {
|
|
|
2227
2254
|
}
|
|
2228
2255
|
if (this.advertisementEventTracker) {
|
|
2229
2256
|
try {
|
|
2257
|
+
if (this.debug) {
|
|
2258
|
+
console.log(`🔄 Starting advertisement event tracking: ${eventType} for ad ${adId} in slot ${slotId}`);
|
|
2259
|
+
}
|
|
2230
2260
|
await this.advertisementEventTracker.trackAdvertisementEvent(adId, slotId, eventType, {});
|
|
2231
2261
|
if (this.debug) {
|
|
2232
2262
|
console.log(`📊 Advertisement event tracked: ${eventType} for ad ${adId} in slot ${slotId}`);
|
|
@@ -2238,6 +2268,11 @@ class AdRenderer {
|
|
|
2238
2268
|
}
|
|
2239
2269
|
}
|
|
2240
2270
|
}
|
|
2271
|
+
else {
|
|
2272
|
+
if (this.debug) {
|
|
2273
|
+
console.warn(`⚠️ AdvertisementEventTracker not available for ${eventType} event`);
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2241
2276
|
};
|
|
2242
2277
|
let sliderElement;
|
|
2243
2278
|
const optimizedSliderOptions = {
|
package/dist/index.standalone.js
CHANGED
|
@@ -42,11 +42,15 @@ class ViewableEventTracker {
|
|
|
42
42
|
static isDuplicateViewable(adId, slotId, debug = false) {
|
|
43
43
|
const key = `${adId}_${slotId}`;
|
|
44
44
|
const now = Date.now();
|
|
45
|
+
// 디버그 모드에 따른 쿨다운 시간 결정
|
|
46
|
+
const cooldownTime = debug ?
|
|
47
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_DEBUG :
|
|
48
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION;
|
|
45
49
|
// 메모리 기반 중복 확인 (새로고침 시 초기화됨)
|
|
46
50
|
const lastViewable = ViewableEventTracker.viewableTracker.get(key);
|
|
47
|
-
if (lastViewable && (now - lastViewable) <
|
|
51
|
+
if (lastViewable && (now - lastViewable) < cooldownTime) {
|
|
48
52
|
if (debug) {
|
|
49
|
-
console.log(`Duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((
|
|
53
|
+
console.log(`Duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((cooldownTime - (now - lastViewable)) / 1000)}s remaining (${debug ? 'debug' : 'production'} mode)`);
|
|
50
54
|
}
|
|
51
55
|
return true;
|
|
52
56
|
}
|
|
@@ -55,9 +59,9 @@ class ViewableEventTracker {
|
|
|
55
59
|
const sessionViewable = sessionStorage.getItem(sessionKey);
|
|
56
60
|
if (sessionViewable) {
|
|
57
61
|
const sessionTime = parseInt(sessionViewable, 10);
|
|
58
|
-
if (!isNaN(sessionTime) && (now - sessionTime) <
|
|
62
|
+
if (!isNaN(sessionTime) && (now - sessionTime) < cooldownTime) {
|
|
59
63
|
if (debug) {
|
|
60
|
-
console.log(`Session-based duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((
|
|
64
|
+
console.log(`Session-based duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((cooldownTime - (now - sessionTime)) / 1000)}s remaining (${debug ? 'debug' : 'production'} mode)`);
|
|
61
65
|
}
|
|
62
66
|
// 메모리에도 기록하여 이후 요청 최적화
|
|
63
67
|
ViewableEventTracker.viewableTracker.set(key, sessionTime);
|
|
@@ -69,6 +73,9 @@ class ViewableEventTracker {
|
|
|
69
73
|
sessionStorage.setItem(sessionKey, now.toString());
|
|
70
74
|
// 오래된 세션 스토리지 데이터 정리 (선택적)
|
|
71
75
|
ViewableEventTracker.cleanupOldViewables();
|
|
76
|
+
if (debug) {
|
|
77
|
+
console.log(`✅ New viewable recorded for ad ${adId} in slot ${slotId} (${debug ? 'debug' : 'production'} mode)`);
|
|
78
|
+
}
|
|
72
79
|
return false;
|
|
73
80
|
}
|
|
74
81
|
/**
|
|
@@ -76,7 +83,8 @@ class ViewableEventTracker {
|
|
|
76
83
|
*/
|
|
77
84
|
static cleanupOldViewables() {
|
|
78
85
|
const now = Date.now();
|
|
79
|
-
|
|
86
|
+
// 프로덕션 쿨다운의 2배 시간이 지난 데이터 정리
|
|
87
|
+
const cleanupThreshold = ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION * 2;
|
|
80
88
|
// 세션 스토리지 정리
|
|
81
89
|
for (let i = 0; i < sessionStorage.length; i++) {
|
|
82
90
|
const key = sessionStorage.key(i);
|
|
@@ -99,14 +107,33 @@ class ViewableEventTracker {
|
|
|
99
107
|
}
|
|
100
108
|
}
|
|
101
109
|
/**
|
|
102
|
-
* 모든 추적 데이터 정리
|
|
110
|
+
* 모든 추적 데이터 정리 (디버그용)
|
|
103
111
|
*/
|
|
104
112
|
static clear() {
|
|
105
113
|
ViewableEventTracker.viewableTracker.clear();
|
|
114
|
+
// 세션 스토리지에서도 adstage_viewable_ 키들 제거
|
|
115
|
+
const keysToRemove = [];
|
|
116
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
117
|
+
const key = sessionStorage.key(i);
|
|
118
|
+
if (key && key.startsWith('adstage_viewable_')) {
|
|
119
|
+
keysToRemove.push(key);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
keysToRemove.forEach(key => sessionStorage.removeItem(key));
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 특정 광고의 viewable 추적 초기화 (디버그용)
|
|
126
|
+
*/
|
|
127
|
+
static clearAdViewable(adId, slotId) {
|
|
128
|
+
const key = `${adId}_${slotId}`;
|
|
129
|
+
ViewableEventTracker.viewableTracker.delete(key);
|
|
130
|
+
const sessionKey = `adstage_viewable_${key}`;
|
|
131
|
+
sessionStorage.removeItem(sessionKey);
|
|
106
132
|
}
|
|
107
133
|
}
|
|
108
134
|
ViewableEventTracker.viewableTracker = new Map();
|
|
109
|
-
ViewableEventTracker.
|
|
135
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION = 300000; // 5분 쿨다운 (프로덕션)
|
|
136
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_DEBUG = 30000; // 30초 쿨다운 (디버그)
|
|
110
137
|
|
|
111
138
|
/**
|
|
112
139
|
* SSR 안전한 DOM API 래퍼 클래스
|
|
@@ -2224,6 +2251,9 @@ class AdRenderer {
|
|
|
2224
2251
|
}
|
|
2225
2252
|
if (this.advertisementEventTracker) {
|
|
2226
2253
|
try {
|
|
2254
|
+
if (this.debug) {
|
|
2255
|
+
console.log(`🔄 Starting advertisement event tracking: ${eventType} for ad ${adId} in slot ${slotId}`);
|
|
2256
|
+
}
|
|
2227
2257
|
await this.advertisementEventTracker.trackAdvertisementEvent(adId, slotId, eventType, {});
|
|
2228
2258
|
if (this.debug) {
|
|
2229
2259
|
console.log(`📊 Advertisement event tracked: ${eventType} for ad ${adId} in slot ${slotId}`);
|
|
@@ -2235,6 +2265,11 @@ class AdRenderer {
|
|
|
2235
2265
|
}
|
|
2236
2266
|
}
|
|
2237
2267
|
}
|
|
2268
|
+
else {
|
|
2269
|
+
if (this.debug) {
|
|
2270
|
+
console.warn(`⚠️ AdvertisementEventTracker not available for ${eventType} event`);
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2238
2273
|
};
|
|
2239
2274
|
let sliderElement;
|
|
2240
2275
|
const optimizedSliderOptions = {
|
package/package.json
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export class ViewableEventTracker {
|
|
9
9
|
private static viewableTracker = new Map<string, number>();
|
|
10
|
-
private static readonly
|
|
10
|
+
private static readonly VIEWABLE_COOLDOWN_PRODUCTION = 300000; // 5분 쿨다운 (프로덕션)
|
|
11
|
+
private static readonly VIEWABLE_COOLDOWN_DEBUG = 30000; // 30초 쿨다운 (디버그)
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* 중복 viewable 이벤트 여부 확인
|
|
@@ -16,11 +17,16 @@ export class ViewableEventTracker {
|
|
|
16
17
|
const key = `${adId}_${slotId}`;
|
|
17
18
|
const now = Date.now();
|
|
18
19
|
|
|
20
|
+
// 디버그 모드에 따른 쿨다운 시간 결정
|
|
21
|
+
const cooldownTime = debug ?
|
|
22
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_DEBUG :
|
|
23
|
+
ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION;
|
|
24
|
+
|
|
19
25
|
// 메모리 기반 중복 확인 (새로고침 시 초기화됨)
|
|
20
26
|
const lastViewable = ViewableEventTracker.viewableTracker.get(key);
|
|
21
|
-
if (lastViewable && (now - lastViewable) <
|
|
27
|
+
if (lastViewable && (now - lastViewable) < cooldownTime) {
|
|
22
28
|
if (debug) {
|
|
23
|
-
console.log(`Duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((
|
|
29
|
+
console.log(`Duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((cooldownTime - (now - lastViewable)) / 1000)}s remaining (${debug ? 'debug' : 'production'} mode)`);
|
|
24
30
|
}
|
|
25
31
|
return true;
|
|
26
32
|
}
|
|
@@ -30,9 +36,9 @@ export class ViewableEventTracker {
|
|
|
30
36
|
const sessionViewable = sessionStorage.getItem(sessionKey);
|
|
31
37
|
if (sessionViewable) {
|
|
32
38
|
const sessionTime = parseInt(sessionViewable, 10);
|
|
33
|
-
if (!isNaN(sessionTime) && (now - sessionTime) <
|
|
39
|
+
if (!isNaN(sessionTime) && (now - sessionTime) < cooldownTime) {
|
|
34
40
|
if (debug) {
|
|
35
|
-
console.log(`Session-based duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((
|
|
41
|
+
console.log(`Session-based duplicate viewable blocked for ad ${adId} in slot ${slotId}. Cooldown: ${Math.round((cooldownTime - (now - sessionTime)) / 1000)}s remaining (${debug ? 'debug' : 'production'} mode)`);
|
|
36
42
|
}
|
|
37
43
|
// 메모리에도 기록하여 이후 요청 최적화
|
|
38
44
|
ViewableEventTracker.viewableTracker.set(key, sessionTime);
|
|
@@ -47,6 +53,10 @@ export class ViewableEventTracker {
|
|
|
47
53
|
// 오래된 세션 스토리지 데이터 정리 (선택적)
|
|
48
54
|
ViewableEventTracker.cleanupOldViewables();
|
|
49
55
|
|
|
56
|
+
if (debug) {
|
|
57
|
+
console.log(`✅ New viewable recorded for ad ${adId} in slot ${slotId} (${debug ? 'debug' : 'production'} mode)`);
|
|
58
|
+
}
|
|
59
|
+
|
|
50
60
|
return false;
|
|
51
61
|
}
|
|
52
62
|
|
|
@@ -55,7 +65,8 @@ export class ViewableEventTracker {
|
|
|
55
65
|
*/
|
|
56
66
|
private static cleanupOldViewables(): void {
|
|
57
67
|
const now = Date.now();
|
|
58
|
-
|
|
68
|
+
// 프로덕션 쿨다운의 2배 시간이 지난 데이터 정리
|
|
69
|
+
const cleanupThreshold = ViewableEventTracker.VIEWABLE_COOLDOWN_PRODUCTION * 2;
|
|
59
70
|
|
|
60
71
|
// 세션 스토리지 정리
|
|
61
72
|
for (let i = 0; i < sessionStorage.length; i++) {
|
|
@@ -81,9 +92,28 @@ export class ViewableEventTracker {
|
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
/**
|
|
84
|
-
* 모든 추적 데이터 정리
|
|
95
|
+
* 모든 추적 데이터 정리 (디버그용)
|
|
85
96
|
*/
|
|
86
97
|
static clear(): void {
|
|
87
98
|
ViewableEventTracker.viewableTracker.clear();
|
|
99
|
+
// 세션 스토리지에서도 adstage_viewable_ 키들 제거
|
|
100
|
+
const keysToRemove: string[] = [];
|
|
101
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
102
|
+
const key = sessionStorage.key(i);
|
|
103
|
+
if (key && key.startsWith('adstage_viewable_')) {
|
|
104
|
+
keysToRemove.push(key);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
keysToRemove.forEach(key => sessionStorage.removeItem(key));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 특정 광고의 viewable 추적 초기화 (디버그용)
|
|
112
|
+
*/
|
|
113
|
+
static clearAdViewable(adId: string, slotId: string): void {
|
|
114
|
+
const key = `${adId}_${slotId}`;
|
|
115
|
+
ViewableEventTracker.viewableTracker.delete(key);
|
|
116
|
+
const sessionKey = `adstage_viewable_${key}`;
|
|
117
|
+
sessionStorage.removeItem(sessionKey);
|
|
88
118
|
}
|
|
89
119
|
}
|
|
@@ -250,6 +250,9 @@ export class AdRenderer {
|
|
|
250
250
|
|
|
251
251
|
if (this.advertisementEventTracker) {
|
|
252
252
|
try {
|
|
253
|
+
if (this.debug) {
|
|
254
|
+
console.log(`🔄 Starting advertisement event tracking: ${eventType} for ad ${adId} in slot ${slotId}`);
|
|
255
|
+
}
|
|
253
256
|
await this.advertisementEventTracker.trackAdvertisementEvent(adId, slotId, eventType, {});
|
|
254
257
|
if (this.debug) {
|
|
255
258
|
console.log(`📊 Advertisement event tracked: ${eventType} for ad ${adId} in slot ${slotId}`);
|
|
@@ -259,6 +262,10 @@ export class AdRenderer {
|
|
|
259
262
|
console.error(`❌ Failed to track ${eventType} event for ad ${adId}:`, error);
|
|
260
263
|
}
|
|
261
264
|
}
|
|
265
|
+
} else {
|
|
266
|
+
if (this.debug) {
|
|
267
|
+
console.warn(`⚠️ AdvertisementEventTracker not available for ${eventType} event`);
|
|
268
|
+
}
|
|
262
269
|
}
|
|
263
270
|
};
|
|
264
271
|
|