@kontextso/sdk-react-native 0.0.9 → 0.0.10-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -30,55 +30,131 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
- AdsContext: () => AdsContext,
34
33
  AdsProvider: () => AdsProvider,
35
34
  InlineAd: () => InlineAd_default,
36
- VISITOR_ID_KEY: () => VISITOR_ID_KEY,
35
+ VISITOR_ID_KEY: () => VISITOR_ID_KEY2,
37
36
  useAd: () => useAd
38
37
  });
39
38
  module.exports = __toCommonJS(src_exports);
40
39
 
41
40
  // src/formats/InlineAd.tsx
42
- var import_react12 = require("react");
43
- var import_react_native5 = require("react-native");
44
-
45
- // src/hooks/useAdViewed.tsx
46
- var import_react6 = require("react");
47
-
48
- // src/context/AdsProvider.tsx
49
- var import_react5 = __toESM(require("react"));
41
+ var import_react10 = require("react");
42
+ var import_react_native4 = require("react-native");
50
43
 
51
- // src/hooks/useInitializeAds.tsx
44
+ // ../sdk-common/dist/index.mjs
52
45
  var import_react = require("react");
53
-
54
- // src/utils.ts
55
- var UNRETRIABLE_ERRORS = [400, 403, 429];
56
- var fetchWithTimeout = async (input, init) => {
57
- const { timeout = 16e3 } = init || {};
46
+ var import_react2 = __toESM(require("react"), 1);
47
+ var import_react3 = require("react");
48
+ var import_react4 = require("react");
49
+ var import_react5 = require("react");
50
+ var import_jsx_runtime = require("react/jsx-runtime");
51
+ var import_react6 = require("react");
52
+ var version = "0.1.12";
53
+ var Logger = class {
54
+ localLevel = "log";
55
+ remoteLevel = "error";
56
+ remoteConfig = null;
57
+ levels = {
58
+ debug: 0,
59
+ info: 1,
60
+ log: 2,
61
+ warn: 3,
62
+ error: 4,
63
+ silent: 5
64
+ };
65
+ setLocalLevel(level) {
66
+ this.localLevel = level;
67
+ }
68
+ setRemoteLevel(level) {
69
+ this.remoteLevel = level;
70
+ }
71
+ configureRemote(url, params) {
72
+ this.remoteConfig = { url, params };
73
+ }
74
+ shouldLog(level, targetLevel) {
75
+ if (targetLevel === "silent") {
76
+ return false;
77
+ }
78
+ return this.levels[level] >= this.levels[targetLevel];
79
+ }
80
+ logToConsole(level, ...args) {
81
+ if (this.shouldLog(level, this.localLevel)) {
82
+ if (level === "silent") {
83
+ return;
84
+ }
85
+ console[level](...args);
86
+ }
87
+ }
88
+ logToRemote(level, ...args) {
89
+ if (this.remoteConfig && this.shouldLog(level, this.remoteLevel)) {
90
+ fetch(
91
+ `${this.remoteConfig.url}/log`,
92
+ {
93
+ method: "POST",
94
+ body: JSON.stringify({
95
+ ...this.remoteConfig.params,
96
+ level,
97
+ message: args,
98
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
99
+ })
100
+ }
101
+ ).catch((e) => {
102
+ });
103
+ }
104
+ }
105
+ debug(...args) {
106
+ this.logToConsole("debug", ...args);
107
+ this.logToRemote("debug", ...args);
108
+ }
109
+ info(...args) {
110
+ this.logToConsole("info", ...args);
111
+ this.logToRemote("info", ...args);
112
+ }
113
+ log(...args) {
114
+ this.logToConsole("log", ...args);
115
+ this.logToRemote("log", ...args);
116
+ }
117
+ warn(...args) {
118
+ this.logToConsole("warn", ...args);
119
+ this.logToRemote("warn", ...args);
120
+ }
121
+ error(...args) {
122
+ this.logToConsole("error", ...args);
123
+ this.logToRemote("error", ...args);
124
+ }
125
+ };
126
+ var log = new Logger();
127
+ var log_default = log;
128
+ var UNRETRIABLE_ERRORS = [403, 429, 404];
129
+ var fetchWithTimeout = async (input, init, customFetch2) => {
130
+ const { timeout = 16e3, ...rest } = init || {};
58
131
  const controller = new AbortController();
59
132
  const id = setTimeout(() => controller.abort(), timeout);
60
133
  try {
61
- const response = await fetch(input, {
62
- ...init,
134
+ const response = await (customFetch2 || fetch)(input, {
135
+ ...rest,
63
136
  signal: controller.signal
64
137
  });
65
- clearTimeout(id);
66
138
  return response;
67
- } catch (e) {
139
+ } catch (err) {
140
+ if (controller.signal.aborted) {
141
+ throw new Error(`Fetch aborted after ${timeout}ms`);
142
+ }
143
+ throw err;
144
+ } finally {
68
145
  clearTimeout(id);
69
- throw e;
70
146
  }
71
147
  };
72
- var fetchRetry = async (input, init, maxRetries = 3, retryPeriod = 500) => {
148
+ var fetchRetry = async (input, init, singleRequestTimeout, maxRetries, onRetry, customFetch2) => {
73
149
  let retries = 0;
74
150
  let response;
75
- let unretriableError;
151
+ let lastError = null;
76
152
  while (retries < maxRetries) {
77
153
  try {
78
- response = await fetchWithTimeout(input, init);
154
+ const requestInit = { ...init, timeout: singleRequestTimeout };
155
+ response = await fetchWithTimeout(input, requestInit, customFetch2);
79
156
  if (UNRETRIABLE_ERRORS.includes(response.status)) {
80
- unretriableError = new Error(response.statusText);
81
- break;
157
+ throw new Error(`Unretriable error: ${response.statusText}`);
82
158
  }
83
159
  if (response.ok) {
84
160
  return response;
@@ -86,18 +162,20 @@ var fetchRetry = async (input, init, maxRetries = 3, retryPeriod = 500) => {
86
162
  throw new Error(`Failed with status ${response.status}`);
87
163
  }
88
164
  } catch (error) {
165
+ log_default.debug(`Retrying ${input} ${retries} times, error: ${error}`);
89
166
  retries++;
90
- await new Promise((resolve) => setTimeout(resolve, retryPeriod));
167
+ lastError = error;
168
+ onRetry?.(error, retries);
91
169
  }
92
170
  }
93
- if (unretriableError) {
94
- throw unretriableError;
95
- }
96
- throw new Error("Failed to fetch after multiple retries");
171
+ throw lastError || new Error("Failed to fetch after multiple retries");
97
172
  };
98
173
  var fixUrl = (adserverUrl, ad) => {
99
174
  if (ad.content) {
100
- ad.content = ad.content.replace("/impression/", `${adserverUrl}/impression/`);
175
+ ad.content = ad.content.replace(
176
+ "/impression/",
177
+ `${adserverUrl}/impression/`
178
+ );
101
179
  ad.content = ad.content.replace("/ad/", `${adserverUrl}/impression/`);
102
180
  }
103
181
  return { ...ad, url: `${adserverUrl}${ad.url}` };
@@ -138,6 +216,16 @@ var mergeAds = ({
138
216
  }
139
217
  return ads;
140
218
  };
219
+ var loadExternalCss = (serverUrl, publisherToken, visitorId) => {
220
+ const visitorIdSearchParam = visitorId ? `&visitorId=${visitorId}` : "";
221
+ const url = `${serverUrl}/sdk/styles?publisherToken=${publisherToken}&sdkVersion=${version}${visitorIdSearchParam}`;
222
+ const link = document.createElement("link");
223
+ link.rel = "stylesheet";
224
+ link.type = "text/css";
225
+ link.href = url;
226
+ document.head.appendChild(link);
227
+ return link;
228
+ };
141
229
  function mergeStyles(propStyles, defaultStyles, overridingStyles) {
142
230
  function deepMerge(target, source) {
143
231
  if (typeof target !== "object" || typeof source !== "object") {
@@ -159,165 +247,36 @@ function mergeStyles(propStyles, defaultStyles, overridingStyles) {
159
247
  mergedStyles = deepMerge(mergedStyles, overridingStyles || {});
160
248
  return mergedStyles;
161
249
  }
162
- var parseMessageText = (text) => {
163
- const parts = [];
164
- let start = 0;
165
- const regex = /(\*(.*?)\*)|\[([^\]]+)\]\(([^)]+)\)/g;
166
- let match;
167
- while ((match = regex.exec(text)) !== null) {
168
- if (match.index > start) {
169
- parts.push({ text: text.substring(start, match.index), textType: "normal" });
170
- }
171
- if (match[1]) {
172
- const themedText = match[2];
173
- const innerMatches = themedText.match(/\[([^\]]+)\]\(([^)]+)\)/g);
174
- if (innerMatches) {
175
- let innerStart = 0;
176
- innerMatches.forEach((linkMatch) => {
177
- const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/;
178
- const innerLink = linkMatch.match(linkRegex);
179
- const linkIndex = themedText.indexOf(linkMatch, innerStart);
180
- if (linkIndex > innerStart) {
181
- parts.push({ text: themedText.substring(innerStart, linkIndex), textType: "themed" });
182
- }
183
- parts.push({ text: innerLink[1], textType: "link", url: innerLink[2] });
184
- innerStart = linkIndex + linkMatch.length;
185
- });
186
- if (innerStart < themedText.length) {
187
- parts.push({ text: themedText.substring(innerStart), textType: "themed" });
188
- }
189
- } else {
190
- parts.push({ text: themedText, textType: "themed" });
191
- }
192
- } else if (match[3] && match[4]) {
193
- parts.push({ text: match[3], textType: "link", url: match[4] });
194
- }
195
- start = match.index + match[0].length;
196
- }
197
- if (start < text.length) {
198
- parts.push({ text: text.substring(start), textType: "normal" });
199
- }
200
- return parts;
201
- };
202
-
203
- // src/log.ts
204
- var Logger = class {
205
- localLevel = "log";
206
- remoteLevel = "error";
207
- remoteConfig = null;
208
- levels = {
209
- debug: 0,
210
- info: 1,
211
- log: 2,
212
- warn: 3,
213
- error: 4,
214
- silent: 5
215
- };
216
- setLocalLevel(level) {
217
- this.localLevel = level;
218
- }
219
- setRemoteLevel(level) {
220
- this.remoteLevel = level;
221
- }
222
- configureRemote(url, params) {
223
- this.remoteConfig = { url, params };
224
- }
225
- shouldLog(level, targetLevel) {
226
- if (targetLevel === "silent") {
227
- return false;
228
- }
229
- return this.levels[level] >= this.levels[targetLevel];
230
- }
231
- logToConsole(level, ...args) {
232
- if (this.shouldLog(level, this.localLevel)) {
233
- if (level === "silent") {
234
- return;
235
- }
236
- console[level](...args);
237
- }
238
- }
239
- logToRemote(level, ...args) {
240
- if (this.remoteConfig && this.shouldLog(level, this.remoteLevel)) {
241
- fetch(
242
- `${this.remoteConfig.url}/log`,
243
- {
244
- method: "POST",
245
- body: JSON.stringify({
246
- ...this.remoteConfig.params,
247
- level,
248
- message: args,
249
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
250
- })
251
- }
252
- ).catch((e) => {
253
- });
254
- }
255
- }
256
- debug(...args) {
257
- this.logToConsole("debug", ...args);
258
- this.logToRemote("debug", ...args);
259
- }
260
- info(...args) {
261
- this.logToConsole("info", ...args);
262
- this.logToRemote("info", ...args);
263
- }
264
- log(...args) {
265
- this.logToConsole("log", ...args);
266
- this.logToRemote("log", ...args);
267
- }
268
- warn(...args) {
269
- this.logToConsole("warn", ...args);
270
- this.logToRemote("warn", ...args);
271
- }
272
- error(...args) {
273
- this.logToConsole("error", ...args);
274
- this.logToRemote("error", ...args);
275
- }
276
- };
277
- var log = new Logger();
278
- var log_default = log;
279
-
280
- // package.json
281
- var version = "0.0.9";
282
-
283
- // src/hooks/useInitializeAds.tsx
284
- var RETRY_PERIOD_MS = 500;
285
- var INIT_RETRIES = 3;
286
- async function initialize(adServerUrl, publisherToken, userId, conversationId, legacyVisitorId, character) {
287
- log_default.log("[BRAIN] init ads started");
250
+ var SINGLE_INIT_TIMEOUT_BUDGET_MS = 5e3;
251
+ async function initialise(adServerUrl, publisherToken, visitorId, userId, conversationId, legacyVisitorId, character, customFetch2) {
252
+ log_default.log("[Kontext] init ads started");
288
253
  const response = await fetchRetry(
289
254
  `${adServerUrl}/init`,
290
255
  {
291
- timeout: 1e4,
292
256
  method: "POST",
293
257
  body: JSON.stringify({
294
258
  publisherToken,
295
259
  userId,
296
- visitorId: userId,
260
+ visitorId,
297
261
  conversationId,
298
- sdkVersion: `native-${version}`,
262
+ sdkVersion: version,
299
263
  legacyVisitorId,
300
264
  character
301
265
  })
302
266
  },
303
- INIT_RETRIES,
304
- RETRY_PERIOD_MS
267
+ SINGLE_INIT_TIMEOUT_BUDGET_MS,
268
+ 3,
269
+ () => {
270
+ log_default.warn("[Kontext] Reinitialising ads");
271
+ },
272
+ customFetch2
305
273
  );
306
- const {
307
- sessionId,
308
- enabledPlacements,
309
- ads,
310
- sessionDisabled,
311
- streamAdServer,
312
- onlyStream,
313
- defaultReactNativeStyles,
314
- overridingReactNativeStyles,
315
- remoteLogLevel
316
- } = await response.json();
274
+ const { sessionId, enabledPlacements, ads, sessionDisabled, streamAdServer, onlyStream, remoteLogLevel, preloadTimeout, streamTimeout, defaultReactNativeStyles, overridingReactNativeStyles } = await response.json();
317
275
  const fixedAds = ads.map((ad) => {
318
- return fixUrl(adServerUrl, ad);
276
+ const fixedAd = fixUrl(adServerUrl, ad);
277
+ return fixedAd;
319
278
  });
320
- log_default.log("[BRAIN] init ads done");
279
+ log_default.log("[Kontext] init ads done");
321
280
  return {
322
281
  sessionDisabled,
323
282
  sessionId,
@@ -325,126 +284,127 @@ async function initialize(adServerUrl, publisherToken, userId, conversationId, l
325
284
  ads: fixedAds,
326
285
  streamAdServer,
327
286
  onlyStream,
328
- defaultReactNativeStylesResponse: defaultReactNativeStyles,
329
- overridingReactNativeStylesResponse: overridingReactNativeStyles,
330
- remoteLogLevel
287
+ remoteLogLevel,
288
+ preloadTimeout,
289
+ streamTimeout,
290
+ defaultReactNativeStyles,
291
+ overridingReactNativeStyles
331
292
  };
332
293
  }
333
294
  function useInitializeAds({
334
295
  adServerUrl,
335
296
  publisherToken,
297
+ visitorId,
336
298
  userId,
337
299
  conversationId,
338
300
  isDisabled,
339
301
  character,
340
- legacyVisitorId
302
+ legacyVisitorId,
303
+ captureError,
304
+ customFetch: customFetch2,
305
+ reactNativePropStyles
341
306
  }) {
342
- const [enabledPlacements, setEnabledPlacements] = (0, import_react.useState)([]);
343
- const [ads, setAds] = (0, import_react.useState)([]);
344
- const [error, setError] = (0, import_react.useState)();
345
- const [streamAdServerUrl, setStreamAdServerUrl] = (0, import_react.useState)();
346
- const [onlyStream, setOnlyStream] = (0, import_react.useState)(false);
347
- const [sessionId, setSessionId] = (0, import_react.useState)();
348
- const [defaultReactNativeStyles, setDefaultReactNativeStyles] = (0, import_react.useState)();
349
- const [overridingReactNativeStyles, setOverridingReactNativeStyles] = (0, import_react.useState)();
350
- (0, import_react.useEffect)(() => {
351
- log_default.setRemoteLevel("debug");
307
+ const [enabledPlacements, setEnabledPlacements] = (0, import_react3.useState)([]);
308
+ const [ads, setAds] = (0, import_react3.useState)([]);
309
+ const [error, setError] = (0, import_react3.useState)();
310
+ const [streamAdServerUrl, setStreamAdServerUrl] = (0, import_react3.useState)();
311
+ const [onlyStream, setOnlyStream] = (0, import_react3.useState)(false);
312
+ const [preloadTimeout, setPreloadTimeout] = (0, import_react3.useState)(8e3);
313
+ const [streamTimeout, setStreamTimeout] = (0, import_react3.useState)(5e3);
314
+ const [reactNativeStyles, setReactNativeStyles] = (0, import_react3.useState)(null);
315
+ const [sessionId, setSessionId] = (0, import_react3.useState)();
316
+ (0, import_react3.useEffect)(() => {
317
+ setSessionId(void 0);
352
318
  log_default.configureRemote(adServerUrl, {
353
319
  publisherToken,
354
320
  userId,
355
- visitorId: userId,
321
+ visitorId,
356
322
  conversationId,
357
323
  character
358
324
  });
359
- setSessionId(void 0);
360
- if (!isDisabled && userId) {
361
- log_default.debug("[BRAIN] Initializing ads.");
362
- initialize(
325
+ if (!isDisabled && visitorId && userId) {
326
+ log_default.debug("[Kontext] Initalising ads.");
327
+ log_default.setRemoteLevel("debug");
328
+ initialise(
363
329
  adServerUrl,
364
330
  publisherToken,
331
+ visitorId,
365
332
  userId,
366
333
  conversationId,
367
334
  legacyVisitorId,
368
- character
369
- ).then(
370
- ({
371
- sessionId: sessionId2,
372
- enabledPlacements: enabledPlacements2,
373
- ads: ads2,
374
- sessionDisabled,
375
- streamAdServer,
376
- onlyStream: onlyStream2,
377
- defaultReactNativeStylesResponse,
378
- overridingReactNativeStylesResponse,
379
- remoteLogLevel
380
- }) => {
335
+ character,
336
+ customFetch2
337
+ ).then(({ sessionId: sessionId2, enabledPlacements: enabledPlacements2, ads: ads2, sessionDisabled, streamAdServer, onlyStream: onlyStream2, remoteLogLevel, preloadTimeout: preloadTimeout2, streamTimeout: streamTimeout2, defaultReactNativeStyles, overridingReactNativeStyles }) => {
338
+ log_default.configureRemote(adServerUrl, {
339
+ publisherToken,
340
+ adServerUrl,
341
+ visitorId,
342
+ userId,
343
+ conversationId,
344
+ legacyVisitorId,
345
+ character,
346
+ sessionId: sessionId2
347
+ });
348
+ if (remoteLogLevel) {
381
349
  log_default.setRemoteLevel(remoteLogLevel || "silent");
382
- log_default.configureRemote(adServerUrl, {
383
- publisherToken,
384
- adServerUrl,
385
- userId,
386
- conversationId,
387
- legacyVisitorId,
388
- character,
389
- sessionId: sessionId2
390
- });
391
- if (!sessionDisabled) {
392
- setSessionId(sessionId2);
393
- setEnabledPlacements(enabledPlacements2);
394
- setAds(ads2);
395
- setStreamAdServerUrl(streamAdServer);
396
- setOnlyStream(onlyStream2);
397
- setDefaultReactNativeStyles(defaultReactNativeStylesResponse);
398
- setOverridingReactNativeStyles(overridingReactNativeStylesResponse);
399
- } else {
400
- log_default.debug("[BRAIN] Session is disabled by server.");
350
+ }
351
+ const mergedStyles = mergeStyles(reactNativePropStyles, defaultReactNativeStyles, overridingReactNativeStyles);
352
+ setReactNativeStyles(mergedStyles);
353
+ if (!sessionDisabled) {
354
+ setSessionId(sessionId2);
355
+ setEnabledPlacements(enabledPlacements2);
356
+ setAds(ads2);
357
+ setStreamAdServerUrl(streamAdServer);
358
+ setOnlyStream(onlyStream2);
359
+ if (preloadTimeout2) {
360
+ setPreloadTimeout(preloadTimeout2);
401
361
  }
362
+ if (streamTimeout2) {
363
+ setStreamTimeout(streamTimeout2);
364
+ }
365
+ } else {
366
+ log_default.info(`[Kontext] Session is disabled. Reason: ${sessionId2}`);
367
+ setSessionId(null);
368
+ }
369
+ }).catch((e) => {
370
+ {
371
+ log_default.warn("[Kontext] Error initializing ads", e);
372
+ setError(e.toString());
373
+ captureError(e);
402
374
  }
403
- ).catch((e) => {
404
- log_default.warn("[BRAIN] Error initializing ads", e);
405
- setError(e.message);
406
375
  });
407
376
  } else {
408
- log_default.debug("[BRAIN] Ads are disabled.");
377
+ log_default.debug("[Kontext] Ads are disabled.");
378
+ setSessionId(null);
409
379
  }
410
- }, [
411
- adServerUrl,
412
- publisherToken,
413
- userId,
414
- conversationId,
415
- isDisabled
416
- ]);
417
- return {
418
- ads,
419
- sessionId,
420
- enabledPlacements,
421
- error,
422
- streamAdServerUrl,
423
- onlyStream,
424
- defaultReactNativeStyles,
425
- overridingReactNativeStyles
426
- };
380
+ }, [adServerUrl, publisherToken, visitorId, userId, conversationId, isDisabled]);
381
+ return { ads, sessionId, enabledPlacements, error, streamAdServerUrl, onlyStream, preloadTimeout, streamTimeout, reactNativeStyles };
427
382
  }
428
-
429
- // src/hooks/usePreloadAds.tsx
430
- var import_react2 = require("react");
431
383
  function usePreloadAds({
432
- userId,
433
384
  sessionId,
434
385
  conversationId,
435
386
  adserverUrl,
436
387
  messages,
437
388
  publisherToken,
438
389
  character,
439
- onlyStream
390
+ onlyStream,
391
+ captureError,
392
+ preloadTimeout,
393
+ customFetch: customFetch2
440
394
  }) {
441
- const [preloadDone, setPreloadDone] = (0, import_react2.useState)(false);
442
- const [ads, setAds] = (0, import_react2.useState)([]);
443
- const userMessagesContent = messages.filter((m) => m.role === "user").map((m) => m.content).join(" ");
444
- (0, import_react2.useEffect)(() => {
395
+ const [preloadDone, setPreloadDone] = (0, import_react4.useState)(false);
396
+ const [ads, setAds] = (0, import_react4.useState)([]);
397
+ const lastUserMessageContent = [...messages].reverse().find((m) => m.role === "user")?.content;
398
+ const userMessagesContent = messages.slice(-6).filter((m) => m.role === "user").map((m) => m.content).join(" ");
399
+ const numberOfAssistantMessagesAtTheEnd = messages.slice().reverse().filter((m) => m.role === "assistant" || m.role === "user").findIndex((m) => m.role === "user");
400
+ const numberOfAssistantFollowups = Math.max(
401
+ 0,
402
+ numberOfAssistantMessagesAtTheEnd - 1
403
+ );
404
+ (0, import_react4.useEffect)(() => {
445
405
  if (onlyStream) {
446
406
  setPreloadDone(true);
447
- log_default.log("[BRAIN] skipping preload ads");
407
+ log_default.log("[Kontext] skipping preload ads");
448
408
  return;
449
409
  }
450
410
  async function preload() {
@@ -452,47 +412,57 @@ function usePreloadAds({
452
412
  if (!sessionId) {
453
413
  return;
454
414
  }
455
- log_default.log("[BRAIN] preload ads started");
456
- try {
457
- const response = await fetchRetry(
458
- `${adserverUrl}/preload`,
459
- {
460
- timeout: 1e4,
461
- method: "POST",
462
- body: JSON.stringify({
463
- messages,
464
- sessionId,
465
- userId,
466
- visitorId: userId,
467
- publisherToken,
468
- conversationId,
469
- character,
470
- sdkVersion: "native"
471
- })
472
- },
473
- 3,
474
- 1e3
475
- );
476
- const { ads: ads2 } = await response.json();
415
+ if (!lastUserMessageContent) {
416
+ return;
417
+ }
418
+ log_default.log("[Kontext] preload ads started");
419
+ const response = await fetchWithTimeout(
420
+ `${adserverUrl}/preload`,
421
+ {
422
+ method: "POST",
423
+ timeout: preloadTimeout,
424
+ body: JSON.stringify({
425
+ messages,
426
+ sessionId,
427
+ publisherToken,
428
+ conversationId,
429
+ character,
430
+ sdkVersion: version
431
+ })
432
+ },
433
+ customFetch2
434
+ );
435
+ if (!response.ok) {
436
+ throw new Error("Error preloading ads. Status: " + response.status);
437
+ }
438
+ const { ads: ads2 } = await response.json();
439
+ ads2.forEach((ad) => {
477
440
  setAds((oldAds) => {
478
- const newAds = ads2.map((ad) => fixUrl(adserverUrl, ad));
479
- return [...oldAds, ...newAds];
441
+ const fixedAd = fixUrl(adserverUrl, ad);
442
+ let found = false;
443
+ let newAds = oldAds.map((a) => {
444
+ if (a.code === ad.code) {
445
+ found = true;
446
+ return fixedAd;
447
+ }
448
+ return a;
449
+ });
450
+ if (!found) {
451
+ newAds.push(fixedAd);
452
+ }
453
+ return newAds;
480
454
  });
481
- setPreloadDone(true);
482
- log_default.log("[BRAIN] preload ads finished");
483
- } catch (e) {
484
- log_default.warn("[BRAIN] Error preloading ads", e);
485
- }
455
+ });
456
+ setPreloadDone(true);
457
+ log_default.log("[Kontext] preload ads finished");
486
458
  }
487
- preload();
488
- }, [sessionId, userMessagesContent, conversationId]);
459
+ preload().catch((e) => {
460
+ captureError(e);
461
+ log_default.error("[Kontext] Error preloading ads", e);
462
+ });
463
+ }, [sessionId, userMessagesContent, numberOfAssistantFollowups]);
489
464
  return { preloadDone, ads };
490
465
  }
491
-
492
- // src/hooks/useStreamAds.tsx
493
- var import_react3 = require("react");
494
-
495
- // src/hooks/data-stream.ts
496
466
  var textStreamPart = {
497
467
  code: "0",
498
468
  name: "text",
@@ -695,12 +665,7 @@ async function* readDataStream(reader, {
695
665
  const concatenatedChunks = concatChunks(chunks, totalLength);
696
666
  totalLength = 0;
697
667
  const streamParts2 = decoder.decode(concatenatedChunks, { stream: true }).split("\n").filter((line) => line !== "").map(parseStreamPart);
698
- let i = 0;
699
668
  for (const streamPart of streamParts2) {
700
- if (!(i % 5)) {
701
- await new Promise((resolve) => setTimeout(resolve));
702
- }
703
- i++;
704
669
  yield streamPart;
705
670
  }
706
671
  if (isAborted?.()) {
@@ -709,25 +674,8 @@ async function* readDataStream(reader, {
709
674
  }
710
675
  }
711
676
  }
712
-
713
- // src/hooks/useStreamAds.tsx
714
- var import_encoding = require("react-native-polyfill-globals/src/encoding");
715
- var import_readable_stream = require("react-native-polyfill-globals/src/readable-stream");
716
- var import_react_native = require("react-native");
717
- var patchFetch = fetch;
718
- if (import_react_native.Platform.OS !== "web") {
719
- (0, import_encoding.polyfill)();
720
- (0, import_readable_stream.polyfill)();
721
- patchFetch = require("react-native-fetch-api").fetch;
722
- }
723
- ErrorUtils.setGlobalHandler((error, isFatal) => {
724
- if (!isFatal) {
725
- log_default.warn(error);
726
- } else {
727
- log_default.error(error);
728
- }
729
- });
730
677
  function useStreamAds({
678
+ visitorId,
731
679
  userId,
732
680
  sessionId,
733
681
  conversationId,
@@ -737,9 +685,12 @@ function useStreamAds({
737
685
  preloadDone,
738
686
  enabledPlacements,
739
687
  character,
740
- publisherToken
688
+ publisherToken,
689
+ captureError,
690
+ streamTimeout,
691
+ customFetch: customFetch2
741
692
  }) {
742
- const [ads, setAds] = (0, import_react3.useState)([]);
693
+ const [ads, setAds] = (0, import_react5.useState)([]);
743
694
  const fetchStream = async (messages2, code) => {
744
695
  const lastAssistantMessage = [...messages2].reverse().find((m) => m.role === "assistant");
745
696
  if (!lastAssistantMessage) {
@@ -755,43 +706,77 @@ function useStreamAds({
755
706
  return newAds;
756
707
  });
757
708
  const body = JSON.stringify({
709
+ visitorId,
758
710
  userId,
759
- visitorId: userId,
760
711
  sessionId,
761
712
  code,
762
713
  messages: messages2,
763
714
  publisherToken,
764
715
  character,
765
716
  conversationId,
766
- sdkVersion: "native"
717
+ sdkVersion: version
767
718
  });
768
719
  try {
769
- const response = await patchFetch(`${adserverUrl}/stream`, {
770
- method: "POST",
771
- body,
772
- headers: {
773
- "Content-Type": "application/json"
720
+ const response = await fetchWithTimeout(
721
+ `${adserverUrl}/stream`,
722
+ {
723
+ method: "POST",
724
+ body,
725
+ headers: {
726
+ "Content-Type": "application/json"
727
+ },
728
+ timeout: streamTimeout
774
729
  },
775
- reactNative: { textStreaming: true }
776
- });
730
+ customFetch2
731
+ );
777
732
  if (!response.ok) {
778
- throw new Error("Error streaming ad");
733
+ throw new Error("Error streaming ad. Status: " + response.status);
779
734
  }
780
735
  if (!response.body) {
781
- throw new Error("Response body is not a readable stream");
736
+ throw new Error("Response body is not readable stream");
782
737
  }
783
- setAds(
784
- (oldAds) => oldAds.map((ad) => ad.messageId === lastAssistantMessage.id && ad.code === code ? { ...ad, isLoading: false, isStreaming: true } : ad)
785
- );
738
+ if (response.status === 204) {
739
+ setAds((oldAds) => {
740
+ const newAds = oldAds.map((ad) => {
741
+ if (ad.messageId === lastAssistantMessage.id && ad.code === code) {
742
+ return {
743
+ ...ad,
744
+ isLoading: false,
745
+ isStreaming: false
746
+ };
747
+ }
748
+ return ad;
749
+ });
750
+ return newAds;
751
+ });
752
+ return;
753
+ }
754
+ setAds((oldAds) => {
755
+ const newAds = oldAds.map((ad) => {
756
+ if (ad.messageId === lastAssistantMessage.id && ad.code === code) {
757
+ return {
758
+ ...ad,
759
+ isLoading: false,
760
+ isStreaming: true
761
+ };
762
+ }
763
+ return ad;
764
+ });
765
+ return newAds;
766
+ });
786
767
  let data = "";
787
768
  let adData = {};
788
- log_default.log(`[BRAIN] streaming ${code} ad started`);
769
+ log_default.log(`[Kontext] streaming ${code} ad started`);
770
+ if (!response.body) {
771
+ throw new Error("Response body is not readable stream");
772
+ }
789
773
  const reader = response.body.getReader();
790
774
  for await (const { type, value } of readDataStream(reader)) {
791
775
  switch (type) {
792
- case "text":
776
+ case "text": {
793
777
  data += value;
794
778
  break;
779
+ }
795
780
  case "data": {
796
781
  let val = value;
797
782
  if (Array.isArray(val)) {
@@ -800,11 +785,12 @@ function useStreamAds({
800
785
  adData = { ...adData, ...val };
801
786
  break;
802
787
  }
803
- case "error":
788
+ case "error": {
804
789
  throw new Error(`Error streaming ad ${value}`);
790
+ }
805
791
  }
806
- setAds(
807
- (oldAds) => oldAds.map((ad) => {
792
+ setAds((oldAds) => {
793
+ const newAds = oldAds.map((ad) => {
808
794
  if (ad.messageId === lastAssistantMessage.id && ad.code === code) {
809
795
  const content = adData.content ?? data;
810
796
  const newAd = fixUrl(adserverUrl, {
@@ -813,82 +799,87 @@ function useStreamAds({
813
799
  isLoading: false,
814
800
  isStreaming: true,
815
801
  content: content.replace(
816
- new RegExp(`/impression/${adData.product.id}/redirect`, "g"),
802
+ new RegExp(`/(ad|impression)/${adData.product.id}/redirect`, "g"),
817
803
  `/impression/${adData.id}/redirect`
818
804
  )
819
805
  });
820
806
  return newAd;
821
807
  }
822
808
  return ad;
823
- })
824
- );
809
+ });
810
+ return newAds;
811
+ });
825
812
  }
826
- setAds(
827
- (oldAds) => oldAds.map(
828
- (ad) => ad.messageId === lastAssistantMessage.id && ad.code === code ? { ...ad, isStreaming: false } : ad
829
- )
830
- );
831
- log_default.log(`[BRAIN] streaming ${code} ad done`);
813
+ setAds((oldAds) => {
814
+ const newAds = oldAds.map((ad) => {
815
+ if (ad.messageId === lastAssistantMessage.id && ad.code === code) {
816
+ return {
817
+ ...ad,
818
+ isStreaming: false
819
+ };
820
+ }
821
+ return ad;
822
+ });
823
+ return newAds;
824
+ });
825
+ log_default.log(`[Kontext] streaming ${code} ad done`);
832
826
  } catch (e) {
833
- log_default.warn("[BRAIN] Error streaming ad", e);
834
- setAds((oldAds) => [...oldAds, { isError: true, code }]);
827
+ captureError(e);
828
+ log_default.error("[Kontext] Error streaming ad", e);
829
+ setAds((oldAds) => {
830
+ let found = false;
831
+ const newAds = oldAds.map((ad) => {
832
+ if (ad.messageId === lastAssistantMessage.id && ad.code === code) {
833
+ found = true;
834
+ return {
835
+ ...ad,
836
+ isLoading: false,
837
+ isStreaming: false,
838
+ isError: true
839
+ };
840
+ }
841
+ return ad;
842
+ });
843
+ if (!found) {
844
+ newAds.push({
845
+ isLoading: false,
846
+ isStreaming: false,
847
+ isError: true,
848
+ code
849
+ });
850
+ }
851
+ return newAds;
852
+ });
835
853
  }
836
854
  };
837
- (0, import_react3.useEffect)(() => {
838
- if (!isLoading && sessionId && messages.length > 2 && messages[messages.length - 1]?.role === "assistant" && preloadDone) {
839
- enabledPlacements.forEach((placement) => {
840
- if (["QUERY_STREAM", "INLINE_AD", "BOX_AD"].includes(placement.format)) {
855
+ (0, import_react5.useEffect)(() => {
856
+ if (!isLoading && sessionId && messages.length > 0 && messages[messages.length - 1]?.role === "assistant" && preloadDone) {
857
+ for (const placement of enabledPlacements) {
858
+ if (placement.format === "QUERY_STREAM" || placement.format === "INLINE_AD" || placement.format === "BOX_AD") {
841
859
  fetchStream(messages, String(placement.code));
842
860
  }
843
- });
861
+ }
844
862
  }
845
- }, [isLoading, preloadDone, sessionId, messages[messages.length - 1]?.role]);
863
+ }, [isLoading, preloadDone, sessionId]);
846
864
  return { ads };
847
865
  }
848
-
849
- // src/components/ErrorBoundary.tsx
850
- var import_react4 = __toESM(require("react"));
851
- var captureErrorFn = (adServerUrl, error, componentStack, context) => {
852
- fetch(`${adServerUrl}/error`, {
866
+ var DEFAULT_AD_SERVER_URL = "https://server.megabrain.co";
867
+ var captureErrorFn = (error, componentStack, additionalData) => {
868
+ const adserverUrl = additionalData?.adserverUrl || DEFAULT_AD_SERVER_URL;
869
+ fetch(`${adserverUrl}/error`, {
853
870
  method: "POST",
854
871
  body: JSON.stringify({
855
- error: error?.message,
872
+ error: error.message,
856
873
  stack: componentStack,
857
- context
874
+ additionalData
858
875
  })
859
876
  }).catch((e) => {
860
- log_default.warn("Error reporting client error", e);
877
+ log_default.error(e);
878
+ }).finally(() => {
879
+ log_default.error(error, componentStack);
861
880
  });
862
881
  };
863
- var ErrorBoundary = class extends import_react4.default.Component {
864
- constructor(props) {
865
- super(props);
866
- this.state = {
867
- hasError: false
868
- };
869
- }
870
- static getDerivedStateFromError() {
871
- return {
872
- hasError: true
873
- };
874
- }
875
- componentDidCatch(error, info) {
876
- const adServerUrl = this.props.adserverUrl;
877
- if (adServerUrl) {
878
- captureErrorFn(adServerUrl, error, info?.componentStack, this.props.reqBodyParams);
879
- }
880
- }
881
- render() {
882
- if (this.state.hasError) {
883
- return this.props.fallback || null;
884
- }
885
- return this.props.children;
886
- }
887
- };
888
-
889
- // src/context/AdsProvider.tsx
890
- var import_jsx_runtime = require("react/jsx-runtime");
891
- var AdsContext = import_react5.default.createContext(null);
882
+ var AdsContext = import_react2.default.createContext(null);
892
883
  AdsContext.displayName = "AdsContext";
893
884
  var VISITOR_ID_KEY = "brain-visitor-id";
894
885
  var AdsProviderWithoutBoundary = ({
@@ -900,48 +891,89 @@ var AdsProviderWithoutBoundary = ({
900
891
  isDisabled,
901
892
  character,
902
893
  conversationId,
894
+ visitorId,
903
895
  userId,
904
896
  logLevel,
905
897
  onAdView,
906
898
  onAdClick,
907
- ...props
899
+ customFetch: customFetch2,
900
+ reactNativePropStyles,
901
+ isReactNative
908
902
  }) => {
909
- const [viewedAds, setViewedAds] = (0, import_react5.useState)([]);
910
- const [clickedAds, setClickedAds] = (0, import_react5.useState)([]);
911
- const adServerUrlOrDefault = adserverUrl || "https://server.megabrain.co";
903
+ const adServerUrlOrDefault = adserverUrl || DEFAULT_AD_SERVER_URL;
912
904
  log_default.setLocalLevel(logLevel || "silent");
905
+ visitorId = visitorId || userId;
906
+ const [viewedAds, setViewedAds] = (0, import_react2.useState)([]);
907
+ const [clickedAds, setClickedAds] = (0, import_react2.useState)([]);
908
+ const captureError = (error) => {
909
+ captureErrorFn(error, error.stack, {
910
+ publisherToken,
911
+ adserverUrl,
912
+ conversationId,
913
+ character,
914
+ visitorId,
915
+ userId,
916
+ isLoading,
917
+ messages
918
+ });
919
+ };
920
+ const legacyVisitorId = typeof window !== "undefined" && typeof window.localStorage !== "undefined" && localStorage.getItem(VISITOR_ID_KEY) ? localStorage.getItem(VISITOR_ID_KEY) : void 0;
921
+ (0, import_react2.useEffect)(() => {
922
+ if (isReactNative) {
923
+ return;
924
+ }
925
+ const linkElement = loadExternalCss(adServerUrlOrDefault, publisherToken, visitorId);
926
+ return () => {
927
+ try {
928
+ document.head.removeChild(linkElement);
929
+ } catch (e) {
930
+ }
931
+ };
932
+ }, [adServerUrlOrDefault, publisherToken, visitorId, isReactNative]);
913
933
  const {
914
934
  ads: initAds,
915
935
  sessionId,
916
936
  enabledPlacements,
917
- error,
937
+ error: initError,
918
938
  streamAdServerUrl,
919
939
  onlyStream,
920
- defaultReactNativeStyles,
921
- overridingReactNativeStyles
940
+ preloadTimeout,
941
+ streamTimeout,
942
+ reactNativeStyles
922
943
  } = useInitializeAds({
923
944
  adServerUrl: adServerUrlOrDefault,
924
945
  publisherToken,
925
946
  userId,
926
- legacyVisitorId: void 0,
947
+ visitorId,
948
+ legacyVisitorId,
927
949
  conversationId,
928
950
  character,
929
- isDisabled: !!isDisabled
951
+ isDisabled: !!isDisabled,
952
+ captureError,
953
+ customFetch: customFetch2,
954
+ reactNativePropStyles
930
955
  });
931
- const styles = mergeStyles(props.styles, defaultReactNativeStyles, overridingReactNativeStyles);
932
- const isInitialised = !!isDisabled || !!error || !!sessionId;
933
- const { preloadDone, ads: preloadAds } = usePreloadAds({
956
+ const isInitialised = !!isDisabled || !!initError || !!sessionId || sessionId === null;
957
+ const {
958
+ preloadDone,
959
+ ads: preloadAds
960
+ } = usePreloadAds({
934
961
  sessionId,
935
962
  adserverUrl: adServerUrlOrDefault,
936
963
  messages,
937
964
  publisherToken,
938
965
  conversationId,
939
966
  userId,
967
+ visitorId,
940
968
  character,
941
- onlyStream
969
+ onlyStream,
970
+ captureError,
971
+ preloadTimeout,
972
+ customFetch: customFetch2
942
973
  });
943
974
  const { ads: streamAds } = useStreamAds({
944
975
  userId,
976
+ visitorId,
945
977
  sessionId,
946
978
  adserverUrl: onlyStream && streamAdServerUrl ? streamAdServerUrl : adServerUrlOrDefault,
947
979
  conversationId,
@@ -950,23 +982,28 @@ var AdsProviderWithoutBoundary = ({
950
982
  character,
951
983
  preloadDone,
952
984
  enabledPlacements,
953
- publisherToken
985
+ publisherToken,
986
+ captureError,
987
+ streamTimeout,
988
+ customFetch: customFetch2
954
989
  });
955
990
  const ads = mergeAds({ initAds, preloadAds, streamAds, viewedAds, clickedAds });
956
991
  const markAdAsViewed = (ad) => {
957
- log_default.debug("[Brain] Calling onAdView");
958
992
  onAdView && onAdView({
959
993
  id: ad.id,
960
994
  code: ad.code,
961
995
  messageId: ad.messageId,
962
996
  content: ad.content
963
997
  });
964
- if (!ad.id) return;
965
- if (viewedAds.includes(ad.id)) return;
998
+ if (!ad.id) {
999
+ return;
1000
+ }
1001
+ if (viewedAds.includes(ad.id)) {
1002
+ return;
1003
+ }
966
1004
  setViewedAds((old) => [...old, ad.id]);
967
1005
  };
968
1006
  const onAdClickInternal = (ad) => {
969
- log_default.debug("[Brain] Calling onAdClick");
970
1007
  onAdClick && onAdClick({
971
1008
  id: ad.id,
972
1009
  code: ad.code,
@@ -989,81 +1026,73 @@ var AdsProviderWithoutBoundary = ({
989
1026
  streamAdServerUrl,
990
1027
  children,
991
1028
  messages,
1029
+ conversationId,
992
1030
  publisherToken,
993
1031
  isLoading,
994
1032
  ads,
995
1033
  sessionId,
996
1034
  isInitialised,
997
- conversationId,
998
1035
  isDisabled,
999
1036
  onAdClickInternal,
1000
1037
  enabledPlacements,
1001
1038
  userId,
1039
+ visitorId,
1002
1040
  markAdAsViewed,
1003
1041
  onlyStream,
1004
- styles
1042
+ preloadTimeout,
1043
+ streamTimeout,
1044
+ reactNativeStyles
1005
1045
  },
1006
1046
  children
1007
1047
  }
1008
1048
  );
1009
1049
  };
1010
- var AdsProvider = ({
1011
- children,
1012
- messages,
1013
- publisherToken,
1014
- isLoading,
1015
- adserverUrl,
1016
- isDisabled,
1017
- character,
1018
- conversationId,
1019
- userId,
1020
- logLevel,
1021
- onAdView,
1022
- onAdClick,
1023
- ...props
1024
- }) => {
1025
- const adServerUrlOrDefault = adserverUrl || "https://server.megabrain.co";
1026
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1027
- ErrorBoundary,
1028
- {
1029
- fallback: children,
1030
- adserverUrl: adServerUrlOrDefault,
1031
- reqBodyParams: {
1032
- publisherToken,
1033
- adserverUrl,
1034
- conversationId,
1035
- character,
1036
- userId,
1037
- isLoading,
1038
- messages
1039
- },
1040
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1041
- AdsProviderWithoutBoundary,
1042
- {
1043
- children,
1044
- messages,
1045
- publisherToken,
1046
- isLoading,
1047
- adserverUrl,
1048
- isDisabled,
1049
- character,
1050
- conversationId,
1051
- userId,
1052
- logLevel,
1053
- onAdView,
1054
- onAdClick,
1055
- ...props
1056
- }
1057
- )
1050
+ function useAd({ code, messageId }) {
1051
+ const context = (0, import_react.useContext)(AdsContext);
1052
+ if (!context) {
1053
+ return null;
1054
+ }
1055
+ const ad = context.ads.find((ad2) => {
1056
+ if (messageId) {
1057
+ return ad2.code === code && ad2.messageId === messageId;
1058
1058
  }
1059
+ return ad2.code === code;
1060
+ });
1061
+ if (!ad) {
1062
+ return null;
1063
+ }
1064
+ const placement = context.enabledPlacements.find((p) => p.code === code);
1065
+ if (!placement) {
1066
+ return null;
1067
+ }
1068
+ const dependencies = placement.config.dependencies?.split(",").map((d) => d.trim()).filter((d) => d);
1069
+ if (!dependencies || dependencies.length === 0) {
1070
+ return ad;
1071
+ }
1072
+ const dependencyAds = context.enabledPlacements.filter(
1073
+ (p) => dependencies.includes(p.code)
1059
1074
  );
1060
- };
1061
-
1062
- // src/hooks/useAdViewed.tsx
1063
- var import_react7 = require("react");
1064
- function useAdViewed(ad) {
1065
- const context = (0, import_react7.useContext)(AdsContext);
1066
- const [stillMounted, setStillMounted] = (0, import_react6.useState)(false);
1075
+ if (!dependencyAds.length) {
1076
+ return ad;
1077
+ }
1078
+ const allAdsLoadedAndNotStreaming = dependencyAds.every((p) => {
1079
+ let a;
1080
+ if (messageId) {
1081
+ a = context.ads.find(
1082
+ (ad2) => ad2.code === p.code && ad2.messageId === messageId
1083
+ );
1084
+ } else {
1085
+ a = context.ads.find((ad2) => ad2.code === p.code);
1086
+ }
1087
+ return a && !a.isLoading && !a.isStreaming || a && a.isError;
1088
+ });
1089
+ if (!allAdsLoadedAndNotStreaming) {
1090
+ return null;
1091
+ }
1092
+ return ad;
1093
+ }
1094
+ function useAdViewed(ad, ref) {
1095
+ const context = (0, import_react6.useContext)(AdsContext);
1067
1096
  const sendRequest = async () => {
1068
1097
  if (!context?.adserverUrl || !ad?.id) {
1069
1098
  return;
@@ -1080,49 +1109,101 @@ function useAdViewed(ad) {
1080
1109
  if (!response.ok) {
1081
1110
  throw new Error("Error sending view request");
1082
1111
  }
1083
- log_default.log("[BRAIN] ad marked as viewed", ad.id, ad.code);
1112
+ log_default.log("[Kontext] ad marked as viewed", ad.id, ad.code);
1084
1113
  } catch (e) {
1085
- log_default.warn("[BRAIN] Error sending view request", e);
1114
+ log_default.error("[Kontext] Error sending view request", e);
1086
1115
  }
1087
1116
  };
1088
1117
  (0, import_react6.useEffect)(() => {
1089
- if (!ad || ad.isError || ad.isLoading || ad.isStreaming || ad.viewed || stillMounted) {
1118
+ if (!ref?.current || !ad || !context?.visitorId || !context?.userId || ad.isError || ad.isLoading || ad.isStreaming || ad.viewed) {
1090
1119
  return;
1091
1120
  }
1092
- log_default.log("[BRAIN] setting timeout", ad.id, ad.code);
1093
- setTimeout(() => {
1094
- log_default.log("[BRAIN] setting setStillMounted", ad.id, ad.code);
1095
- setStillMounted(true);
1096
- }, 1e3);
1097
- }, [ad]);
1098
- (0, import_react6.useEffect)(() => {
1099
- if (stillMounted) {
1100
- log_default.log("[BRAIN] sending request");
1121
+ if (typeof window.IntersectionObserver === "undefined") {
1101
1122
  sendRequest();
1123
+ return;
1102
1124
  }
1103
- }, [stillMounted]);
1125
+ const observer = new window.IntersectionObserver((entries, observer2) => {
1126
+ entries.forEach((entry) => {
1127
+ if (entry.isIntersecting) {
1128
+ sendRequest();
1129
+ observer2.unobserve(entry.target);
1130
+ }
1131
+ });
1132
+ });
1133
+ observer.observe(ref?.current);
1134
+ return () => {
1135
+ observer.disconnect();
1136
+ };
1137
+ }, [ad]);
1104
1138
  }
1105
1139
 
1106
1140
  // src/components/MarkdownText.tsx
1107
- var import_react8 = require("react");
1108
- var import_react_native2 = require("react-native");
1141
+ var import_react7 = require("react");
1142
+ var import_react_native = require("react-native");
1143
+
1144
+ // src/utils.ts
1145
+ var getStyles = (context) => {
1146
+ return context.reactNativeStyles;
1147
+ };
1148
+ var parseMessageText = (text) => {
1149
+ const parts = [];
1150
+ let start = 0;
1151
+ const regex = /(\*(.*?)\*)|\[([^\]]+)\]\(([^)]+)\)/g;
1152
+ let match;
1153
+ while ((match = regex.exec(text)) !== null) {
1154
+ if (match.index > start) {
1155
+ parts.push({ text: text.substring(start, match.index), textType: "normal" });
1156
+ }
1157
+ if (match[1]) {
1158
+ const themedText = match[2];
1159
+ const innerMatches = themedText.match(/\[([^\]]+)\]\(([^)]+)\)/g);
1160
+ if (innerMatches) {
1161
+ let innerStart = 0;
1162
+ innerMatches.forEach((linkMatch) => {
1163
+ const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/;
1164
+ const innerLink = linkMatch.match(linkRegex);
1165
+ const linkIndex = themedText.indexOf(linkMatch, innerStart);
1166
+ if (linkIndex > innerStart) {
1167
+ parts.push({ text: themedText.substring(innerStart, linkIndex), textType: "themed" });
1168
+ }
1169
+ parts.push({ text: innerLink[1], textType: "link", url: innerLink[2] });
1170
+ innerStart = linkIndex + linkMatch.length;
1171
+ });
1172
+ if (innerStart < themedText.length) {
1173
+ parts.push({ text: themedText.substring(innerStart), textType: "themed" });
1174
+ }
1175
+ } else {
1176
+ parts.push({ text: themedText, textType: "themed" });
1177
+ }
1178
+ } else if (match[3] && match[4]) {
1179
+ parts.push({ text: match[3], textType: "link", url: match[4] });
1180
+ }
1181
+ start = match.index + match[0].length;
1182
+ }
1183
+ if (start < text.length) {
1184
+ parts.push({ text: text.substring(start), textType: "normal" });
1185
+ }
1186
+ return parts;
1187
+ };
1188
+
1189
+ // src/components/MarkdownText.tsx
1109
1190
  var import_jsx_runtime2 = require("react/jsx-runtime");
1110
1191
  function MarkdownText({
1111
1192
  content,
1112
1193
  onLinkClick
1113
1194
  }) {
1114
- const context = (0, import_react8.useContext)(AdsContext);
1195
+ const context = (0, import_react7.useContext)(AdsContext);
1115
1196
  const textParts = parseMessageText(content);
1116
- const styles = context?.styles?.markdownText;
1197
+ const styles = getStyles(context)?.markdownText;
1117
1198
  const linkClickHandler = (href) => {
1118
1199
  onLinkClick();
1119
- import_react_native2.Linking.openURL(href).catch((err) => log_default.warn("Failed to open URL:", err));
1200
+ import_react_native.Linking.openURL(href).catch((err) => log.warn("Failed to open URL:", err));
1120
1201
  return false;
1121
1202
  };
1122
1203
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: textParts.map((t, i) => {
1123
1204
  if (t.textType === "link") {
1124
1205
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1125
- import_react_native2.Pressable,
1206
+ import_react_native.Pressable,
1126
1207
  {
1127
1208
  onPress: () => {
1128
1209
  linkClickHandler(t.url);
@@ -1130,31 +1211,32 @@ function MarkdownText({
1130
1211
  style: ({ pressed }) => [{ opacity: pressed ? 0.8 : 1 }],
1131
1212
  hitSlop: { top: 20, bottom: 20, left: 10, right: 10 },
1132
1213
  onStartShouldSetResponder: () => true,
1133
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles?.link, children: t.text })
1214
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native.Text, { style: styles?.link, children: t.text })
1134
1215
  },
1135
1216
  i + "link"
1136
1217
  );
1137
1218
  } else if (t.textType === "themed") {
1138
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles?.em, children: t.text }, i + "em");
1219
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native.Text, { style: styles?.em, children: t.text }, i + "em");
1139
1220
  } else {
1140
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles?.normal, children: t.text }, i + "normal");
1221
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native.Text, { style: styles?.normal, children: t.text }, i + "normal");
1141
1222
  }
1142
1223
  }) });
1143
1224
  }
1144
1225
 
1145
1226
  // src/components/VideoPlayer.tsx
1146
1227
  var import_expo_av = require("expo-av");
1147
- var import_react10 = require("react");
1148
- var import_react_native4 = require("react-native");
1149
-
1150
- // src/components/VideoProgressBar.tsx
1151
1228
  var import_react9 = require("react");
1152
1229
  var import_react_native3 = require("react-native");
1230
+
1231
+ // src/components/VideoProgressBar.tsx
1232
+ var import_react8 = require("react");
1233
+ var import_react_native2 = require("react-native");
1153
1234
  var import_jsx_runtime3 = require("react/jsx-runtime");
1154
1235
  function VideoProgressBar({ videoRef }) {
1155
- const [progress, setProgress] = (0, import_react9.useState)(0);
1156
- const styles = (0, import_react9.useContext)(AdsContext)?.styles?.videoPlayer?.videoProgress;
1157
- (0, import_react9.useEffect)(() => {
1236
+ const [progress, setProgress] = (0, import_react8.useState)(0);
1237
+ const context = (0, import_react8.useContext)(AdsContext);
1238
+ const styles = getStyles(context)?.videoPlayer?.videoProgress;
1239
+ (0, import_react8.useEffect)(() => {
1158
1240
  const interval = setInterval(() => {
1159
1241
  if (!videoRef.current) {
1160
1242
  return;
@@ -1170,7 +1252,7 @@ function VideoProgressBar({ videoRef }) {
1170
1252
  }, 1e3);
1171
1253
  return () => clearInterval(interval);
1172
1254
  }, [videoRef.current]);
1173
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: styles?.progressContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [styles?.progressBar, { width: `${progress}%` }] }) });
1255
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.View, { style: styles?.progressContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.View, { style: [styles?.progressBar, { width: `${progress}%` }] }) });
1174
1256
  }
1175
1257
 
1176
1258
  // src/components/VideoPlayer.tsx
@@ -1187,14 +1269,15 @@ var VideoPlayer = ({
1187
1269
  mediaPlacement,
1188
1270
  onLinkClick
1189
1271
  }) => {
1190
- const videoRef = (0, import_react10.useRef)(null);
1191
- const [isPlaying, setIsPlaying] = (0, import_react10.useState)(false);
1192
- const [isPaused, setIsPaused] = (0, import_react10.useState)(true);
1193
- const [isEnded, setIsEnded] = (0, import_react10.useState)(false);
1194
- const [showDownloadBadge, setShowDownloadBadge] = (0, import_react10.useState)(false);
1195
- const lastCallbackTimeRef = (0, import_react10.useRef)(0);
1196
- const styles = (0, import_react10.useContext)(AdsContext)?.styles?.videoPlayer;
1197
- (0, import_react10.useEffect)(() => {
1272
+ const videoRef = (0, import_react9.useRef)(null);
1273
+ const [isPlaying, setIsPlaying] = (0, import_react9.useState)(false);
1274
+ const [isPaused, setIsPaused] = (0, import_react9.useState)(true);
1275
+ const [isEnded, setIsEnded] = (0, import_react9.useState)(false);
1276
+ const [showDownloadBadge, setShowDownloadBadge] = (0, import_react9.useState)(false);
1277
+ const lastCallbackTimeRef = (0, import_react9.useRef)(0);
1278
+ const context = (0, import_react9.useContext)(AdsContext);
1279
+ const styles = getStyles(context)?.videoPlayer;
1280
+ (0, import_react9.useEffect)(() => {
1198
1281
  const interval = setInterval(() => {
1199
1282
  if (videoRef.current) {
1200
1283
  videoRef.current.getStatusAsync().then((status) => {
@@ -1238,7 +1321,7 @@ var VideoPlayer = ({
1238
1321
  };
1239
1322
  const handleLinkClick = (url) => {
1240
1323
  if (url) {
1241
- import_react_native4.Linking.openURL(url).catch((err) => log_default.warn("Failed to open URL:", err));
1324
+ import_react_native3.Linking.openURL(url).catch((err) => log.warn("Failed to open URL:", err));
1242
1325
  onLinkClick();
1243
1326
  }
1244
1327
  };
@@ -1248,7 +1331,7 @@ var VideoPlayer = ({
1248
1331
  setIsPaused(false);
1249
1332
  onProgress(100);
1250
1333
  };
1251
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: [videoOrientation === "horizontal" ? styles?.videoOuterContainerHorizontal : styles?.videoOuterContainerVertical, mediaPlacement === "top" && styles?.videoPlacementBottom, mediaPlacement === "bottom" && styles?.videoPlacementBottom], children: [
1334
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native3.View, { style: [videoOrientation === "horizontal" ? styles?.videoOuterContainerHorizontal : styles?.videoOuterContainerVertical, mediaPlacement === "top" && styles?.videoPlacementBottom, mediaPlacement === "bottom" && styles?.videoPlacementBottom], children: [
1252
1335
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1253
1336
  import_expo_av.Video,
1254
1337
  {
@@ -1267,71 +1350,24 @@ var VideoPlayer = ({
1267
1350
  }
1268
1351
  ),
1269
1352
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VideoProgressBar, { videoRef }),
1270
- !isEnded && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.TouchableOpacity, { style: isPlaying ? styles?.playOverlay : styles?.pauseOverlay, onPress: handlePlayPause, children: !isPlaying && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: styles?.playButton, children: "\u25B6" }) }),
1271
- (isPaused && !isEnded || showDownloadBadge && !isEnded) && badgeText && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.TouchableOpacity, { style: styles?.videoBadge, onPress: handleBadgeClick, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: styles?.videoBadgeText, children: showDownloadBadge && !isPaused && !isEnded ? ctaText : badgeText }) }),
1272
- isEnded && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: styles?.endOverlay, children: [
1273
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.TouchableOpacity, { style: styles?.endOverlayTouch, onPress: () => handleLinkClick(clickUrl), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: styles?.endButton, children: ctaText }) }),
1274
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.Text, { style: styles?.endText, children: endText })
1353
+ !isEnded && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.TouchableOpacity, { style: isPlaying ? styles?.playOverlay : styles?.pauseOverlay, onPress: handlePlayPause, children: !isPlaying && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.Text, { style: styles?.playButton, children: "\u25B6" }) }),
1354
+ (isPaused && !isEnded || showDownloadBadge && !isEnded) && badgeText && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.TouchableOpacity, { style: styles?.videoBadge, onPress: handleBadgeClick, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.Text, { style: styles?.videoBadgeText, children: showDownloadBadge && !isPaused && !isEnded ? ctaText : badgeText }) }),
1355
+ isEnded && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native3.View, { style: styles?.endOverlay, children: [
1356
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.TouchableOpacity, { style: styles?.endOverlayTouch, onPress: () => handleLinkClick(clickUrl), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.Text, { style: styles?.endButton, children: ctaText }) }),
1357
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.Text, { style: styles?.endText, children: endText })
1275
1358
  ] })
1276
1359
  ] });
1277
1360
  };
1278
1361
 
1279
- // src/hooks/useAd.tsx
1280
- var import_react11 = require("react");
1281
- function useAd({ code, messageId }) {
1282
- const context = (0, import_react11.useContext)(AdsContext);
1283
- if (!context) {
1284
- return null;
1285
- }
1286
- const ad = context.ads.find((ad2) => {
1287
- if (messageId) {
1288
- return ad2.code === code && ad2.messageId === messageId;
1289
- }
1290
- return ad2.code === code;
1291
- });
1292
- if (!ad) {
1293
- return null;
1294
- }
1295
- const placement = context.enabledPlacements.find((p) => p.code === code);
1296
- if (!placement) {
1297
- return null;
1298
- }
1299
- const dependencies = placement.config.dependencies?.split(",").map((d) => d.trim()).filter((d) => d);
1300
- if (!dependencies || dependencies.length === 0) {
1301
- return ad;
1302
- }
1303
- const dependencyAds = context.enabledPlacements.filter(
1304
- (p) => dependencies.includes(p.code)
1305
- );
1306
- if (!dependencyAds.length) {
1307
- return ad;
1308
- }
1309
- const allAdsLoadedAndNotStreaming = dependencyAds.every((p) => {
1310
- let a;
1311
- if (messageId) {
1312
- a = context.ads.find(
1313
- (ad2) => ad2.code === p.code && ad2.messageId === messageId
1314
- );
1315
- } else {
1316
- a = context.ads.find((ad2) => ad2.code === p.code);
1317
- }
1318
- return a && !a.isLoading && !a.isStreaming || a && a.isError;
1319
- });
1320
- if (!allAdsLoadedAndNotStreaming) {
1321
- return null;
1322
- }
1323
- return ad;
1324
- }
1325
-
1326
1362
  // src/formats/InlineAd.tsx
1327
1363
  var import_jsx_runtime5 = require("react/jsx-runtime");
1328
1364
  var InlineAd = ({ code, messageId, wrapper }) => {
1329
1365
  const ad = useAd({ code, messageId });
1330
- const [linkIncluded, setLinkIncluded] = (0, import_react12.useState)(false);
1331
- const context = (0, import_react12.useContext)(AdsContext);
1332
- const styles = context?.styles?.inlineAd;
1366
+ const [linkIncluded, setLinkIncluded] = (0, import_react10.useState)(false);
1367
+ const context = (0, import_react10.useContext)(AdsContext);
1368
+ const styles = getStyles(context)?.inlineAd;
1333
1369
  useAdViewed(ad);
1334
- (0, import_react12.useEffect)(() => {
1370
+ (0, import_react10.useEffect)(() => {
1335
1371
  if (ad?.content && !ad.isStreaming && !ad.content.match(/\[.*?\]\(.*?\)/) && !linkIncluded) {
1336
1372
  setLinkIncluded(true);
1337
1373
  }
@@ -1340,16 +1376,16 @@ var InlineAd = ({ code, messageId, wrapper }) => {
1340
1376
  if (ad.isLoading || ad.content?.trim().toLowerCase().includes("none"))
1341
1377
  return null;
1342
1378
  const onProgress = (progress) => {
1343
- log_default.log(`Progress: ${progress}`);
1379
+ log.log(`Progress: ${progress}`);
1344
1380
  };
1345
1381
  const handleImageClick = (url) => {
1346
1382
  if (url) {
1347
1383
  context?.onAdClickInternal(ad);
1348
- if (import_react_native5.Platform.OS === "web") {
1384
+ if (import_react_native4.Platform.OS === "web") {
1349
1385
  window.open(url, "_blank");
1350
1386
  } else {
1351
- import_react_native5.Linking.openURL(url).catch(
1352
- (err) => log_default.warn("Failed to open URL:", err)
1387
+ import_react_native4.Linking.openURL(url).catch(
1388
+ (err) => log.warn("Failed to open URL:", err)
1353
1389
  );
1354
1390
  }
1355
1391
  }
@@ -1358,14 +1394,14 @@ var InlineAd = ({ code, messageId, wrapper }) => {
1358
1394
  if (ad.clicked && ad.rewardContent) {
1359
1395
  adContent = ad.rewardContent;
1360
1396
  }
1361
- const content = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: styles?.container, children: [
1362
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: styles?.adBadgeContainer, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: styles?.adBadgeText, children: "Ad" }) }),
1397
+ const content = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { style: styles?.container, children: [
1398
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.View, { style: styles?.adBadgeContainer, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: styles?.adBadgeText, children: "Ad" }) }),
1363
1399
  ad.imageUrl && ad.mediaPlacement === "top" && !ad.isStreaming && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1364
- import_react_native5.TouchableOpacity,
1400
+ import_react_native4.TouchableOpacity,
1365
1401
  {
1366
1402
  style: styles?.imageContainer,
1367
1403
  onPress: () => handleImageClick(ad.url),
1368
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Image, { source: { uri: ad.imageUrl }, style: styles?.image })
1404
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Image, { source: { uri: ad.imageUrl }, style: styles?.image })
1369
1405
  }
1370
1406
  ),
1371
1407
  ad.videoUrl && ad.mediaPlacement === "top" && !ad.isStreaming && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
@@ -1383,7 +1419,7 @@ var InlineAd = ({ code, messageId, wrapper }) => {
1383
1419
  clickUrl: ad.url
1384
1420
  }
1385
1421
  ),
1386
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Text, { style: styles?.contentContainer, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1422
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Text, { style: styles?.contentContainer, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1387
1423
  MarkdownText,
1388
1424
  {
1389
1425
  onLinkClick: () => context?.onAdClickInternal(ad),
@@ -1391,11 +1427,11 @@ var InlineAd = ({ code, messageId, wrapper }) => {
1391
1427
  }
1392
1428
  ) }),
1393
1429
  ad.imageUrl && ad.mediaPlacement === "bottom" && !ad.isStreaming && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1394
- import_react_native5.TouchableOpacity,
1430
+ import_react_native4.TouchableOpacity,
1395
1431
  {
1396
1432
  style: styles?.imageContainer,
1397
1433
  onPress: () => handleImageClick(ad.url),
1398
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.Image, { source: { uri: ad.imageUrl }, style: styles?.image })
1434
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.Image, { source: { uri: ad.imageUrl }, style: styles?.image })
1399
1435
  }
1400
1436
  ),
1401
1437
  ad.videoUrl && ad.mediaPlacement === "bottom" && !ad.isStreaming && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
@@ -1417,9 +1453,121 @@ var InlineAd = ({ code, messageId, wrapper }) => {
1417
1453
  return wrapper ? wrapper(content) : content;
1418
1454
  };
1419
1455
  var InlineAd_default = InlineAd;
1456
+
1457
+ // src/components/ErrorBoundary.tsx
1458
+ var import_react11 = __toESM(require("react"));
1459
+ var captureErrorFn2 = (adServerUrl, error, componentStack, context) => {
1460
+ fetch(`${adServerUrl}/error`, {
1461
+ method: "POST",
1462
+ body: JSON.stringify({
1463
+ error: error?.message,
1464
+ stack: componentStack,
1465
+ context
1466
+ })
1467
+ }).catch((e) => {
1468
+ log.warn("Error reporting client error", e);
1469
+ });
1470
+ };
1471
+ var ErrorBoundary = class extends import_react11.default.Component {
1472
+ constructor(props) {
1473
+ super(props);
1474
+ this.state = {
1475
+ hasError: false
1476
+ };
1477
+ }
1478
+ static getDerivedStateFromError() {
1479
+ return {
1480
+ hasError: true
1481
+ };
1482
+ }
1483
+ componentDidCatch(error, info) {
1484
+ const adServerUrl = this.props.adserverUrl;
1485
+ if (adServerUrl) {
1486
+ captureErrorFn2(adServerUrl, error, info?.componentStack, this.props.reqBodyParams);
1487
+ }
1488
+ }
1489
+ render() {
1490
+ if (this.state.hasError) {
1491
+ return this.props.fallback || null;
1492
+ }
1493
+ return this.props.children;
1494
+ }
1495
+ };
1496
+
1497
+ // src/context/AdsProvider.tsx
1498
+ var import_react_native5 = require("react-native");
1499
+ var import_encoding = require("react-native-polyfill-globals/src/encoding");
1500
+ var import_readable_stream = require("react-native-polyfill-globals/src/readable-stream");
1501
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1502
+ var VISITOR_ID_KEY2 = "brain-visitor-id";
1503
+ var customFetch = fetch;
1504
+ if (import_react_native5.Platform.OS !== "web") {
1505
+ (0, import_encoding.polyfill)();
1506
+ (0, import_readable_stream.polyfill)();
1507
+ customFetch = require("react-native-fetch-api").fetch;
1508
+ }
1509
+ ErrorUtils.setGlobalHandler((error, isFatal) => {
1510
+ if (!isFatal) {
1511
+ log.warn(error);
1512
+ } else {
1513
+ log.error(error);
1514
+ }
1515
+ });
1516
+ var AdsProvider = ({
1517
+ children,
1518
+ messages,
1519
+ publisherToken,
1520
+ isLoading,
1521
+ adserverUrl,
1522
+ isDisabled,
1523
+ character,
1524
+ conversationId,
1525
+ userId,
1526
+ logLevel,
1527
+ onAdView,
1528
+ onAdClick,
1529
+ styles
1530
+ }) => {
1531
+ const adServerUrlOrDefault = adserverUrl || "https://server.megabrain.co";
1532
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1533
+ ErrorBoundary,
1534
+ {
1535
+ fallback: children,
1536
+ adserverUrl: adServerUrlOrDefault,
1537
+ reqBodyParams: {
1538
+ publisherToken,
1539
+ adserverUrl,
1540
+ conversationId,
1541
+ character,
1542
+ userId,
1543
+ isLoading,
1544
+ messages
1545
+ },
1546
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1547
+ AdsProviderWithoutBoundary,
1548
+ {
1549
+ children,
1550
+ messages,
1551
+ publisherToken,
1552
+ isLoading,
1553
+ adserverUrl,
1554
+ isDisabled,
1555
+ character,
1556
+ conversationId,
1557
+ userId,
1558
+ logLevel,
1559
+ onAdView,
1560
+ onAdClick,
1561
+ reactNativePropStyles: styles,
1562
+ customFetch,
1563
+ isReactNative: true
1564
+ }
1565
+ )
1566
+ }
1567
+ );
1568
+ };
1420
1569
  // Annotate the CommonJS export names for ESM import in node:
1421
1570
  0 && (module.exports = {
1422
- AdsContext,
1423
1571
  AdsProvider,
1424
1572
  InlineAd,
1425
1573
  VISITOR_ID_KEY,