@blux.ai/web-sdk 2.2.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blux.ai/web-sdk",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "The official Blux JavaScript browser client library",
5
5
  "main": "dist/src/index.js",
6
6
  "module": "dist/src/index.js",
@@ -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?: string;
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
- readonly requestQueue$: BehaviorSubject<EventRequest[]>;
32
- readonly inappQueue$: BehaviorSubject<APIs.inappsDispatcher.ResponseData | undefined>;
33
- private readonly inappPollDelay$;
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: Record<string, string | boolean | number | null>;
89
+ customUserProperties: NonNullable<APIs.bluxUsersUpdateProperties.Body["custom_user_properties"]>;
75
90
  }): Promise<void>;
76
91
  sendEvent(event: BluxEvent | BluxEvent[]): void;
77
92
  private urlAndRef$;
@@ -1,19 +1,17 @@
1
1
  import axios from "axios";
2
- // eslint-disable-next-line no-restricted-imports
2
+ import ObjectId from "bson-objectid";
3
3
  import dayjs from "dayjs";
4
- import { asyncScheduler, BehaviorSubject, catchError, combineLatest, concatMap, debounceTime, distinctUntilChanged, exhaustMap, filter, firstValueFrom, from, groupBy, map, mergeMap, NEVER, observeOn, Subject, switchMap, throwError, timeout, timer, withLatestFrom, } from "rxjs";
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 { updateCustomUserProperties } from "./apis/updateCustomUserProperties";
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
- requestQueue$ = new BehaviorSubject([]);
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
- inappPollDelay$ = new BehaviorSubject(5000);
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,39 +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
- onlineAndVisible$
80
- .pipe(switchMap((active) => active
81
- ? this.inappPollDelay$.pipe(distinctUntilChanged(), switchMap((delay, index) =>
82
- // init 직후는 바로 호출, 이후에는 delay 호출
83
- index === 0 ? timer(0, delay) : timer(delay, delay)))
84
- : NEVER), withLatestFrom(this.bluxUser$), map(([_, bluxUser]) => bluxUser), filterNullable(), exhaustMap((bluxUser) => this.handleInappEvent(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)
107
+ return NEVER;
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(nextPollDelayMs);
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
+ }
151
+ }))
85
152
  .subscribe();
86
153
  }
87
- combineLatest([this.requestQueue$, this.bluxUser$.pipe(filterNullable())])
88
- .pipe(filter(([requests]) => requests.length > 0), exhaustMap(async ([requests, bluxUser]) => {
89
- const events = requests.map((request) => ({
90
- ...request,
91
- internal_event_properties: {
92
- ...request.internal_event_properties,
93
- url: `${this.urlAndRef$.value?.url ?? null}`,
94
- ref: `${this.urlAndRef$.value?.ref ?? null}`,
95
- },
96
- blux_id: bluxUser.id,
97
- device_id: bluxUser.deviceId,
98
- }));
99
- await this.handleSendRequest({ bluxUser, events });
100
- return requests.map((r) => r.id); // TODO: @all return successed requests only
101
- }), map((requestIdsSucceeded) => this.requestQueue$.value.filter((request) => !requestIdsSucceeded.includes(request.id))), observeOn(asyncScheduler))
102
- .subscribe(this.requestQueue$);
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();
103
184
  this.bluxUser$.subscribe((bluxUser) => {
104
185
  if (bluxUser)
105
186
  SessionStorage.setBluxUserId(bluxUser.id);
106
187
  });
107
- this.inappQueue$
108
- .pipe(filterNullable())
109
- .pipe(concatMap((inapp) => from(this.displayInapp(inapp))))
110
- .subscribe();
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
+ }
111
194
  this.init()
112
195
  .then(() => {
113
196
  completionCallback?.({ success: true });
@@ -116,44 +199,19 @@ export class BluxClient {
116
199
  completionCallback?.({ success: false, errorMessage: error.message });
117
200
  });
118
201
  }
202
+ async enqueueRequest(action) {
203
+ return new Promise((resolve, reject) => {
204
+ const item = { action, resolve, reject };
205
+ this.apiRequestQueue$.next(item);
206
+ });
207
+ }
119
208
  generateApiHeader({ bluxAPIKey }) {
120
209
  return {
121
210
  Authorization: bluxAPIKey,
122
211
  };
123
212
  }
124
- async handleSendRequest({ bluxUser, events, }) {
125
- try {
126
- await collectEvent(this.api, {
127
- blux_user_id: bluxUser.id,
128
- application_id: bluxUser.applicationId,
129
- }, {
130
- events,
131
- }, this.generateApiHeader(bluxUser));
132
- }
133
- catch (error) {
134
- Logger.error(error, { tags: { from: "request-events-api" } });
135
- }
136
- }
137
- async handleInappEvent(bluxUser) {
138
- try {
139
- const { data } = await inappsDispatch(this.api, {
140
- application_id: bluxUser.applicationId,
141
- }, {
142
- blux_user_id: bluxUser.id,
143
- device_id: bluxUser.deviceId ?? "",
144
- platform: this.sdkInfo.type,
145
- }, this.generateApiHeader(bluxUser));
146
- this.inappPollDelay$.next(data.nextPollDelay);
147
- this.inappQueue$.next(data);
148
- }
149
- catch (error) {
150
- Logger.error(error, { tags: { from: "request-inapps-api" } });
151
- }
152
- }
153
213
  async displayInapp(inapp) {
154
214
  return new Promise((resolve) => {
155
- if (!inapp.shouldDisplay)
156
- return resolve(true);
157
215
  const bluxUser = this.bluxUser$.getValue();
158
216
  const hideTimestamp = LocalStorage.getInappHideTimestamp(inapp.inappId);
159
217
  const isShouldSkip = hideTimestamp !== null && dayjs().isBefore(dayjs(hideTimestamp));
@@ -197,19 +255,24 @@ export class BluxClient {
197
255
  }
198
256
  else if (message.action === "link") {
199
257
  if (bluxUser) {
200
- createCrmEvent(this.api, {
258
+ this.enqueueRequest(() => createCrmEvent(this.api, {
201
259
  application_id: this.bluxApplicationId,
202
260
  }, {
203
261
  notification_id: inapp.notificationId,
204
262
  crm_event_type: "inapp_opened",
205
263
  captured_at: new Date().toISOString(),
206
- }, this.generateApiHeader(bluxUser));
264
+ }, this.generateApiHeader(bluxUser)));
207
265
  }
208
266
  if (message.data.is_blux_landing) {
209
267
  // TODO: @all 스키마상에는 개인화 랜딩이 존재하나, 콘솔에는 필드가 없음 -> 추후 이에 따른 핸들링이 필요함
210
268
  }
211
269
  else {
212
- window.open(message.data.url, "_blank");
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
+ }
213
276
  }
214
277
  }
215
278
  iframeElement.remove();
@@ -222,12 +285,12 @@ export class BluxClient {
222
285
  window.visualViewport?.addEventListener("scroll", handleViewportChange);
223
286
  window.addEventListener("message", handleMessage);
224
287
  if (bluxUser) {
225
- notificationsUpdate(this.api, {
288
+ this.enqueueRequest(() => notificationsUpdate(this.api, {
226
289
  application_id: this.bluxApplicationId,
227
290
  notification_id: inapp.notificationId,
228
291
  }, {
229
292
  status: "received",
230
- }, this.generateApiHeader(bluxUser));
293
+ }, this.generateApiHeader(bluxUser)));
231
294
  }
232
295
  });
233
296
  }
@@ -240,6 +303,8 @@ export class BluxClient {
240
303
  return;
241
304
  }
242
305
  const blux_user_id = new URLSearchParams(window.location.search).get("blux_user_id");
306
+ const sessionId = SessionStorage.getSessionId() ?? new ObjectId().toHexString();
307
+ SessionStorage.setSessionId(sessionId);
243
308
  const isBluxUserIdExistInSessionStorage = SessionStorage.getBluxUserId();
244
309
  if (!isBluxUserIdExistInSessionStorage)
245
310
  this.sendEvent(new VisitEvent({}));
@@ -284,7 +349,7 @@ export class BluxClient {
284
349
  this.impressedElements.push(entry.target);
285
350
  });
286
351
  const { data } = await initialize(this.api, { application_id: this.bluxApplicationId }, {
287
- isVisitHandlingInSdk: true,
352
+ session_id: sessionId ?? undefined,
288
353
  device_id: deviceId ?? undefined,
289
354
  country_code: navigator.language.split("-")[1],
290
355
  device_model: navigator.userAgent,
@@ -319,18 +384,19 @@ export class BluxClient {
319
384
  return bluxUser;
320
385
  }
321
386
  async signIn({ userId }) {
322
- if (this.bridge) {
323
- this.bridge.signIn({ userId });
324
- return;
325
- }
326
387
  try {
388
+ if (this.bridge) {
389
+ this.bridge.signIn({ userId });
390
+ return;
391
+ }
327
392
  const bluxUser = await this.getBluxUserWithTimeout();
328
- 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)));
329
394
  if (bluxIdInResponse !== bluxUser.id) {
330
395
  Logger.debug("Blux id is changed in signIn.");
331
396
  this.bluxUser$.next({
332
397
  ...bluxUser,
333
398
  id: bluxIdInResponse,
399
+ userId,
334
400
  });
335
401
  }
336
402
  }
@@ -339,17 +405,18 @@ export class BluxClient {
339
405
  }
340
406
  }
341
407
  async signOut() {
342
- if (this.bridge) {
343
- this.bridge.signOut();
344
- return;
345
- }
346
408
  try {
409
+ if (this.bridge) {
410
+ this.bridge.signOut();
411
+ return;
412
+ }
347
413
  const bluxUser = await this.getBluxUserWithTimeout();
348
- 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)));
349
415
  Logger.debug("Blux id is changed in signOut.");
350
416
  this.bluxUser$.next({
351
417
  ...bluxUser,
352
418
  id: bluxIdInResponse,
419
+ userId: undefined,
353
420
  });
354
421
  }
355
422
  catch (error) {
@@ -357,41 +424,55 @@ export class BluxClient {
357
424
  }
358
425
  }
359
426
  async setUserProperties({ userProperties, }) {
360
- if (this.bridge) {
361
- this.bridge.setUserProperties(userProperties);
362
- return;
363
- }
364
427
  try {
365
- const bluxUser = await this.getBluxUserWithTimeout();
366
- await updateUserProperties(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { properties: userProperties }, this.generateApiHeader(bluxUser));
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
+ });
367
439
  }
368
440
  catch (error) {
369
441
  Logger.error(error, { tags: { from: "setUserProperties" } });
370
442
  }
371
443
  }
372
444
  async setCustomUserProperties({ customUserProperties, }) {
373
- if (this.bridge) {
374
- this.bridge.setCustomUserProperties(customUserProperties);
375
- return;
376
- }
377
445
  try {
378
- const bluxUser = await this.getBluxUserWithTimeout();
379
- await updateCustomUserProperties(this.api, { application_id: bluxUser.applicationId, blux_user_id: bluxUser.id }, { properties: customUserProperties }, this.generateApiHeader(bluxUser));
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
+ });
380
457
  }
381
458
  catch (error) {
382
459
  Logger.error(error, { tags: { from: "setCustomUserProperties" } });
383
460
  }
384
461
  }
385
462
  sendEvent(event) {
386
- const requests = (Array.isArray(event) ? event : [event]).map((e) => e.request);
387
- if (this.bridge) {
388
- this.bridge.sendEvent({ requests });
389
- return;
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" } });
390
475
  }
391
- this.requestQueue$.next([
392
- ...this.requestQueue$.value,
393
- ...requests.filter((request) => !this.requestQueue$.value.map((r) => r.id).includes(request.id)),
394
- ]);
395
476
  }
396
477
  urlAndRef$ = new BehaviorSubject(undefined);
397
478
  handleUrlAndRef() {