@blux.ai/web-sdk 2.2.1 → 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.1",
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, } 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,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
- combineLatest([
80
- onlineAndVisible$.pipe(distinctUntilChanged()),
81
- this.bluxUser$,
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
- return this.inappPollDelay$.pipe(distinctUntilChanged(), switchMap((delay) => timer(0, delay)), exhaustMap(() => this.handleInappEvent(bluxUser)));
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
+ }
87
151
  }))
88
152
  .subscribe();
89
153
  }
90
- combineLatest([this.requestQueue$, this.bluxUser$.pipe(filterNullable())])
91
- .pipe(filter(([requests]) => requests.length > 0), exhaustMap(async ([requests, bluxUser]) => {
92
- const events = requests.map((request) => ({
93
- ...request,
94
- internal_event_properties: {
95
- ...request.internal_event_properties,
96
- url: `${this.urlAndRef$.value?.url ?? null}`,
97
- ref: `${this.urlAndRef$.value?.ref ?? null}`,
98
- },
99
- blux_id: bluxUser.id,
100
- device_id: bluxUser.deviceId,
101
- }));
102
- await this.handleSendRequest({ bluxUser, events });
103
- return requests.map((r) => r.id); // TODO: @all return successed requests only
104
- }), map((requestIdsSucceeded) => this.requestQueue$.value.filter((request) => !requestIdsSucceeded.includes(request.id))), observeOn(asyncScheduler))
105
- .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();
106
184
  this.bluxUser$.subscribe((bluxUser) => {
107
185
  if (bluxUser)
108
186
  SessionStorage.setBluxUserId(bluxUser.id);
109
187
  });
110
- this.inappQueue$
111
- .pipe(filterNullable())
112
- .pipe(concatMap((inapp) => from(this.displayInapp(inapp))))
113
- .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
+ }
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
- 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
+ }
216
276
  }
217
277
  }
218
278
  iframeElement.remove();
@@ -225,12 +285,12 @@ 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
  }
@@ -243,6 +303,8 @@ export class BluxClient {
243
303
  return;
244
304
  }
245
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);
246
308
  const isBluxUserIdExistInSessionStorage = SessionStorage.getBluxUserId();
247
309
  if (!isBluxUserIdExistInSessionStorage)
248
310
  this.sendEvent(new VisitEvent({}));
@@ -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
- isVisitHandlingInSdk: true,
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
- const bluxUser = await this.getBluxUserWithTimeout();
369
- 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
+ });
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
- const bluxUser = await this.getBluxUserWithTimeout();
382
- 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
+ });
383
457
  }
384
458
  catch (error) {
385
459
  Logger.error(error, { tags: { from: "setCustomUserProperties" } });
386
460
  }
387
461
  }
388
462
  sendEvent(event) {
389
- const requests = (Array.isArray(event) ? event : [event]).map((e) => e.request);
390
- if (this.bridge) {
391
- this.bridge.sendEvent({ requests });
392
- 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" } });
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() {