@blux.ai/web-sdk 2.2.13 → 2.2.14
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/.tsbuildinfo.noEmit +1 -1
- package/dist/BluxClient.d.ts +0 -2
- package/dist/BluxClient.js +70 -41
- package/dist/BluxClient.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/utils/observables.js +13 -17
- package/dist/utils/observables.js.map +1 -1
- package/package.json +1 -1
- package/scripts/cafe24/.tsbuildinfo.noEmit +1 -0
- package/scripts/cafe24/dist/.temp/index.d.ts +1 -0
- package/scripts/cafe24/dist/blux_collector.js +1 -0
- package/scripts/cafe24/dist/custom_scripts/daiso.d.ts +1 -0
- package/scripts/cafe24/dist/custom_scripts/daiso.js +114 -0
- package/scripts/cafe24/dist/custom_scripts/nerdy.d.ts +16 -0
- package/scripts/cafe24/dist/custom_scripts/nerdy.js +734 -0
- package/scripts/cafe24/dist/custom_scripts/vogoplay.d.ts +6 -0
- package/scripts/cafe24/dist/custom_scripts/vogoplay.js +147 -0
- package/scripts/cafe24/dist/deploy_all.d.ts +1 -0
- package/scripts/cafe24/dist/tsconfig.tsbuildinfo +1 -0
- package/scripts/sdk/.tsbuildinfo.noEmit +1 -0
- package/scripts/sdk/dist/tsconfig.tsbuildinfo +1 -0
package/dist/BluxClient.d.ts
CHANGED
|
@@ -45,8 +45,6 @@ type InAppCustomActionEvent = {
|
|
|
45
45
|
*/
|
|
46
46
|
type InAppCustomActionHandler = (event: InAppCustomActionEvent) => void | Promise<void>;
|
|
47
47
|
declare class BluxClient {
|
|
48
|
-
private readonly isBrowser;
|
|
49
|
-
private static readonly EMPTY_REC_RESPONSE;
|
|
50
48
|
private readonly api;
|
|
51
49
|
private readonly sdkInfo;
|
|
52
50
|
readonly bluxUser$: BehaviorSubject<BluxUser | undefined>;
|
package/dist/BluxClient.js
CHANGED
|
@@ -20,7 +20,7 @@ import { AddClickEvent } from "./events/AddClickEvent.js";
|
|
|
20
20
|
import { VisitEvent } from "./events/VisitEvent.js";
|
|
21
21
|
import "./events/index.js";
|
|
22
22
|
import { LocalStorage } from "./utils/LocalStorage.js";
|
|
23
|
-
import {
|
|
23
|
+
import { onlineAndVisible$ } from "./utils/observables.js";
|
|
24
24
|
import { filterNullable } from "./utils/operators.js";
|
|
25
25
|
import { SessionStorage } from "./utils/SessionStorage.js";
|
|
26
26
|
import axios from "axios";
|
|
@@ -29,13 +29,7 @@ import dayjs from "dayjs";
|
|
|
29
29
|
import { BehaviorSubject, NEVER, Subject, bufferTime, catchError, combineLatest, concatMap, debounceTime, filter, first, firstValueFrom, from, groupBy, map, merge, mergeMap, skip, switchMap, throwError, timeout, timer } from "rxjs";
|
|
30
30
|
|
|
31
31
|
//#region src/BluxClient.ts
|
|
32
|
-
var BluxClient = class
|
|
33
|
-
isBrowser = typeof window !== "undefined";
|
|
34
|
-
static EMPTY_REC_RESPONSE = {
|
|
35
|
-
item_ids: [],
|
|
36
|
-
metadata: {},
|
|
37
|
-
recommendation_id: null
|
|
38
|
-
};
|
|
32
|
+
var BluxClient = class {
|
|
39
33
|
api = axios.create();
|
|
40
34
|
sdkInfo = {
|
|
41
35
|
type: DevicePlatform.browser,
|
|
@@ -57,14 +51,14 @@ var BluxClient = class BluxClient {
|
|
|
57
51
|
bluxApplicationId;
|
|
58
52
|
bluxAPIKey;
|
|
59
53
|
customDeviceId;
|
|
60
|
-
bridge
|
|
54
|
+
bridge;
|
|
61
55
|
impressedElements = [];
|
|
62
56
|
intersectionObservingElements = [];
|
|
63
|
-
intersectionObserver =
|
|
57
|
+
intersectionObserver = new IntersectionObserver((entries) => {
|
|
64
58
|
entries.forEach((entry) => {
|
|
65
59
|
this.intersectionEntry$.next(entry);
|
|
66
60
|
});
|
|
67
|
-
})
|
|
61
|
+
});
|
|
68
62
|
intersectionEntry$ = new Subject();
|
|
69
63
|
hitElements = [];
|
|
70
64
|
currentInappCleanup = null;
|
|
@@ -88,10 +82,6 @@ var BluxClient = class BluxClient {
|
|
|
88
82
|
this.bluxApplicationId = bluxApplicationId;
|
|
89
83
|
this.bluxAPIKey = bluxAPIKey;
|
|
90
84
|
this.customDeviceId = customDeviceId;
|
|
91
|
-
if (!this.isBrowser) {
|
|
92
|
-
completionCallback?.({ success: true });
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
85
|
const baseUrl = window?._BLUX_SDK_?.baseUrl ?? "https://api.blux.ai/prod";
|
|
96
86
|
this.api.defaults.baseURL = baseUrl;
|
|
97
87
|
this.bridge = this.resolveBridge(bridgeOptions);
|
|
@@ -107,7 +97,7 @@ var BluxClient = class BluxClient {
|
|
|
107
97
|
* (1) 보내야할 이벤트를 100ms씩 뭉쳐서 보내고, 1개 이상 쌓여있을 때 api 요청
|
|
108
98
|
* (2) collectEvent의 응답에서 온 nextPollDelayMs 값 만큼 이후에 빈 배열로 api 요청 (1)로 보내면 초기화됨
|
|
109
99
|
*/
|
|
110
|
-
if (!this.bridge) merge(this.eventQueue$.pipe(bufferTime(100), filter((requests) => requests.length > 0)), combineLatest([this.nextPollDelayMs$,
|
|
100
|
+
if (!this.bridge) merge(this.eventQueue$.pipe(bufferTime(100), filter((requests) => requests.length > 0)), combineLatest([this.nextPollDelayMs$, onlineAndVisible$]).pipe(switchMap(([delay, isOnlineAndVisible]) => {
|
|
111
101
|
if (!isOnlineAndVisible || delay == null) return NEVER;
|
|
112
102
|
const targetTime = this.lastPollTimestamp + delay;
|
|
113
103
|
return timer(Math.max(0, targetTime - Date.now()));
|
|
@@ -172,7 +162,7 @@ var BluxClient = class BluxClient {
|
|
|
172
162
|
this.bluxUser$.subscribe((bluxUser) => {
|
|
173
163
|
if (bluxUser) SessionStorage.setBluxUserId(bluxUser.id);
|
|
174
164
|
});
|
|
175
|
-
if (!this.bridge) this.inappQueue$.pipe(filterNullable()).pipe(concatMap((inapp) =>
|
|
165
|
+
if (!this.bridge) this.inappQueue$.pipe(filterNullable()).pipe(concatMap((inapp) => onlineAndVisible$.pipe(first(Boolean), concatMap(() => from(this.displayInapp(inapp)))))).subscribe();
|
|
176
166
|
this.init().then(() => {
|
|
177
167
|
completionCallback?.({ success: true });
|
|
178
168
|
}).catch((error) => {
|
|
@@ -200,6 +190,10 @@ var BluxClient = class BluxClient {
|
|
|
200
190
|
const bluxUser = this.bluxUser$.getValue();
|
|
201
191
|
const hideTimestamp = LocalStorage.getInappHideTimestamp(inapp.inappId);
|
|
202
192
|
if (hideTimestamp !== null && dayjs().isBefore(dayjs(hideTimestamp))) return resolve(true);
|
|
193
|
+
Logger.debug(`[inapp:${inapp.inappId}] displayInapp started`, { extra: {
|
|
194
|
+
htmlLength: inapp.htmlString.length,
|
|
195
|
+
baseUrl: inapp.baseUrl
|
|
196
|
+
} });
|
|
203
197
|
const iframeElement = document.createElement("iframe");
|
|
204
198
|
const headInjection = `<script>
|
|
205
199
|
(function() {
|
|
@@ -225,11 +219,39 @@ var BluxClient = class BluxClient {
|
|
|
225
219
|
iframeElement.style.height = `${window.innerHeight}px`;
|
|
226
220
|
iframeElement.style.top = "0";
|
|
227
221
|
iframeElement.style.left = "0";
|
|
222
|
+
iframeElement.style.border = "none";
|
|
223
|
+
iframeElement.style.pointerEvents = "none";
|
|
228
224
|
iframeElement.style.zIndex = "9999";
|
|
229
225
|
iframeElement.id = `blux-inapp-${inapp.inappId}`;
|
|
230
226
|
document.body.appendChild(iframeElement);
|
|
227
|
+
let iframeContentReady = false;
|
|
228
|
+
let cleanupTimeoutId = null;
|
|
229
|
+
iframeElement.addEventListener("load", () => {
|
|
230
|
+
Logger.debug(`[inapp:${inapp.inappId}] iframe load event fired`);
|
|
231
|
+
try {
|
|
232
|
+
const doc = iframeElement.contentDocument;
|
|
233
|
+
Logger.debug(`[inapp:${inapp.inappId}] contentDocument accessible: ${!!doc}, bodyLength: ${doc?.body?.innerHTML?.length ?? "N/A"}`);
|
|
234
|
+
} catch (e) {
|
|
235
|
+
Logger.debug(`[inapp:${inapp.inappId}] contentDocument access blocked`, { extra: { error: e } });
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
iframeElement.addEventListener("error", (e) => {
|
|
239
|
+
Logger.warning(`[inapp:${inapp.inappId}] iframe error event`, { extra: { error: e } });
|
|
240
|
+
});
|
|
241
|
+
const INAPP_IFRAME_TIMEOUT_MS = 1e4;
|
|
242
|
+
cleanupTimeoutId = setTimeout(() => {
|
|
243
|
+
if (!iframeContentReady) {
|
|
244
|
+
Logger.warning(`[inapp:${inapp.inappId}] iframe timeout - no postMessage received within ${INAPP_IFRAME_TIMEOUT_MS}ms, cleaning up`);
|
|
245
|
+
cleanup();
|
|
246
|
+
}
|
|
247
|
+
}, INAPP_IFRAME_TIMEOUT_MS);
|
|
231
248
|
let urlChangeSubscription = null;
|
|
232
249
|
const cleanup = () => {
|
|
250
|
+
Logger.debug(`[inapp:${inapp.inappId}] cleanup called`);
|
|
251
|
+
if (cleanupTimeoutId !== null) {
|
|
252
|
+
clearTimeout(cleanupTimeoutId);
|
|
253
|
+
cleanupTimeoutId = null;
|
|
254
|
+
}
|
|
233
255
|
URL.revokeObjectURL(blobUrl);
|
|
234
256
|
iframeElement.remove();
|
|
235
257
|
window.removeEventListener("message", handleMessage);
|
|
@@ -252,20 +274,38 @@ var BluxClient = class BluxClient {
|
|
|
252
274
|
};
|
|
253
275
|
const handleMessage = (event) => {
|
|
254
276
|
if (event.source !== iframeElement.contentWindow) return;
|
|
277
|
+
if (!iframeContentReady) {
|
|
278
|
+
iframeContentReady = true;
|
|
279
|
+
iframeElement.style.pointerEvents = "auto";
|
|
280
|
+
Logger.debug(`[inapp:${inapp.inappId}] first postMessage received, pointer-events enabled`, { extra: { action: event.data?.action } });
|
|
281
|
+
}
|
|
255
282
|
const message = event.data;
|
|
256
283
|
if (message.action === "resize") {
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
284
|
+
const data = message.data;
|
|
285
|
+
if ("location" in data) {
|
|
286
|
+
iframeElement.style.width = "90vw";
|
|
287
|
+
iframeElement.style.maxWidth = "448px";
|
|
288
|
+
iframeElement.style.height = `${data.height}px`;
|
|
289
|
+
iframeElement.style.left = "50%";
|
|
290
|
+
iframeElement.style.transform = "translateX(-50%)";
|
|
291
|
+
if (data.location === "top") {
|
|
292
|
+
iframeElement.style.top = "0";
|
|
293
|
+
iframeElement.style.bottom = "auto";
|
|
294
|
+
} else {
|
|
295
|
+
iframeElement.style.top = "auto";
|
|
296
|
+
iframeElement.style.bottom = "0";
|
|
297
|
+
}
|
|
266
298
|
} else {
|
|
267
|
-
|
|
268
|
-
|
|
299
|
+
if (data.width !== void 0) {
|
|
300
|
+
iframeElement.style.width = `${data.width}px`;
|
|
301
|
+
iframeElement.style.maxWidth = "none";
|
|
302
|
+
}
|
|
303
|
+
if (data.height !== void 0) iframeElement.style.height = `${data.height}px`;
|
|
304
|
+
iframeElement.style.transform = "none";
|
|
305
|
+
iframeElement.style.top = data.top !== void 0 ? `${data.top}px` : "auto";
|
|
306
|
+
iframeElement.style.bottom = data.bottom !== void 0 ? `${data.bottom}px` : "auto";
|
|
307
|
+
iframeElement.style.left = data.left !== void 0 ? `${data.left}px` : "auto";
|
|
308
|
+
iframeElement.style.right = data.right !== void 0 ? `${data.right}px` : "auto";
|
|
269
309
|
}
|
|
270
310
|
window.visualViewport?.removeEventListener("resize", handleViewportChange);
|
|
271
311
|
window.visualViewport?.removeEventListener("scroll", handleViewportChange);
|
|
@@ -410,7 +450,6 @@ var BluxClient = class BluxClient {
|
|
|
410
450
|
})));
|
|
411
451
|
}
|
|
412
452
|
async signIn({ userId }) {
|
|
413
|
-
if (!this.isBrowser) return;
|
|
414
453
|
try {
|
|
415
454
|
if (this.bridge) {
|
|
416
455
|
this.bridge.signIn({ userId });
|
|
@@ -437,7 +476,6 @@ var BluxClient = class BluxClient {
|
|
|
437
476
|
}
|
|
438
477
|
}
|
|
439
478
|
async signOut() {
|
|
440
|
-
if (!this.isBrowser) return;
|
|
441
479
|
try {
|
|
442
480
|
if (this.bridge) {
|
|
443
481
|
this.bridge.signOut();
|
|
@@ -459,7 +497,6 @@ var BluxClient = class BluxClient {
|
|
|
459
497
|
}
|
|
460
498
|
}
|
|
461
499
|
async setUserProperties({ userProperties }) {
|
|
462
|
-
if (!this.isBrowser) return;
|
|
463
500
|
try {
|
|
464
501
|
if (this.bridge) {
|
|
465
502
|
this.bridge.setUserProperties(userProperties);
|
|
@@ -477,7 +514,6 @@ var BluxClient = class BluxClient {
|
|
|
477
514
|
}
|
|
478
515
|
}
|
|
479
516
|
async setCustomUserProperties({ customUserProperties }) {
|
|
480
|
-
if (!this.isBrowser) return;
|
|
481
517
|
try {
|
|
482
518
|
if (this.bridge) {
|
|
483
519
|
this.bridge.setCustomUserProperties(customUserProperties);
|
|
@@ -495,7 +531,6 @@ var BluxClient = class BluxClient {
|
|
|
495
531
|
}
|
|
496
532
|
}
|
|
497
533
|
sendEvent(event) {
|
|
498
|
-
if (!this.isBrowser) return;
|
|
499
534
|
try {
|
|
500
535
|
const requests = (Array.isArray(event) ? event : [event]).map((e) => ({
|
|
501
536
|
...e.request,
|
|
@@ -528,7 +563,6 @@ var BluxClient = class BluxClient {
|
|
|
528
563
|
* ```
|
|
529
564
|
*/
|
|
530
565
|
dismissInApp() {
|
|
531
|
-
if (!this.isBrowser) return;
|
|
532
566
|
this.currentInappCleanup?.();
|
|
533
567
|
}
|
|
534
568
|
/**
|
|
@@ -553,7 +587,6 @@ var BluxClient = class BluxClient {
|
|
|
553
587
|
* ```
|
|
554
588
|
*/
|
|
555
589
|
addInAppCustomActionHandler(handler) {
|
|
556
|
-
if (!this.isBrowser) return () => {};
|
|
557
590
|
this.inAppCustomActionHandlers.add(handler);
|
|
558
591
|
return () => {
|
|
559
592
|
this.inAppCustomActionHandlers.delete(handler);
|
|
@@ -598,10 +631,10 @@ var BluxClient = class BluxClient {
|
|
|
598
631
|
registerImpressionTracker() {
|
|
599
632
|
const targetElements = Array.from(document.querySelectorAll(`[${BLUX_ATTRIBUTES.tracking_id}]`));
|
|
600
633
|
this.intersectionObservingElements.filter((e) => !targetElements.includes(e)).forEach((e) => {
|
|
601
|
-
this.intersectionObserver
|
|
634
|
+
this.intersectionObserver.unobserve(e);
|
|
602
635
|
});
|
|
603
636
|
targetElements.filter((element) => !this.intersectionObservingElements.includes(element)).forEach((element) => {
|
|
604
|
-
this.intersectionObserver
|
|
637
|
+
this.intersectionObserver.observe(element);
|
|
605
638
|
});
|
|
606
639
|
this.intersectionObservingElements = targetElements;
|
|
607
640
|
}
|
|
@@ -635,7 +668,6 @@ var BluxClient = class BluxClient {
|
|
|
635
668
|
});
|
|
636
669
|
}
|
|
637
670
|
async getUserRec(rec) {
|
|
638
|
-
if (!this.isBrowser) return BluxClient.EMPTY_REC_RESPONSE;
|
|
639
671
|
try {
|
|
640
672
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
641
673
|
const recRequest = rec.request;
|
|
@@ -657,7 +689,6 @@ var BluxClient = class BluxClient {
|
|
|
657
689
|
}
|
|
658
690
|
}
|
|
659
691
|
async getItemRec(rec) {
|
|
660
|
-
if (!this.isBrowser) return BluxClient.EMPTY_REC_RESPONSE;
|
|
661
692
|
try {
|
|
662
693
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
663
694
|
const recRequest = rec.request;
|
|
@@ -680,7 +711,6 @@ var BluxClient = class BluxClient {
|
|
|
680
711
|
}
|
|
681
712
|
}
|
|
682
713
|
async getItemsRec(rec) {
|
|
683
|
-
if (!this.isBrowser) return BluxClient.EMPTY_REC_RESPONSE;
|
|
684
714
|
try {
|
|
685
715
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
686
716
|
const recRequest = rec.request;
|
|
@@ -703,7 +733,6 @@ var BluxClient = class BluxClient {
|
|
|
703
733
|
}
|
|
704
734
|
}
|
|
705
735
|
async getCategoryRec(rec) {
|
|
706
|
-
if (!this.isBrowser) return BluxClient.EMPTY_REC_RESPONSE;
|
|
707
736
|
try {
|
|
708
737
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
709
738
|
const recRequest = rec.request;
|
package/dist/BluxClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BluxClient.js","names":["packageJson.version"],"sources":["../src/BluxClient.ts"],"sourcesContent":["import axios from \"axios\";\nimport ObjectId from \"bson-objectid\";\nimport dayjs from \"dayjs\";\nimport {\n BehaviorSubject,\n bufferTime,\n catchError,\n combineLatest,\n concatMap,\n debounceTime,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n NEVER,\n skip,\n Subject,\n Subscription,\n switchMap,\n throwError,\n timeout,\n timer,\n} from \"rxjs\";\n\nimport packageJson from \"../package.json\";\nimport { DevicePlatform, type APIs } from \"./apis/APIs\";\nimport { createCrmEvent } from \"./apis/createCrmEvent\";\nimport { collectEvent } from \"./apis/createEvent\";\nimport { getItemRecommendations } from \"./apis/getItemRecommendations\";\nimport { initialize } from \"./apis/initialize\";\nimport { notificationsUpdate } from \"./apis/notificationsUpdate\";\nimport { signIn } from \"./apis/signIn\";\nimport { signOut } from \"./apis/signOut\";\nimport { updateProperties } from \"./apis/updateProperties\";\nimport { AndroidBridge } from \"./bridges/AndroidBridge\";\nimport { Bridge, BridgePlatform } from \"./bridges/Bridge\";\nimport { FlutterBridge } from \"./bridges/FlutterBridge\";\nimport { IosBridge } from \"./bridges/IosBridge\";\nimport { RNBridge } from \"./bridges/RNBridge\";\nimport { BLUX_ATTRIBUTES } from \"./constants/BLUX_ATTRIBUTES\";\nimport {\n AddClickEvent,\n AddPageVisitEvent,\n AddSectionViewEvent,\n VisitEvent,\n} from \"./events\";\nimport { LocalStorage } from \"./utils/LocalStorage\";\nimport { Logger } from \"./utils/Logger\";\nimport { getOnlineAndVisible$ } from \"./utils/observables\";\nimport { filterNullable } from \"./utils/operators\";\nimport { SessionStorage } from \"./utils/SessionStorage\";\n\nimport type { Event as BluxEvent } from \"./events/Event\";\nimport type { EventRequest } from \"./events/types\";\nimport type { CategoryRec, ItemRec, ItemsRec, UserRec } from \"./recs\";\nimport type { LogLevel } from \"./utils/Logger\";\nimport type { AxiosInstance } from \"axios\";\n\nexport type SdkInfo = {\n type: DevicePlatform;\n version: string;\n};\n\ntype BluxUser = {\n id: string;\n bluxAPIKey: string;\n applicationId: string;\n deviceId: string;\n userId?: string;\n};\n\ntype BridgeOptions =\n | {\n /**\n * @deprecated `bridgePlatform`을 사용하세요.\n */\n useRNBridge?: boolean;\n }\n | { bridgePlatform?: BridgePlatform };\n\ntype InappMessageResponse = NonNullable<\n APIs.bluxUsersCollectEventsV2.ResponseData[\"inapp\"]\n>;\n\ntype ApiRequestQueueJob<T> = {\n action: () => Promise<T>;\n resolve: (value: T) => void;\n reject: (error: unknown) => void;\n};\n\ntype UserPropertiesQueueItem = {\n userProperties?: APIs.bluxUsersUpdateProperties.Body[\"user_properties\"];\n customUserProperties?: APIs.bluxUsersUpdateProperties.Body[\"custom_user_properties\"];\n resolve: () => void;\n reject: (error: unknown) => void;\n};\n\n/**\n * 인앱 메시지에서 BluxBridge.triggerAction() 호출 시 전달되는 이벤트\n */\nexport type InAppCustomActionEvent = {\n /** 액션 식별자 */\n actionId: string;\n /** 액션에 전달된 데이터 */\n data: Record<string, unknown>;\n};\n\n/**\n * 인앱 커스텀 액션 핸들러 타입\n */\nexport type InAppCustomActionHandler = (\n event: InAppCustomActionEvent,\n) => void | Promise<void>;\n\nexport class BluxClient {\n private readonly isBrowser = typeof window !== \"undefined\";\n\n private static readonly EMPTY_REC_RESPONSE: APIs.bluxUsersGetItemRecommendationsV2.ResponseData =\n {\n item_ids: [],\n metadata: {},\n recommendation_id: null,\n };\n\n private readonly api: AxiosInstance = axios.create();\n\n private readonly sdkInfo: SdkInfo = {\n type: DevicePlatform.browser,\n version: packageJson.version,\n };\n\n public readonly bluxUser$ = new BehaviorSubject<BluxUser | undefined>(\n undefined,\n );\n\n /**\n * 내부 async 작업을 1개씩 직렬로 처리하는 큐입니다.\n * `enqueueRequest()`로 넣으면, 호출자는 완료 시점까지 `await` 할 수 있습니다.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public readonly apiRequestQueue$ = new Subject<ApiRequestQueueJob<any>>();\n public readonly inappQueue$ = new BehaviorSubject<\n InappMessageResponse | undefined\n >(undefined);\n public readonly eventQueue$ = new Subject<EventRequest>();\n public readonly userPropertiesQueue$ = new Subject<UserPropertiesQueueItem>();\n\n private readonly INITIAL_NEXT_POLL_DELAY_MS = 10 * 1000;\n private readonly nextPollDelayMs$ = new BehaviorSubject<number | null>(\n this.INITIAL_NEXT_POLL_DELAY_MS,\n );\n private cachedNextPollDelayMs: number | null =\n this.INITIAL_NEXT_POLL_DELAY_MS;\n private lastPollTimestamp: number = Date.now();\n\n private readonly bluxApplicationId: string;\n private readonly bluxAPIKey: string;\n private readonly customDeviceId?: string;\n\n private readonly bridge: Bridge | null = null;\n\n // Impression 관련 변수\n private impressedElements: Element[] = [];\n private intersectionObservingElements: Element[] = [];\n private readonly intersectionObserver = this.isBrowser\n ? new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n this.intersectionEntry$.next(entry);\n });\n })\n : null;\n\n private readonly intersectionEntry$ =\n new Subject<IntersectionObserverEntry>();\n\n // Hit 관련 변수\n private hitElements: Element[] = [];\n\n // 현재 표시 중인 인앱 메시지의 cleanup 함수\n private currentInappCleanup: (() => void) | null = null;\n\n // 인앱 커스텀 액션 핸들러 (복수 등록 가능)\n private inAppCustomActionHandlers: Set<InAppCustomActionHandler> = new Set();\n\n private resolveBridge(bridgeOptions: BridgeOptions): Bridge | null {\n if (\"useRNBridge\" in bridgeOptions && bridgeOptions.useRNBridge) {\n return new RNBridge();\n }\n\n if (\"bridgePlatform\" in bridgeOptions && bridgeOptions.bridgePlatform) {\n switch (bridgeOptions.bridgePlatform) {\n case \"none\":\n return null;\n case \"android\":\n return new AndroidBridge();\n case \"ios\":\n return new IosBridge();\n case \"react-native\":\n return new RNBridge();\n case \"flutter\":\n return new FlutterBridge();\n default: {\n const exhaustiveCheck: never = bridgeOptions.bridgePlatform;\n Logger.error(`Unknown bridge platform: ${exhaustiveCheck}`, {\n tags: { from: \"resolveBridge\" },\n });\n }\n }\n }\n\n return null;\n }\n\n constructor(\n {\n bluxApplicationId,\n bluxAPIKey,\n customDeviceId,\n ...bridgeOptions\n }: {\n bluxApplicationId: string;\n bluxAPIKey: string;\n customDeviceId?: string;\n } & BridgeOptions,\n completionCallback?: (args: {\n errorMessage?: string;\n success: boolean;\n }) => void,\n ) {\n this.bluxApplicationId = bluxApplicationId;\n this.bluxAPIKey = bluxAPIKey;\n this.customDeviceId = customDeviceId;\n\n if (!this.isBrowser) {\n completionCallback?.({ success: true });\n return;\n }\n\n const baseUrl = window?._BLUX_SDK_?.baseUrl ?? \"https://api.blux.ai/prod\";\n this.api.defaults.baseURL = baseUrl;\n\n this.bridge = this.resolveBridge(bridgeOptions);\n\n // api 요청 항상 하나씩 처리\n this.apiRequestQueue$\n .pipe(\n concatMap(async (job) => {\n try {\n const result = await job.action();\n job.resolve(result);\n } catch (error) {\n job.reject(error);\n }\n }),\n )\n .subscribe();\n\n /**\n * (1) 보내야할 이벤트를 100ms씩 뭉쳐서 보내고, 1개 이상 쌓여있을 때 api 요청\n * (2) collectEvent의 응답에서 온 nextPollDelayMs 값 만큼 이후에 빈 배열로 api 요청 (1)로 보내면 초기화됨\n */\n\n if (!this.bridge) {\n merge(\n this.eventQueue$.pipe(\n bufferTime(100),\n filter((requests) => requests.length > 0),\n ),\n // onlineAndVisible일 때만 polling, 남은 시간 계산하여 타이머 시작\n combineLatest([this.nextPollDelayMs$, getOnlineAndVisible$()]).pipe(\n switchMap(([delay, isOnlineAndVisible]) => {\n if (!isOnlineAndVisible || delay == null) return NEVER;\n\n const targetTime = this.lastPollTimestamp + delay;\n const remainingDelay = Math.max(0, targetTime - Date.now());\n\n return timer(remainingDelay);\n }),\n map(() => [] as EventRequest[]),\n ),\n )\n .pipe(\n concatMap(async (requests) => {\n this.nextPollDelayMs$.next(null);\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n\n const events = requests.map((request) => ({\n ...request,\n blux_id: bluxUser.id,\n device_id: bluxUser.deviceId,\n }));\n\n const {\n data: { nextPollDelayMs, inapp },\n } = await this.enqueueRequest(() =>\n collectEvent(\n this.api,\n {\n blux_user_id: bluxUser.id,\n application_id: bluxUser.applicationId,\n },\n {\n device_id: bluxUser.deviceId,\n events,\n },\n this.generateApiHeader(bluxUser),\n ),\n );\n\n this.lastPollTimestamp = Date.now();\n this.cachedNextPollDelayMs = nextPollDelayMs;\n this.nextPollDelayMs$.next(Math.max(nextPollDelayMs, 3000));\n\n if (inapp) {\n this.inappQueue$.next(inapp);\n }\n } catch (error) {\n Logger.error(error, { tags: { from: \"eventQueue\" } });\n this.lastPollTimestamp = Date.now();\n if (this.cachedNextPollDelayMs !== null) {\n const nextPollDelay =\n this.cachedNextPollDelayMs > 1000 * 60 * 60 * 24\n ? this.cachedNextPollDelayMs\n : this.cachedNextPollDelayMs * 2;\n this.cachedNextPollDelayMs = nextPollDelay;\n this.nextPollDelayMs$.next(nextPollDelay);\n }\n }\n }),\n )\n .subscribe();\n }\n\n // api 호출 수 절감을 위해 100ms씩 뭉쳐서 보내고, custom_user_properties와 user_properties를 합쳐서 보냄\n this.userPropertiesQueue$\n .pipe(\n bufferTime(100),\n filter((items) => items.length > 0),\n concatMap(async (items) => {\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n\n const mergedUserProperties = items.reduce(\n (acc, item) => ({ ...acc, ...(item.userProperties ?? {}) }),\n {} as NonNullable<\n APIs.bluxUsersUpdateProperties.Body[\"user_properties\"]\n >,\n );\n\n const mergedCustomUserProperties = items.reduce(\n (acc, item) => ({ ...acc, ...(item.customUserProperties ?? {}) }),\n {} as NonNullable<\n APIs.bluxUsersUpdateProperties.Body[\"custom_user_properties\"]\n >,\n );\n\n const payload: APIs.bluxUsersUpdateProperties.Body = {};\n if (Object.keys(mergedUserProperties).length > 0) {\n payload.user_properties = mergedUserProperties;\n }\n if (Object.keys(mergedCustomUserProperties).length > 0) {\n payload.custom_user_properties = mergedCustomUserProperties;\n }\n\n if (Object.keys(payload).length === 0) {\n items.forEach((item) => item.resolve());\n return;\n }\n\n await this.enqueueRequest(() =>\n updateProperties(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n payload,\n this.generateApiHeader(bluxUser),\n ),\n );\n\n items.forEach((item) => item.resolve());\n } catch (error) {\n items.forEach((item) => item.reject(error));\n Logger.error(error, { tags: { from: \"userPropertiesQueue\" } });\n }\n }),\n )\n .subscribe();\n\n this.bluxUser$.subscribe((bluxUser) => {\n if (bluxUser) SessionStorage.setBluxUserId(bluxUser.id);\n });\n\n if (!this.bridge) {\n this.inappQueue$\n .pipe(filterNullable())\n .pipe(\n concatMap((inapp) =>\n getOnlineAndVisible$().pipe(\n first(Boolean),\n concatMap(() => from(this.displayInapp(inapp))),\n ),\n ),\n )\n .subscribe();\n }\n\n this.init()\n .then(() => {\n completionCallback?.({ success: true });\n })\n .catch((error) => {\n completionCallback?.({ success: false, errorMessage: error.message });\n });\n }\n\n private async enqueueRequest<T>(action: () => Promise<T>) {\n return new Promise<T>((resolve, reject) => {\n const item: ApiRequestQueueJob<T> = { action, resolve, reject };\n this.apiRequestQueue$.next(item);\n });\n }\n\n private generateApiHeader({ bluxAPIKey }: { bluxAPIKey: string }) {\n return {\n Authorization: bluxAPIKey,\n };\n }\n\n private async displayInapp(inapp: InappMessageResponse) {\n return new Promise((resolve) => {\n const bluxUser = this.bluxUser$.getValue();\n\n const hideTimestamp = LocalStorage.getInappHideTimestamp(inapp.inappId);\n const isShouldSkip =\n hideTimestamp !== null && dayjs().isBefore(dayjs(hideTimestamp));\n\n if (isShouldSkip) return resolve(true);\n\n const iframeElement = document.createElement(\"iframe\");\n\n // Blob URL 방식: 실제 URL 컨텍스트를 가지므로 Next.js가 정상 작동\n // <base> 태그로 외부 리소스 경로 설정\n // history.replaceState/pushState 에러 방지를 위한 polyfill 추가\n const historyPolyfill = `<script>\n (function() {\n var origReplaceState = history.replaceState;\n var origPushState = history.pushState;\n history.replaceState = function() {\n try { return origReplaceState.apply(this, arguments); }\n catch(e) { console.debug('[Blux] history.replaceState blocked in blob context'); }\n };\n history.pushState = function() {\n try { return origPushState.apply(this, arguments); }\n catch(e) { console.debug('[Blux] history.pushState blocked in blob context'); }\n };\n })();\n </script>`;\n const headInjection = `${historyPolyfill}<base href=\"${inapp.baseUrl}/\">`;\n const htmlWithBase = inapp.htmlString.includes(\"<head>\")\n ? inapp.htmlString.replace(\"<head>\", `<head>${headInjection}`)\n : inapp.htmlString;\n\n const blob = new Blob([htmlWithBase], { type: \"text/html\" });\n const blobUrl = URL.createObjectURL(blob);\n\n iframeElement.sandbox.add(\n \"allow-scripts\",\n \"allow-same-origin\",\n \"allow-forms\",\n );\n iframeElement.src = blobUrl;\n iframeElement.style.position = \"fixed\";\n iframeElement.style.width = `${window.innerWidth}px`;\n iframeElement.style.height = `${window.innerHeight}px`;\n iframeElement.style.top = \"0\";\n iframeElement.style.left = \"0\";\n\n iframeElement.style.zIndex = \"9999\";\n iframeElement.id = `blux-inapp-${inapp.inappId}`;\n\n document.body.appendChild(iframeElement);\n\n let urlChangeSubscription: Subscription | null = null;\n\n const cleanup = () => {\n URL.revokeObjectURL(blobUrl);\n iframeElement.remove();\n window.removeEventListener(\"message\", handleMessage);\n window.visualViewport?.removeEventListener(\n \"resize\",\n handleViewportChange,\n );\n window.visualViewport?.removeEventListener(\n \"scroll\",\n handleViewportChange,\n );\n urlChangeSubscription?.unsubscribe();\n this.currentInappCleanup = null;\n resolve(inapp.inappId);\n };\n\n // 현재 인앱 cleanup 함수 저장\n this.currentInappCleanup = cleanup;\n const handleViewportChange = () => {\n const width = window.visualViewport?.width ?? window.innerWidth;\n const height = window.visualViewport?.height ?? window.innerHeight;\n const left = window.visualViewport?.offsetLeft ?? 0;\n const top = window.visualViewport?.offsetTop ?? 0;\n\n iframeElement.style.width = `${width}px`;\n iframeElement.style.height = `${height}px`;\n iframeElement.style.left = `${left}px`;\n iframeElement.style.top = `${top}px`;\n };\n\n const handleMessage = (\n event: MessageEvent<\n | {\n action: \"hide\";\n data: {\n days_to_hide: number;\n };\n }\n | {\n action: \"link\";\n data:\n | {\n is_blux_landing: false;\n url: string;\n open_in_new_tab: boolean;\n /**\n * Safari 팝업 차단 우회를 위해 iframe에서 직접 링크를 연 경우 true\n * 이 플래그가 true면 window.open을 스킵하고 이벤트만 찍음\n */\n opened_by_iframe?: boolean;\n }\n | {\n is_blux_landing: true;\n landing_id: string;\n };\n }\n | {\n action: \"resize\";\n data: {\n height: number;\n location: \"top\" | \"bottom\";\n };\n }\n | {\n action: \"custom_action\";\n data: {\n action_id: string;\n data: Record<string, unknown>;\n should_dismiss: boolean;\n };\n }\n | {\n action: \"inapp_opened\";\n data: {\n button_id: string;\n };\n }\n >,\n ) => {\n if (event.source !== iframeElement.contentWindow) return;\n\n const message = event.data;\n\n if (message.action === \"resize\") {\n const { height, location } = message.data;\n // 배너용 iframe 스타일 조정\n iframeElement.style.width = \"90vw\";\n iframeElement.style.maxWidth = \"448px\";\n iframeElement.style.height = `${height}px`;\n iframeElement.style.left = \"50%\";\n iframeElement.style.transform = \"translateX(-50%)\";\n if (location === \"top\") {\n iframeElement.style.top = \"0\";\n iframeElement.style.bottom = \"auto\";\n } else {\n iframeElement.style.top = \"auto\";\n iframeElement.style.bottom = \"0\";\n }\n\n window.visualViewport?.removeEventListener(\n \"resize\",\n handleViewportChange,\n );\n window.visualViewport?.removeEventListener(\n \"scroll\",\n handleViewportChange,\n );\n return; // resize는 cleanup하지 않음\n }\n\n if (message.action === \"hide\") {\n const { days_to_hide } = message.data;\n if (days_to_hide !== 0) {\n const expiresAt = dayjs().add(days_to_hide, \"days\").valueOf();\n LocalStorage.setInappHideTimestamp(inapp.inappId, expiresAt);\n }\n } else if (message.action === \"link\") {\n // createCrmEvent 호출\n const crmEventPromise = bluxUser\n ? this.enqueueRequest(() =>\n createCrmEvent(\n this.api,\n {\n application_id: this.bluxApplicationId,\n },\n {\n notification_id: inapp.notificationId,\n crm_event_type: \"inapp_opened\",\n captured_at: new Date().toISOString(),\n },\n this.generateApiHeader(bluxUser),\n ),\n )\n : Promise.resolve();\n\n if (message.data.is_blux_landing) {\n // TODO: @all 스키마상에는 개인화 랜딩이 존재하나, 콘솔에는 필드가 없음 -> 추후 이에 따른 핸들링이 필요함\n } else {\n const { url, open_in_new_tab, opened_by_iframe } = message.data;\n const needsLocationChange = opened_by_iframe && !open_in_new_tab;\n\n // 하고하우스 특별 처리\n if (this.bluxApplicationId === \"6878af275ead5a75abbdacd7\") {\n crmEventPromise.finally(() => {\n window.top?.postMessage(\n {\n type: \"blux_inapp_message\",\n url,\n },\n window.location.origin,\n );\n });\n } else if (needsLocationChange) {\n // opened_by_iframe이고 현재 탭 이동인 경우: createCrmEvent 완료 후 이동\n crmEventPromise.finally(() => {\n window.location.href = url;\n });\n } else if (!opened_by_iframe) {\n // 기존 방식 (iframe에서 열지 않은 경우)\n if (open_in_new_tab) {\n window.open(url, \"_blank\");\n } else {\n window.location.href = url;\n }\n }\n // opened_by_iframe && open_in_new_tab인 경우: iframe에서 이미 새 탭 열었으므로 스킵\n }\n } else if (message.action === \"custom_action\") {\n const { action_id, data, should_dismiss } = message.data;\n\n // 등록된 모든 핸들러 호출\n for (const handler of this.inAppCustomActionHandlers) {\n try {\n handler({ actionId: action_id, data });\n } catch (error) {\n Logger.error(error, {\n tags: { from: \"inAppCustomActionHandler\" },\n });\n }\n }\n\n // should_dismiss가 false면 cleanup하지 않음\n if (!should_dismiss) {\n return;\n }\n } else if (message.action === \"inapp_opened\") {\n // data-blux-click 속성으로 인한 클릭 이벤트 추적\n if (bluxUser) {\n this.enqueueRequest(() =>\n createCrmEvent(\n this.api,\n {\n application_id: this.bluxApplicationId,\n },\n {\n notification_id: inapp.notificationId,\n crm_event_type: \"inapp_opened\",\n captured_at: new Date().toISOString(),\n },\n this.generateApiHeader(bluxUser),\n ),\n );\n }\n return; // 인앱메시지를 닫지 않음\n }\n\n cleanup();\n };\n\n // URL 변경 시 인앱메시지 닫기 (SPA 뒤로가기/앞으로가기 대응)\n urlChangeSubscription = this.urlAndRef$\n .pipe(filterNullable(), skip(1), first())\n .subscribe(() => {\n cleanup();\n });\n\n window.visualViewport?.addEventListener(\"resize\", handleViewportChange);\n window.visualViewport?.addEventListener(\"scroll\", handleViewportChange);\n window.addEventListener(\"message\", handleMessage);\n\n if (bluxUser) {\n this.enqueueRequest(() =>\n notificationsUpdate(\n this.api,\n {\n application_id: this.bluxApplicationId,\n notification_id: inapp.notificationId,\n },\n {\n status: \"received\",\n },\n this.generateApiHeader(bluxUser),\n ),\n );\n }\n });\n }\n\n private async init() {\n this.handleUrlAndRef();\n // handle page visit event\n this.urlAndRef$.pipe(filterNullable()).subscribe(() => {\n this.sendEvent(new AddPageVisitEvent({}));\n });\n\n if (this.bridge) {\n this.bridge.initialize({\n bluxApplicationId: this.bluxApplicationId,\n bluxAPIKey: this.bluxAPIKey,\n customDeviceId: this.customDeviceId,\n });\n return;\n }\n\n const blux_user_id = new URLSearchParams(window.location.search).get(\n \"blux_user_id\",\n );\n const sessionId =\n SessionStorage.getSessionId() ?? new ObjectId().toHexString();\n SessionStorage.setSessionId(sessionId);\n\n const isBluxUserIdExistInSessionStorage = SessionStorage.getBluxUserId();\n if (!isBluxUserIdExistInSessionStorage) this.sendEvent(new VisitEvent({}));\n\n Logger.debug(`Init with application id: ${this.bluxApplicationId}`);\n\n const deviceId = LocalStorage.getDeviceId();\n\n if (!deviceId) {\n Logger.debug(\"No saved Device ID, register a new one.\");\n }\n\n this.registerHitTracker();\n\n // 페이지 이동 시 추천 지표 수집 관련 변수 초기화\n this.urlAndRef$.pipe(filterNullable()).subscribe(() => {\n this.impressedElements = [];\n });\n\n this.registerImpressionTracker();\n new MutationObserver(() => {\n this.registerImpressionTracker();\n }).observe(document, { subtree: true, childList: true });\n\n // 500ms 연속으로 엘리먼트 들어있으면 추천 지표 수집\n const MIN_IMPRESSION_TIME = 500;\n this.intersectionEntry$\n .pipe(\n groupBy((entry) => entry.target),\n mergeMap((group$) =>\n group$.pipe(\n debounceTime(MIN_IMPRESSION_TIME),\n filter((entry) => entry.isIntersecting),\n ),\n ),\n )\n .subscribe((entry) => {\n const trackingId = entry.target.getAttribute(\n BLUX_ATTRIBUTES.tracking_id,\n );\n if (!trackingId) {\n Logger.warning(\n `Tracking ID is not found in the parent elements. Please check the tracking ID(${BLUX_ATTRIBUTES.tracking_id}) is set correctly.`,\n );\n return;\n }\n if (this.impressedElements.includes(entry.target)) return;\n\n this.sendEvent(\n new AddSectionViewEvent({\n section: trackingId,\n tracking: {\n id: trackingId,\n type: \"impression\",\n },\n }),\n );\n this.impressedElements.push(entry.target);\n });\n\n const { data } = await initialize(\n this.api,\n { application_id: this.bluxApplicationId },\n {\n session_id: sessionId ?? undefined,\n device_id: deviceId ?? undefined,\n country_code: navigator.language.split(\"-\")[1],\n device_model: navigator.userAgent,\n language_code: navigator.language.split(\"-\")[0],\n platform: DevicePlatform.browser,\n os_version: navigator.userAgent,\n sdk_version: this.sdkInfo.version,\n sdk_type: this.sdkInfo.type,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n blux_user_id: blux_user_id ?? undefined,\n custom_device_id: this.customDeviceId,\n },\n this.generateApiHeader({\n bluxAPIKey: this.bluxAPIKey,\n }),\n );\n\n if (data.device_id) LocalStorage.setDeviceId(data.device_id);\n\n this.bluxUser$.next({\n id: data.blux_user_id,\n bluxAPIKey: this.bluxAPIKey,\n applicationId: this.bluxApplicationId,\n deviceId: data.device_id,\n });\n }\n\n public setLogLevel(logLevel: LogLevel) {\n Logger.setLevel(logLevel);\n }\n\n private async getBluxUserWithTimeout() {\n const bluxUser = await firstValueFrom(\n this.bluxUser$.pipe(\n filterNullable(),\n timeout(5000),\n catchError((error) => {\n return throwError(() =>\n error.name === \"TimeoutError\"\n ? new Error(\n \"Application ID is not initialized. Please initialize BluxClient.\",\n )\n : error,\n );\n }),\n ),\n );\n\n return bluxUser;\n }\n\n public async signIn({ userId }: { userId: string }) {\n if (!this.isBrowser) return;\n try {\n if (this.bridge) {\n this.bridge.signIn({ userId });\n return;\n }\n\n const bluxUser = await this.getBluxUserWithTimeout();\n\n const {\n data: { blux_user_id: bluxIdInResponse },\n } = await this.enqueueRequest(() =>\n signIn(\n this.api,\n { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id },\n { user_id: userId, device_id: bluxUser.deviceId },\n this.generateApiHeader(bluxUser),\n ),\n );\n\n if (bluxIdInResponse !== bluxUser.id) {\n Logger.debug(\"Blux id is changed in signIn.\");\n this.bluxUser$.next({\n ...bluxUser,\n id: bluxIdInResponse,\n userId,\n });\n }\n } catch (error) {\n Logger.error(error, { tags: { from: \"signIn\" } });\n }\n }\n\n public async signOut() {\n if (!this.isBrowser) return;\n try {\n if (this.bridge) {\n this.bridge.signOut();\n return;\n }\n\n const bluxUser = await this.getBluxUserWithTimeout();\n\n const {\n data: { blux_user_id: bluxIdInResponse },\n } = await this.enqueueRequest(() =>\n signOut(\n this.api,\n { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id },\n { device_id: bluxUser.deviceId },\n this.generateApiHeader(bluxUser),\n ),\n );\n\n Logger.debug(\"Blux id is changed in signOut.\");\n this.bluxUser$.next({\n ...bluxUser,\n id: bluxIdInResponse,\n userId: undefined,\n });\n } catch (error) {\n Logger.error(error, { tags: { from: \"signOut\" } });\n }\n }\n\n public async setUserProperties({\n userProperties,\n }: {\n userProperties: NonNullable<\n APIs.bluxUsersUpdateProperties.Body[\"user_properties\"]\n >;\n }) {\n if (!this.isBrowser) return;\n try {\n if (this.bridge) {\n this.bridge.setUserProperties(userProperties);\n return;\n }\n\n await new Promise<void>((resolve, reject) => {\n this.userPropertiesQueue$.next({\n userProperties,\n resolve,\n reject,\n });\n });\n } catch (error) {\n Logger.error(error, { tags: { from: \"setUserProperties\" } });\n }\n }\n\n public async setCustomUserProperties({\n customUserProperties,\n }: {\n customUserProperties: NonNullable<\n APIs.bluxUsersUpdateProperties.Body[\"custom_user_properties\"]\n >;\n }) {\n if (!this.isBrowser) return;\n try {\n if (this.bridge) {\n this.bridge.setCustomUserProperties(customUserProperties);\n return;\n }\n\n await new Promise<void>((resolve, reject) => {\n this.userPropertiesQueue$.next({\n customUserProperties,\n resolve,\n reject,\n });\n });\n } catch (error) {\n Logger.error(error, { tags: { from: \"setCustomUserProperties\" } });\n }\n }\n\n public sendEvent(event: BluxEvent | BluxEvent[]) {\n if (!this.isBrowser) return;\n try {\n const requests = (Array.isArray(event) ? event : [event]).map((e) => ({\n ...e.request,\n internal_event_properties: {\n url: this.urlAndRef$.value?.url,\n ref: this.urlAndRef$.value?.ref,\n },\n }));\n\n if (this.bridge) {\n this.bridge.sendEvent({ requests });\n return;\n }\n\n requests.forEach((request) => {\n this.eventQueue$.next(request);\n });\n } catch (error) {\n Logger.error(error, { tags: { from: \"sendEvent\" } });\n }\n }\n\n /**\n * 현재 표시 중인 인앱 메시지를 프로그래밍 방식으로 닫습니다.\n *\n * Custom HTML 인앱에서 async 핸들러 완료 후 수동으로 닫을 때 사용합니다.\n *\n * @example\n * ```typescript\n * // BluxBridge.triggerAction('share', { url: '...' }, false); // shouldDismiss: false\n * // 핸들러에서 async 작업 완료 후:\n * bluxClient.dismissInApp();\n * ```\n */\n public dismissInApp() {\n if (!this.isBrowser) return;\n this.currentInappCleanup?.();\n }\n\n /**\n * Custom HTML 인앱에서 BluxBridge.triggerAction() 호출 시 실행될 핸들러를 등록합니다.\n * 여러 핸들러를 등록할 수 있으며, 등록 순서대로 실행됩니다.\n *\n * @param handler - 커스텀 액션 핸들러 함수\n * @returns 핸들러를 제거하는 unsubscribe 함수\n *\n * @example\n * ```typescript\n * const unsubscribe = bluxClient.addInAppCustomActionHandler(async (event) => {\n * if (event.actionId === 'share') {\n * await navigator.share({ url: event.data.url as string });\n * // async 작업 완료 후 수동으로 닫기 (shouldDismiss: false로 호출한 경우)\n * bluxClient.dismissInApp();\n * }\n * });\n *\n * // 핸들러 제거\n * unsubscribe();\n * ```\n */\n public addInAppCustomActionHandler(\n handler: InAppCustomActionHandler,\n ): () => void {\n if (!this.isBrowser) return () => {};\n this.inAppCustomActionHandlers.add(handler);\n return () => {\n this.inAppCustomActionHandlers.delete(handler);\n };\n }\n\n private urlAndRef$ = new BehaviorSubject<\n { url: string; ref: string | undefined } | undefined\n >(undefined);\n\n private handleUrlAndRef() {\n // set url and ref to local storage\n this.urlAndRef$.pipe(filterNullable()).subscribe(({ url, ref }) => {\n if (ref) {\n LocalStorage.setRef(ref);\n }\n LocalStorage.setUrl(url);\n });\n // init url and ref from local storage\n this.urlAndRef$.next({\n url: window.location.href,\n ref: LocalStorage.getUrl() ?? undefined,\n });\n\n // observe url change\n const handleUrlChange = () => {\n const prevUrl = this.urlAndRef$.value?.url;\n const currentUrl = window.location.href;\n if (prevUrl !== currentUrl) {\n this.urlAndRef$.next({\n url: currentUrl,\n ref: prevUrl ?? undefined,\n });\n }\n };\n\n // SPA: popstate (뒤로가기/앞으로가기)\n window.addEventListener(\"popstate\", handleUrlChange);\n // 현재 브라우저에는 URL상태를 추적하기 위한 리스너가 존재하지 않습니다.\n // 그래서 pushState와 replaceState를 직접 수정하여 추적합니다.\n // @reference https://stackoverflow.com/a/64927639\n // @reference https://github.com/amplitude/Amplitude-TypeScript/blob/main/packages/plugin-page-view-tracking-browser/src/page-view-tracking.ts\n // SPA: pushState/replaceState proxy\n history.pushState = new Proxy(history.pushState, {\n apply: (target, thisArg, [state, unused, url]) => {\n target.apply(thisArg, [state, unused, url]);\n handleUrlChange();\n },\n });\n history.replaceState = new Proxy(history.replaceState, {\n apply: (target, thisArg, [state, unused, url]) => {\n target.apply(thisArg, [state, unused, url]);\n handleUrlChange();\n },\n });\n }\n\n private registerImpressionTracker() {\n const targetElements = Array.from(\n document.querySelectorAll(`[${BLUX_ATTRIBUTES.tracking_id}]`),\n );\n\n const removed = this.intersectionObservingElements.filter(\n (e) => !targetElements.includes(e),\n );\n\n removed.forEach((e) => {\n this.intersectionObserver?.unobserve(e);\n });\n\n const added = targetElements.filter(\n (element) => !this.intersectionObservingElements.includes(element),\n );\n\n added.forEach((element) => {\n this.intersectionObserver?.observe(element);\n });\n\n this.intersectionObservingElements = targetElements;\n }\n\n private registerHitTracker() {\n const handleDelegatedClick = (event: Event) => {\n if (!(event.target instanceof Element)) return;\n\n const eventTarget = event.target;\n\n const targetItemElement = eventTarget.closest(\n `[${BLUX_ATTRIBUTES.item_id}]`,\n );\n if (!targetItemElement) return;\n\n const itemId = targetItemElement.getAttribute(BLUX_ATTRIBUTES.item_id);\n if (!itemId) return;\n\n const targetSectionElement = eventTarget.closest(\n `[${BLUX_ATTRIBUTES.tracking_id}]`,\n );\n const trackingId = targetSectionElement?.getAttribute(\n BLUX_ATTRIBUTES.tracking_id,\n );\n if (!trackingId) {\n Logger.warning(\n `Tracking ID is not found in the parent elements. Please check the tracking ID(${BLUX_ATTRIBUTES.tracking_id}) is set correctly.`,\n );\n return;\n }\n\n if (!this.hitElements.includes(targetItemElement)) {\n this.sendEvent(\n new AddClickEvent({\n itemId,\n tracking: {\n id: trackingId,\n type: \"hit\",\n },\n }),\n );\n this.hitElements.push(targetItemElement);\n }\n };\n document.addEventListener(\"click\", handleDelegatedClick);\n this.urlAndRef$.pipe(filterNullable()).subscribe(() => {\n this.hitElements = [];\n });\n }\n\n public async getUserRec(\n rec: UserRec,\n ): Promise<APIs.bluxUsersGetItemRecommendationsV2.ResponseData> {\n if (!this.isBrowser) return BluxClient.EMPTY_REC_RESPONSE;\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n const recRequest = rec.request;\n\n const recommendationResponse = await getItemRecommendations(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n {\n call_type: recRequest.call_type,\n limit: recRequest.limit,\n offset: recRequest.offset,\n },\n this.generateApiHeader(bluxUser),\n );\n\n return recommendationResponse.data;\n } catch (error) {\n Logger.error(error, { tags: { from: \"getItemRecommendations\" } });\n return {\n item_ids: [],\n metadata: {},\n recommendation_id: null,\n };\n }\n }\n\n public async getItemRec(\n rec: ItemRec,\n ): Promise<APIs.bluxUsersGetItemRecommendationsV2.ResponseData> {\n if (!this.isBrowser) return BluxClient.EMPTY_REC_RESPONSE;\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n const recRequest = rec.request;\n\n const recommendationResponse = await getItemRecommendations(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n {\n call_type: recRequest.call_type,\n limit: recRequest.limit,\n offset: recRequest.offset,\n item_id: recRequest.item_id,\n },\n this.generateApiHeader(bluxUser),\n );\n\n return recommendationResponse.data;\n } catch (error) {\n Logger.error(error, { tags: { from: \"getItemRecommendations\" } });\n return {\n item_ids: [],\n metadata: {},\n recommendation_id: null,\n };\n }\n }\n\n public async getItemsRec(\n rec: ItemsRec,\n ): Promise<APIs.bluxUsersGetItemRecommendationsV2.ResponseData> {\n if (!this.isBrowser) return BluxClient.EMPTY_REC_RESPONSE;\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n const recRequest = rec.request;\n\n const recommendationResponse = await getItemRecommendations(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n {\n call_type: recRequest.call_type,\n limit: recRequest.limit,\n offset: recRequest.offset,\n item_ids: recRequest.item_ids,\n },\n this.generateApiHeader(bluxUser),\n );\n\n return recommendationResponse.data;\n } catch (error) {\n Logger.error(error, { tags: { from: \"getItemRecommendations\" } });\n return {\n item_ids: [],\n metadata: {},\n recommendation_id: null,\n };\n }\n }\n\n public async getCategoryRec(\n rec: CategoryRec,\n ): Promise<APIs.bluxUsersGetItemRecommendationsV2.ResponseData> {\n if (!this.isBrowser) return BluxClient.EMPTY_REC_RESPONSE;\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n const recRequest = rec.request;\n\n const recommendationResponse = await getItemRecommendations(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n {\n call_type: recRequest.call_type,\n limit: recRequest.limit,\n offset: recRequest.offset,\n category_id: recRequest.category_id,\n },\n this.generateApiHeader(bluxUser),\n );\n\n return recommendationResponse.data;\n } catch (error) {\n Logger.error(error, { tags: { from: \"getItemRecommendations\" } });\n return {\n item_ids: [],\n metadata: {},\n recommendation_id: null,\n };\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsHA,IAAa,aAAb,MAAa,WAAW;CACtB,AAAiB,YAAY,OAAO,WAAW;CAE/C,OAAwB,qBACtB;EACE,UAAU,EAAE;EACZ,UAAU,EAAE;EACZ,mBAAmB;EACpB;CAEH,AAAiB,MAAqB,MAAM,QAAQ;CAEpD,AAAiB,UAAmB;EAClC,MAAM,eAAe;EACZA;EACV;CAED,AAAgB,YAAY,IAAI,gBAC9B,OACD;;;;;CAOD,AAAgB,mBAAmB,IAAI,SAAkC;CACzE,AAAgB,cAAc,IAAI,gBAEhC,OAAU;CACZ,AAAgB,cAAc,IAAI,SAAuB;CACzD,AAAgB,uBAAuB,IAAI,SAAkC;CAE7E,AAAiB,6BAA6B,KAAK;CACnD,AAAiB,mBAAmB,IAAI,gBACtC,KAAK,2BACN;CACD,AAAQ,wBACN,KAAK;CACP,AAAQ,oBAA4B,KAAK,KAAK;CAE9C,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,AAAiB,SAAwB;CAGzC,AAAQ,oBAA+B,EAAE;CACzC,AAAQ,gCAA2C,EAAE;CACrD,AAAiB,uBAAuB,KAAK,YACzC,IAAI,sBAAsB,YAAY;AACpC,UAAQ,SAAS,UAAU;AACzB,QAAK,mBAAmB,KAAK,MAAM;IACnC;GACF,GACF;CAEJ,AAAiB,qBACf,IAAI,SAAoC;CAG1C,AAAQ,cAAyB,EAAE;CAGnC,AAAQ,sBAA2C;CAGnD,AAAQ,4CAA2D,IAAI,KAAK;CAE5E,AAAQ,cAAc,eAA6C;AACjE,MAAI,iBAAiB,iBAAiB,cAAc,YAClD,QAAO,IAAI,UAAU;AAGvB,MAAI,oBAAoB,iBAAiB,cAAc,eACrD,SAAQ,cAAc,gBAAtB;GACE,KAAK,OACH,QAAO;GACT,KAAK,UACH,QAAO,IAAI,eAAe;GAC5B,KAAK,MACH,QAAO,IAAI,WAAW;GACxB,KAAK,eACH,QAAO,IAAI,UAAU;GACvB,KAAK,UACH,QAAO,IAAI,eAAe;GAC5B,SAAS;IACP,MAAM,kBAAyB,cAAc;AAC7C,WAAO,MAAM,4BAA4B,mBAAmB,EAC1D,MAAM,EAAE,MAAM,iBAAiB,EAChC,CAAC;;;AAKR,SAAO;;CAGT,YACE,EACE,mBACA,YACA,gBACA,GAAG,iBAML,oBAIA;AACA,OAAK,oBAAoB;AACzB,OAAK,aAAa;AAClB,OAAK,iBAAiB;AAEtB,MAAI,CAAC,KAAK,WAAW;AACnB,wBAAqB,EAAE,SAAS,MAAM,CAAC;AACvC;;EAGF,MAAM,UAAU,QAAQ,YAAY,WAAW;AAC/C,OAAK,IAAI,SAAS,UAAU;AAE5B,OAAK,SAAS,KAAK,cAAc,cAAc;AAG/C,OAAK,iBACF,KACC,UAAU,OAAO,QAAQ;AACvB,OAAI;IACF,MAAM,SAAS,MAAM,IAAI,QAAQ;AACjC,QAAI,QAAQ,OAAO;YACZ,OAAO;AACd,QAAI,OAAO,MAAM;;IAEnB,CACH,CACA,WAAW;;;;;AAOd,MAAI,CAAC,KAAK,OACR,OACE,KAAK,YAAY,KACf,WAAW,IAAI,EACf,QAAQ,aAAa,SAAS,SAAS,EAAE,CAC1C,EAED,cAAc,CAAC,KAAK,kBAAkB,sBAAsB,CAAC,CAAC,CAAC,KAC7D,WAAW,CAAC,OAAO,wBAAwB;AACzC,OAAI,CAAC,sBAAsB,SAAS,KAAM,QAAO;GAEjD,MAAM,aAAa,KAAK,oBAAoB;AAG5C,UAAO,MAFgB,KAAK,IAAI,GAAG,aAAa,KAAK,KAAK,CAAC,CAE/B;IAC5B,EACF,UAAU,EAAE,CAAmB,CAChC,CACF,CACE,KACC,UAAU,OAAO,aAAa;AAC5B,QAAK,iBAAiB,KAAK,KAAK;AAChC,OAAI;IACF,MAAM,WAAW,MAAM,KAAK,wBAAwB;IAEpD,MAAM,SAAS,SAAS,KAAK,aAAa;KACxC,GAAG;KACH,SAAS,SAAS;KAClB,WAAW,SAAS;KACrB,EAAE;IAEH,MAAM,EACJ,MAAM,EAAE,iBAAiB,YACvB,MAAM,KAAK,qBACb,aACE,KAAK,KACL;KACE,cAAc,SAAS;KACvB,gBAAgB,SAAS;KAC1B,EACD;KACE,WAAW,SAAS;KACpB;KACD,EACD,KAAK,kBAAkB,SAAS,CACjC,CACF;AAED,SAAK,oBAAoB,KAAK,KAAK;AACnC,SAAK,wBAAwB;AAC7B,SAAK,iBAAiB,KAAK,KAAK,IAAI,iBAAiB,IAAK,CAAC;AAE3D,QAAI,MACF,MAAK,YAAY,KAAK,MAAM;YAEvB,OAAO;AACd,WAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,EAAE,CAAC;AACrD,SAAK,oBAAoB,KAAK,KAAK;AACnC,QAAI,KAAK,0BAA0B,MAAM;KACvC,MAAM,gBACJ,KAAK,wBAAwB,MAAO,KAAK,KAAK,KAC1C,KAAK,wBACL,KAAK,wBAAwB;AACnC,UAAK,wBAAwB;AAC7B,UAAK,iBAAiB,KAAK,cAAc;;;IAG7C,CACH,CACA,WAAW;AAIhB,OAAK,qBACF,KACC,WAAW,IAAI,EACf,QAAQ,UAAU,MAAM,SAAS,EAAE,EACnC,UAAU,OAAO,UAAU;AACzB,OAAI;IACF,MAAM,WAAW,MAAM,KAAK,wBAAwB;IAEpD,MAAM,uBAAuB,MAAM,QAChC,KAAK,UAAU;KAAE,GAAG;KAAK,GAAI,KAAK,kBAAkB,EAAE;KAAG,GAC1D,EAAE,CAGH;IAED,MAAM,6BAA6B,MAAM,QACtC,KAAK,UAAU;KAAE,GAAG;KAAK,GAAI,KAAK,wBAAwB,EAAE;KAAG,GAChE,EAAE,CAGH;IAED,MAAM,UAA+C,EAAE;AACvD,QAAI,OAAO,KAAK,qBAAqB,CAAC,SAAS,EAC7C,SAAQ,kBAAkB;AAE5B,QAAI,OAAO,KAAK,2BAA2B,CAAC,SAAS,EACnD,SAAQ,yBAAyB;AAGnC,QAAI,OAAO,KAAK,QAAQ,CAAC,WAAW,GAAG;AACrC,WAAM,SAAS,SAAS,KAAK,SAAS,CAAC;AACvC;;AAGF,UAAM,KAAK,qBACT,iBACE,KAAK,KACL;KACE,gBAAgB,SAAS;KACzB,cAAc,SAAS;KACxB,EACD,SACA,KAAK,kBAAkB,SAAS,CACjC,CACF;AAED,UAAM,SAAS,SAAS,KAAK,SAAS,CAAC;YAChC,OAAO;AACd,UAAM,SAAS,SAAS,KAAK,OAAO,MAAM,CAAC;AAC3C,WAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,EAAE,CAAC;;IAEhE,CACH,CACA,WAAW;AAEd,OAAK,UAAU,WAAW,aAAa;AACrC,OAAI,SAAU,gBAAe,cAAc,SAAS,GAAG;IACvD;AAEF,MAAI,CAAC,KAAK,OACR,MAAK,YACF,KAAK,gBAAgB,CAAC,CACtB,KACC,WAAW,UACT,sBAAsB,CAAC,KACrB,MAAM,QAAQ,EACd,gBAAgB,KAAK,KAAK,aAAa,MAAM,CAAC,CAAC,CAChD,CACF,CACF,CACA,WAAW;AAGhB,OAAK,MAAM,CACR,WAAW;AACV,wBAAqB,EAAE,SAAS,MAAM,CAAC;IACvC,CACD,OAAO,UAAU;AAChB,wBAAqB;IAAE,SAAS;IAAO,cAAc,MAAM;IAAS,CAAC;IACrE;;CAGN,MAAc,eAAkB,QAA0B;AACxD,SAAO,IAAI,SAAY,SAAS,WAAW;GACzC,MAAM,OAA8B;IAAE;IAAQ;IAAS;IAAQ;AAC/D,QAAK,iBAAiB,KAAK,KAAK;IAChC;;CAGJ,AAAQ,kBAAkB,EAAE,cAAsC;AAChE,SAAO,EACL,eAAe,YAChB;;CAGH,MAAc,aAAa,OAA6B;AACtD,SAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,WAAW,KAAK,UAAU,UAAU;GAE1C,MAAM,gBAAgB,aAAa,sBAAsB,MAAM,QAAQ;AAIvE,OAFE,kBAAkB,QAAQ,OAAO,CAAC,SAAS,MAAM,cAAc,CAAC,CAEhD,QAAO,QAAQ,KAAK;GAEtC,MAAM,gBAAgB,SAAS,cAAc,SAAS;GAmBtD,MAAM,gBAAgB;;;;;;;;;;;;;8BAAiC,MAAM,QAAQ;GACrE,MAAM,eAAe,MAAM,WAAW,SAAS,SAAS,GACpD,MAAM,WAAW,QAAQ,UAAU,SAAS,gBAAgB,GAC5D,MAAM;GAEV,MAAM,OAAO,IAAI,KAAK,CAAC,aAAa,EAAE,EAAE,MAAM,aAAa,CAAC;GAC5D,MAAM,UAAU,IAAI,gBAAgB,KAAK;AAEzC,iBAAc,QAAQ,IACpB,iBACA,qBACA,cACD;AACD,iBAAc,MAAM;AACpB,iBAAc,MAAM,WAAW;AAC/B,iBAAc,MAAM,QAAQ,GAAG,OAAO,WAAW;AACjD,iBAAc,MAAM,SAAS,GAAG,OAAO,YAAY;AACnD,iBAAc,MAAM,MAAM;AAC1B,iBAAc,MAAM,OAAO;AAE3B,iBAAc,MAAM,SAAS;AAC7B,iBAAc,KAAK,cAAc,MAAM;AAEvC,YAAS,KAAK,YAAY,cAAc;GAExC,IAAI,wBAA6C;GAEjD,MAAM,gBAAgB;AACpB,QAAI,gBAAgB,QAAQ;AAC5B,kBAAc,QAAQ;AACtB,WAAO,oBAAoB,WAAW,cAAc;AACpD,WAAO,gBAAgB,oBACrB,UACA,qBACD;AACD,WAAO,gBAAgB,oBACrB,UACA,qBACD;AACD,2BAAuB,aAAa;AACpC,SAAK,sBAAsB;AAC3B,YAAQ,MAAM,QAAQ;;AAIxB,QAAK,sBAAsB;GAC3B,MAAM,6BAA6B;IACjC,MAAM,QAAQ,OAAO,gBAAgB,SAAS,OAAO;IACrD,MAAM,SAAS,OAAO,gBAAgB,UAAU,OAAO;IACvD,MAAM,OAAO,OAAO,gBAAgB,cAAc;IAClD,MAAM,MAAM,OAAO,gBAAgB,aAAa;AAEhD,kBAAc,MAAM,QAAQ,GAAG,MAAM;AACrC,kBAAc,MAAM,SAAS,GAAG,OAAO;AACvC,kBAAc,MAAM,OAAO,GAAG,KAAK;AACnC,kBAAc,MAAM,MAAM,GAAG,IAAI;;GAGnC,MAAM,iBACJ,UA+CG;AACH,QAAI,MAAM,WAAW,cAAc,cAAe;IAElD,MAAM,UAAU,MAAM;AAEtB,QAAI,QAAQ,WAAW,UAAU;KAC/B,MAAM,EAAE,QAAQ,aAAa,QAAQ;AAErC,mBAAc,MAAM,QAAQ;AAC5B,mBAAc,MAAM,WAAW;AAC/B,mBAAc,MAAM,SAAS,GAAG,OAAO;AACvC,mBAAc,MAAM,OAAO;AAC3B,mBAAc,MAAM,YAAY;AAChC,SAAI,aAAa,OAAO;AACtB,oBAAc,MAAM,MAAM;AAC1B,oBAAc,MAAM,SAAS;YACxB;AACL,oBAAc,MAAM,MAAM;AAC1B,oBAAc,MAAM,SAAS;;AAG/B,YAAO,gBAAgB,oBACrB,UACA,qBACD;AACD,YAAO,gBAAgB,oBACrB,UACA,qBACD;AACD;;AAGF,QAAI,QAAQ,WAAW,QAAQ;KAC7B,MAAM,EAAE,iBAAiB,QAAQ;AACjC,SAAI,iBAAiB,GAAG;MACtB,MAAM,YAAY,OAAO,CAAC,IAAI,cAAc,OAAO,CAAC,SAAS;AAC7D,mBAAa,sBAAsB,MAAM,SAAS,UAAU;;eAErD,QAAQ,WAAW,QAAQ;KAEpC,MAAM,kBAAkB,WACpB,KAAK,qBACH,eACE,KAAK,KACL,EACE,gBAAgB,KAAK,mBACtB,EACD;MACE,iBAAiB,MAAM;MACvB,gBAAgB;MAChB,8BAAa,IAAI,MAAM,EAAC,aAAa;MACtC,EACD,KAAK,kBAAkB,SAAS,CACjC,CACF,GACD,QAAQ,SAAS;AAErB,SAAI,QAAQ,KAAK,iBAAiB,QAE3B;MACL,MAAM,EAAE,KAAK,iBAAiB,qBAAqB,QAAQ;MAC3D,MAAM,sBAAsB,oBAAoB,CAAC;AAGjD,UAAI,KAAK,sBAAsB,2BAC7B,iBAAgB,cAAc;AAC5B,cAAO,KAAK,YACV;QACE,MAAM;QACN;QACD,EACD,OAAO,SAAS,OACjB;QACD;eACO,oBAET,iBAAgB,cAAc;AAC5B,cAAO,SAAS,OAAO;QACvB;eACO,CAAC,iBAEV,KAAI,gBACF,QAAO,KAAK,KAAK,SAAS;UAE1B,QAAO,SAAS,OAAO;;eAKpB,QAAQ,WAAW,iBAAiB;KAC7C,MAAM,EAAE,WAAW,MAAM,mBAAmB,QAAQ;AAGpD,UAAK,MAAM,WAAW,KAAK,0BACzB,KAAI;AACF,cAAQ;OAAE,UAAU;OAAW;OAAM,CAAC;cAC/B,OAAO;AACd,aAAO,MAAM,OAAO,EAClB,MAAM,EAAE,MAAM,4BAA4B,EAC3C,CAAC;;AAKN,SAAI,CAAC,eACH;eAEO,QAAQ,WAAW,gBAAgB;AAE5C,SAAI,SACF,MAAK,qBACH,eACE,KAAK,KACL,EACE,gBAAgB,KAAK,mBACtB,EACD;MACE,iBAAiB,MAAM;MACvB,gBAAgB;MAChB,8BAAa,IAAI,MAAM,EAAC,aAAa;MACtC,EACD,KAAK,kBAAkB,SAAS,CACjC,CACF;AAEH;;AAGF,aAAS;;AAIX,2BAAwB,KAAK,WAC1B,KAAK,gBAAgB,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CACxC,gBAAgB;AACf,aAAS;KACT;AAEJ,UAAO,gBAAgB,iBAAiB,UAAU,qBAAqB;AACvE,UAAO,gBAAgB,iBAAiB,UAAU,qBAAqB;AACvE,UAAO,iBAAiB,WAAW,cAAc;AAEjD,OAAI,SACF,MAAK,qBACH,oBACE,KAAK,KACL;IACE,gBAAgB,KAAK;IACrB,iBAAiB,MAAM;IACxB,EACD,EACE,QAAQ,YACT,EACD,KAAK,kBAAkB,SAAS,CACjC,CACF;IAEH;;CAGJ,MAAc,OAAO;AACnB,OAAK,iBAAiB;AAEtB,OAAK,WAAW,KAAK,gBAAgB,CAAC,CAAC,gBAAgB;AACrD,QAAK,UAAU,IAAI,kBAAkB,EAAE,CAAC,CAAC;IACzC;AAEF,MAAI,KAAK,QAAQ;AACf,QAAK,OAAO,WAAW;IACrB,mBAAmB,KAAK;IACxB,YAAY,KAAK;IACjB,gBAAgB,KAAK;IACtB,CAAC;AACF;;EAGF,MAAM,eAAe,IAAI,gBAAgB,OAAO,SAAS,OAAO,CAAC,IAC/D,eACD;EACD,MAAM,YACJ,eAAe,cAAc,IAAI,IAAI,UAAU,CAAC,aAAa;AAC/D,iBAAe,aAAa,UAAU;AAGtC,MAAI,CADsC,eAAe,eAAe,CAChC,MAAK,UAAU,IAAI,WAAW,EAAE,CAAC,CAAC;AAE1E,SAAO,MAAM,6BAA6B,KAAK,oBAAoB;EAEnE,MAAM,WAAW,aAAa,aAAa;AAE3C,MAAI,CAAC,SACH,QAAO,MAAM,0CAA0C;AAGzD,OAAK,oBAAoB;AAGzB,OAAK,WAAW,KAAK,gBAAgB,CAAC,CAAC,gBAAgB;AACrD,QAAK,oBAAoB,EAAE;IAC3B;AAEF,OAAK,2BAA2B;AAChC,MAAI,uBAAuB;AACzB,QAAK,2BAA2B;IAChC,CAAC,QAAQ,UAAU;GAAE,SAAS;GAAM,WAAW;GAAM,CAAC;EAGxD,MAAM,sBAAsB;AAC5B,OAAK,mBACF,KACC,SAAS,UAAU,MAAM,OAAO,EAChC,UAAU,WACR,OAAO,KACL,aAAa,oBAAoB,EACjC,QAAQ,UAAU,MAAM,eAAe,CACxC,CACF,CACF,CACA,WAAW,UAAU;GACpB,MAAM,aAAa,MAAM,OAAO,aAC9B,gBAAgB,YACjB;AACD,OAAI,CAAC,YAAY;AACf,WAAO,QACL,iFAAiF,gBAAgB,YAAY,qBAC9G;AACD;;AAEF,OAAI,KAAK,kBAAkB,SAAS,MAAM,OAAO,CAAE;AAEnD,QAAK,UACH,IAAI,oBAAoB;IACtB,SAAS;IACT,UAAU;KACR,IAAI;KACJ,MAAM;KACP;IACF,CAAC,CACH;AACD,QAAK,kBAAkB,KAAK,MAAM,OAAO;IACzC;EAEJ,MAAM,EAAE,SAAS,MAAM,WACrB,KAAK,KACL,EAAE,gBAAgB,KAAK,mBAAmB,EAC1C;GACE,YAAY,aAAa;GACzB,WAAW,YAAY;GACvB,cAAc,UAAU,SAAS,MAAM,IAAI,CAAC;GAC5C,cAAc,UAAU;GACxB,eAAe,UAAU,SAAS,MAAM,IAAI,CAAC;GAC7C,UAAU,eAAe;GACzB,YAAY,UAAU;GACtB,aAAa,KAAK,QAAQ;GAC1B,UAAU,KAAK,QAAQ;GACvB,UAAU,KAAK,gBAAgB,CAAC,iBAAiB,CAAC;GAClD,cAAc,gBAAgB;GAC9B,kBAAkB,KAAK;GACxB,EACD,KAAK,kBAAkB,EACrB,YAAY,KAAK,YAClB,CAAC,CACH;AAED,MAAI,KAAK,UAAW,cAAa,YAAY,KAAK,UAAU;AAE5D,OAAK,UAAU,KAAK;GAClB,IAAI,KAAK;GACT,YAAY,KAAK;GACjB,eAAe,KAAK;GACpB,UAAU,KAAK;GAChB,CAAC;;CAGJ,AAAO,YAAY,UAAoB;AACrC,SAAO,SAAS,SAAS;;CAG3B,MAAc,yBAAyB;AAiBrC,SAhBiB,MAAM,eACrB,KAAK,UAAU,KACb,gBAAgB,EAChB,QAAQ,IAAK,EACb,YAAY,UAAU;AACpB,UAAO,iBACL,MAAM,SAAS,iCACX,IAAI,MACF,mEACD,GACD,MACL;IACD,CACH,CACF;;CAKH,MAAa,OAAO,EAAE,UAA8B;AAClD,MAAI,CAAC,KAAK,UAAW;AACrB,MAAI;AACF,OAAI,KAAK,QAAQ;AACf,SAAK,OAAO,OAAO,EAAE,QAAQ,CAAC;AAC9B;;GAGF,MAAM,WAAW,MAAM,KAAK,wBAAwB;GAEpD,MAAM,EACJ,MAAM,EAAE,cAAc,uBACpB,MAAM,KAAK,qBACb,OACE,KAAK,KACL;IAAE,gBAAgB,SAAS;IAAe,cAAc,SAAS;IAAI,EACrE;IAAE,SAAS;IAAQ,WAAW,SAAS;IAAU,EACjD,KAAK,kBAAkB,SAAS,CACjC,CACF;AAED,OAAI,qBAAqB,SAAS,IAAI;AACpC,WAAO,MAAM,gCAAgC;AAC7C,SAAK,UAAU,KAAK;KAClB,GAAG;KACH,IAAI;KACJ;KACD,CAAC;;WAEG,OAAO;AACd,UAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,EAAE,CAAC;;;CAIrD,MAAa,UAAU;AACrB,MAAI,CAAC,KAAK,UAAW;AACrB,MAAI;AACF,OAAI,KAAK,QAAQ;AACf,SAAK,OAAO,SAAS;AACrB;;GAGF,MAAM,WAAW,MAAM,KAAK,wBAAwB;GAEpD,MAAM,EACJ,MAAM,EAAE,cAAc,uBACpB,MAAM,KAAK,qBACb,QACE,KAAK,KACL;IAAE,gBAAgB,SAAS;IAAe,cAAc,SAAS;IAAI,EACrE,EAAE,WAAW,SAAS,UAAU,EAChC,KAAK,kBAAkB,SAAS,CACjC,CACF;AAED,UAAO,MAAM,iCAAiC;AAC9C,QAAK,UAAU,KAAK;IAClB,GAAG;IACH,IAAI;IACJ,QAAQ;IACT,CAAC;WACK,OAAO;AACd,UAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,EAAE,CAAC;;;CAItD,MAAa,kBAAkB,EAC7B,kBAKC;AACD,MAAI,CAAC,KAAK,UAAW;AACrB,MAAI;AACF,OAAI,KAAK,QAAQ;AACf,SAAK,OAAO,kBAAkB,eAAe;AAC7C;;AAGF,SAAM,IAAI,SAAe,SAAS,WAAW;AAC3C,SAAK,qBAAqB,KAAK;KAC7B;KACA;KACA;KACD,CAAC;KACF;WACK,OAAO;AACd,UAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,EAAE,CAAC;;;CAIhE,MAAa,wBAAwB,EACnC,wBAKC;AACD,MAAI,CAAC,KAAK,UAAW;AACrB,MAAI;AACF,OAAI,KAAK,QAAQ;AACf,SAAK,OAAO,wBAAwB,qBAAqB;AACzD;;AAGF,SAAM,IAAI,SAAe,SAAS,WAAW;AAC3C,SAAK,qBAAqB,KAAK;KAC7B;KACA;KACA;KACD,CAAC;KACF;WACK,OAAO;AACd,UAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,EAAE,CAAC;;;CAItE,AAAO,UAAU,OAAgC;AAC/C,MAAI,CAAC,KAAK,UAAW;AACrB,MAAI;GACF,MAAM,YAAY,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,KAAK,OAAO;IACpE,GAAG,EAAE;IACL,2BAA2B;KACzB,KAAK,KAAK,WAAW,OAAO;KAC5B,KAAK,KAAK,WAAW,OAAO;KAC7B;IACF,EAAE;AAEH,OAAI,KAAK,QAAQ;AACf,SAAK,OAAO,UAAU,EAAE,UAAU,CAAC;AACnC;;AAGF,YAAS,SAAS,YAAY;AAC5B,SAAK,YAAY,KAAK,QAAQ;KAC9B;WACK,OAAO;AACd,UAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,EAAE,CAAC;;;;;;;;;;;;;;;CAgBxD,AAAO,eAAe;AACpB,MAAI,CAAC,KAAK,UAAW;AACrB,OAAK,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;CAwB9B,AAAO,4BACL,SACY;AACZ,MAAI,CAAC,KAAK,UAAW,cAAa;AAClC,OAAK,0BAA0B,IAAI,QAAQ;AAC3C,eAAa;AACX,QAAK,0BAA0B,OAAO,QAAQ;;;CAIlD,AAAQ,aAAa,IAAI,gBAEvB,OAAU;CAEZ,AAAQ,kBAAkB;AAExB,OAAK,WAAW,KAAK,gBAAgB,CAAC,CAAC,WAAW,EAAE,KAAK,UAAU;AACjE,OAAI,IACF,cAAa,OAAO,IAAI;AAE1B,gBAAa,OAAO,IAAI;IACxB;AAEF,OAAK,WAAW,KAAK;GACnB,KAAK,OAAO,SAAS;GACrB,KAAK,aAAa,QAAQ,IAAI;GAC/B,CAAC;EAGF,MAAM,wBAAwB;GAC5B,MAAM,UAAU,KAAK,WAAW,OAAO;GACvC,MAAM,aAAa,OAAO,SAAS;AACnC,OAAI,YAAY,WACd,MAAK,WAAW,KAAK;IACnB,KAAK;IACL,KAAK,WAAW;IACjB,CAAC;;AAKN,SAAO,iBAAiB,YAAY,gBAAgB;AAMpD,UAAQ,YAAY,IAAI,MAAM,QAAQ,WAAW,EAC/C,QAAQ,QAAQ,SAAS,CAAC,OAAO,QAAQ,SAAS;AAChD,UAAO,MAAM,SAAS;IAAC;IAAO;IAAQ;IAAI,CAAC;AAC3C,oBAAiB;KAEpB,CAAC;AACF,UAAQ,eAAe,IAAI,MAAM,QAAQ,cAAc,EACrD,QAAQ,QAAQ,SAAS,CAAC,OAAO,QAAQ,SAAS;AAChD,UAAO,MAAM,SAAS;IAAC;IAAO;IAAQ;IAAI,CAAC;AAC3C,oBAAiB;KAEpB,CAAC;;CAGJ,AAAQ,4BAA4B;EAClC,MAAM,iBAAiB,MAAM,KAC3B,SAAS,iBAAiB,IAAI,gBAAgB,YAAY,GAAG,CAC9D;AAMD,EAJgB,KAAK,8BAA8B,QAChD,MAAM,CAAC,eAAe,SAAS,EAAE,CACnC,CAEO,SAAS,MAAM;AACrB,QAAK,sBAAsB,UAAU,EAAE;IACvC;AAMF,EAJc,eAAe,QAC1B,YAAY,CAAC,KAAK,8BAA8B,SAAS,QAAQ,CACnE,CAEK,SAAS,YAAY;AACzB,QAAK,sBAAsB,QAAQ,QAAQ;IAC3C;AAEF,OAAK,gCAAgC;;CAGvC,AAAQ,qBAAqB;EAC3B,MAAM,wBAAwB,UAAiB;AAC7C,OAAI,EAAE,MAAM,kBAAkB,SAAU;GAExC,MAAM,cAAc,MAAM;GAE1B,MAAM,oBAAoB,YAAY,QACpC,IAAI,gBAAgB,QAAQ,GAC7B;AACD,OAAI,CAAC,kBAAmB;GAExB,MAAM,SAAS,kBAAkB,aAAa,gBAAgB,QAAQ;AACtE,OAAI,CAAC,OAAQ;GAKb,MAAM,aAHuB,YAAY,QACvC,IAAI,gBAAgB,YAAY,GACjC,EACwC,aACvC,gBAAgB,YACjB;AACD,OAAI,CAAC,YAAY;AACf,WAAO,QACL,iFAAiF,gBAAgB,YAAY,qBAC9G;AACD;;AAGF,OAAI,CAAC,KAAK,YAAY,SAAS,kBAAkB,EAAE;AACjD,SAAK,UACH,IAAI,cAAc;KAChB;KACA,UAAU;MACR,IAAI;MACJ,MAAM;MACP;KACF,CAAC,CACH;AACD,SAAK,YAAY,KAAK,kBAAkB;;;AAG5C,WAAS,iBAAiB,SAAS,qBAAqB;AACxD,OAAK,WAAW,KAAK,gBAAgB,CAAC,CAAC,gBAAgB;AACrD,QAAK,cAAc,EAAE;IACrB;;CAGJ,MAAa,WACX,KAC8D;AAC9D,MAAI,CAAC,KAAK,UAAW,QAAO,WAAW;AACvC,MAAI;GACF,MAAM,WAAW,MAAM,KAAK,wBAAwB;GACpD,MAAM,aAAa,IAAI;AAgBvB,WAd+B,MAAM,uBACnC,KAAK,KACL;IACE,gBAAgB,SAAS;IACzB,cAAc,SAAS;IACxB,EACD;IACE,WAAW,WAAW;IACtB,OAAO,WAAW;IAClB,QAAQ,WAAW;IACpB,EACD,KAAK,kBAAkB,SAAS,CACjC,EAE6B;WACvB,OAAO;AACd,UAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,EAAE,CAAC;AACjE,UAAO;IACL,UAAU,EAAE;IACZ,UAAU,EAAE;IACZ,mBAAmB;IACpB;;;CAIL,MAAa,WACX,KAC8D;AAC9D,MAAI,CAAC,KAAK,UAAW,QAAO,WAAW;AACvC,MAAI;GACF,MAAM,WAAW,MAAM,KAAK,wBAAwB;GACpD,MAAM,aAAa,IAAI;AAiBvB,WAf+B,MAAM,uBACnC,KAAK,KACL;IACE,gBAAgB,SAAS;IACzB,cAAc,SAAS;IACxB,EACD;IACE,WAAW,WAAW;IACtB,OAAO,WAAW;IAClB,QAAQ,WAAW;IACnB,SAAS,WAAW;IACrB,EACD,KAAK,kBAAkB,SAAS,CACjC,EAE6B;WACvB,OAAO;AACd,UAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,EAAE,CAAC;AACjE,UAAO;IACL,UAAU,EAAE;IACZ,UAAU,EAAE;IACZ,mBAAmB;IACpB;;;CAIL,MAAa,YACX,KAC8D;AAC9D,MAAI,CAAC,KAAK,UAAW,QAAO,WAAW;AACvC,MAAI;GACF,MAAM,WAAW,MAAM,KAAK,wBAAwB;GACpD,MAAM,aAAa,IAAI;AAiBvB,WAf+B,MAAM,uBACnC,KAAK,KACL;IACE,gBAAgB,SAAS;IACzB,cAAc,SAAS;IACxB,EACD;IACE,WAAW,WAAW;IACtB,OAAO,WAAW;IAClB,QAAQ,WAAW;IACnB,UAAU,WAAW;IACtB,EACD,KAAK,kBAAkB,SAAS,CACjC,EAE6B;WACvB,OAAO;AACd,UAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,EAAE,CAAC;AACjE,UAAO;IACL,UAAU,EAAE;IACZ,UAAU,EAAE;IACZ,mBAAmB;IACpB;;;CAIL,MAAa,eACX,KAC8D;AAC9D,MAAI,CAAC,KAAK,UAAW,QAAO,WAAW;AACvC,MAAI;GACF,MAAM,WAAW,MAAM,KAAK,wBAAwB;GACpD,MAAM,aAAa,IAAI;AAiBvB,WAf+B,MAAM,uBACnC,KAAK,KACL;IACE,gBAAgB,SAAS;IACzB,cAAc,SAAS;IACxB,EACD;IACE,WAAW,WAAW;IACtB,OAAO,WAAW;IAClB,QAAQ,WAAW;IACnB,aAAa,WAAW;IACzB,EACD,KAAK,kBAAkB,SAAS,CACjC,EAE6B;WACvB,OAAO;AACd,UAAO,MAAM,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,EAAE,CAAC;AACjE,UAAO;IACL,UAAU,EAAE;IACZ,UAAU,EAAE;IACZ,mBAAmB;IACpB"}
|
|
1
|
+
{"version":3,"file":"BluxClient.js","names":["packageJson.version"],"sources":["../src/BluxClient.ts"],"sourcesContent":["import axios from \"axios\";\nimport ObjectId from \"bson-objectid\";\nimport dayjs from \"dayjs\";\nimport {\n BehaviorSubject,\n bufferTime,\n catchError,\n combineLatest,\n concatMap,\n debounceTime,\n filter,\n first,\n firstValueFrom,\n from,\n groupBy,\n map,\n merge,\n mergeMap,\n NEVER,\n skip,\n Subject,\n Subscription,\n switchMap,\n throwError,\n timeout,\n timer,\n} from \"rxjs\";\n\nimport packageJson from \"../package.json\";\nimport { DevicePlatform, type APIs } from \"./apis/APIs\";\nimport { createCrmEvent } from \"./apis/createCrmEvent\";\nimport { collectEvent } from \"./apis/createEvent\";\nimport { getItemRecommendations } from \"./apis/getItemRecommendations\";\nimport { initialize } from \"./apis/initialize\";\nimport { notificationsUpdate } from \"./apis/notificationsUpdate\";\nimport { signIn } from \"./apis/signIn\";\nimport { signOut } from \"./apis/signOut\";\nimport { updateProperties } from \"./apis/updateProperties\";\nimport { AndroidBridge } from \"./bridges/AndroidBridge\";\nimport { Bridge, BridgePlatform } from \"./bridges/Bridge\";\nimport { FlutterBridge } from \"./bridges/FlutterBridge\";\nimport { IosBridge } from \"./bridges/IosBridge\";\nimport { RNBridge } from \"./bridges/RNBridge\";\nimport { BLUX_ATTRIBUTES } from \"./constants/BLUX_ATTRIBUTES\";\nimport {\n AddClickEvent,\n AddPageVisitEvent,\n AddSectionViewEvent,\n VisitEvent,\n} from \"./events\";\nimport { LocalStorage } from \"./utils/LocalStorage\";\nimport { Logger } from \"./utils/Logger\";\nimport { onlineAndVisible$ } from \"./utils/observables\";\nimport { filterNullable } from \"./utils/operators\";\nimport { SessionStorage } from \"./utils/SessionStorage\";\n\nimport type { Event as BluxEvent } from \"./events/Event\";\nimport type { EventRequest } from \"./events/types\";\nimport type { CategoryRec, ItemRec, ItemsRec, UserRec } from \"./recs\";\nimport type { LogLevel } from \"./utils/Logger\";\nimport type { AxiosInstance } from \"axios\";\n\nexport type SdkInfo = {\n type: DevicePlatform;\n version: string;\n};\n\ntype BluxUser = {\n id: string;\n bluxAPIKey: string;\n applicationId: string;\n deviceId: string;\n userId?: string;\n};\n\ntype BridgeOptions =\n | {\n /**\n * @deprecated `bridgePlatform`을 사용하세요.\n */\n useRNBridge?: boolean;\n }\n | { bridgePlatform?: BridgePlatform };\n\ntype InappMessageResponse = NonNullable<\n APIs.bluxUsersCollectEventsV2.ResponseData[\"inapp\"]\n>;\n\ntype ApiRequestQueueJob<T> = {\n action: () => Promise<T>;\n resolve: (value: T) => void;\n reject: (error: unknown) => void;\n};\n\ntype UserPropertiesQueueItem = {\n userProperties?: APIs.bluxUsersUpdateProperties.Body[\"user_properties\"];\n customUserProperties?: APIs.bluxUsersUpdateProperties.Body[\"custom_user_properties\"];\n resolve: () => void;\n reject: (error: unknown) => void;\n};\n\n/**\n * 인앱 메시지에서 BluxBridge.triggerAction() 호출 시 전달되는 이벤트\n */\nexport type InAppCustomActionEvent = {\n /** 액션 식별자 */\n actionId: string;\n /** 액션에 전달된 데이터 */\n data: Record<string, unknown>;\n};\n\n/**\n * 인앱 커스텀 액션 핸들러 타입\n */\nexport type InAppCustomActionHandler = (\n event: InAppCustomActionEvent,\n) => void | Promise<void>;\n\nexport class BluxClient {\n private readonly api: AxiosInstance = axios.create();\n\n private readonly sdkInfo: SdkInfo = {\n type: DevicePlatform.browser,\n version: packageJson.version,\n };\n\n public readonly bluxUser$ = new BehaviorSubject<BluxUser | undefined>(\n undefined,\n );\n\n /**\n * 내부 async 작업을 1개씩 직렬로 처리하는 큐입니다.\n * `enqueueRequest()`로 넣으면, 호출자는 완료 시점까지 `await` 할 수 있습니다.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public readonly apiRequestQueue$ = new Subject<ApiRequestQueueJob<any>>();\n public readonly inappQueue$ = new BehaviorSubject<\n InappMessageResponse | undefined\n >(undefined);\n public readonly eventQueue$ = new Subject<EventRequest>();\n public readonly userPropertiesQueue$ = new Subject<UserPropertiesQueueItem>();\n\n private readonly INITIAL_NEXT_POLL_DELAY_MS = 10 * 1000;\n private readonly nextPollDelayMs$ = new BehaviorSubject<number | null>(\n this.INITIAL_NEXT_POLL_DELAY_MS,\n );\n private cachedNextPollDelayMs: number | null =\n this.INITIAL_NEXT_POLL_DELAY_MS;\n private lastPollTimestamp: number = Date.now();\n\n private readonly bluxApplicationId: string;\n private readonly bluxAPIKey: string;\n private readonly customDeviceId?: string;\n\n private readonly bridge: Bridge | null;\n\n // Impression 관련 변수\n private impressedElements: Element[] = [];\n private intersectionObservingElements: Element[] = [];\n private readonly intersectionObserver = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n this.intersectionEntry$.next(entry);\n });\n },\n );\n\n private readonly intersectionEntry$ =\n new Subject<IntersectionObserverEntry>();\n\n // Hit 관련 변수\n private hitElements: Element[] = [];\n\n // 현재 표시 중인 인앱 메시지의 cleanup 함수\n private currentInappCleanup: (() => void) | null = null;\n\n // 인앱 커스텀 액션 핸들러 (복수 등록 가능)\n private inAppCustomActionHandlers: Set<InAppCustomActionHandler> = new Set();\n\n private resolveBridge(bridgeOptions: BridgeOptions): Bridge | null {\n if (\"useRNBridge\" in bridgeOptions && bridgeOptions.useRNBridge) {\n return new RNBridge();\n }\n\n if (\"bridgePlatform\" in bridgeOptions && bridgeOptions.bridgePlatform) {\n switch (bridgeOptions.bridgePlatform) {\n case \"none\":\n return null;\n case \"android\":\n return new AndroidBridge();\n case \"ios\":\n return new IosBridge();\n case \"react-native\":\n return new RNBridge();\n case \"flutter\":\n return new FlutterBridge();\n default: {\n const exhaustiveCheck: never = bridgeOptions.bridgePlatform;\n Logger.error(`Unknown bridge platform: ${exhaustiveCheck}`, {\n tags: { from: \"resolveBridge\" },\n });\n }\n }\n }\n\n return null;\n }\n\n constructor(\n {\n bluxApplicationId,\n bluxAPIKey,\n customDeviceId,\n ...bridgeOptions\n }: {\n bluxApplicationId: string;\n bluxAPIKey: string;\n customDeviceId?: string;\n } & BridgeOptions,\n completionCallback?: (args: {\n errorMessage?: string;\n success: boolean;\n }) => void,\n ) {\n this.bluxApplicationId = bluxApplicationId;\n this.bluxAPIKey = bluxAPIKey;\n this.customDeviceId = customDeviceId;\n\n const baseUrl = window?._BLUX_SDK_?.baseUrl ?? \"https://api.blux.ai/prod\";\n this.api.defaults.baseURL = baseUrl;\n\n this.bridge = this.resolveBridge(bridgeOptions);\n\n // api 요청 항상 하나씩 처리\n this.apiRequestQueue$\n .pipe(\n concatMap(async (job) => {\n try {\n const result = await job.action();\n job.resolve(result);\n } catch (error) {\n job.reject(error);\n }\n }),\n )\n .subscribe();\n\n /**\n * (1) 보내야할 이벤트를 100ms씩 뭉쳐서 보내고, 1개 이상 쌓여있을 때 api 요청\n * (2) collectEvent의 응답에서 온 nextPollDelayMs 값 만큼 이후에 빈 배열로 api 요청 (1)로 보내면 초기화됨\n */\n\n if (!this.bridge) {\n merge(\n this.eventQueue$.pipe(\n bufferTime(100),\n filter((requests) => requests.length > 0),\n ),\n // onlineAndVisible일 때만 polling, 남은 시간 계산하여 타이머 시작\n combineLatest([this.nextPollDelayMs$, onlineAndVisible$]).pipe(\n switchMap(([delay, isOnlineAndVisible]) => {\n if (!isOnlineAndVisible || delay == null) return NEVER;\n\n const targetTime = this.lastPollTimestamp + delay;\n const remainingDelay = Math.max(0, targetTime - Date.now());\n\n return timer(remainingDelay);\n }),\n map(() => [] as EventRequest[]),\n ),\n )\n .pipe(\n concatMap(async (requests) => {\n this.nextPollDelayMs$.next(null);\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n\n const events = requests.map((request) => ({\n ...request,\n blux_id: bluxUser.id,\n device_id: bluxUser.deviceId,\n }));\n\n const {\n data: { nextPollDelayMs, inapp },\n } = await this.enqueueRequest(() =>\n collectEvent(\n this.api,\n {\n blux_user_id: bluxUser.id,\n application_id: bluxUser.applicationId,\n },\n {\n device_id: bluxUser.deviceId,\n events,\n },\n this.generateApiHeader(bluxUser),\n ),\n );\n\n this.lastPollTimestamp = Date.now();\n this.cachedNextPollDelayMs = nextPollDelayMs;\n this.nextPollDelayMs$.next(Math.max(nextPollDelayMs, 3000));\n\n if (inapp) {\n this.inappQueue$.next(inapp);\n }\n } catch (error) {\n Logger.error(error, { tags: { from: \"eventQueue\" } });\n this.lastPollTimestamp = Date.now();\n if (this.cachedNextPollDelayMs !== null) {\n const nextPollDelay =\n this.cachedNextPollDelayMs > 1000 * 60 * 60 * 24\n ? this.cachedNextPollDelayMs\n : this.cachedNextPollDelayMs * 2;\n this.cachedNextPollDelayMs = nextPollDelay;\n this.nextPollDelayMs$.next(nextPollDelay);\n }\n }\n }),\n )\n .subscribe();\n }\n\n // api 호출 수 절감을 위해 100ms씩 뭉쳐서 보내고, custom_user_properties와 user_properties를 합쳐서 보냄\n this.userPropertiesQueue$\n .pipe(\n bufferTime(100),\n filter((items) => items.length > 0),\n concatMap(async (items) => {\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n\n const mergedUserProperties = items.reduce(\n (acc, item) => ({ ...acc, ...(item.userProperties ?? {}) }),\n {} as NonNullable<\n APIs.bluxUsersUpdateProperties.Body[\"user_properties\"]\n >,\n );\n\n const mergedCustomUserProperties = items.reduce(\n (acc, item) => ({ ...acc, ...(item.customUserProperties ?? {}) }),\n {} as NonNullable<\n APIs.bluxUsersUpdateProperties.Body[\"custom_user_properties\"]\n >,\n );\n\n const payload: APIs.bluxUsersUpdateProperties.Body = {};\n if (Object.keys(mergedUserProperties).length > 0) {\n payload.user_properties = mergedUserProperties;\n }\n if (Object.keys(mergedCustomUserProperties).length > 0) {\n payload.custom_user_properties = mergedCustomUserProperties;\n }\n\n if (Object.keys(payload).length === 0) {\n items.forEach((item) => item.resolve());\n return;\n }\n\n await this.enqueueRequest(() =>\n updateProperties(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n payload,\n this.generateApiHeader(bluxUser),\n ),\n );\n\n items.forEach((item) => item.resolve());\n } catch (error) {\n items.forEach((item) => item.reject(error));\n Logger.error(error, { tags: { from: \"userPropertiesQueue\" } });\n }\n }),\n )\n .subscribe();\n\n this.bluxUser$.subscribe((bluxUser) => {\n if (bluxUser) SessionStorage.setBluxUserId(bluxUser.id);\n });\n\n if (!this.bridge) {\n this.inappQueue$\n .pipe(filterNullable())\n .pipe(\n concatMap((inapp) =>\n onlineAndVisible$.pipe(\n first(Boolean),\n concatMap(() => from(this.displayInapp(inapp))),\n ),\n ),\n )\n .subscribe();\n }\n\n this.init()\n .then(() => {\n completionCallback?.({ success: true });\n })\n .catch((error) => {\n completionCallback?.({ success: false, errorMessage: error.message });\n });\n }\n\n private async enqueueRequest<T>(action: () => Promise<T>) {\n return new Promise<T>((resolve, reject) => {\n const item: ApiRequestQueueJob<T> = { action, resolve, reject };\n this.apiRequestQueue$.next(item);\n });\n }\n\n private generateApiHeader({ bluxAPIKey }: { bluxAPIKey: string }) {\n return {\n Authorization: bluxAPIKey,\n };\n }\n\n private async displayInapp(inapp: InappMessageResponse) {\n return new Promise((resolve) => {\n const bluxUser = this.bluxUser$.getValue();\n\n const hideTimestamp = LocalStorage.getInappHideTimestamp(inapp.inappId);\n const isShouldSkip =\n hideTimestamp !== null && dayjs().isBefore(dayjs(hideTimestamp));\n\n if (isShouldSkip) return resolve(true);\n\n Logger.debug(`[inapp:${inapp.inappId}] displayInapp started`, {\n extra: { htmlLength: inapp.htmlString.length, baseUrl: inapp.baseUrl },\n });\n\n const iframeElement = document.createElement(\"iframe\");\n\n // Blob URL 방식: 실제 URL 컨텍스트를 가지므로 Next.js가 정상 작동\n // <base> 태그로 외부 리소스 경로 설정\n // history.replaceState/pushState 에러 방지를 위한 polyfill 추가\n const historyPolyfill = `<script>\n (function() {\n var origReplaceState = history.replaceState;\n var origPushState = history.pushState;\n history.replaceState = function() {\n try { return origReplaceState.apply(this, arguments); }\n catch(e) { console.debug('[Blux] history.replaceState blocked in blob context'); }\n };\n history.pushState = function() {\n try { return origPushState.apply(this, arguments); }\n catch(e) { console.debug('[Blux] history.pushState blocked in blob context'); }\n };\n })();\n </script>`;\n const headInjection = `${historyPolyfill}<base href=\"${inapp.baseUrl}/\">`;\n const htmlWithBase = inapp.htmlString.includes(\"<head>\")\n ? inapp.htmlString.replace(\"<head>\", `<head>${headInjection}`)\n : inapp.htmlString;\n\n const blob = new Blob([htmlWithBase], { type: \"text/html\" });\n const blobUrl = URL.createObjectURL(blob);\n\n iframeElement.sandbox.add(\n \"allow-scripts\",\n \"allow-same-origin\",\n \"allow-forms\",\n );\n iframeElement.src = blobUrl;\n iframeElement.style.position = \"fixed\";\n iframeElement.style.width = `${window.innerWidth}px`;\n iframeElement.style.height = `${window.innerHeight}px`;\n iframeElement.style.top = \"0\";\n iframeElement.style.left = \"0\";\n iframeElement.style.border = \"none\";\n iframeElement.style.pointerEvents = \"none\";\n\n iframeElement.style.zIndex = \"9999\";\n iframeElement.id = `blux-inapp-${inapp.inappId}`;\n\n document.body.appendChild(iframeElement);\n\n let iframeContentReady = false;\n let cleanupTimeoutId: ReturnType<typeof setTimeout> | null = null;\n\n iframeElement.addEventListener(\"load\", () => {\n Logger.debug(`[inapp:${inapp.inappId}] iframe load event fired`);\n try {\n const doc = iframeElement.contentDocument;\n Logger.debug(\n `[inapp:${inapp.inappId}] contentDocument accessible: ${!!doc}, bodyLength: ${doc?.body?.innerHTML?.length ?? \"N/A\"}`,\n );\n } catch (e) {\n Logger.debug(\n `[inapp:${inapp.inappId}] contentDocument access blocked`,\n { extra: { error: e } },\n );\n }\n });\n\n iframeElement.addEventListener(\"error\", (e) => {\n Logger.warning(`[inapp:${inapp.inappId}] iframe error event`, {\n extra: { error: e },\n });\n });\n\n // 일정 시간 내에 iframe으로부터 postMessage가 없으면 cleanup\n const INAPP_IFRAME_TIMEOUT_MS = 10_000;\n cleanupTimeoutId = setTimeout(() => {\n if (!iframeContentReady) {\n Logger.warning(\n `[inapp:${inapp.inappId}] iframe timeout - no postMessage received within ${INAPP_IFRAME_TIMEOUT_MS}ms, cleaning up`,\n );\n cleanup();\n }\n }, INAPP_IFRAME_TIMEOUT_MS);\n\n let urlChangeSubscription: Subscription | null = null;\n\n const cleanup = () => {\n Logger.debug(`[inapp:${inapp.inappId}] cleanup called`);\n if (cleanupTimeoutId !== null) {\n clearTimeout(cleanupTimeoutId);\n cleanupTimeoutId = null;\n }\n URL.revokeObjectURL(blobUrl);\n iframeElement.remove();\n window.removeEventListener(\"message\", handleMessage);\n window.visualViewport?.removeEventListener(\n \"resize\",\n handleViewportChange,\n );\n window.visualViewport?.removeEventListener(\n \"scroll\",\n handleViewportChange,\n );\n urlChangeSubscription?.unsubscribe();\n this.currentInappCleanup = null;\n resolve(inapp.inappId);\n };\n\n // 현재 인앱 cleanup 함수 저장\n this.currentInappCleanup = cleanup;\n const handleViewportChange = () => {\n const width = window.visualViewport?.width ?? window.innerWidth;\n const height = window.visualViewport?.height ?? window.innerHeight;\n const left = window.visualViewport?.offsetLeft ?? 0;\n const top = window.visualViewport?.offsetTop ?? 0;\n\n iframeElement.style.width = `${width}px`;\n iframeElement.style.height = `${height}px`;\n iframeElement.style.left = `${left}px`;\n iframeElement.style.top = `${top}px`;\n };\n\n const handleMessage = (\n event: MessageEvent<\n | {\n action: \"hide\";\n data: {\n days_to_hide: number;\n };\n }\n | {\n action: \"link\";\n data:\n | {\n is_blux_landing: false;\n url: string;\n open_in_new_tab: boolean;\n /**\n * Safari 팝업 차단 우회를 위해 iframe에서 직접 링크를 연 경우 true\n * 이 플래그가 true면 window.open을 스킵하고 이벤트만 찍음\n */\n opened_by_iframe?: boolean;\n }\n | {\n is_blux_landing: true;\n landing_id: string;\n };\n }\n | {\n action: \"resize\";\n data:\n | {\n height: number;\n location: \"top\" | \"bottom\";\n }\n | {\n width?: number;\n height?: number;\n top?: number;\n bottom?: number;\n left?: number;\n right?: number;\n };\n }\n | {\n action: \"custom_action\";\n data: {\n action_id: string;\n data: Record<string, unknown>;\n should_dismiss: boolean;\n };\n }\n | {\n action: \"inapp_opened\";\n data: {\n button_id: string;\n };\n }\n >,\n ) => {\n if (event.source !== iframeElement.contentWindow) return;\n\n // iframe 콘텐츠가 정상적으로 postMessage를 보낸 시점에 pointer-events 활성화\n if (!iframeContentReady) {\n iframeContentReady = true;\n iframeElement.style.pointerEvents = \"auto\";\n Logger.debug(\n `[inapp:${inapp.inappId}] first postMessage received, pointer-events enabled`,\n { extra: { action: event.data?.action } },\n );\n }\n\n const message = event.data;\n\n if (message.action === \"resize\") {\n const data = message.data;\n\n if (\"location\" in data) {\n // 기존 배너용 resize (location 기반)\n iframeElement.style.width = \"90vw\";\n iframeElement.style.maxWidth = \"448px\";\n iframeElement.style.height = `${data.height}px`;\n iframeElement.style.left = \"50%\";\n iframeElement.style.transform = \"translateX(-50%)\";\n if (data.location === \"top\") {\n iframeElement.style.top = \"0\";\n iframeElement.style.bottom = \"auto\";\n } else {\n iframeElement.style.top = \"auto\";\n iframeElement.style.bottom = \"0\";\n }\n } else {\n // Custom HTML 절대 위치 지정\n if (data.width !== undefined) {\n iframeElement.style.width = `${data.width}px`;\n iframeElement.style.maxWidth = \"none\";\n }\n if (data.height !== undefined) {\n iframeElement.style.height = `${data.height}px`;\n }\n iframeElement.style.transform = \"none\";\n iframeElement.style.top =\n data.top !== undefined ? `${data.top}px` : \"auto\";\n iframeElement.style.bottom =\n data.bottom !== undefined ? `${data.bottom}px` : \"auto\";\n iframeElement.style.left =\n data.left !== undefined ? `${data.left}px` : \"auto\";\n iframeElement.style.right =\n data.right !== undefined ? `${data.right}px` : \"auto\";\n }\n\n window.visualViewport?.removeEventListener(\n \"resize\",\n handleViewportChange,\n );\n window.visualViewport?.removeEventListener(\n \"scroll\",\n handleViewportChange,\n );\n return; // resize는 cleanup하지 않음\n }\n\n if (message.action === \"hide\") {\n const { days_to_hide } = message.data;\n if (days_to_hide !== 0) {\n const expiresAt = dayjs().add(days_to_hide, \"days\").valueOf();\n LocalStorage.setInappHideTimestamp(inapp.inappId, expiresAt);\n }\n } else if (message.action === \"link\") {\n // createCrmEvent 호출\n const crmEventPromise = bluxUser\n ? this.enqueueRequest(() =>\n createCrmEvent(\n this.api,\n {\n application_id: this.bluxApplicationId,\n },\n {\n notification_id: inapp.notificationId,\n crm_event_type: \"inapp_opened\",\n captured_at: new Date().toISOString(),\n },\n this.generateApiHeader(bluxUser),\n ),\n )\n : Promise.resolve();\n\n if (message.data.is_blux_landing) {\n // TODO: @all 스키마상에는 개인화 랜딩이 존재하나, 콘솔에는 필드가 없음 -> 추후 이에 따른 핸들링이 필요함\n } else {\n const { url, open_in_new_tab, opened_by_iframe } = message.data;\n const needsLocationChange = opened_by_iframe && !open_in_new_tab;\n\n // 하고하우스 특별 처리\n if (this.bluxApplicationId === \"6878af275ead5a75abbdacd7\") {\n crmEventPromise.finally(() => {\n window.top?.postMessage(\n {\n type: \"blux_inapp_message\",\n url,\n },\n window.location.origin,\n );\n });\n } else if (needsLocationChange) {\n // opened_by_iframe이고 현재 탭 이동인 경우: createCrmEvent 완료 후 이동\n crmEventPromise.finally(() => {\n window.location.href = url;\n });\n } else if (!opened_by_iframe) {\n // 기존 방식 (iframe에서 열지 않은 경우)\n if (open_in_new_tab) {\n window.open(url, \"_blank\");\n } else {\n window.location.href = url;\n }\n }\n // opened_by_iframe && open_in_new_tab인 경우: iframe에서 이미 새 탭 열었으므로 스킵\n }\n } else if (message.action === \"custom_action\") {\n const { action_id, data, should_dismiss } = message.data;\n\n // 등록된 모든 핸들러 호출\n for (const handler of this.inAppCustomActionHandlers) {\n try {\n handler({ actionId: action_id, data });\n } catch (error) {\n Logger.error(error, {\n tags: { from: \"inAppCustomActionHandler\" },\n });\n }\n }\n\n // should_dismiss가 false면 cleanup하지 않음\n if (!should_dismiss) {\n return;\n }\n } else if (message.action === \"inapp_opened\") {\n // data-blux-click 속성으로 인한 클릭 이벤트 추적\n if (bluxUser) {\n this.enqueueRequest(() =>\n createCrmEvent(\n this.api,\n {\n application_id: this.bluxApplicationId,\n },\n {\n notification_id: inapp.notificationId,\n crm_event_type: \"inapp_opened\",\n captured_at: new Date().toISOString(),\n },\n this.generateApiHeader(bluxUser),\n ),\n );\n }\n return; // 인앱메시지를 닫지 않음\n }\n\n cleanup();\n };\n\n // URL 변경 시 인앱메시지 닫기 (SPA 뒤로가기/앞으로가기 대응)\n urlChangeSubscription = this.urlAndRef$\n .pipe(filterNullable(), skip(1), first())\n .subscribe(() => {\n cleanup();\n });\n\n window.visualViewport?.addEventListener(\"resize\", handleViewportChange);\n window.visualViewport?.addEventListener(\"scroll\", handleViewportChange);\n window.addEventListener(\"message\", handleMessage);\n\n if (bluxUser) {\n this.enqueueRequest(() =>\n notificationsUpdate(\n this.api,\n {\n application_id: this.bluxApplicationId,\n notification_id: inapp.notificationId,\n },\n {\n status: \"received\",\n },\n this.generateApiHeader(bluxUser),\n ),\n );\n }\n });\n }\n\n private async init() {\n this.handleUrlAndRef();\n // handle page visit event\n this.urlAndRef$.pipe(filterNullable()).subscribe(() => {\n this.sendEvent(new AddPageVisitEvent({}));\n });\n\n if (this.bridge) {\n this.bridge.initialize({\n bluxApplicationId: this.bluxApplicationId,\n bluxAPIKey: this.bluxAPIKey,\n customDeviceId: this.customDeviceId,\n });\n return;\n }\n\n const blux_user_id = new URLSearchParams(window.location.search).get(\n \"blux_user_id\",\n );\n const sessionId =\n SessionStorage.getSessionId() ?? new ObjectId().toHexString();\n SessionStorage.setSessionId(sessionId);\n\n const isBluxUserIdExistInSessionStorage = SessionStorage.getBluxUserId();\n if (!isBluxUserIdExistInSessionStorage) this.sendEvent(new VisitEvent({}));\n\n Logger.debug(`Init with application id: ${this.bluxApplicationId}`);\n\n const deviceId = LocalStorage.getDeviceId();\n\n if (!deviceId) {\n Logger.debug(\"No saved Device ID, register a new one.\");\n }\n\n this.registerHitTracker();\n\n // 페이지 이동 시 추천 지표 수집 관련 변수 초기화\n this.urlAndRef$.pipe(filterNullable()).subscribe(() => {\n this.impressedElements = [];\n });\n\n this.registerImpressionTracker();\n new MutationObserver(() => {\n this.registerImpressionTracker();\n }).observe(document, { subtree: true, childList: true });\n\n // 500ms 연속으로 엘리먼트 들어있으면 추천 지표 수집\n const MIN_IMPRESSION_TIME = 500;\n this.intersectionEntry$\n .pipe(\n groupBy((entry) => entry.target),\n mergeMap((group$) =>\n group$.pipe(\n debounceTime(MIN_IMPRESSION_TIME),\n filter((entry) => entry.isIntersecting),\n ),\n ),\n )\n .subscribe((entry) => {\n const trackingId = entry.target.getAttribute(\n BLUX_ATTRIBUTES.tracking_id,\n );\n if (!trackingId) {\n Logger.warning(\n `Tracking ID is not found in the parent elements. Please check the tracking ID(${BLUX_ATTRIBUTES.tracking_id}) is set correctly.`,\n );\n return;\n }\n if (this.impressedElements.includes(entry.target)) return;\n\n this.sendEvent(\n new AddSectionViewEvent({\n section: trackingId,\n tracking: {\n id: trackingId,\n type: \"impression\",\n },\n }),\n );\n this.impressedElements.push(entry.target);\n });\n\n const { data } = await initialize(\n this.api,\n { application_id: this.bluxApplicationId },\n {\n session_id: sessionId ?? undefined,\n device_id: deviceId ?? undefined,\n country_code: navigator.language.split(\"-\")[1],\n device_model: navigator.userAgent,\n language_code: navigator.language.split(\"-\")[0],\n platform: DevicePlatform.browser,\n os_version: navigator.userAgent,\n sdk_version: this.sdkInfo.version,\n sdk_type: this.sdkInfo.type,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n blux_user_id: blux_user_id ?? undefined,\n custom_device_id: this.customDeviceId,\n },\n this.generateApiHeader({\n bluxAPIKey: this.bluxAPIKey,\n }),\n );\n\n if (data.device_id) LocalStorage.setDeviceId(data.device_id);\n\n this.bluxUser$.next({\n id: data.blux_user_id,\n bluxAPIKey: this.bluxAPIKey,\n applicationId: this.bluxApplicationId,\n deviceId: data.device_id,\n });\n }\n\n public setLogLevel(logLevel: LogLevel) {\n Logger.setLevel(logLevel);\n }\n\n private async getBluxUserWithTimeout() {\n const bluxUser = await firstValueFrom(\n this.bluxUser$.pipe(\n filterNullable(),\n timeout(5000),\n catchError((error) => {\n return throwError(() =>\n error.name === \"TimeoutError\"\n ? new Error(\n \"Application ID is not initialized. Please initialize BluxClient.\",\n )\n : error,\n );\n }),\n ),\n );\n\n return bluxUser;\n }\n\n public async signIn({ userId }: { userId: string }) {\n try {\n if (this.bridge) {\n this.bridge.signIn({ userId });\n return;\n }\n\n const bluxUser = await this.getBluxUserWithTimeout();\n\n const {\n data: { blux_user_id: bluxIdInResponse },\n } = await this.enqueueRequest(() =>\n signIn(\n this.api,\n { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id },\n { user_id: userId, device_id: bluxUser.deviceId },\n this.generateApiHeader(bluxUser),\n ),\n );\n\n if (bluxIdInResponse !== bluxUser.id) {\n Logger.debug(\"Blux id is changed in signIn.\");\n this.bluxUser$.next({\n ...bluxUser,\n id: bluxIdInResponse,\n userId,\n });\n }\n } catch (error) {\n Logger.error(error, { tags: { from: \"signIn\" } });\n }\n }\n\n public async signOut() {\n try {\n if (this.bridge) {\n this.bridge.signOut();\n return;\n }\n\n const bluxUser = await this.getBluxUserWithTimeout();\n\n const {\n data: { blux_user_id: bluxIdInResponse },\n } = await this.enqueueRequest(() =>\n signOut(\n this.api,\n { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id },\n { device_id: bluxUser.deviceId },\n this.generateApiHeader(bluxUser),\n ),\n );\n\n Logger.debug(\"Blux id is changed in signOut.\");\n this.bluxUser$.next({\n ...bluxUser,\n id: bluxIdInResponse,\n userId: undefined,\n });\n } catch (error) {\n Logger.error(error, { tags: { from: \"signOut\" } });\n }\n }\n\n public async setUserProperties({\n userProperties,\n }: {\n userProperties: NonNullable<\n APIs.bluxUsersUpdateProperties.Body[\"user_properties\"]\n >;\n }) {\n try {\n if (this.bridge) {\n this.bridge.setUserProperties(userProperties);\n return;\n }\n\n await new Promise<void>((resolve, reject) => {\n this.userPropertiesQueue$.next({\n userProperties,\n resolve,\n reject,\n });\n });\n } catch (error) {\n Logger.error(error, { tags: { from: \"setUserProperties\" } });\n }\n }\n\n public async setCustomUserProperties({\n customUserProperties,\n }: {\n customUserProperties: NonNullable<\n APIs.bluxUsersUpdateProperties.Body[\"custom_user_properties\"]\n >;\n }) {\n try {\n if (this.bridge) {\n this.bridge.setCustomUserProperties(customUserProperties);\n return;\n }\n\n await new Promise<void>((resolve, reject) => {\n this.userPropertiesQueue$.next({\n customUserProperties,\n resolve,\n reject,\n });\n });\n } catch (error) {\n Logger.error(error, { tags: { from: \"setCustomUserProperties\" } });\n }\n }\n\n public sendEvent(event: BluxEvent | BluxEvent[]) {\n try {\n const requests = (Array.isArray(event) ? event : [event]).map((e) => ({\n ...e.request,\n internal_event_properties: {\n url: this.urlAndRef$.value?.url,\n ref: this.urlAndRef$.value?.ref,\n },\n }));\n\n if (this.bridge) {\n this.bridge.sendEvent({ requests });\n return;\n }\n\n requests.forEach((request) => {\n this.eventQueue$.next(request);\n });\n } catch (error) {\n Logger.error(error, { tags: { from: \"sendEvent\" } });\n }\n }\n\n /**\n * 현재 표시 중인 인앱 메시지를 프로그래밍 방식으로 닫습니다.\n *\n * Custom HTML 인앱에서 async 핸들러 완료 후 수동으로 닫을 때 사용합니다.\n *\n * @example\n * ```typescript\n * // BluxBridge.triggerAction('share', { url: '...' }, false); // shouldDismiss: false\n * // 핸들러에서 async 작업 완료 후:\n * bluxClient.dismissInApp();\n * ```\n */\n public dismissInApp() {\n this.currentInappCleanup?.();\n }\n\n /**\n * Custom HTML 인앱에서 BluxBridge.triggerAction() 호출 시 실행될 핸들러를 등록합니다.\n * 여러 핸들러를 등록할 수 있으며, 등록 순서대로 실행됩니다.\n *\n * @param handler - 커스텀 액션 핸들러 함수\n * @returns 핸들러를 제거하는 unsubscribe 함수\n *\n * @example\n * ```typescript\n * const unsubscribe = bluxClient.addInAppCustomActionHandler(async (event) => {\n * if (event.actionId === 'share') {\n * await navigator.share({ url: event.data.url as string });\n * // async 작업 완료 후 수동으로 닫기 (shouldDismiss: false로 호출한 경우)\n * bluxClient.dismissInApp();\n * }\n * });\n *\n * // 핸들러 제거\n * unsubscribe();\n * ```\n */\n public addInAppCustomActionHandler(\n handler: InAppCustomActionHandler,\n ): () => void {\n this.inAppCustomActionHandlers.add(handler);\n return () => {\n this.inAppCustomActionHandlers.delete(handler);\n };\n }\n\n private urlAndRef$ = new BehaviorSubject<\n { url: string; ref: string | undefined } | undefined\n >(undefined);\n\n private handleUrlAndRef() {\n // set url and ref to local storage\n this.urlAndRef$.pipe(filterNullable()).subscribe(({ url, ref }) => {\n if (ref) {\n LocalStorage.setRef(ref);\n }\n LocalStorage.setUrl(url);\n });\n // init url and ref from local storage\n this.urlAndRef$.next({\n url: window.location.href,\n ref: LocalStorage.getUrl() ?? undefined,\n });\n\n // observe url change\n const handleUrlChange = () => {\n const prevUrl = this.urlAndRef$.value?.url;\n const currentUrl = window.location.href;\n if (prevUrl !== currentUrl) {\n this.urlAndRef$.next({\n url: currentUrl,\n ref: prevUrl ?? undefined,\n });\n }\n };\n\n // SPA: popstate (뒤로가기/앞으로가기)\n window.addEventListener(\"popstate\", handleUrlChange);\n // 현재 브라우저에는 URL상태를 추적하기 위한 리스너가 존재하지 않습니다.\n // 그래서 pushState와 replaceState를 직접 수정하여 추적합니다.\n // @reference https://stackoverflow.com/a/64927639\n // @reference https://github.com/amplitude/Amplitude-TypeScript/blob/main/packages/plugin-page-view-tracking-browser/src/page-view-tracking.ts\n // SPA: pushState/replaceState proxy\n history.pushState = new Proxy(history.pushState, {\n apply: (target, thisArg, [state, unused, url]) => {\n target.apply(thisArg, [state, unused, url]);\n handleUrlChange();\n },\n });\n history.replaceState = new Proxy(history.replaceState, {\n apply: (target, thisArg, [state, unused, url]) => {\n target.apply(thisArg, [state, unused, url]);\n handleUrlChange();\n },\n });\n }\n\n private registerImpressionTracker() {\n const targetElements = Array.from(\n document.querySelectorAll(`[${BLUX_ATTRIBUTES.tracking_id}]`),\n );\n\n const removed = this.intersectionObservingElements.filter(\n (e) => !targetElements.includes(e),\n );\n\n removed.forEach((e) => {\n this.intersectionObserver.unobserve(e);\n });\n\n const added = targetElements.filter(\n (element) => !this.intersectionObservingElements.includes(element),\n );\n\n added.forEach((element) => {\n this.intersectionObserver.observe(element);\n });\n\n this.intersectionObservingElements = targetElements;\n }\n\n private registerHitTracker() {\n const handleDelegatedClick = (event: Event) => {\n if (!(event.target instanceof Element)) return;\n\n const eventTarget = event.target;\n\n const targetItemElement = eventTarget.closest(\n `[${BLUX_ATTRIBUTES.item_id}]`,\n );\n if (!targetItemElement) return;\n\n const itemId = targetItemElement.getAttribute(BLUX_ATTRIBUTES.item_id);\n if (!itemId) return;\n\n const targetSectionElement = eventTarget.closest(\n `[${BLUX_ATTRIBUTES.tracking_id}]`,\n );\n const trackingId = targetSectionElement?.getAttribute(\n BLUX_ATTRIBUTES.tracking_id,\n );\n if (!trackingId) {\n Logger.warning(\n `Tracking ID is not found in the parent elements. Please check the tracking ID(${BLUX_ATTRIBUTES.tracking_id}) is set correctly.`,\n );\n return;\n }\n\n if (!this.hitElements.includes(targetItemElement)) {\n this.sendEvent(\n new AddClickEvent({\n itemId,\n tracking: {\n id: trackingId,\n type: \"hit\",\n },\n }),\n );\n this.hitElements.push(targetItemElement);\n }\n };\n document.addEventListener(\"click\", handleDelegatedClick);\n this.urlAndRef$.pipe(filterNullable()).subscribe(() => {\n this.hitElements = [];\n });\n }\n\n public async getUserRec(\n rec: UserRec,\n ): Promise<APIs.bluxUsersGetItemRecommendationsV2.ResponseData> {\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n const recRequest = rec.request;\n\n const recommendationResponse = await getItemRecommendations(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n {\n call_type: recRequest.call_type,\n limit: recRequest.limit,\n offset: recRequest.offset,\n },\n this.generateApiHeader(bluxUser),\n );\n\n return recommendationResponse.data;\n } catch (error) {\n Logger.error(error, { tags: { from: \"getItemRecommendations\" } });\n return {\n item_ids: [],\n metadata: {},\n recommendation_id: null,\n };\n }\n }\n\n public async getItemRec(\n rec: ItemRec,\n ): Promise<APIs.bluxUsersGetItemRecommendationsV2.ResponseData> {\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n const recRequest = rec.request;\n\n const recommendationResponse = await getItemRecommendations(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n {\n call_type: recRequest.call_type,\n limit: recRequest.limit,\n offset: recRequest.offset,\n item_id: recRequest.item_id,\n },\n this.generateApiHeader(bluxUser),\n );\n\n return recommendationResponse.data;\n } catch (error) {\n Logger.error(error, { tags: { from: \"getItemRecommendations\" } });\n return {\n item_ids: [],\n metadata: {},\n recommendation_id: null,\n };\n }\n }\n\n public async getItemsRec(\n rec: ItemsRec,\n ): Promise<APIs.bluxUsersGetItemRecommendationsV2.ResponseData> {\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n const recRequest = rec.request;\n\n const recommendationResponse = await getItemRecommendations(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n {\n call_type: recRequest.call_type,\n limit: recRequest.limit,\n offset: recRequest.offset,\n item_ids: recRequest.item_ids,\n },\n this.generateApiHeader(bluxUser),\n );\n\n return recommendationResponse.data;\n } catch (error) {\n Logger.error(error, { tags: { from: \"getItemRecommendations\" } });\n return {\n item_ids: [],\n metadata: {},\n recommendation_id: null,\n };\n }\n }\n\n public async getCategoryRec(\n rec: CategoryRec,\n ): Promise<APIs.bluxUsersGetItemRecommendationsV2.ResponseData> {\n try {\n const bluxUser = await this.getBluxUserWithTimeout();\n const recRequest = rec.request;\n\n const recommendationResponse = await getItemRecommendations(\n this.api,\n {\n application_id: bluxUser.applicationId,\n blux_user_id: bluxUser.id,\n },\n {\n call_type: recRequest.call_type,\n limit: recRequest.limit,\n offset: recRequest.offset,\n category_id: recRequest.category_id,\n },\n this.generateApiHeader(bluxUser),\n );\n\n return recommendationResponse.data;\n } catch (error) {\n Logger.error(error, { tags: { from: \"getItemRecommendations\" } });\n return {\n item_ids: [],\n metadata: {},\n recommendation_id: null,\n };\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/package.js
CHANGED
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import { combineLatest, distinctUntilChanged, fromEvent, map, merge, of, shareReplay, startWith } from "rxjs";
|
|
2
2
|
|
|
3
3
|
//#region src/utils/observables.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
refCount: true
|
|
17
|
-
}));
|
|
18
|
-
return onlineAndVisible$;
|
|
19
|
-
}
|
|
4
|
+
const visible$ = fromEvent(document, "visibilitychange").pipe(startWith(0), map(() => document.visibilityState === "visible"), distinctUntilChanged(), shareReplay({
|
|
5
|
+
bufferSize: 1,
|
|
6
|
+
refCount: true
|
|
7
|
+
}));
|
|
8
|
+
const online$ = merge(fromEvent(window, "online").pipe(map(() => true)), fromEvent(window, "offline").pipe(map(() => false)), of(navigator.onLine)).pipe(distinctUntilChanged(), shareReplay({
|
|
9
|
+
bufferSize: 1,
|
|
10
|
+
refCount: true
|
|
11
|
+
}));
|
|
12
|
+
const onlineAndVisible$ = combineLatest([visible$, online$]).pipe(map(([v, o]) => v && o), distinctUntilChanged(), shareReplay({
|
|
13
|
+
bufferSize: 1,
|
|
14
|
+
refCount: true
|
|
15
|
+
}));
|
|
20
16
|
|
|
21
17
|
//#endregion
|
|
22
|
-
export {
|
|
18
|
+
export { onlineAndVisible$ };
|
|
23
19
|
//# sourceMappingURL=observables.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observables.js","names":[],"sources":["../../src/utils/observables.ts"],"sourcesContent":["import {\n fromEvent,\n startWith,\n map,\n distinctUntilChanged,\n shareReplay,\n merge,\n of,\n combineLatest,\n
|
|
1
|
+
{"version":3,"file":"observables.js","names":[],"sources":["../../src/utils/observables.ts"],"sourcesContent":["import {\n fromEvent,\n startWith,\n map,\n distinctUntilChanged,\n shareReplay,\n merge,\n of,\n combineLatest,\n} from \"rxjs\";\n\nconst visible$ = fromEvent(document, \"visibilitychange\").pipe(\n startWith(0),\n map(() => document.visibilityState === \"visible\"),\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true }),\n);\n\nconst online$ = merge(\n fromEvent(window, \"online\").pipe(map(() => true)),\n fromEvent(window, \"offline\").pipe(map(() => false)),\n of(navigator.onLine),\n).pipe(distinctUntilChanged(), shareReplay({ bufferSize: 1, refCount: true }));\n\nexport const onlineAndVisible$ = combineLatest([visible$, online$]).pipe(\n map(([v, o]) => v && o),\n distinctUntilChanged(),\n shareReplay({ bufferSize: 1, refCount: true }),\n);\n"],"mappings":";;;AAWA,MAAM,WAAW,UAAU,UAAU,mBAAmB,CAAC,KACvD,UAAU,EAAE,EACZ,UAAU,SAAS,oBAAoB,UAAU,EACjD,sBAAsB,EACtB,YAAY;CAAE,YAAY;CAAG,UAAU;CAAM,CAAC,CAC/C;AAED,MAAM,UAAU,MACd,UAAU,QAAQ,SAAS,CAAC,KAAK,UAAU,KAAK,CAAC,EACjD,UAAU,QAAQ,UAAU,CAAC,KAAK,UAAU,MAAM,CAAC,EACnD,GAAG,UAAU,OAAO,CACrB,CAAC,KAAK,sBAAsB,EAAE,YAAY;CAAE,YAAY;CAAG,UAAU;CAAM,CAAC,CAAC;AAE9E,MAAa,oBAAoB,cAAc,CAAC,UAAU,QAAQ,CAAC,CAAC,KAClE,KAAK,CAAC,GAAG,OAAO,KAAK,EAAE,EACvB,sBAAsB,EACtB,YAAY;CAAE,YAAY;CAAG,UAAU;CAAM,CAAC,CAC/C"}
|