@blux.ai/web-sdk 2.2.1 → 2.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +1 -1
- package/dist/src/BluxClient.d.ts +33 -18
- package/dist/src/BluxClient.js +184 -106
- package/dist/src/BluxClient.js.map +1 -1
- package/dist/src/apis/APIs.d.ts +53 -101
- package/dist/src/apis/APIs.js +41 -64
- package/dist/src/apis/APIs.js.map +1 -1
- package/dist/src/apis/createEvent.d.ts +2 -2
- package/dist/src/apis/createEvent.js +1 -1
- package/dist/src/apis/createEvent.js.map +1 -1
- package/dist/src/apis/updateProperties.d.ts +4 -0
- package/dist/src/apis/{inappsDispatch.js → updateProperties.js} +3 -3
- package/dist/src/apis/updateProperties.js.map +1 -0
- package/dist/src/utils/SessionStorage.d.ts +2 -0
- package/dist/src/utils/SessionStorage.js +7 -0
- package/dist/src/utils/SessionStorage.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/src/apis/inappsDispatch.d.ts +0 -5
- package/dist/src/apis/inappsDispatch.js.map +0 -1
- package/dist/src/apis/updateCustomUserProperties.d.ts +0 -4
- package/dist/src/apis/updateCustomUserProperties.js +0 -7
- package/dist/src/apis/updateCustomUserProperties.js.map +0 -1
- package/dist/src/apis/updateUserProperties.d.ts +0 -4
- package/dist/src/apis/updateUserProperties.js +0 -7
- package/dist/src/apis/updateUserProperties.js.map +0 -1
package/dist/package.json
CHANGED
package/dist/src/BluxClient.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BehaviorSubject } from "rxjs";
|
|
1
|
+
import { BehaviorSubject, Subject } from "rxjs";
|
|
2
2
|
import { DevicePlatform, type APIs } from "./apis/APIs";
|
|
3
3
|
import { BridgePlatform } from "./bridges/Bridge";
|
|
4
4
|
import type { Event as BluxEvent } from "./events/Event";
|
|
@@ -13,7 +13,7 @@ type BluxUser = {
|
|
|
13
13
|
id: string;
|
|
14
14
|
bluxAPIKey: string;
|
|
15
15
|
applicationId: string;
|
|
16
|
-
deviceId
|
|
16
|
+
deviceId: string;
|
|
17
17
|
userId?: string;
|
|
18
18
|
};
|
|
19
19
|
type BridgeOptions = {
|
|
@@ -24,13 +24,38 @@ type BridgeOptions = {
|
|
|
24
24
|
} | {
|
|
25
25
|
bridgePlatform?: BridgePlatform;
|
|
26
26
|
};
|
|
27
|
+
type ApiRequestQueueJob<T> = {
|
|
28
|
+
action: () => Promise<T>;
|
|
29
|
+
resolve: (value: T) => void;
|
|
30
|
+
reject: (error: unknown) => void;
|
|
31
|
+
};
|
|
32
|
+
type UserPropertiesQueueItem = {
|
|
33
|
+
userProperties?: APIs.bluxUsersUpdateProperties.Body["user_properties"];
|
|
34
|
+
customUserProperties?: APIs.bluxUsersUpdateProperties.Body["custom_user_properties"];
|
|
35
|
+
resolve: () => void;
|
|
36
|
+
reject: (error: unknown) => void;
|
|
37
|
+
};
|
|
27
38
|
export declare class BluxClient {
|
|
28
39
|
private readonly api;
|
|
29
40
|
private readonly sdkInfo;
|
|
30
41
|
readonly bluxUser$: BehaviorSubject<BluxUser | undefined>;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
/**
|
|
43
|
+
* 내부 async 작업을 1개씩 직렬로 처리하는 큐입니다.
|
|
44
|
+
* `enqueueRequest()`로 넣으면, 호출자는 완료 시점까지 `await` 할 수 있습니다.
|
|
45
|
+
*/
|
|
46
|
+
readonly apiRequestQueue$: Subject<ApiRequestQueueJob<any>>;
|
|
47
|
+
readonly inappQueue$: BehaviorSubject<{
|
|
48
|
+
notificationId: string;
|
|
49
|
+
inappId: string;
|
|
50
|
+
htmlString: string;
|
|
51
|
+
baseUrl: string;
|
|
52
|
+
} | undefined>;
|
|
53
|
+
readonly eventQueue$: Subject<EventRequest>;
|
|
54
|
+
readonly userPropertiesQueue$: Subject<UserPropertiesQueueItem>;
|
|
55
|
+
private readonly INITIAL_NEXT_POLL_DELAY_MS;
|
|
56
|
+
private readonly nextPollDelayMs$;
|
|
57
|
+
private cachedNextPollDelayMs;
|
|
58
|
+
private lastPollTimestamp;
|
|
34
59
|
private readonly bluxApplicationId;
|
|
35
60
|
private readonly bluxAPIKey;
|
|
36
61
|
private readonly bridge;
|
|
@@ -47,9 +72,8 @@ export declare class BluxClient {
|
|
|
47
72
|
errorMessage?: string;
|
|
48
73
|
success: boolean;
|
|
49
74
|
}) => void);
|
|
75
|
+
private enqueueRequest;
|
|
50
76
|
private generateApiHeader;
|
|
51
|
-
private handleSendRequest;
|
|
52
|
-
private handleInappEvent;
|
|
53
77
|
private displayInapp;
|
|
54
78
|
private init;
|
|
55
79
|
setLogLevel(logLevel: LogLevel): void;
|
|
@@ -59,19 +83,10 @@ export declare class BluxClient {
|
|
|
59
83
|
}): Promise<void>;
|
|
60
84
|
signOut(): Promise<void>;
|
|
61
85
|
setUserProperties({ userProperties, }: {
|
|
62
|
-
userProperties:
|
|
63
|
-
phone_number?: string;
|
|
64
|
-
email_address?: string;
|
|
65
|
-
marketing_notification_consent?: boolean;
|
|
66
|
-
nighttime_notification_consent?: boolean;
|
|
67
|
-
marketing_notification_sms_consent?: boolean;
|
|
68
|
-
marketing_notification_email_consent?: boolean;
|
|
69
|
-
marketing_notification_push_consent?: boolean;
|
|
70
|
-
marketing_notification_kakao_consent?: boolean;
|
|
71
|
-
};
|
|
86
|
+
userProperties: NonNullable<APIs.bluxUsersUpdateProperties.Body["user_properties"]>;
|
|
72
87
|
}): Promise<void>;
|
|
73
88
|
setCustomUserProperties({ customUserProperties, }: {
|
|
74
|
-
customUserProperties:
|
|
89
|
+
customUserProperties: NonNullable<APIs.bluxUsersUpdateProperties.Body["custom_user_properties"]>;
|
|
75
90
|
}): Promise<void>;
|
|
76
91
|
sendEvent(event: BluxEvent | BluxEvent[]): void;
|
|
77
92
|
private urlAndRef$;
|
package/dist/src/BluxClient.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
-
|
|
2
|
+
import ObjectId from "bson-objectid";
|
|
3
3
|
import dayjs from "dayjs";
|
|
4
|
-
import {
|
|
4
|
+
import { BehaviorSubject, bufferTime, catchError, combineLatest, concatMap, debounceTime, filter, first, firstValueFrom, from, groupBy, merge, mergeMap, NEVER, Subject, switchMap, throwError, timer, timeout, map, } from "rxjs";
|
|
5
5
|
import packageJson from "../package.json";
|
|
6
6
|
import { DevicePlatform } from "./apis/APIs";
|
|
7
7
|
import { createCrmEvent } from "./apis/createCrmEvent";
|
|
8
8
|
import { collectEvent } from "./apis/createEvent";
|
|
9
9
|
import { getItemRecommendations } from "./apis/getItemRecommendations";
|
|
10
|
-
import { inappsDispatch } from "./apis/inappsDispatch";
|
|
11
10
|
import { initialize } from "./apis/initialize";
|
|
12
11
|
import { notificationsUpdate } from "./apis/notificationsUpdate";
|
|
13
12
|
import { signIn } from "./apis/signIn";
|
|
14
13
|
import { signOut } from "./apis/signOut";
|
|
15
|
-
import {
|
|
16
|
-
import { updateUserProperties } from "./apis/updateUserProperties";
|
|
14
|
+
import { updateProperties } from "./apis/updateProperties";
|
|
17
15
|
import { FlutterBridge } from "./bridges/FlutterBridge";
|
|
18
16
|
import { RNBridge } from "./bridges/RNBridge";
|
|
19
17
|
import { BLUX_ATTRIBUTES } from "./constants/BLUX_ATTRIBUTES";
|
|
@@ -30,9 +28,19 @@ export class BluxClient {
|
|
|
30
28
|
version: packageJson.version,
|
|
31
29
|
};
|
|
32
30
|
bluxUser$ = new BehaviorSubject(undefined);
|
|
33
|
-
|
|
31
|
+
/**
|
|
32
|
+
* 내부 async 작업을 1개씩 직렬로 처리하는 큐입니다.
|
|
33
|
+
* `enqueueRequest()`로 넣으면, 호출자는 완료 시점까지 `await` 할 수 있습니다.
|
|
34
|
+
*/
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
|
+
apiRequestQueue$ = new Subject();
|
|
34
37
|
inappQueue$ = new BehaviorSubject(undefined);
|
|
35
|
-
|
|
38
|
+
eventQueue$ = new Subject();
|
|
39
|
+
userPropertiesQueue$ = new Subject();
|
|
40
|
+
INITIAL_NEXT_POLL_DELAY_MS = 10 * 1000;
|
|
41
|
+
nextPollDelayMs$ = new BehaviorSubject(this.INITIAL_NEXT_POLL_DELAY_MS);
|
|
42
|
+
cachedNextPollDelayMs = this.INITIAL_NEXT_POLL_DELAY_MS;
|
|
43
|
+
lastPollTimestamp = Date.now();
|
|
36
44
|
bluxApplicationId;
|
|
37
45
|
bluxAPIKey;
|
|
38
46
|
bridge;
|
|
@@ -75,42 +83,114 @@ export class BluxClient {
|
|
|
75
83
|
const baseUrl = window?._BLUX_SDK_?.baseUrl ?? "https://api.blux.ai/prod";
|
|
76
84
|
this.api.defaults.baseURL = baseUrl;
|
|
77
85
|
this.bridge = this.resolveBridge(bridgeOptions);
|
|
86
|
+
// api 요청 항상 하나씩 처리
|
|
87
|
+
this.apiRequestQueue$
|
|
88
|
+
.pipe(concatMap(async (job) => {
|
|
89
|
+
try {
|
|
90
|
+
const result = await job.action();
|
|
91
|
+
job.resolve(result);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
job.reject(error);
|
|
95
|
+
}
|
|
96
|
+
}))
|
|
97
|
+
.subscribe();
|
|
98
|
+
/**
|
|
99
|
+
* (1) 보내야할 이벤트를 100ms씩 뭉쳐서 보내고, 1개 이상 쌓여있을 때 api 요청
|
|
100
|
+
* (2) collectEvent의 응답에서 온 nextPollDelayMs 값 만큼 이후에 빈 배열로 api 요청 (1)로 보내면 초기화됨
|
|
101
|
+
*/
|
|
78
102
|
if (!this.bridge) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.pipe(switchMap(([isOnlineAndVisible, bluxUser]) => {
|
|
84
|
-
if (!isOnlineAndVisible || !bluxUser)
|
|
103
|
+
merge(this.eventQueue$.pipe(bufferTime(100), filter((requests) => requests.length > 0)),
|
|
104
|
+
// onlineAndVisible일 때만 polling, 남은 시간 계산하여 타이머 시작
|
|
105
|
+
combineLatest([this.nextPollDelayMs$, onlineAndVisible$]).pipe(switchMap(([delay, isOnlineAndVisible]) => {
|
|
106
|
+
if (!isOnlineAndVisible || delay == null)
|
|
85
107
|
return NEVER;
|
|
86
|
-
|
|
108
|
+
const targetTime = this.lastPollTimestamp + delay;
|
|
109
|
+
const remainingDelay = Math.max(0, targetTime - Date.now());
|
|
110
|
+
return timer(remainingDelay);
|
|
111
|
+
}), map(() => [])))
|
|
112
|
+
.pipe(concatMap(async (requests) => {
|
|
113
|
+
this.nextPollDelayMs$.next(null);
|
|
114
|
+
try {
|
|
115
|
+
const bluxUser = await this.getBluxUserWithTimeout();
|
|
116
|
+
const events = requests.map((request) => ({
|
|
117
|
+
...request,
|
|
118
|
+
internal_event_properties: {
|
|
119
|
+
...request.internal_event_properties,
|
|
120
|
+
url: `${this.urlAndRef$.value?.url ?? null}`,
|
|
121
|
+
ref: `${this.urlAndRef$.value?.ref ?? null}`,
|
|
122
|
+
},
|
|
123
|
+
blux_id: bluxUser.id,
|
|
124
|
+
device_id: bluxUser.deviceId,
|
|
125
|
+
}));
|
|
126
|
+
const { data: { nextPollDelayMs, inapp }, } = await this.enqueueRequest(() => collectEvent(this.api, {
|
|
127
|
+
blux_user_id: bluxUser.id,
|
|
128
|
+
application_id: bluxUser.applicationId,
|
|
129
|
+
}, {
|
|
130
|
+
device_id: bluxUser.deviceId,
|
|
131
|
+
events,
|
|
132
|
+
}, this.generateApiHeader(bluxUser)));
|
|
133
|
+
this.lastPollTimestamp = Date.now();
|
|
134
|
+
this.cachedNextPollDelayMs = nextPollDelayMs;
|
|
135
|
+
this.nextPollDelayMs$.next(Math.min(nextPollDelayMs, 3000));
|
|
136
|
+
if (inapp) {
|
|
137
|
+
this.inappQueue$.next(inapp);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
Logger.error(error, { tags: { from: "eventQueue" } });
|
|
142
|
+
this.lastPollTimestamp = Date.now();
|
|
143
|
+
if (this.cachedNextPollDelayMs !== null) {
|
|
144
|
+
const nextPollDelay = this.cachedNextPollDelayMs > 1000 * 60 * 60 * 24
|
|
145
|
+
? this.cachedNextPollDelayMs
|
|
146
|
+
: this.cachedNextPollDelayMs * 2;
|
|
147
|
+
this.cachedNextPollDelayMs = nextPollDelay;
|
|
148
|
+
this.nextPollDelayMs$.next(nextPollDelay);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
87
151
|
}))
|
|
88
152
|
.subscribe();
|
|
89
153
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
154
|
+
// api 호출 수 절감을 위해 100ms씩 뭉쳐서 보내고, custom_user_properties와 user_properties를 합쳐서 보냄
|
|
155
|
+
this.userPropertiesQueue$
|
|
156
|
+
.pipe(bufferTime(100), filter((items) => items.length > 0), concatMap(async (items) => {
|
|
157
|
+
try {
|
|
158
|
+
const bluxUser = await this.getBluxUserWithTimeout();
|
|
159
|
+
const mergedUserProperties = items.reduce((acc, item) => ({ ...acc, ...(item.userProperties ?? {}) }), {});
|
|
160
|
+
const mergedCustomUserProperties = items.reduce((acc, item) => ({ ...acc, ...(item.customUserProperties ?? {}) }), {});
|
|
161
|
+
const payload = {};
|
|
162
|
+
if (Object.keys(mergedUserProperties).length > 0) {
|
|
163
|
+
payload.user_properties = mergedUserProperties;
|
|
164
|
+
}
|
|
165
|
+
if (Object.keys(mergedCustomUserProperties).length > 0) {
|
|
166
|
+
payload.custom_user_properties = mergedCustomUserProperties;
|
|
167
|
+
}
|
|
168
|
+
if (Object.keys(payload).length === 0) {
|
|
169
|
+
items.forEach((item) => item.resolve());
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
await this.enqueueRequest(() => updateProperties(this.api, {
|
|
173
|
+
application_id: bluxUser.applicationId,
|
|
174
|
+
blux_user_id: bluxUser.id,
|
|
175
|
+
}, payload, this.generateApiHeader(bluxUser)));
|
|
176
|
+
items.forEach((item) => item.resolve());
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
items.forEach((item) => item.reject(error));
|
|
180
|
+
Logger.error(error, { tags: { from: "userPropertiesQueue" } });
|
|
181
|
+
}
|
|
182
|
+
}))
|
|
183
|
+
.subscribe();
|
|
106
184
|
this.bluxUser$.subscribe((bluxUser) => {
|
|
107
185
|
if (bluxUser)
|
|
108
186
|
SessionStorage.setBluxUserId(bluxUser.id);
|
|
109
187
|
});
|
|
110
|
-
this.
|
|
111
|
-
.
|
|
112
|
-
|
|
113
|
-
|
|
188
|
+
if (!this.bridge) {
|
|
189
|
+
this.inappQueue$
|
|
190
|
+
.pipe(filterNullable())
|
|
191
|
+
.pipe(concatMap((inapp) => onlineAndVisible$.pipe(first(Boolean), concatMap(() => from(this.displayInapp(inapp))))))
|
|
192
|
+
.subscribe();
|
|
193
|
+
}
|
|
114
194
|
this.init()
|
|
115
195
|
.then(() => {
|
|
116
196
|
completionCallback?.({ success: true });
|
|
@@ -119,44 +199,19 @@ export class BluxClient {
|
|
|
119
199
|
completionCallback?.({ success: false, errorMessage: error.message });
|
|
120
200
|
});
|
|
121
201
|
}
|
|
202
|
+
async enqueueRequest(action) {
|
|
203
|
+
return new Promise((resolve, reject) => {
|
|
204
|
+
const item = { action, resolve, reject };
|
|
205
|
+
this.apiRequestQueue$.next(item);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
122
208
|
generateApiHeader({ bluxAPIKey }) {
|
|
123
209
|
return {
|
|
124
210
|
Authorization: bluxAPIKey,
|
|
125
211
|
};
|
|
126
212
|
}
|
|
127
|
-
async handleSendRequest({ bluxUser, events, }) {
|
|
128
|
-
try {
|
|
129
|
-
await collectEvent(this.api, {
|
|
130
|
-
blux_user_id: bluxUser.id,
|
|
131
|
-
application_id: bluxUser.applicationId,
|
|
132
|
-
}, {
|
|
133
|
-
events,
|
|
134
|
-
}, this.generateApiHeader(bluxUser));
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
Logger.error(error, { tags: { from: "request-events-api" } });
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
async handleInappEvent(bluxUser) {
|
|
141
|
-
try {
|
|
142
|
-
const { data } = await inappsDispatch(this.api, {
|
|
143
|
-
application_id: bluxUser.applicationId,
|
|
144
|
-
}, {
|
|
145
|
-
blux_user_id: bluxUser.id,
|
|
146
|
-
device_id: bluxUser.deviceId ?? "",
|
|
147
|
-
platform: this.sdkInfo.type,
|
|
148
|
-
}, this.generateApiHeader(bluxUser));
|
|
149
|
-
this.inappPollDelay$.next(data.nextPollDelay);
|
|
150
|
-
this.inappQueue$.next(data);
|
|
151
|
-
}
|
|
152
|
-
catch (error) {
|
|
153
|
-
Logger.error(error, { tags: { from: "request-inapps-api" } });
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
213
|
async displayInapp(inapp) {
|
|
157
214
|
return new Promise((resolve) => {
|
|
158
|
-
if (!inapp.shouldDisplay)
|
|
159
|
-
return resolve(true);
|
|
160
215
|
const bluxUser = this.bluxUser$.getValue();
|
|
161
216
|
const hideTimestamp = LocalStorage.getInappHideTimestamp(inapp.inappId);
|
|
162
217
|
const isShouldSkip = hideTimestamp !== null && dayjs().isBefore(dayjs(hideTimestamp));
|
|
@@ -200,19 +255,24 @@ export class BluxClient {
|
|
|
200
255
|
}
|
|
201
256
|
else if (message.action === "link") {
|
|
202
257
|
if (bluxUser) {
|
|
203
|
-
createCrmEvent(this.api, {
|
|
258
|
+
this.enqueueRequest(() => createCrmEvent(this.api, {
|
|
204
259
|
application_id: this.bluxApplicationId,
|
|
205
260
|
}, {
|
|
206
261
|
notification_id: inapp.notificationId,
|
|
207
262
|
crm_event_type: "inapp_opened",
|
|
208
263
|
captured_at: new Date().toISOString(),
|
|
209
|
-
}, this.generateApiHeader(bluxUser));
|
|
264
|
+
}, this.generateApiHeader(bluxUser)));
|
|
210
265
|
}
|
|
211
266
|
if (message.data.is_blux_landing) {
|
|
212
267
|
// TODO: @all 스키마상에는 개인화 랜딩이 존재하나, 콘솔에는 필드가 없음 -> 추후 이에 따른 핸들링이 필요함
|
|
213
268
|
}
|
|
214
269
|
else {
|
|
215
|
-
|
|
270
|
+
if (message.data.open_in_new_tab) {
|
|
271
|
+
window.open(message.data.url, "_blank");
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
window.location.href = message.data.url;
|
|
275
|
+
}
|
|
216
276
|
}
|
|
217
277
|
}
|
|
218
278
|
iframeElement.remove();
|
|
@@ -225,16 +285,21 @@ export class BluxClient {
|
|
|
225
285
|
window.visualViewport?.addEventListener("scroll", handleViewportChange);
|
|
226
286
|
window.addEventListener("message", handleMessage);
|
|
227
287
|
if (bluxUser) {
|
|
228
|
-
notificationsUpdate(this.api, {
|
|
288
|
+
this.enqueueRequest(() => notificationsUpdate(this.api, {
|
|
229
289
|
application_id: this.bluxApplicationId,
|
|
230
290
|
notification_id: inapp.notificationId,
|
|
231
291
|
}, {
|
|
232
292
|
status: "received",
|
|
233
|
-
}, this.generateApiHeader(bluxUser));
|
|
293
|
+
}, this.generateApiHeader(bluxUser)));
|
|
234
294
|
}
|
|
235
295
|
});
|
|
236
296
|
}
|
|
237
297
|
async init() {
|
|
298
|
+
this.handleUrlAndRef();
|
|
299
|
+
// handle page visit event
|
|
300
|
+
this.urlAndRef$.pipe(filterNullable()).subscribe(() => {
|
|
301
|
+
this.sendEvent(new AddPageVisitEvent({}));
|
|
302
|
+
});
|
|
238
303
|
if (this.bridge) {
|
|
239
304
|
this.bridge.initialize({
|
|
240
305
|
bluxApplicationId: this.bluxApplicationId,
|
|
@@ -243,6 +308,8 @@ export class BluxClient {
|
|
|
243
308
|
return;
|
|
244
309
|
}
|
|
245
310
|
const blux_user_id = new URLSearchParams(window.location.search).get("blux_user_id");
|
|
311
|
+
const sessionId = SessionStorage.getSessionId() ?? new ObjectId().toHexString();
|
|
312
|
+
SessionStorage.setSessionId(sessionId);
|
|
246
313
|
const isBluxUserIdExistInSessionStorage = SessionStorage.getBluxUserId();
|
|
247
314
|
if (!isBluxUserIdExistInSessionStorage)
|
|
248
315
|
this.sendEvent(new VisitEvent({}));
|
|
@@ -251,11 +318,6 @@ export class BluxClient {
|
|
|
251
318
|
if (!deviceId) {
|
|
252
319
|
Logger.debug("No saved Device ID, register a new one.");
|
|
253
320
|
}
|
|
254
|
-
this.handleUrlAndRef();
|
|
255
|
-
// handle page visit event
|
|
256
|
-
this.urlAndRef$.pipe(filterNullable()).subscribe(() => {
|
|
257
|
-
this.sendEvent(new AddPageVisitEvent({}));
|
|
258
|
-
});
|
|
259
321
|
this.registerHitTracker();
|
|
260
322
|
// 페이지 이동 시 추천 지표 수집 관련 변수 초기화
|
|
261
323
|
this.urlAndRef$.pipe(filterNullable()).subscribe(() => {
|
|
@@ -287,7 +349,7 @@ export class BluxClient {
|
|
|
287
349
|
this.impressedElements.push(entry.target);
|
|
288
350
|
});
|
|
289
351
|
const { data } = await initialize(this.api, { application_id: this.bluxApplicationId }, {
|
|
290
|
-
|
|
352
|
+
session_id: sessionId ?? undefined,
|
|
291
353
|
device_id: deviceId ?? undefined,
|
|
292
354
|
country_code: navigator.language.split("-")[1],
|
|
293
355
|
device_model: navigator.userAgent,
|
|
@@ -322,18 +384,19 @@ export class BluxClient {
|
|
|
322
384
|
return bluxUser;
|
|
323
385
|
}
|
|
324
386
|
async signIn({ userId }) {
|
|
325
|
-
if (this.bridge) {
|
|
326
|
-
this.bridge.signIn({ userId });
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
387
|
try {
|
|
388
|
+
if (this.bridge) {
|
|
389
|
+
this.bridge.signIn({ userId });
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
330
392
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
331
|
-
const { data: { blux_user_id: bluxIdInResponse }, } = await signIn(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { user_id: userId, device_id: bluxUser.deviceId }, this.generateApiHeader(bluxUser));
|
|
393
|
+
const { data: { blux_user_id: bluxIdInResponse }, } = await this.enqueueRequest(() => signIn(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { user_id: userId, device_id: bluxUser.deviceId }, this.generateApiHeader(bluxUser)));
|
|
332
394
|
if (bluxIdInResponse !== bluxUser.id) {
|
|
333
395
|
Logger.debug("Blux id is changed in signIn.");
|
|
334
396
|
this.bluxUser$.next({
|
|
335
397
|
...bluxUser,
|
|
336
398
|
id: bluxIdInResponse,
|
|
399
|
+
userId,
|
|
337
400
|
});
|
|
338
401
|
}
|
|
339
402
|
}
|
|
@@ -342,17 +405,18 @@ export class BluxClient {
|
|
|
342
405
|
}
|
|
343
406
|
}
|
|
344
407
|
async signOut() {
|
|
345
|
-
if (this.bridge) {
|
|
346
|
-
this.bridge.signOut();
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
408
|
try {
|
|
409
|
+
if (this.bridge) {
|
|
410
|
+
this.bridge.signOut();
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
350
413
|
const bluxUser = await this.getBluxUserWithTimeout();
|
|
351
|
-
const { data: { blux_user_id: bluxIdInResponse }, } = await signOut(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { device_id: bluxUser.deviceId }, this.generateApiHeader(bluxUser));
|
|
414
|
+
const { data: { blux_user_id: bluxIdInResponse }, } = await this.enqueueRequest(() => signOut(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { device_id: bluxUser.deviceId }, this.generateApiHeader(bluxUser)));
|
|
352
415
|
Logger.debug("Blux id is changed in signOut.");
|
|
353
416
|
this.bluxUser$.next({
|
|
354
417
|
...bluxUser,
|
|
355
418
|
id: bluxIdInResponse,
|
|
419
|
+
userId: undefined,
|
|
356
420
|
});
|
|
357
421
|
}
|
|
358
422
|
catch (error) {
|
|
@@ -360,41 +424,55 @@ export class BluxClient {
|
|
|
360
424
|
}
|
|
361
425
|
}
|
|
362
426
|
async setUserProperties({ userProperties, }) {
|
|
363
|
-
if (this.bridge) {
|
|
364
|
-
this.bridge.setUserProperties(userProperties);
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
427
|
try {
|
|
368
|
-
|
|
369
|
-
|
|
428
|
+
if (this.bridge) {
|
|
429
|
+
this.bridge.setUserProperties(userProperties);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
await new Promise((resolve, reject) => {
|
|
433
|
+
this.userPropertiesQueue$.next({
|
|
434
|
+
userProperties,
|
|
435
|
+
resolve,
|
|
436
|
+
reject,
|
|
437
|
+
});
|
|
438
|
+
});
|
|
370
439
|
}
|
|
371
440
|
catch (error) {
|
|
372
441
|
Logger.error(error, { tags: { from: "setUserProperties" } });
|
|
373
442
|
}
|
|
374
443
|
}
|
|
375
444
|
async setCustomUserProperties({ customUserProperties, }) {
|
|
376
|
-
if (this.bridge) {
|
|
377
|
-
this.bridge.setCustomUserProperties(customUserProperties);
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
445
|
try {
|
|
381
|
-
|
|
382
|
-
|
|
446
|
+
if (this.bridge) {
|
|
447
|
+
this.bridge.setCustomUserProperties(customUserProperties);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
await new Promise((resolve, reject) => {
|
|
451
|
+
this.userPropertiesQueue$.next({
|
|
452
|
+
customUserProperties,
|
|
453
|
+
resolve,
|
|
454
|
+
reject,
|
|
455
|
+
});
|
|
456
|
+
});
|
|
383
457
|
}
|
|
384
458
|
catch (error) {
|
|
385
459
|
Logger.error(error, { tags: { from: "setCustomUserProperties" } });
|
|
386
460
|
}
|
|
387
461
|
}
|
|
388
462
|
sendEvent(event) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
this.bridge
|
|
392
|
-
|
|
463
|
+
try {
|
|
464
|
+
const requests = (Array.isArray(event) ? event : [event]).map((e) => e.request);
|
|
465
|
+
if (this.bridge) {
|
|
466
|
+
this.bridge.sendEvent({ requests });
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
requests.forEach((request) => {
|
|
470
|
+
this.eventQueue$.next(request);
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
Logger.error(error, { tags: { from: "sendEvent" } });
|
|
393
475
|
}
|
|
394
|
-
this.requestQueue$.next([
|
|
395
|
-
...this.requestQueue$.value,
|
|
396
|
-
...requests.filter((request) => !this.requestQueue$.value.map((r) => r.id).includes(request.id)),
|
|
397
|
-
]);
|
|
398
476
|
}
|
|
399
477
|
urlAndRef$ = new BehaviorSubject(undefined);
|
|
400
478
|
handleUrlAndRef() {
|