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